void GCOVProfiler::insertIndirectCounterIncrement() { Function *Fn = cast<Function>(GCOVProfiler::getIncrementIndirectCounterFunc()); Fn->setUnnamedAddr(true); Fn->setLinkage(GlobalValue::InternalLinkage); Fn->addFnAttr(Attributes::NoInline); if (NoRedZone) Fn->addFnAttr(Attributes::NoRedZone); Type *Int32Ty = Type::getInt32Ty(*Ctx); Type *Int64Ty = Type::getInt64Ty(*Ctx); Constant *NegOne = ConstantInt::get(Int32Ty, 0xffffffff); // Create basic blocks for function. BasicBlock *BB = BasicBlock::Create(*Ctx, "entry", Fn); IRBuilder<> Builder(BB); BasicBlock *PredNotNegOne = BasicBlock::Create(*Ctx, "", Fn); BasicBlock *CounterEnd = BasicBlock::Create(*Ctx, "", Fn); BasicBlock *Exit = BasicBlock::Create(*Ctx, "exit", Fn); // uint32_t pred = *predecessor; // if (pred == 0xffffffff) return; Argument *Arg = Fn->arg_begin(); Arg->setName("predecessor"); Value *Pred = Builder.CreateLoad(Arg, "pred"); Value *Cond = Builder.CreateICmpEQ(Pred, NegOne); BranchInst::Create(Exit, PredNotNegOne, Cond, BB); Builder.SetInsertPoint(PredNotNegOne); // uint64_t *counter = counters[pred]; // if (!counter) return; Value *ZExtPred = Builder.CreateZExt(Pred, Int64Ty); Arg = llvm::next(Fn->arg_begin()); Arg->setName("counters"); Value *GEP = Builder.CreateGEP(Arg, ZExtPred); Value *Counter = Builder.CreateLoad(GEP, "counter"); Cond = Builder.CreateICmpEQ(Counter, Constant::getNullValue(Int64Ty->getPointerTo())); Builder.CreateCondBr(Cond, Exit, CounterEnd); // ++*counter; Builder.SetInsertPoint(CounterEnd); Value *Add = Builder.CreateAdd(Builder.CreateLoad(Counter), ConstantInt::get(Int64Ty, 1)); Builder.CreateStore(Add, Counter); Builder.CreateBr(Exit); // Fill in the exit block. Builder.SetInsertPoint(Exit); Builder.CreateRetVoid(); }
static Function* createAdd1(Module *M) { // Create the add1 function entry and insert this entry into module M. The // function will have a return type of "int" and take an argument of "int". // The '0' terminates the list of argument types. Function *Add1F = cast<Function>(M->getOrInsertFunction("add1", Type::Int32Ty, Type::Int32Ty, (Type *)0)); // Add a basic block to the function. As before, it automatically inserts // because of the last argument. BasicBlock *BB = BasicBlock::Create("EntryBlock", Add1F); // Get pointers to the constant `1'. Value *One = ConstantInt::get(Type::Int32Ty, 1); // Get pointers to the integer argument of the add1 function... assert(Add1F->arg_begin() != Add1F->arg_end()); // Make sure there's an arg Argument *ArgX = Add1F->arg_begin(); // Get the arg ArgX->setName("AnArg"); // Give it a nice symbolic name for fun. // Create the add instruction, inserting it into the end of BB. Instruction *Add = BinaryOperator::CreateAdd(One, ArgX, "addresult", BB); // Create the return instruction and add it to the basic block ReturnInst::Create(Add, BB); // Now, function add1 is ready. return Add1F; }
virtual void visit(Function *type) { Function *funTy = control()->newFunction(0, 0); funTy->copy(type); funTy->setConst(type->isConst()); funTy->setVolatile(type->isVolatile()); funTy->setName(rewrite->rewriteName(type->name())); funTy->setReturnType(rewrite->rewriteType(type->returnType())); for (unsigned i = 0, argc = type->argumentCount(); i < argc; ++i) { Symbol *arg = type->argumentAt(i); Argument *newArg = control()->newArgument(0, 0); newArg->copy(arg); newArg->setName(rewrite->rewriteName(arg->name())); newArg->setType(rewrite->rewriteType(arg->type())); // the copy() call above set the scope to 'type' // reset it to 0 before adding addMember to avoid assert newArg->resetEnclosingScope(); funTy->addMember(newArg); } temps.append(funTy); }
Argument *Engine::newArgument(Function *function, const QString &name, const Type *type) { Argument *a = new Argument(function); a->setName(name); a->setType(type); _symbols.append(a); return a; }
static Function *CreateFibFunction(Module *M, LLVMContext &Context) { // Create the fib function and insert it into module M. This function is said // to return an int and take an int parameter. Function *FibF = cast<Function>(M->getOrInsertFunction("fib", Type::getInt32Ty(Context), Type::getInt32Ty(Context), (Type *)0)); // Add a basic block to the function. BasicBlock *BB = BasicBlock::Create(Context, "EntryBlock", FibF); // Get pointers to the constants. Value *One = ConstantInt::get(Type::getInt32Ty(Context), 1); Value *Two = ConstantInt::get(Type::getInt32Ty(Context), 2); // Get pointer to the integer argument of the add1 function... Argument *ArgX = FibF->arg_begin(); // Get the arg. ArgX->setName("AnArg"); // Give it a nice symbolic name for fun. // Create the true_block. BasicBlock *RetBB = BasicBlock::Create(Context, "return", FibF); // Create an exit block. BasicBlock* RecurseBB = BasicBlock::Create(Context, "recurse", FibF); // Create the "if (arg <= 2) goto exitbb" Value *CondInst = new ICmpInst(*BB, ICmpInst::ICMP_SLE, ArgX, Two, "cond"); BranchInst::Create(RetBB, RecurseBB, CondInst, BB); // Create: ret int 1 ReturnInst::Create(Context, One, RetBB); // create fib(x-1) Value *Sub = BinaryOperator::CreateSub(ArgX, One, "arg", RecurseBB); CallInst *CallFibX1 = CallInst::Create(FibF, Sub, "fibx1", RecurseBB); CallFibX1->setTailCall(); // create fib(x-2) Sub = BinaryOperator::CreateSub(ArgX, Two, "arg", RecurseBB); CallInst *CallFibX2 = CallInst::Create(FibF, Sub, "fibx2", RecurseBB); CallFibX2->setTailCall(); // fib(x-1)+fib(x-2) Value *Sum = BinaryOperator::CreateAdd(CallFibX1, CallFibX2, "addresult", RecurseBB); // Create the return instruction and add it to the basic block ReturnInst::Create(Context, Sum, RecurseBB); return FibF; }
void ActionRequest::initArgumentList() { Node *actNode = getActionNode(); if (actNode == NULL) return; int nArgNodes = actNode->getNNodes(); argumentList.clear(); for (int n = 0; n < nArgNodes; n++) { Argument *arg = new Argument(); Node *argNode = actNode->getNode(n); arg->setName(argNode->getName()); arg->setValue(argNode->getValue()); argumentList.add(arg); } }
int main() { InitializeNativeTarget(); LLVMContext Context; // Create some module to put our function into it. Module *M = new Module("test", Context); // Create the add1 function entry and insert this entry into module M. The // function will have a return type of "int" and take an argument of "int". // The '0' terminates the list of argument types. Function *Add1F = cast<Function>(M->getOrInsertFunction("add1", Type::getInt32Ty(Context), Type::getInt32Ty(Context), (Type *)0)); // Add a basic block to the function. As before, it automatically inserts // because of the last argument. BasicBlock *BB = BasicBlock::Create(Context, "EntryBlock", Add1F); // Create a basic block builder with default parameters. The builder will // automatically append instructions to the basic block `BB'. IRBuilder<> builder(BB); // Get pointers to the constant `1'. Value *One = builder.getInt32(1); // Get pointers to the integer argument of the add1 function... assert(Add1F->arg_begin() != Add1F->arg_end()); // Make sure there's an arg Argument *ArgX = Add1F->arg_begin(); // Get the arg ArgX->setName("AnArg"); // Give it a nice symbolic name for fun. // Create the add instruction, inserting it into the end of BB. Value *Add = builder.CreateAdd(One, ArgX); // Create the return instruction and add it to the basic block builder.CreateRet(Add); // Now, function add1 is ready. // Now we're going to create function `foo', which returns an int and takes no // arguments. Function *FooF = cast<Function>(M->getOrInsertFunction("foo", Type::getInt32Ty(Context), (Type *)0)); // Add a basic block to the FooF function. BB = BasicBlock::Create(Context, "EntryBlock", FooF); // Tell the basic block builder to attach itself to the new basic block builder.SetInsertPoint(BB); // Get pointer to the constant `10'. Value *Ten = builder.getInt32(10); // Pass Ten to the call to Add1F CallInst *Add1CallRes = builder.CreateCall(Add1F, Ten); Add1CallRes->setTailCall(true); // Create the return instruction and add it to the basic block. builder.CreateRet(Add1CallRes); // Now we create the JIT. ExecutionEngine* EE = EngineBuilder(M).create(); outs() << "We just constructed this LLVM module:\n\n" << *M; outs() << "\n\nRunning foo: "; outs().flush(); // Call the `foo' function with no arguments: std::vector<GenericValue> noargs; GenericValue gv = EE->runFunction(FooF, noargs); // Import result of execution: outs() << "Result: " << gv.IntVal << "\n"; EE->freeMachineCodeForFunction(FooF); delete EE; llvm_shutdown(); return 0; }
int main() { // Create some module to put our function into it. Module *M = new Module("test"); // Create the add1 function entry and insert this entry into module M. The // function will have a return type of "int" and take an argument of "int". // The '0' terminates the list of argument types. Function *Add1F = cast<Function>(M->getOrInsertFunction("add1", Type::Int32Ty, Type::Int32Ty, (Type *)0)); // Add a basic block to the function. As before, it automatically inserts // because of the last argument. BasicBlock *BB = BasicBlock::Create("EntryBlock", Add1F); // Get pointers to the constant `1'. Value *One = ConstantInt::get(Type::Int32Ty, 1); // Get pointers to the integer argument of the add1 function... assert(Add1F->arg_begin() != Add1F->arg_end()); // Make sure there's an arg Argument *ArgX = Add1F->arg_begin(); // Get the arg ArgX->setName("AnArg"); // Give it a nice symbolic name for fun. // Create the add instruction, inserting it into the end of BB. Instruction *Add = BinaryOperator::CreateAdd(One, ArgX, "addresult", BB); // Create the return instruction and add it to the basic block ReturnInst::Create(Add, BB); // Now, function add1 is ready. // Now we going to create function `foo', which returns an int and takes no // arguments. Function *FooF = cast<Function>(M->getOrInsertFunction("foo", Type::Int32Ty, (Type *)0)); // Add a basic block to the FooF function. BB = BasicBlock::Create("EntryBlock", FooF); // Get pointers to the constant `10'. Value *Ten = ConstantInt::get(Type::Int32Ty, 10); // Pass Ten to the call call: CallInst *Add1CallRes = CallInst::Create(Add1F, Ten, "add1", BB); Add1CallRes->setTailCall(true); // Create the return instruction and add it to the basic block. ReturnInst::Create(Add1CallRes, BB); // Now we create the JIT. ExistingModuleProvider* MP = new ExistingModuleProvider(M); ExecutionEngine* EE = ExecutionEngine::create(MP, false); outs() << "We just constructed this LLVM module:\n\n" << *M; outs() << "\n\nRunning foo: "; outs().flush(); // Call the `foo' function with no arguments: std::vector<GenericValue> noargs; GenericValue gv = EE->runFunction(FooF, noargs); // Import result of execution: outs() << "Result: " << gv.IntVal << "\n"; return 0; }
void SharkFunction::initialize(const char *name) { // Create the function _function = Function::Create( entry_point_type(), GlobalVariable::InternalLinkage, name); // Get our arguments Function::arg_iterator ai = function()->arg_begin(); Argument *method = ai++; method->setName("method"); Argument *osr_buf = NULL; if (is_osr()) { osr_buf = ai++; osr_buf->setName("osr_buf"); } Argument *base_pc = ai++; base_pc->setName("base_pc"); code_buffer()->set_base_pc(base_pc); Argument *thread = ai++; thread->setName("thread"); set_thread(thread); // Create the list of blocks set_block_insertion_point(NULL); _blocks = NEW_RESOURCE_ARRAY(SharkTopLevelBlock*, block_count()); for (int i = 0; i < block_count(); i++) { ciTypeFlow::Block *b = flow()->pre_order_at(i); // Work around a bug in pre_order_at() that does not return // the correct pre-ordering. If pre_order_at() were correct // this line could simply be: // _blocks[i] = new SharkTopLevelBlock(this, b); _blocks[b->pre_order()] = new SharkTopLevelBlock(this, b); } // Walk the tree from the start block to determine which // blocks are entered and which blocks require phis SharkTopLevelBlock *start_block = block(flow()->start_block_num()); assert(start_block->start() == flow()->start_bci(), "blocks out of order"); start_block->enter(); // Initialize all entered blocks for (int i = 0; i < block_count(); i++) { if (block(i)->entered()) block(i)->initialize(); } // Create and push our stack frame set_block_insertion_point(&function()->front()); builder()->SetInsertPoint(CreateBlock()); _stack = SharkStack::CreateBuildAndPushFrame(this, method); // Create the entry state SharkState *entry_state; if (is_osr()) { entry_state = new SharkOSREntryState(start_block, method, osr_buf); // Free the OSR buffer builder()->CreateCall(builder()->osr_migration_end(), osr_buf); } else { entry_state = new SharkNormalEntryState(start_block, method); // Lock if necessary if (is_synchronized()) { SharkTopLevelBlock *locker = new SharkTopLevelBlock(this, start_block->ciblock()); locker->add_incoming(entry_state); set_block_insertion_point(start_block->entry_block()); locker->acquire_method_lock(); entry_state = locker->current_state(); } } // Transition into the method proper start_block->add_incoming(entry_state); builder()->CreateBr(start_block->entry_block()); // Parse the blocks for (int i = 0; i < block_count(); i++) { if (!block(i)->entered()) continue; if (i + 1 < block_count()) set_block_insertion_point(block(i + 1)->entry_block()); else set_block_insertion_point(NULL); block(i)->emit_IR(); } do_deferred_zero_checks(); }
void SharkNativeWrapper::initialize(const char *name) { // Create the function _function = Function::Create( SharkType::entry_point_type(), GlobalVariable::InternalLinkage, name); // Get our arguments Function::arg_iterator ai = function()->arg_begin(); Argument *method = ai++; method->setName("method"); Argument *base_pc = ai++; base_pc->setName("base_pc"); code_buffer()->set_base_pc(base_pc); Argument *thread = ai++; thread->setName("thread"); set_thread(thread); // Create and push our stack frame builder()->SetInsertPoint(CreateBlock()); _stack = SharkStack::CreateBuildAndPushFrame(this, method); NOT_PRODUCT(method = NULL); // Create the oopmap. We use the one oopmap for every call site in // the wrapper, which results in the odd mild inefficiency but is a // damn sight easier to code. OopMap *oopmap = new OopMap( SharkStack::oopmap_slot_munge(stack()->oopmap_frame_size()), SharkStack::oopmap_slot_munge(arg_size())); oopmap->set_oop(SharkStack::slot2reg(stack()->method_slot_offset())); // Set up the oop_tmp slot if required: // - For static methods we use it to handlize the class argument // for the call, and to protect the same during slow path locks // (if synchronized). // - For methods returning oops, we use it to protect the return // value across safepoints or slow path unlocking. if (is_static() || is_returning_oop()) { _oop_tmp_slot = stack()->slot_addr( stack()->oop_tmp_slot_offset(), SharkType::oop_type(), "oop_tmp_slot"); oopmap->set_oop(SharkStack::slot2reg(stack()->oop_tmp_slot_offset())); } // Set up the monitor slot, for synchronized methods if (is_synchronized()) { Unimplemented(); _lock_slot_offset = 23; } // Start building the argument list std::vector<const Type*> param_types; std::vector<Value*> param_values; const PointerType *box_type = PointerType::getUnqual(SharkType::oop_type()); // First argument is the JNIEnv param_types.push_back(SharkType::jniEnv_type()); param_values.push_back( builder()->CreateAddressOfStructEntry( thread, JavaThread::jni_environment_offset(), SharkType::jniEnv_type(), "jni_environment")); // For static methods, the second argument is the class if (is_static()) { builder()->CreateStore( builder()->CreateInlineOop( JNIHandles::make_local( target()->method_holder()->klass_part()->java_mirror())), oop_tmp_slot()); param_types.push_back(box_type); param_values.push_back(oop_tmp_slot()); _receiver_slot_offset = stack()->oop_tmp_slot_offset(); } else if (is_returning_oop()) { // The oop_tmp slot is registered in the oopmap, // so we need to clear it. This is one of the // mild inefficiencies I mentioned earlier. builder()->CreateStore(LLVMValue::null(), oop_tmp_slot()); } // Parse the arguments for (int i = 0; i < arg_size(); i++) { int slot_offset = stack()->locals_slots_offset() + arg_size() - 1 - i; int adjusted_offset = slot_offset; BasicBlock *null, *not_null, *merge; Value *box; PHINode *phi; switch (arg_type(i)) { case T_VOID: break; case T_OBJECT: case T_ARRAY: null = CreateBlock("null"); not_null = CreateBlock("not_null"); merge = CreateBlock("merge"); box = stack()->slot_addr(slot_offset, SharkType::oop_type()); builder()->CreateCondBr( builder()->CreateICmp( ICmpInst::ICMP_EQ, builder()->CreateLoad(box), LLVMValue::null()), null, not_null); builder()->SetInsertPoint(null); builder()->CreateBr(merge); builder()->SetInsertPoint(not_null); builder()->CreateBr(merge); builder()->SetInsertPoint(merge); phi = builder()->CreatePHI(box_type, "boxed_object"); phi->addIncoming(ConstantPointerNull::get(box_type), null); phi->addIncoming(box, not_null); box = phi; param_types.push_back(box_type); param_values.push_back(box); oopmap->set_oop(SharkStack::slot2reg(slot_offset)); if (i == 0 && !is_static()) _receiver_slot_offset = slot_offset; break; case T_LONG: case T_DOUBLE: adjusted_offset--; // fall through default: const Type *param_type = SharkType::to_stackType(arg_type(i)); param_types.push_back(param_type); param_values.push_back( builder()->CreateLoad(stack()->slot_addr(adjusted_offset, param_type))); } } // The oopmap is now complete, and everything is written // into the frame except the PC. int pc_offset = code_buffer()->create_unique_offset(); _oop_maps = new OopMapSet(); oop_maps()->add_gc_map(pc_offset, oopmap); builder()->CreateStore( builder()->code_buffer_address(pc_offset), stack()->slot_addr(stack()->pc_slot_offset())); // Set up the Java frame anchor stack()->CreateSetLastJavaFrame(); // Lock if necessary if (is_synchronized()) Unimplemented(); // Change the thread state to _thread_in_native CreateSetThreadState(_thread_in_native); // Make the call BasicType result_type = target()->result_type(); const Type* return_type; if (result_type == T_VOID) return_type = SharkType::void_type(); else if (is_returning_oop()) return_type = box_type; else return_type = SharkType::to_arrayType(result_type); Value* native_function = builder()->CreateIntToPtr( LLVMValue::intptr_constant((intptr_t) target()->native_function()), PointerType::getUnqual( FunctionType::get(return_type, param_types, false))); Value *result = builder()->CreateCall( native_function, param_values.begin(), param_values.end()); // Start the transition back to _thread_in_Java CreateSetThreadState(_thread_in_native_trans); // Make sure new state is visible in the GC thread if (os::is_MP()) { if (UseMembar) builder()->CreateMemoryBarrier(SharkBuilder::BARRIER_STORELOAD); else CreateWriteMemorySerializePage(); } // Handle safepoint operations, pending suspend requests, // and pending asynchronous exceptions. BasicBlock *check_thread = CreateBlock("check_thread"); BasicBlock *do_safepoint = CreateBlock("do_safepoint"); BasicBlock *safepointed = CreateBlock("safepointed"); Value *global_state = builder()->CreateLoad( builder()->CreateIntToPtr( LLVMValue::intptr_constant( (intptr_t) SafepointSynchronize::address_of_state()), PointerType::getUnqual(SharkType::jint_type())), "global_state"); builder()->CreateCondBr( builder()->CreateICmpNE( global_state, LLVMValue::jint_constant(SafepointSynchronize::_not_synchronized)), do_safepoint, check_thread); builder()->SetInsertPoint(check_thread); Value *thread_state = builder()->CreateValueOfStructEntry( thread, JavaThread::suspend_flags_offset(), SharkType::jint_type(), "thread_state"); builder()->CreateCondBr( builder()->CreateICmpNE( thread_state, LLVMValue::jint_constant(0)), do_safepoint, safepointed); builder()->SetInsertPoint(do_safepoint); builder()->CreateCall( builder()->check_special_condition_for_native_trans(), thread); builder()->CreateBr(safepointed); // Finally we can change the thread state to _thread_in_Java builder()->SetInsertPoint(safepointed); CreateSetThreadState(_thread_in_Java); // Clear the frame anchor stack()->CreateResetLastJavaFrame(); // If there is a pending exception then we can just unwind and // return. It seems totally wrong that unlocking is skipped here // but apparently the template interpreter does this so we do too. BasicBlock *exception = CreateBlock("exception"); BasicBlock *no_exception = CreateBlock("no_exception"); builder()->CreateCondBr( builder()->CreateICmpEQ( CreateLoadPendingException(), LLVMValue::null()), no_exception, exception); builder()->SetInsertPoint(exception); CreateResetHandleBlock(); stack()->CreatePopFrame(0); builder()->CreateRet(LLVMValue::jint_constant(0)); builder()->SetInsertPoint(no_exception); // If the result was an oop then unbox it before // releasing the handle it might be protected by if (is_returning_oop()) { BasicBlock *null = builder()->GetInsertBlock(); BasicBlock *not_null = CreateBlock("not_null"); BasicBlock *merge = CreateBlock("merge"); builder()->CreateCondBr( builder()->CreateICmpNE(result, ConstantPointerNull::get(box_type)), not_null, merge); builder()->SetInsertPoint(not_null); Value *unboxed_result = builder()->CreateLoad(result); builder()->CreateBr(merge); builder()->SetInsertPoint(merge); PHINode *phi = builder()->CreatePHI(SharkType::oop_type(), "result"); phi->addIncoming(LLVMValue::null(), null); phi->addIncoming(unboxed_result, not_null); result = phi; } // Reset handle block CreateResetHandleBlock(); // Unlock if necessary. if (is_synchronized()) Unimplemented(); // Unwind and return Value *result_addr = stack()->CreatePopFrame(type2size[result_type]); if (result_type != T_VOID) { bool needs_cast = false; bool is_signed = false; switch (result_type) { case T_BOOLEAN: result = builder()->CreateICmpNE(result, LLVMValue::jbyte_constant(0)); needs_cast = true; break; case T_CHAR: needs_cast = true; break; case T_BYTE: case T_SHORT: needs_cast = true; is_signed = true; break; } if (needs_cast) { result = builder()->CreateIntCast( result, SharkType::to_stackType(result_type), is_signed); } builder()->CreateStore( result, builder()->CreateIntToPtr( result_addr, PointerType::getUnqual(SharkType::to_stackType(result_type)))); } builder()->CreateRet(LLVMValue::jint_constant(0)); }
// Creates the helper function that will do the setjmp() call and // function call for implementing Invoke. Creates the call to the // helper function. Returns a Value which is zero on the normal // execution path and non-zero if the landingpad block should be // entered. Value *FuncRewriter::createSetjmpWrappedCall(InvokeInst *Invoke) { Type *I32 = Type::getInt32Ty(Func->getContext()); // Allocate space for storing the invoke's result temporarily (so // that the helper function can return multiple values). We don't // need to do this if the result is unused, and we can't if its type // is void. Instruction *ResultAlloca = NULL; if (!Invoke->use_empty()) { ResultAlloca = new AllocaInst(Invoke->getType(), "invoke_result_ptr"); Func->getEntryBlock().getInstList().push_front(ResultAlloca); } // Create type for the helper function. SmallVector<Type *, 10> ArgTypes; for (unsigned I = 0, E = Invoke->getNumArgOperands(); I < E; ++I) ArgTypes.push_back(Invoke->getArgOperand(I)->getType()); ArgTypes.push_back(Invoke->getCalledValue()->getType()); ArgTypes.push_back(FrameJmpBuf->getType()); if (ResultAlloca) ArgTypes.push_back(Invoke->getType()->getPointerTo()); FunctionType *FTy = FunctionType::get(I32, ArgTypes, false); // Create the helper function. Function *HelperFunc = Function::Create( FTy, GlobalValue::InternalLinkage, Func->getName() + "_setjmp_caller"); Func->getParent()->getFunctionList().insertAfter(Func, HelperFunc); BasicBlock *EntryBB = BasicBlock::Create(Func->getContext(), "", HelperFunc); BasicBlock *NormalBB = BasicBlock::Create(Func->getContext(), "normal", HelperFunc); BasicBlock *ExceptionBB = BasicBlock::Create(Func->getContext(), "exception", HelperFunc); // Unpack the helper function's arguments. Function::arg_iterator ArgIter = HelperFunc->arg_begin(); SmallVector<Value *, 10> InnerCallArgs; for (unsigned I = 0, E = Invoke->getNumArgOperands(); I < E; ++I) { ArgIter->setName("arg"); InnerCallArgs.push_back(ArgIter++); } Argument *CalleeArg = ArgIter++; Argument *JmpBufArg = ArgIter++; CalleeArg->setName("func_ptr"); JmpBufArg->setName("jmp_buf"); // Create setjmp() call. Value *SetjmpArgs[] = { JmpBufArg }; CallInst *SetjmpCall = CallInst::Create(SetjmpIntrinsic, SetjmpArgs, "invoke_sj", EntryBB); CopyDebug(SetjmpCall, Invoke); // Setting the "returns_twice" attribute here prevents optimization // passes from inlining HelperFunc into its caller. SetjmpCall->setCanReturnTwice(); // Check setjmp()'s result. Value *IsZero = CopyDebug(new ICmpInst(*EntryBB, CmpInst::ICMP_EQ, SetjmpCall, ConstantInt::get(I32, 0), "invoke_sj_is_zero"), Invoke); CopyDebug(BranchInst::Create(NormalBB, ExceptionBB, IsZero, EntryBB), Invoke); // Handle the normal, non-exceptional code path. CallInst *InnerCall = CallInst::Create(CalleeArg, InnerCallArgs, "", NormalBB); CopyDebug(InnerCall, Invoke); InnerCall->setAttributes(Invoke->getAttributes()); InnerCall->setCallingConv(Invoke->getCallingConv()); if (ResultAlloca) { InnerCall->setName("result"); Argument *ResultArg = ArgIter++; ResultArg->setName("result_ptr"); CopyDebug(new StoreInst(InnerCall, ResultArg, NormalBB), Invoke); } ReturnInst::Create(Func->getContext(), ConstantInt::get(I32, 0), NormalBB); // Handle the exceptional code path. ReturnInst::Create(Func->getContext(), ConstantInt::get(I32, 1), ExceptionBB); // Create the outer call to the helper function. SmallVector<Value *, 10> OuterCallArgs; for (unsigned I = 0, E = Invoke->getNumArgOperands(); I < E; ++I) OuterCallArgs.push_back(Invoke->getArgOperand(I)); OuterCallArgs.push_back(Invoke->getCalledValue()); OuterCallArgs.push_back(FrameJmpBuf); if (ResultAlloca) OuterCallArgs.push_back(ResultAlloca); CallInst *OuterCall = CallInst::Create(HelperFunc, OuterCallArgs, "invoke_is_exc", Invoke); CopyDebug(OuterCall, Invoke); // Retrieve the function return value stored in the alloca. We only // need to do this on the non-exceptional path, but we currently do // it unconditionally because that is simpler. if (ResultAlloca) { Value *Result = new LoadInst(ResultAlloca, "", Invoke); Result->takeName(Invoke); Invoke->replaceAllUsesWith(Result); } return OuterCall; }
void initLLVM() { InitializeNativeTarget(); // Create some module to put our function into it. std::unique_ptr<Module> Owner = make_unique<Module>("test", Context); Module *M = Owner.get(); // Create the add1 function entry and insert this entry into module M. The // function will have a return type of "int" and take an argument of "int". // The '0' terminates the list of argument types. Function *Add1F = cast<Function>(M->getOrInsertFunction( "add1", Type::getInt32Ty(Context), Type::getInt32Ty(Context), (Type*)0 )); // Add a basic block to the function. As before, it automatically inserts // because of the last argument. BasicBlock *BB = BasicBlock::Create(Context, "EntryBlock", Add1F); // Create a basic block builder with default parameters. The builder will // automatically append instructions to the basic block `BB'. IRBuilder<> builder(BB); // Get pointers to the constant `1'. Value *One = builder.getInt32(1); // Get pointers to the integer argument of the add1 function... assert(Add1F->arg_begin() != Add1F->arg_end()); // Make sure there's an arg Argument *ArgX = Add1F->arg_begin(); // Get the arg ArgX->setName("AnArg"); // Give it a nice symbolic name for fun. // Create the add instruction, inserting it into the end of BB. Value *Add = builder.CreateAdd(One, ArgX); // Create the return instruction and add it to the basic block builder.CreateRet(Add); // Now, function add1 is ready. // Now we're going to create function `foo', // which returns an int and takes no arguments. FooF = cast<Function>(M->getOrInsertFunction( "foo", Type::getInt32Ty(Context), (Type *)0 )); // Add a basic block to the FooF function. BB = BasicBlock::Create(Context, "EntryBlock", FooF); // Tell the basic block builder to attach itself to the new basic block builder.SetInsertPoint(BB); // Get pointer to the constant `10'. Value *Ten = builder.getInt32(10); // Pass Ten to the call to Add1F CallInst *Add1CallRes = builder.CreateCall(Add1F, Ten); Add1CallRes->setTailCall(true); // Create the return instruction and add it to the basic block. builder.CreateRet(Add1CallRes); // Now we create the JIT. EE = EngineBuilder(std::move(Owner)).create(); /* outs() << "We just constructed this LLVM module:\n\n" << *M; outs() << "\n\nRunning foo: "; outs().flush(); */ }