void code_emitter::emit_main_filter_funcs () { // init x #ifdef DEBUG_OUTPUT printf("emitting init x for %s\n", filter->name); #endif x_vars_var = setup_init_x_or_y_function(init_x_function_name(filter), "y", x_vars_type); compiler_slice_code_for_const(filter_code->first_stmt, CONST_X); emit_stmts(filter_code->first_stmt, SLICE_X_CONST); builder->CreateRet(ret_var); finish_function(); // init y #ifdef DEBUG_OUTPUT printf("emitting init y for %s\n", filter->name); #endif y_vars_var = setup_init_x_or_y_function(init_y_function_name(filter), "x", y_vars_type); compiler_slice_code_for_const(filter_code->first_stmt, CONST_Y); emit_stmts(filter_code->first_stmt, SLICE_Y_CONST); builder->CreateRet(ret_var); finish_function(); // filter #ifdef DEBUG_OUTPUT printf("emitting main filter func for %s\n", filter->name); #endif setup_filter_function(true); compiler_slice_code_for_const(filter_code->first_stmt, CONST_NONE); //fetch_all_const_values(); emit_stmts(filter_code->first_stmt, SLICE_NO_CONST); finish_function(); }
Function* FunctionAST::Codegen() { Function* theFunction = Proto->Codegen(); if(theFunction == 0) return 0; BasicBlock* BB = BasicBlock::Create(getGlobalContext(),"entry",theFunction); Builder.SetInsertPoint(BB); Proto->CreateArgumentAllocas(theFunction); vector<ExprAST*>::iterator it = Body.begin(); Value* last; for(it = Body.begin(); it != Body.end(); ++it) { last = (*it)->Codegen(); if (!last) break; } if(last) { Builder.CreateRet(last); verifyFunction(*theFunction); NamedValues.clear(); return theFunction; } //If it gets here there's an error! erase the function theFunction->eraseFromParent(); return 0; }
void code_emitter::emit_init_frame_function () { #ifdef DEBUG_OUTPUT printf("emitting init frame for %s\n", filter->name); #endif xy_vars_type = build_const_value_infos(CONST_X | CONST_Y); setup_init_frame_function(); compiler_slice_code_for_const(filter_code->first_stmt, CONST_X | CONST_Y); emit_stmts(filter_code->first_stmt, SLICE_XY_CONST); builder->CreateRet(ret_var); finish_function(); }
/* * float t1(float p) { return (p>0)?p:-p; } */ Function *createAbs(Module *m, LLVMContext &Context) { Type *floatTy = Type::getFloatTy(Context); Type *ArgTypes[] = { floatTy }; FunctionType *Ty = FunctionType::get(floatTy, ArgTypes, false); Function *func = Function::Create(Ty, GlobalValue::ExternalLinkage, "fabs", m); BasicBlock *bb = BasicBlock::Create(Context, "EntryBlock", func); IRBuilder<> *builder = new IRBuilder<>(bb); Value *arg0 = func->arg_begin();arg0->setName("arg0"); Value *v = builder->CreateFCmpOGE(arg0, ConstantFP::get(floatTy, 0.0)); Value *v0 = builder->CreateFNeg(arg0); Value *ret = builder->CreateSelect(v, arg0, v0); builder->CreateRet(ret); return func; }
int main(int argc, char **argv) { InitializeNativeTarget(); LLVMContext &Context = getGlobalContext(); Module *m = new Module("test", Context); Type *intTy = Type::getInt64Ty(Context); StructType* structTy = StructType::create(Context, "struct.list"); std::vector<Type*> fields; fields.push_back(intTy); fields.push_back(PointerType::get(structTy, 0)); if (structTy->isOpaque()) { structTy->setBody(fields, false); } /* * int f1(struct x *p) { return p->next->l1; } */ std::vector<Type*> args_type; args_type.push_back(PointerType::get(structTy, 0)); FunctionType *fnTy = FunctionType::get(intTy, args_type, false); Function *func = Function::Create(fnTy, GlobalValue::ExternalLinkage, "f1", m); Value *v = func->arg_begin(); BasicBlock *bb = BasicBlock::Create(Context, "EntryBlock", func); IRBuilder<> *builder = new IRBuilder<>(bb); v = builder->CreateStructGEP(v, 1); v = builder->CreateLoad(v, "load0"); v = builder->CreateStructGEP(v, 0); v = builder->CreateLoad(v, "load1"); builder->CreateRet(v); (*m).dump(); { ExecutionEngine *ee = EngineBuilder(m). setEngineKind(EngineKind::JIT).create(); void *f = ee->getPointerToFunction(func); typedef int (*func_t) (struct x *); struct x o = {10, NULL}, v = {}; v.next = &o; std::cout << ((func_t)f)(&v) << std::endl; } return 0; }
Value *UserFunctionSexp::codegen(SexpCompilerContext& ctx) { vector<const Type*> doubles(args ? args->length(): 0, ctx.getDoubleTy()); FunctionType *type = FunctionType::get(ctx.getDoubleTy(), doubles, false); Function *func = Function::Create(type, Function::ExternalLinkage, name, &ctx.getToplevelModule()); if (args) { Function::arg_iterator it = func->arg_begin(); ConsSexp *cons = args; SymbolSexp *sym; while (cons && (sym = dynamic_cast<SymbolSexp*>(cons->car))) { it->setName(sym->getName()); cons = dynamic_cast<ConsSexp*>(cons->cdr); ++it; } } if (body) { BasicBlock *block = BasicBlock::Create(ctx.getLLVMContext(), "entry", func); Value *val = NULL; IRBuilder<> *builder = ctx.pushBuilder(block); for (ConsSexp *cons = body; cons; cons = dynamic_cast<ConsSexp*>(cons->cdr)) { if (cons->car) val = cons->car->codegen(ctx); } if (val) builder->CreateRet(val); ctx.popBuilder(); } return func; }
codegen_value ast::distribution::createConstructor(Module *module, IRBuilder<> &builder, const string &ctor_name, Type *parameter_type, const vector<type_spec> ¶m_type_list, Value *eval, Value *sample, Value *pdf, Value *emit, Function *dtor) { //create function accepting parameters as arguments vector<Type*> arg_types; for (auto it = param_type_list.begin(); it != param_type_list.end(); ++it) arg_types.push_back((*it)->llvm_type()); FunctionType *ft = FunctionType::get(state->types["dfunc"]->llvm_type(), arg_types, false); Function *f = Function::Create(ft, Function::ExternalLinkage, ctor_name, module); BasicBlock *bb = BasicBlock::Create(getGlobalContext(), "func_entry", f); builder.SetInsertPoint(bb); //setup arguments for the alloc call Value *gd_scene = module->getNamedGlobal(".__gd_scene"); assert(gd_scene != NULL); Value *scene_ptr = builder.CreateLoad(gd_scene); //compute the shader flags codegen_value flag_val = codegen_all_flags(module, builder); return errors::codegen_call(flag_val, [&] (Value *&flag_bitmask) -> codegen_value { //get memory for a new distribution object Value *dfunc_ptr = state->types["dfunc"]->allocate(module, builder); //initialize the object and dynamically allocate parameter memory (calling a builtin function) Type* int_ptr_ty = Type::getInt32Ty(getGlobalContext())->getPointerTo(); vector<Type*> alloc_arg_types({state->types["scene_ptr"]->llvm_type(), Type::getInt32Ty(getGlobalContext()), state->types["shader_flag"]->llvm_type(), int_ptr_ty, int_ptr_ty, int_ptr_ty, int_ptr_ty, dtor->getType(), dfunc_ptr->getType()}); FunctionType *alloc_type = FunctionType::get(Type::getInt32PtrTy(getGlobalContext()), alloc_arg_types, false); Function *alloc_func = GetExternalFunction(module, "gd_builtin_alloc_dfunc", alloc_type); int param_data_size = DataLayout(module).getTypeAllocSize(parameter_type); Constant *param_size_arg = ConstantInt::get(getGlobalContext(), APInt(8*sizeof(int), param_data_size)); vector<Value*> alloc_args({scene_ptr, param_size_arg, flag_bitmask, builder.CreatePointerCast(eval, int_ptr_ty), builder.CreatePointerCast(sample, int_ptr_ty), builder.CreatePointerCast(pdf, int_ptr_ty), builder.CreatePointerCast(emit, int_ptr_ty), dtor, dfunc_ptr}); Value *param_ptr = builder.CreatePointerCast(builder.CreateCall(alloc_func, alloc_args), parameter_type->getPointerTo(), "dfunc_param_ptr"); //set each parameter auto arg_it = f->arg_begin(); unsigned int field_idx = 0; for (auto it = param_type_list.begin(); it != param_type_list.end(); ++it, ++arg_it, ++field_idx) { Value *param_copy = (*it)->copy(arg_it, module, builder); (*it)->store(param_copy, builder.CreateStructGEP(param_ptr, field_idx), module, builder); } //return the object Value *rt_val = builder.CreateLoad(dfunc_ptr, "dist_ref"); builder.CreateRet(rt_val); return f; }); }
// ============================================================================= // andOOPIsGone (formerly: createProcess) // // Formerly, OOP permitted the same SC_{METHOD,THREAD} functions to apply // to each copy of a SC_MODULE. Aaaaand it's gone ! // (but OTOH we enable better optimizations) // Creates a new C-style function that calls the old member function with the // given sc_module. The call is then inlined. // FIXME: assumes the method is non-virtual and that sc_module is the first // inherited class of the SC_MODULE // ============================================================================= Function *TwetoPassImpl::andOOPIsGone(Function * oldProc, sc_core::sc_module * initiatorMod) { if (!oldProc) return NULL; // can't statically optimize if the address of the module isn't predictible // TODO: also handle already-static variables, which also have // fixed $pc-relative addresses if (staticopt == optlevel && !permalloc::is_from (initiatorMod)) return NULL; LLVMContext & context = getGlobalContext(); FunctionType *funType = oldProc->getFunctionType(); Type *type = funType->getParamType(0); FunctionType *newProcType = FunctionType::get(oldProc->getReturnType(), ArrayRef < Type * >(), false); // Create the new function std::ostringstream id; id << proc_counter++; std::string name = oldProc->getName().str() + std::string("_clone_") + id.str(); Function *newProc = Function::Create(newProcType, Function::ExternalLinkage, name, this->llvmMod); assert(newProc->empty()); newProc->addFnAttr(Attribute::InlineHint); // Create call to old function BasicBlock *bb = BasicBlock::Create(context, "entry", newProc); IRBuilder <> *irb = new IRBuilder <> (context); irb->SetInsertPoint(bb); Value* thisAddr = createRelocatablePointer (type, initiatorMod, irb); CallInst *ci = irb->CreateCall(oldProc, ArrayRef < Value * >(std::vector<Value*>(1,thisAddr))); //bb->getInstList().insert(ci, thisAddr); if (ci->getType()->isVoidTy()) irb->CreateRetVoid(); else irb->CreateRet(ci); // The function should be valid now verifyFunction(*newProc); { // Inline the call DataLayout *td = new DataLayout(this->llvmMod); InlineFunctionInfo i(NULL, td); bool success = InlineFunction(ci, i); assert(success); verifyFunction(*newProc); } // further optimize the function inlineBasicIO (initiatorMod, newProc); newProc->dump(); return newProc; }
int main(int argc, char **argv) { InitializeNativeTarget(); LLVMContext &Context = getGlobalContext(); Module *m = new Module("test", Context); Module *TheM = LoadModule("struct.c.bc"); std::string ErrMsg; if (Linker::LinkModules(m, TheM, Linker::DestroySource, &ErrMsg)) { std::cout << "error" << ErrMsg << std::endl; return 1; } StructType* ctxTy = StructType::create(Context, "struct.kcontext_t"); StructType* sfpTy = StructType::create(Context, "struct.ksfp_t"); Type *Int64Ty = Type::getInt64Ty(Context); Type *ArgsTy[] = { PointerType::get(ctxTy, 0), PointerType::get(sfpTy, 0), Int64Ty }; Type *floatTy = Type::getDoubleTy(Context); FunctionType *fnTy = FunctionType::get(floatTy, ArgsTy, false); Function *Frand = CreateF(m, ctxTy, sfpTy); Function *F = Function::Create(fnTy, GlobalValue::ExternalLinkage, "test", m); BasicBlock *bb = BasicBlock::Create(Context, "EntryBlock", F); IRBuilder<> *builder = new IRBuilder<>(bb); Function::arg_iterator I = F->arg_begin(); Value *Ctx = I++; Value *Sfp = I++; Value *Rix = I; Value *Args[] = { Ctx, Sfp, Rix }; Value *v = builder->CreateCall(Frand, Args); builder->CreateRet(v); std::cout << "before" << std::endl; (*m).dump(); ExecutionEngine *ee = EngineBuilder(m).setEngineKind(EngineKind::JIT).create(); PassManager mpm; mpm.add(createIPSCCPPass()); mpm.add(createFunctionInliningPass()); mpm.add(createLICMPass()); mpm.add(createGVNPass()); mpm.add(createGlobalDCEPass()); mpm.run(*m); std::cout << std::endl << "before" << std::endl; (*m).dump(); //{ // void *ptr = ee->getPointerToFunction(F); // typedef struct ksfp_t { // double v; // void *p; // } ksfp_t; // typedef float (*F_t)(void *, ksfp_t *, long); // ksfp_t sfp_[100] = {}; // F_t fptr = (F_t) ptr; // std::cout << fptr(NULL, sfp_, 0) << std::endl; // asm volatile("int3"); // std::cout << ((float (*)())ptr)() << std::endl; //} return 0; }
// ============================================================================= // createProcess // // Create a new function that contains a call to the old function. // We inline the call in order to clone the old function's implementation. // ============================================================================= Function *TLMBasicPassImpl::createProcess(Function *oldProc, sc_core::sc_module *initiatorMod) { LLVMContext &context = getGlobalContext(); IntegerType *intType; if (this->is64Bit) { intType = Type::getInt64Ty(context); } else { intType = Type::getInt32Ty(context); } // Retrieve a pointer to the initiator module ConstantInt *initiatorModVal = ConstantInt::getSigned(intType,reinterpret_cast<intptr_t>(initiatorMod)); FunctionType *funType = oldProc->getFunctionType(); Type *type = funType->getParamType(0); IntToPtrInst *thisAddr = new IntToPtrInst(initiatorModVal, type, ""); // Compute the type of the new function FunctionType *oldProcType = oldProc->getFunctionType(); Value **argsBegin = new Value*[1]; Value **argsEnd = argsBegin; *argsEnd++ = thisAddr; const unsigned argsSize = argsEnd-argsBegin; Value **args = argsBegin; assert(oldProcType->getNumParams()==argsSize); assert(!oldProc->isDeclaration()); std::vector<Type*> argTypes; for (unsigned i = 0; i!=argsSize; ++i) argTypes.push_back(oldProcType->getParamType(i)); FunctionType *newProcType = FunctionType::get(oldProc->getReturnType(), ArrayRef<Type*>(argTypes), false); // Create the new function std::ostringstream id; id << proc_counter++; std::string name = oldProc->getName().str()+std::string("_clone_")+id.str(); Function *newProc = Function::Create(newProcType, Function::ExternalLinkage, name, this->llvmMod); assert(newProc->empty()); newProc->addFnAttr(Attributes::InlineHint); { // Set name of newfunc arguments and complete args Function::arg_iterator nai = newProc->arg_begin(); Function::arg_iterator oai = oldProc->arg_begin(); for (unsigned i = 0; i!=argsSize; ++i, ++oai) { nai->setName(oai->getName()); args[i] = nai; ++nai; } assert(nai==newProc->arg_end()); assert(oai==oldProc->arg_end()); } // Create call to old function BasicBlock *bb = BasicBlock::Create(context, "entry", newProc); IRBuilder<> *irb = new IRBuilder<>(context); irb->SetInsertPoint(bb); CallInst *ci = irb->CreateCall(oldProc, ArrayRef<Value*>(argsBegin, argsEnd)); bb->getInstList().insert(ci, thisAddr); if (ci->getType()->isVoidTy()) irb->CreateRetVoid(); else irb->CreateRet(ci); // The function should be valid now verifyFunction(*newProc); { // Inline the call DataLayout *td = new DataLayout(this->llvmMod); InlineFunctionInfo i(NULL, td); bool success = InlineFunction(ci, i); assert(success); verifyFunction(*newProc); } //newProc->dump(); return newProc; }
void code_emitter::emit_stmts (statement_t *stmt, unsigned int slice_flag) { for (; stmt != NULL; stmt = stmt->next) { if (!must_emit_stmt(stmt, slice_flag)) continue; switch (stmt->kind) { case STMT_NIL : g_assert(slice_flag == SLICE_IGNORE); break; case STMT_ASSIGN : #ifdef DEBUG_OUTPUT compiler_print_assign_statement(stmt); printf("\n"); #endif if (stmt->v.assign.rhs->kind == RHS_OP && stmt->v.assign.rhs->v.op.op->index == OP_OUTPUT_TUPLE) builder->CreateRet(emit_primary(&stmt->v.assign.rhs->v.op.args[0])); else set_value(stmt->v.assign.lhs, emit_rhs(stmt->v.assign.rhs)); break; case STMT_IF_COND : { Value *condition_number = emit_rhs(stmt->v.if_cond.condition); Value *condition; map<rhs_t*, Value*> rhs_map; if (condition_number->getType() == Type::Int32Ty) condition = builder->CreateICmpNE(condition_number, make_int_const(0)); else if (condition_number->getType() == Type::FloatTy) condition = builder->CreateFCmpONE(condition_number, make_float_const(0.0)); else g_assert_not_reached(); BasicBlock *then_bb = BasicBlock::Create("then", current_function); BasicBlock *else_bb = BasicBlock::Create("else"); BasicBlock *merge_bb = BasicBlock::Create("ifcont"); builder->CreateCondBr(condition, then_bb, else_bb); builder->SetInsertPoint(then_bb); emit_stmts(stmt->v.if_cond.consequent, slice_flag); emit_phi_rhss(stmt->v.if_cond.exit, true, &rhs_map, slice_flag); builder->CreateBr(merge_bb); then_bb = builder->GetInsertBlock(); current_function->getBasicBlockList().push_back(else_bb); builder->SetInsertPoint(else_bb); emit_stmts(stmt->v.if_cond.alternative, slice_flag); emit_phi_rhss(stmt->v.if_cond.exit, false, &rhs_map, slice_flag); builder->CreateBr(merge_bb); else_bb = builder->GetInsertBlock(); current_function->getBasicBlockList().push_back(merge_bb); builder->SetInsertPoint(merge_bb); emit_phis(stmt->v.if_cond.exit, then_bb, else_bb, rhs_map, slice_flag); } break; case STMT_WHILE_LOOP: { BasicBlock *start_bb = builder->GetInsertBlock(); BasicBlock *entry_bb = BasicBlock::Create("entry", current_function); BasicBlock *body_bb = BasicBlock::Create("body"); BasicBlock *exit_bb = BasicBlock::Create("exit"); map<rhs_t*, Value*> rhs_map; emit_phi_rhss(stmt->v.while_loop.entry, true, &rhs_map, slice_flag); builder->CreateBr(entry_bb); builder->SetInsertPoint(entry_bb); emit_phis(stmt->v.while_loop.entry, start_bb, NULL, rhs_map, slice_flag); Value *invariant_number = emit_rhs(stmt->v.while_loop.invariant); Value *invariant; if (invariant_number->getType() == Type::Int32Ty) invariant = builder->CreateICmpNE(invariant_number, make_int_const(0)); else if (invariant_number->getType() == Type::FloatTy) invariant = builder->CreateFCmpONE(invariant_number, make_float_const(0.0)); else g_assert_not_reached(); builder->CreateCondBr(invariant, body_bb, exit_bb); current_function->getBasicBlockList().push_back(body_bb); builder->SetInsertPoint(body_bb); emit_stmts(stmt->v.while_loop.body, slice_flag); body_bb = builder->GetInsertBlock(); emit_phi_rhss(stmt->v.while_loop.entry, false, &rhs_map, slice_flag); emit_phis(stmt->v.while_loop.entry, NULL, body_bb, rhs_map, slice_flag); builder->CreateBr(entry_bb); current_function->getBasicBlockList().push_back(exit_bb); builder->SetInsertPoint(exit_bb); } break; default: g_assert_not_reached(); break; } } }
Value* Return::codeGen(CodeGenContext &context) { IRBuilder<> *builder = context.currentBuilder(); Value *returnValue = returnExpr.codeGen(context); return builder->CreateRet(returnValue); }
JITFunction* CompilePipeline(Pipeline *pipeline, Thread *thread) { size_t i = 0; size_t size = 0; std::unique_ptr<Module> owner = make_unique<Module>("PipelineFunction", thread->context); Module *module = owner.get(); std::string fname = std::string("PipelineFunction") + std::to_string(thread->functions++); size_t input_count = pipeline->inputData->objects.size(); size_t output_count = pipeline->outputData->objects.size(); size_t function_arg_count = 6; size_t arg_count = input_count + output_count + (function_arg_count - 2); size_t start_addr = input_count + output_count; size_t end_addr = start_addr + 1; size_t result_sizes_addr = end_addr + 1; size_t thread_nr_addr = result_sizes_addr + 1; IRBuilder<> *builder = &thread->builder; auto passmanager = CreatePassManager(module, thread->jit.get()); module->setDataLayout(thread->jit->getTargetMachine().createDataLayout()); Type *int8_tpe = Type::getInt8Ty(thread->context); Type *int8ptr_tpe = PointerType::get(int8_tpe, 0); Type *int8ptrptr_tpe = PointerType::get(int8ptr_tpe, 0); Type *int64_tpe = Type::getInt64Ty(thread->context); Type *int64ptr_tpe = PointerType::get(int64_tpe, 0); JITInformation info; // arguments of the function // the arguments are (void **result, void** inputs, size_t start, size_t end); // note that we don't actually use void**, we use int8**, because LLVM does not support void pointers std::vector<Type*> arguments(function_arg_count); i = 0; arguments[i++] = int8ptrptr_tpe; // void** results arguments[i++] = int8ptrptr_tpe; // void** inputs arguments[i++] = int64_tpe; // size_t start arguments[i++] = int64_tpe; // size_t end arguments[i++] = int64ptr_tpe; // size_t* result_sizes arguments[i++] = int64_tpe; // size_t thread_nr assert(i == function_arg_count); /*for(auto inputs = pipeline->inputData->objects.begin(); inputs != pipeline->inputData->objects.end(); inputs++, i++) { arguments[i] = PointerType::get(getLLVMType(thread->context, inputs->type), 0); } for(auto outputs = pipeline->outputData->objects.begin(); outputs != pipeline->outputData->objects.end(); outputs++, i++) { arguments[i] = PointerType::get(getLLVMType(thread->context, outputs->type), 0); }*/ // create the LLVM function FunctionType *prototype = FunctionType::get(int64_tpe, arguments, false); Function *function = Function::Create(prototype, GlobalValue::ExternalLinkage, fname, module); function->setCallingConv(CallingConv::C); // create the basic blocks BasicBlock *loop_entry = BasicBlock::Create(thread->context, "entry", function, 0); BasicBlock *loop_cond = BasicBlock::Create(thread->context, "for.cond", function, 0); BasicBlock *loop_body = BasicBlock::Create(thread->context, "for.body", function, 0); BasicBlock *loop_inc = BasicBlock::Create(thread->context, "for.inc", function, 0); BasicBlock *loop_end = BasicBlock::Create(thread->context, "for.end", function, 0); info.builder = &thread->builder; info.context = &thread->context; info.function = function; info.loop_entry = loop_entry; info.loop_cond = loop_cond; info.loop_body = loop_body; info.loop_inc = loop_inc; info.loop_end = loop_end; info.current = loop_body; #ifndef _NOTDEBUG // argument names (for debug purposes only) std::vector<std::string> argument_names(arg_count); i = 0; for(auto inputs = pipeline->inputData->objects.begin(); inputs != pipeline->inputData->objects.end(); inputs++, i++) { argument_names[i] = std::string("inputs") + std::to_string(i); } for(auto outputs = pipeline->outputData->objects.begin(); outputs != pipeline->outputData->objects.end(); outputs++, i++) { argument_names[i] = std::string("outputs") + std::to_string(i - input_count); } argument_names[i++] = "start"; argument_names[i++] = "end"; argument_names[i++] = "result_sizes"; argument_names[i++] = "thread_nr"; #endif std::vector<AllocaInst*> argument_addresses(arg_count); builder->SetInsertPoint(loop_entry); { // allocate space for the arguments auto args = function->arg_begin(); i = 0; for(auto outputs = pipeline->outputData->objects.begin(); outputs != pipeline->outputData->objects.end(); outputs++, i++) { Type *column_type = PointerType::get(getLLVMType(thread->context, outputs->source->type), 0); Value *voidptrptr = builder->CreateGEP(int8ptr_tpe, &*args, ConstantInt::get(int64_tpe, i, true)); Value *voidptr = builder->CreateLoad(voidptrptr, "voidptr"); Value *columnptr = builder->CreatePointerCast(voidptr, column_type); argument_addresses[i] = builder->CreateAlloca(column_type, nullptr, argument_names[i]); builder->CreateStore(columnptr, argument_addresses[i]); outputs->alloca_address = (void*) argument_addresses[i]; if (size == 0 || size == 1) { assert(outputs->source->size >= 0); size = outputs->source->size; } assert(size == outputs->source->size || outputs->source->size == 1); } args++; for(auto inputs = pipeline->inputData->objects.begin(); inputs != pipeline->inputData->objects.end(); inputs++, i++) { Type *column_type = PointerType::get(getLLVMType(thread->context, inputs->source->type), 0); Value *voidptrptr = builder->CreateGEP(int8ptr_tpe, &*args, ConstantInt::get(int64_tpe, i - output_count, true)); Value *voidptr = builder->CreateLoad(voidptrptr, "voidptr"); Value *columnptr = builder->CreatePointerCast(voidptr, column_type); argument_addresses[i] = builder->CreateAlloca(column_type, nullptr, argument_names[i]); builder->CreateStore(columnptr, argument_addresses[i]); inputs->alloca_address = (void*) argument_addresses[i]; if (size == 0 || size == 1) { assert(inputs->source->size >= 0); size = inputs->source->size; } assert(size == inputs->source->size || inputs->source->size == 1); } args++; argument_addresses[i] = builder->CreateAlloca(arguments[2], nullptr, argument_names[i]); builder->CreateStore(&*args, argument_addresses[i]); args++; i++; argument_addresses[i] = builder->CreateAlloca(arguments[3], nullptr, argument_names[i]); builder->CreateStore(&*args, argument_addresses[i]); args++; i++; argument_addresses[i] = builder->CreateAlloca(arguments[4], nullptr, argument_names[i]); builder->CreateStore(&*args, argument_addresses[i]); args++; i++; argument_addresses[i] = builder->CreateAlloca(arguments[5], nullptr, argument_names[i]); builder->CreateStore(&*args, argument_addresses[i]); args++; i++; assert(args == function->arg_end()); assert(i == arg_count); info.index_addr = argument_addresses[start_addr]; info.thread_addr = argument_addresses[thread_nr_addr]; PerformInitialization(info, pipeline->operation); builder->CreateBr(loop_cond); } // for loop condition: index < end builder->SetInsertPoint(loop_cond); { LoadInst *index = builder->CreateLoad(argument_addresses[start_addr], "index"); LoadInst *end = builder->CreateLoad(argument_addresses[end_addr], "end"); Value *condition = builder->CreateICmpSLT(index, end, "index < end"); builder->CreateCondBr(condition, loop_body, loop_end); } // loop body: perform the computation builder->SetInsertPoint(loop_body); { LoadInst *index = builder->CreateLoad(argument_addresses[start_addr], "index"); info.index = index; info.index_addr = argument_addresses[start_addr]; // perform the computation over the given index // we don't use the return value because the final assignment has already taken place Value *v = PerformOperation(info, thread->builder, thread->context, pipeline->operation, pipeline->inputData, pipeline->outputData); if (v == NULL) { // failed to perform operation printf("Failed to compile pipeline %s\n", pipeline->name); return NULL; } builder->CreateBr(loop_inc); } // loop increment: index++ builder->SetInsertPoint(loop_inc); { LoadInst *index = builder->CreateLoad(argument_addresses[start_addr], "index"); Value *incremented_index = builder->CreateAdd(index, ConstantInt::get(int64_tpe, 1, true), "index++"); builder->CreateStore(incremented_index, argument_addresses[start_addr]); builder->CreateBr(loop_cond); } // loop end: return; (nothing happens here because we have no return value) builder->SetInsertPoint(loop_end); { // return the output size of each of the columns int i = 0; Value *result_sizes = builder->CreateLoad(argument_addresses[result_sizes_addr], "result_sizes[]"); for(auto it = pipeline->outputData->objects.begin(); it != pipeline->outputData->objects.end(); it++) { Value* output_count; if (it->index_addr) { output_count = builder->CreateLoad((Value*) it->index_addr, "count"); } else { output_count = ConstantInt::get(int64_tpe, 1, true); } Value *output_addr = builder->CreateGEP(int64_tpe, result_sizes, ConstantInt::get(int64_tpe, i, true)); builder->CreateStore(output_count, output_addr); i++; } builder->CreateRet(ConstantInt::get(int64_tpe, 0, true)); } #ifndef _NOTDEBUG verifyFunction(*function); verifyModule(*module); #endif //printf("LLVM for pipeline %s\n", pipeline->name); module->dump(); passmanager->run(*function); // dump generated LLVM code //module->dump(); auto handle = thread->jit->addModule(std::move(owner)); jit_function compiled_function = (jit_function) thread->jit->findSymbol(fname).getAddress(); if (!compiled_function) { printf("Error creating function.\n"); return NULL; } JITFunction *jf = CreateJITFunction(thread, pipeline); jf->size = size; jf->function = compiled_function; jf->jit = thread->jit.get(); jf->handle = handle; assert(jf->function); return jf; }