void init_builtins(CodeGenState *code_gen) { code_gen->builtin_types[Builtin::Void] = Type::getVoidTy(code_gen->ctx); code_gen->builtin_types[Builtin::S8] = Type::getInt8Ty(code_gen->ctx); code_gen->builtin_types[Builtin::U8] = Type::getInt8Ty(code_gen->ctx); code_gen->builtin_types[Builtin::S16] = Type::getInt16Ty(code_gen->ctx); code_gen->builtin_types[Builtin::U16] = Type::getInt16Ty(code_gen->ctx); code_gen->builtin_types[Builtin::S32] = Type::getInt32Ty(code_gen->ctx); code_gen->builtin_types[Builtin::U32] = Type::getInt32Ty(code_gen->ctx); code_gen->builtin_types[Builtin::S64] = Type::getInt64Ty(code_gen->ctx); code_gen->builtin_types[Builtin::U64] = Type::getInt64Ty(code_gen->ctx); code_gen->builtin_types[Builtin::Float32] = Type::getFloatTy(code_gen->ctx); code_gen->builtin_types[Builtin::Float64] = Type::getDoubleTy(code_gen->ctx); // TODO: is it a good idea to use i1 here? code_gen->builtin_types[Builtin::Bool] = Type::getInt1Ty(code_gen->ctx); { // TODO: read doxygen, not sure how it works SmallVector<AttributeSet, 4> Attrs; AttributeSet PAS; { AttrBuilder B; B.addAttribute(Attribute::NoUnwind); PAS = AttributeSet::get(code_gen->ctx, ~0U, B); } Attrs.push_back(PAS); code_gen->default_func_attr = AttributeSet::get(code_gen->ctx, Attrs); } }
// removeAttribute() currently does not work on Attribute::Alignment // (it fails with an assertion error), so we have to take a more // convoluted route to removing this attribute by recreating the // AttributeSet. AttributeSet RemoveAttrs(LLVMContext &Context, AttributeSet Attrs) { SmallVector<AttributeSet, 8> AttrList; for (unsigned Slot = 0; Slot < Attrs.getNumSlots(); ++Slot) { unsigned Index = Attrs.getSlotIndex(Slot); AttrBuilder AB; for (AttributeSet::iterator Attr = Attrs.begin(Slot), E = Attrs.end(Slot); Attr != E; ++Attr) { if (Attr->isEnumAttribute() && Attr->getKindAsEnum() != Attribute::ByVal && Attr->getKindAsEnum() != Attribute::StructRet) { AB.addAttribute(*Attr); } // IR semantics require that ByVal implies NoAlias. However, IR // semantics do not require StructRet to imply NoAlias. For // example, a global variable address can be passed as a // StructRet argument, although Clang does not do so and Clang // explicitly adds NoAlias to StructRet arguments. if (Attr->isEnumAttribute() && Attr->getKindAsEnum() == Attribute::ByVal) { AB.addAttribute(Attribute::get(Context, Attribute::NoAlias)); } } AttrList.push_back(AttributeSet::get(Context, Index, AB)); } return AttributeSet::get(Context, AttrList); }
/// \brief If the inlined function had a higher stack protection level than the /// calling function, then bump up the caller's stack protection level. static void AdjustCallerSSPLevel(Function *Caller, Function *Callee) { // If upgrading the SSP attribute, clear out the old SSP Attributes first. // Having multiple SSP attributes doesn't actually hurt, but it adds useless // clutter to the IR. AttrBuilder B; B.addAttribute(Attribute::StackProtect) .addAttribute(Attribute::StackProtectStrong) .addAttribute(Attribute::StackProtectReq); AttributeSet OldSSPAttr = AttributeSet::get(Caller->getContext(), AttributeSet::FunctionIndex, B); if (Callee->hasFnAttribute(Attribute::SafeStack)) { Caller->removeAttributes(AttributeSet::FunctionIndex, OldSSPAttr); Caller->addFnAttr(Attribute::SafeStack); } else if (Callee->hasFnAttribute(Attribute::StackProtectReq) && !Caller->hasFnAttribute(Attribute::SafeStack)) { Caller->removeAttributes(AttributeSet::FunctionIndex, OldSSPAttr); Caller->addFnAttr(Attribute::StackProtectReq); } else if (Callee->hasFnAttribute(Attribute::StackProtectStrong) && !Caller->hasFnAttribute(Attribute::SafeStack) && !Caller->hasFnAttribute(Attribute::StackProtectReq)) { Caller->removeAttributes(AttributeSet::FunctionIndex, OldSSPAttr); Caller->addFnAttr(Attribute::StackProtectStrong); } else if (Callee->hasFnAttribute(Attribute::StackProtect) && !Caller->hasFnAttribute(Attribute::SafeStack) && !Caller->hasFnAttribute(Attribute::StackProtectReq) && !Caller->hasFnAttribute(Attribute::StackProtectStrong)) Caller->addFnAttr(Attribute::StackProtect); }
extern "C" void LLVMAddFunctionAttribute(LLVMValueRef Fn, unsigned index, uint64_t Val) { Function *A = unwrap<Function>(Fn); AttrBuilder B; B.addRawValue(Val); A->addAttributes(index, AttributeSet::get(A->getContext(), index, B)); }
void X86RetpolineThunks::createThunkFunction(Module &M, StringRef Name) { assert(Name.startswith(ThunkNamePrefix) && "Created a thunk with an unexpected prefix!"); LLVMContext &Ctx = M.getContext(); auto Type = FunctionType::get(Type::getVoidTy(Ctx), false); Function *F = Function::Create(Type, GlobalValue::LinkOnceODRLinkage, Name, &M); F->setVisibility(GlobalValue::HiddenVisibility); F->setComdat(M.getOrInsertComdat(Name)); // Add Attributes so that we don't create a frame, unwind information, or // inline. AttrBuilder B; B.addAttribute(llvm::Attribute::NoUnwind); B.addAttribute(llvm::Attribute::Naked); F->addAttributes(llvm::AttributeList::FunctionIndex, B); // Populate our function a bit so that we can verify. BasicBlock *Entry = BasicBlock::Create(Ctx, "entry", F); IRBuilder<> Builder(Entry); Builder.CreateRetVoid(); // MachineFunctions/MachineBasicBlocks aren't created automatically for the // IR-level constructs we already made. Create them and insert them into the // module. MachineFunction &MF = MMI->getOrCreateMachineFunction(*F); MachineBasicBlock *EntryMBB = MF.CreateMachineBasicBlock(Entry); // Insert EntryMBB into MF. It's not in the module until we do this. MF.insert(MF.end(), EntryMBB); }
void DynInstMarker::insertInstrumentation(BasicBlock::iterator& ii, Function::iterator& bi, Module* mod) { std::vector<Type*>FuncTy_4_args; FunctionType* FuncTy_4 = FunctionType::get( /*Result=*/Type::getVoidTy(mod->getContext()), /*Params=*/FuncTy_4_args, /*isVarArg=*/false); InlineAsm* ptr_10 = InlineAsm::get(FuncTy_4, "nop", "~{dirflag},~{fpsr},~{flags}",true); CallInst* void_9 = CallInst::Create(ptr_10, "", (&(*ii))); void_9->setCallingConv(CallingConv::C); void_9->setTailCall(false); AttributeSet void_9_PAL; { SmallVector<AttributeSet, 4> Attrs; AttributeSet PAS; { AttrBuilder B; B.addAttribute(Attribute::NoUnwind); PAS = AttributeSet::get(mod->getContext(), ~0U, B); } Attrs.push_back(PAS); void_9_PAL = AttributeSet::get(mod->getContext(), Attrs); } void_9->setAttributes(void_9_PAL); }
extern "C" void LLVMRustAddDereferenceableAttr(LLVMValueRef Fn, unsigned Index, uint64_t Bytes) { Function *A = unwrap<Function>(Fn); AttrBuilder B; B.addDereferenceableAttr(Bytes); A->addAttributes(Index, AttributeSet::get(A->getContext(), Index, B)); }
extern "C" void LLVMAddFunctionAttrStringValue(LLVMValueRef Fn, unsigned index, const char *Name, const char *Value) { Function *F = unwrap<Function>(Fn); AttrBuilder B; B.addAttribute(Name, Value); F->addAttributes(index, AttributeSet::get(F->getContext(), index, B)); }
Value* NFunctionDeclaration::codeGen(CodeGenContext& context) { vector<Type*> argTypes; VariableList::const_iterator it; for (it = arguments.begin(); it != arguments.end(); it++) { argTypes.push_back(typeOf((**it).type)); } FunctionType *ftype = FunctionType::get(typeOf(type), makeArrayRef(argTypes), false); Function *function = Function::Create(ftype, GlobalValue::ExternalLinkage, id.name.c_str(), context.module); BasicBlock *bblock = BasicBlock::Create(getGlobalContext(), "entry", function, 0); BasicBlock *returnBlock = BasicBlock::Create(getGlobalContext(), "return", function, 0); function->setCallingConv(CallingConv::C); AttributeSet func_func_PAL; { SmallVector<AttributeSet, 4> Attrs; AttributeSet PAS; { AttrBuilder B; B.addAttribute(Attribute::NoUnwind); PAS = AttributeSet::get(getGlobalContext(), ~0U, B); } Attrs.push_back(PAS); func_func_PAL = AttributeSet::get(getGlobalContext(), Attrs); } function->setAttributes(func_func_PAL); context.setCurrentFunction(function); context.setReturnBlock(returnBlock); context.isTopLevel = false; context.pushBlock(bblock, false); Function::arg_iterator argsValues = function->arg_begin(); Value* argumentValue; for (it = arguments.begin(); it != arguments.end(); it++) { (**it).codeGen(context); argumentValue = argsValues++; argumentValue->setName((*it)->id.name.c_str()); StoreInst *inst = new StoreInst(argumentValue, context.locals()[(*it)->id.name], false, bblock); } block.codeGen(context); ReturnInst::Create(getGlobalContext(), context.getCurrentReturnValue(), context.getReturnBlock()); context.popBlock(); context.isTopLevel = true; std::cout << "Creating function: " << id.name << endl; return function; }
extern "C" void LLVMAddCallSiteAttribute(LLVMValueRef Instr, unsigned index, uint64_t Val) { CallSite Call = CallSite(unwrap<Instruction>(Instr)); AttrBuilder B; B.addRawValue(Val); Call.setAttributes( Call.getAttributes().addAttributes(Call->getContext(), index, AttributeSet::get(Call->getContext(), index, B))); }
extern "C" void LLVMAddDereferenceableCallSiteAttr(LLVMValueRef Instr, unsigned idx, uint64_t b) { CallSite Call = CallSite(unwrap<Instruction>(Instr)); AttrBuilder B; B.addDereferenceableAttr(b); Call.setAttributes( Call.getAttributes().addAttributes(Call->getContext(), idx, AttributeSet::get(Call->getContext(), idx, B))); }
// // remove the use-soft-float attribute // static void removeUseSoftFloat(Function &F) { AttrBuilder B; DEBUG(errs() << "removing -use-soft-float\n"); B.addAttribute("use-soft-float", "false"); F.removeAttributes(AttributeList::FunctionIndex, B); if (F.hasFnAttribute("use-soft-float")) { DEBUG(errs() << "still has -use-soft-float\n"); } F.addAttributes(AttributeList::FunctionIndex, B); }
const AttributeSetImpl *LLVM_General_GetSlotAttributeSet( LLVMContextRef context, unsigned index, const AttributeImpl **attributes, unsigned length ) { AttrBuilder builder; for (unsigned i = 0; i < length; i++) builder.addAttribute(unwrap(attributes[i])); return wrap(AttributeSet::get(*unwrap(context), index, builder)); }
static bool addReadAttrs(const SCCNodeSet &SCCNodes, AARGetterT AARGetter) { // Check if any of the functions in the SCC read or write memory. If they // write memory then they can't be marked readnone or readonly. bool ReadsMemory = false; for (Function *F : SCCNodes) { // Call the callable parameter to look up AA results for this function. AAResults &AAR = AARGetter(*F); switch (checkFunctionMemoryAccess(*F, AAR, SCCNodes)) { case MAK_MayWrite: return false; case MAK_ReadOnly: ReadsMemory = true; break; case MAK_ReadNone: // Nothing to do! break; } } // Success! Functions in this SCC do not access memory, or only read memory. // Give them the appropriate attribute. bool MadeChange = false; for (Function *F : SCCNodes) { if (F->doesNotAccessMemory()) // Already perfect! continue; if (F->onlyReadsMemory() && ReadsMemory) // No change. continue; MadeChange = true; // Clear out any existing attributes. AttrBuilder B; B.addAttribute(Attribute::ReadOnly).addAttribute(Attribute::ReadNone); F->removeAttributes( AttributeSet::FunctionIndex, AttributeSet::get(F->getContext(), AttributeSet::FunctionIndex, B)); // Add in the new attribute. F->addAttribute(AttributeSet::FunctionIndex, ReadsMemory ? Attribute::ReadOnly : Attribute::ReadNone); if (ReadsMemory) ++NumReadOnly; else ++NumReadNone; } return MadeChange; }
extern "C" void LLVMRemoveFunctionAttrString(LLVMValueRef fn, unsigned index, const char *Name) { Function *f = unwrap<Function>(fn); LLVMContext &C = f->getContext(); AttrBuilder B; B.addAttribute(Name); AttributeSet to_remove = AttributeSet::get(C, index, B); AttributeSet attrs = f->getAttributes(); f->setAttributes(attrs.removeAttributes(f->getContext(), index, to_remove)); }
/// Deduce returned attributes for the SCC. static bool addArgumentReturnedAttrs(const SCCNodeSet &SCCNodes) { bool Changed = false; AttrBuilder B; B.addAttribute(Attribute::Returned); // Check each function in turn, determining if an argument is always returned. for (Function *F : SCCNodes) { // We can infer and propagate function attributes only when we know that the // definition we'll get at link time is *exactly* the definition we see now. // For more details, see GlobalValue::mayBeDerefined. if (!F->hasExactDefinition()) continue; if (F->getReturnType()->isVoidTy()) continue; // There is nothing to do if an argument is already marked as 'returned'. if (any_of(F->args(), [](const Argument &Arg) { return Arg.hasReturnedAttr(); })) continue; auto FindRetArg = [&]() -> Value * { Value *RetArg = nullptr; for (BasicBlock &BB : *F) if (auto *Ret = dyn_cast<ReturnInst>(BB.getTerminator())) { // Note that stripPointerCasts should look through functions with // returned arguments. Value *RetVal = Ret->getReturnValue()->stripPointerCasts(); if (!isa<Argument>(RetVal) || RetVal->getType() != F->getReturnType()) return nullptr; if (!RetArg) RetArg = RetVal; else if (RetArg != RetVal) return nullptr; } return RetArg; }; if (Value *RetArg = FindRetArg()) { auto *A = cast<Argument>(RetArg); A->addAttr(AttributeSet::get(F->getContext(), A->getArgNo() + 1, B)); ++NumReturned; Changed = true; } } return Changed; }
/** * Set the shader type we want to compile * * @param type shader type to set */ extern "C" void radeon_llvm_shader_type(LLVMValueRef F, unsigned type) { Function *Func = unwrap<Function>(F); int Idx = AttributeSet::FunctionIndex; AttrBuilder B; char Str[2]; sprintf(Str, "%1d", type); B.addAttribute("ShaderType", Str); AttributeSet Set = AttributeSet::get(Func->getContext(), Idx, B); Func->addAttributes(Idx, Set); }
bool needPassByRef(jl_datatype_t *dt, AttrBuilder &ab) override { size_t size = jl_datatype_size(dt); if (is_complex64(dt) || is_complex128(dt) || (jl_is_primitivetype(dt) && size <= 8)) return false; ab.addAttribute(Attribute::ByVal); return true; }
bool needPassByRef(jl_datatype_t *dt, AttrBuilder &ab) override { jl_datatype_t *ty0 = NULL; bool hva = false; if (jl_datatype_size(dt) > 64 && isHFA(dt, &ty0, &hva) > 8) { ab.addAttribute(Attribute::ByVal); return true; } return false; }
/* Compile the AST into a module */ void CodeGenContext::generateCode(NBlock& root) { std::cout << "Generating code...\n"; /* Create the top level interpreter function to call as entry */ vector<Type*> argTypes; FunctionType *ftype = FunctionType::get(Type::getVoidTy(getGlobalContext()), makeArrayRef(argTypes), false); //mainFunction = Function::Create(ftype, GlobalValue::ExternalLinkage, "main", module); //BasicBlock *bblock = BasicBlock::Create(getGlobalContext(), "entry", mainFunction, 0); //mainFunction->setCallingConv(CallingConv::C); AttributeSet func_func_PAL; { SmallVector<AttributeSet, 4> Attrs; AttributeSet PAS; { AttrBuilder B; B.addAttribute(Attribute::NoUnwind); PAS = AttributeSet::get(getGlobalContext(), ~0U, B); } Attrs.push_back(PAS); func_func_PAL = AttributeSet::get(getGlobalContext(), Attrs); } //mainFunction->setAttributes(func_func_PAL); /* Push a new variable/block context */ //pushBlock(bblock, false); root.codeGen(*this); /* emit bytecode for the toplevel block */ //ReturnInst::Create(getGlobalContext(), bblock); //popBlock(); /* Print the bytecode in a human-readable format to see if our program compiled properly */ std::cout << "Code is generated.\n"; //module->dump(); verifyModule(*module, PrintMessageAction); PassManager pm; pm.add(createPrintModulePass(&outs())); pm.run(*module); }
/// Replaces the given call site (Call or Invoke) with a gc.statepoint /// intrinsic with an empty deoptimization arguments list. This does /// NOT do explicit relocation for GC support. static Value *ReplaceWithStatepoint(const CallSite &CS /* to replace */) { assert(CS.getInstruction()->getModule() && "must be set"); // TODO: technically, a pass is not allowed to get functions from within a // function pass since it might trigger a new function addition. Refactor // this logic out to the initialization of the pass. Doesn't appear to // matter in practice. // Then go ahead and use the builder do actually do the inserts. We insert // immediately before the previous instruction under the assumption that all // arguments will be available here. We can't insert afterwards since we may // be replacing a terminator. IRBuilder<> Builder(CS.getInstruction()); // Note: The gc args are not filled in at this time, that's handled by // RewriteStatepointsForGC (which is currently under review). // Create the statepoint given all the arguments Instruction *Token = nullptr; uint64_t ID; uint32_t NumPatchBytes; AttributeSet OriginalAttrs = CS.getAttributes(); Attribute AttrID = OriginalAttrs.getAttribute(AttributeSet::FunctionIndex, "statepoint-id"); Attribute AttrNumPatchBytes = OriginalAttrs.getAttribute( AttributeSet::FunctionIndex, "statepoint-num-patch-bytes"); AttrBuilder AttrsToRemove; bool HasID = AttrID.isStringAttribute() && !AttrID.getValueAsString().getAsInteger(10, ID); if (HasID) AttrsToRemove.addAttribute("statepoint-id"); else ID = 0xABCDEF00; bool HasNumPatchBytes = AttrNumPatchBytes.isStringAttribute() && !AttrNumPatchBytes.getValueAsString().getAsInteger(10, NumPatchBytes); if (HasNumPatchBytes) AttrsToRemove.addAttribute("statepoint-num-patch-bytes"); else NumPatchBytes = 0; OriginalAttrs = OriginalAttrs.removeAttributes( CS.getInstruction()->getContext(), AttributeSet::FunctionIndex, AttrsToRemove); if (CS.isCall()) { CallInst *ToReplace = cast<CallInst>(CS.getInstruction()); CallInst *Call = Builder.CreateGCStatepointCall( ID, NumPatchBytes, CS.getCalledValue(), makeArrayRef(CS.arg_begin(), CS.arg_end()), None, None, "safepoint_token"); Call->setTailCall(ToReplace->isTailCall()); Call->setCallingConv(ToReplace->getCallingConv()); // In case if we can handle this set of attributes - set up function // attributes directly on statepoint and return attributes later for // gc_result intrinsic. Call->setAttributes(OriginalAttrs.getFnAttributes()); Token = Call; // Put the following gc_result and gc_relocate calls immediately after // the old call (which we're about to delete). assert(ToReplace->getNextNode() && "not a terminator, must have next"); Builder.SetInsertPoint(ToReplace->getNextNode()); Builder.SetCurrentDebugLocation(ToReplace->getNextNode()->getDebugLoc()); } else if (CS.isInvoke()) { InvokeInst *ToReplace = cast<InvokeInst>(CS.getInstruction()); // Insert the new invoke into the old block. We'll remove the old one in a // moment at which point this will become the new terminator for the // original block. Builder.SetInsertPoint(ToReplace->getParent()); InvokeInst *Invoke = Builder.CreateGCStatepointInvoke( ID, NumPatchBytes, CS.getCalledValue(), ToReplace->getNormalDest(), ToReplace->getUnwindDest(), makeArrayRef(CS.arg_begin(), CS.arg_end()), None, None, "safepoint_token"); Invoke->setCallingConv(ToReplace->getCallingConv()); // In case if we can handle this set of attributes - set up function // attributes directly on statepoint and return attributes later for // gc_result intrinsic. Invoke->setAttributes(OriginalAttrs.getFnAttributes()); Token = Invoke; // We'll insert the gc.result into the normal block BasicBlock *NormalDest = ToReplace->getNormalDest(); // Can not insert gc.result in case of phi nodes preset. // Should have removed this cases prior to running this function assert(!isa<PHINode>(NormalDest->begin())); Instruction *IP = &*(NormalDest->getFirstInsertionPt()); Builder.SetInsertPoint(IP); } else { llvm_unreachable("unexpect type of CallSite"); } assert(Token); // Handle the return value of the original call - update all uses to use a // gc_result hanging off the statepoint node we just inserted // Only add the gc_result iff there is actually a used result if (!CS.getType()->isVoidTy() && !CS.getInstruction()->use_empty()) { std::string TakenName = CS.getInstruction()->hasName() ? CS.getInstruction()->getName() : ""; CallInst *GCResult = Builder.CreateGCResult(Token, CS.getType(), TakenName); GCResult->setAttributes(OriginalAttrs.getRetAttributes()); return GCResult; } else { // No return value for the call. return nullptr; } }
Module* makeLLVMModule() { // Module Construction Module* mod = new Module("./test/test1.ll", getGlobalContext()); mod->setDataLayout("0x37c1810"); mod->setTargetTriple("x86_64-pc-linux-gnu"); // Type Definitions PointerType* PointerTy_0 = PointerType::get(IntegerType::get(mod->getContext(), 32), 0); ArrayType* ArrayTy_1 = ArrayType::get(IntegerType::get(mod->getContext(), 32), 3);//数组大小根据ast信息生成 PointerType* PointerTy_2 = PointerType::get(ArrayTy_1, 0); ArrayType* ArrayTy_3 = ArrayType::get(IntegerType::get(mod->getContext(), 32), 2); PointerType* PointerTy_4 = PointerType::get(ArrayTy_3, 0); std::vector<Type*>FuncTy_5_args; FunctionType* FuncTy_5 = FunctionType::get( /*Result=*/Type::getVoidTy(mod->getContext()), /*Params=*/FuncTy_5_args, /*isVarArg=*/false); PointerType* PointerTy_6 = PointerType::get(IntegerType::get(mod->getContext(), 8), 0); std::vector<Type*>FuncTy_8_args; FuncTy_8_args.push_back(PointerTy_6); FuncTy_8_args.push_back(PointerTy_6); FuncTy_8_args.push_back(IntegerType::get(mod->getContext(), 64)); FuncTy_8_args.push_back(IntegerType::get(mod->getContext(), 32)); FuncTy_8_args.push_back(IntegerType::get(mod->getContext(), 1)); FunctionType* FuncTy_8 = FunctionType::get( /*Result=*/Type::getVoidTy(mod->getContext()), /*Params=*/FuncTy_8_args, /*isVarArg=*/false); PointerType* PointerTy_7 = PointerType::get(FuncTy_8, 0); PointerType* PointerTy_9 = PointerType::get(FuncTy_5, 0); // Function Declarations Function* func_antest = mod->getFunction("antest"); if (!func_antest) { func_antest = Function::Create( /*Type=*/FuncTy_5, /*Linkage=*/GlobalValue::ExternalLinkage, /*Name=*/"antest", mod); func_antest->setCallingConv(CallingConv::C); } AttributeSet func_antest_PAL; { SmallVector<AttributeSet, 4> Attrs; AttributeSet PAS; { AttrBuilder B; B.addAttribute(Attribute::NoUnwind); PAS = AttributeSet::get(mod->getContext(), ~0U, B); } Attrs.push_back(PAS); func_antest_PAL = AttributeSet::get(mod->getContext(), Attrs); } func_antest->setAttributes(func_antest_PAL); Function* func_llvm_memcpy_p0i8_p0i8_i64 = mod->getFunction("llvm.memcpy.p0i8.p0i8.i64"); if (!func_llvm_memcpy_p0i8_p0i8_i64) { func_llvm_memcpy_p0i8_p0i8_i64 = Function::Create( /*Type=*/FuncTy_8, /*Linkage=*/GlobalValue::ExternalLinkage, /*Name=*/"llvm.memcpy.p0i8.p0i8.i64", mod); // (external, no body) func_llvm_memcpy_p0i8_p0i8_i64->setCallingConv(CallingConv::C); } AttributeSet func_llvm_memcpy_p0i8_p0i8_i64_PAL; { SmallVector<AttributeSet, 4> Attrs; AttributeSet PAS; { AttrBuilder B; B.addAttribute(Attribute::NoCapture); PAS = AttributeSet::get(mod->getContext(), 1U, B); } Attrs.push_back(PAS); { AttrBuilder B; B.addAttribute(Attribute::ReadOnly); B.addAttribute(Attribute::NoCapture); PAS = AttributeSet::get(mod->getContext(), 2U, B); } Attrs.push_back(PAS); { AttrBuilder B; B.addAttribute(Attribute::NoUnwind); PAS = AttributeSet::get(mod->getContext(), ~0U, B); } Attrs.push_back(PAS); func_llvm_memcpy_p0i8_p0i8_i64_PAL = AttributeSet::get(mod->getContext(), Attrs); } func_llvm_memcpy_p0i8_p0i8_i64->setAttributes(func_llvm_memcpy_p0i8_p0i8_i64_PAL); Function* func_testf = mod->getFunction("testf"); if (!func_testf) { func_testf = Function::Create( /*Type=*/FuncTy_5, /*Linkage=*/GlobalValue::ExternalLinkage, /*Name=*/"testf", mod); func_testf->setCallingConv(CallingConv::C); } AttributeSet func_testf_PAL; { SmallVector<AttributeSet, 4> Attrs; AttributeSet PAS; { AttrBuilder B; B.addAttribute(Attribute::NoUnwind); PAS = AttributeSet::get(mod->getContext(), ~0U, B); } Attrs.push_back(PAS); func_testf_PAL = AttributeSet::get(mod->getContext(), Attrs); } func_testf->setAttributes(func_testf_PAL); Function* func_main = mod->getFunction("main"); if (!func_main) { func_main = Function::Create( /*Type=*/FuncTy_5, /*Linkage=*/GlobalValue::ExternalLinkage, /*Name=*/"main", mod); func_main->setCallingConv(CallingConv::C); } AttributeSet func_main_PAL; { SmallVector<AttributeSet, 4> Attrs; AttributeSet PAS; { AttrBuilder B; B.addAttribute(Attribute::NoUnwind); PAS = AttributeSet::get(mod->getContext(), ~0U, B); } Attrs.push_back(PAS); func_main_PAL = AttributeSet::get(mod->getContext(), Attrs); } func_main->setAttributes(func_main_PAL); // Global Variable Declarations ------global按照这个写,区别只在于isConstant的值,自然可区分开 //局部变量,若为数组,则也是按照global储存的,link做成了private GlobalVariable* gvar_int32_a = new GlobalVariable(/*Module=*/*mod, /*Type=*/IntegerType::get(mod->getContext(), 32), /*isConstant=*/false, /*Linkage=*/GlobalValue::ExternalLinkage, /*Initializer=*/0, // has initializer, specified below /*Name=*/"a"); gvar_int32_a->setAlignment(4); ConstantInt* const_int32_10 = ConstantInt::get(mod->getContext(), APInt(32, StringRef("0"), 10)); gvar_int32_a->setInitializer(const_int32_10); GlobalVariable* gvar_int32_csta = new GlobalVariable(/*Module=*/*mod, /*Type=*/IntegerType::get(mod->getContext(), 32), /*isConstant=*/true, /*Linkage=*/GlobalValue::ExternalLinkage, /*Initializer=*/0, // has initializer, specified below /*Name=*/"csta"); gvar_int32_csta->setAlignment(4); ConstantInt* const_int32_11 = ConstantInt::get(mod->getContext(), APInt(32, StringRef("1"), 10)); gvar_int32_csta->setInitializer(const_int32_11); //gvar_int32_csta是global var类型 GlobalVariable* gvar_array_astr = new GlobalVariable(/*Module=*/*mod, /*Type=*/ArrayTy_1, /*isConstant=*/true, /*Linkage=*/GlobalValue::ExternalLinkage, /*Initializer=*/0, // has initializer, specified below /*Name=*/"astr"); gvar_array_astr->setAlignment(4); std::vector<Constant*> const_array_12_elems; ConstantInt* const_int32_13 = ConstantInt::get(mod->getContext(), APInt(32, StringRef("9"), 10)); const_array_12_elems.push_back(const_int32_13); ConstantInt* const_int32_14 = ConstantInt::get(mod->getContext(), APInt(32, StringRef("8"), 10)); const_array_12_elems.push_back(const_int32_14); ConstantInt* const_int32_15 = ConstantInt::get(mod->getContext(), APInt(32, StringRef("7"), 10)); const_array_12_elems.push_back(const_int32_15); Constant* const_array_12 = ConstantArray::get(ArrayTy_1, const_array_12_elems); gvar_array_astr->setInitializer(const_array_12); GlobalVariable* gvar_array_alot = new GlobalVariable(/*Module=*/*mod, /*Type=*/ArrayTy_1, /*isConstant=*/true, /*Linkage=*/GlobalValue::ExternalLinkage, /*Initializer=*/0, // has initializer, specified below /*Name=*/"alot"); gvar_array_alot->setAlignment(4); std::vector<Constant*> const_array_16_elems; ConstantInt* const_int32_17 = ConstantInt::get(mod->getContext(), APInt(32, StringRef("6"), 10)); const_array_16_elems.push_back(const_int32_17); ConstantInt* const_int32_18 = ConstantInt::get(mod->getContext(), APInt(32, StringRef("5"), 10)); const_array_16_elems.push_back(const_int32_18); ConstantInt* const_int32_19 = ConstantInt::get(mod->getContext(), APInt(32, StringRef("4"), 10)); const_array_16_elems.push_back(const_int32_19); Constant* const_array_16 = ConstantArray::get(ArrayTy_1, const_array_16_elems); gvar_array_alot->setInitializer(const_array_16); GlobalVariable* gvar_array_antest_sthrl = new GlobalVariable(/*Module=*/*mod, /*Type=*/ArrayTy_1, /*isConstant=*/true, /*Linkage=*/GlobalValue::PrivateLinkage, /*Initializer=*/0, // has initializer, specified below /*Name=*/"antest.sthrl"); gvar_array_antest_sthrl->setAlignment(4); GlobalVariable* gvar_array_antest_hehe = new GlobalVariable(/*Module=*/*mod, /*Type=*/ArrayTy_3, /*isConstant=*/true, /*Linkage=*/GlobalValue::PrivateLinkage, /*Initializer=*/0, // has initializer, specified below /*Name=*/"antest.hehe"); gvar_array_antest_hehe->setAlignment(4); GlobalVariable* gvar_int32_xka = new GlobalVariable(/*Module=*/*mod, /*Type=*/IntegerType::get(mod->getContext(), 32), /*isConstant=*/false, /*Linkage=*/GlobalValue::CommonLinkage, /*Initializer=*/0, // has initializer, specified below /*Name=*/"xka"); gvar_int32_xka->setAlignment(4); gvar_int32_xka->setInitializer(const_int32_10); // Constant Definitions 为了之后的赋值 std::vector<Constant*> const_array_20_elems; ConstantInt* const_int32_21 = ConstantInt::get(mod->getContext(), APInt(32, StringRef("3"), 10)); const_array_20_elems.push_back(const_int32_21); ConstantInt* const_int32_22 = ConstantInt::get(mod->getContext(), APInt(32, StringRef("11"), 10)); const_array_20_elems.push_back(const_int32_22); ConstantInt* const_int32_23 = ConstantInt::get(mod->getContext(), APInt(32, StringRef("22"), 10)); const_array_20_elems.push_back(const_int32_23); Constant* const_array_20 = ConstantArray::get(ArrayTy_1, const_array_20_elems); std::vector<Constant*> const_array_24_elems; ConstantInt* const_int32_25 = ConstantInt::get(mod->getContext(), APInt(32, StringRef("-1"), 10)); const_array_24_elems.push_back(const_int32_25); ConstantInt* const_int32_26 = ConstantInt::get(mod->getContext(), APInt(32, StringRef("-2"), 10)); const_array_24_elems.push_back(const_int32_26); Constant* const_array_24 = ConstantArray::get(ArrayTy_3, const_array_24_elems); ConstantInt* const_int32_27 = ConstantInt::get(mod->getContext(), APInt(32, StringRef("123"), 10)); ConstantInt* const_int32_28 = ConstantInt::get(mod->getContext(), APInt(32, StringRef("234"), 10)); ConstantInt* const_int32_29 = ConstantInt::get(mod->getContext(), APInt(32, StringRef("456"), 10)); ConstantInt* const_int32_30 = ConstantInt::get(mod->getContext(), APInt(32, StringRef("567"), 10)); Constant* const_ptr_31 = ConstantExpr::getCast(Instruction::BitCast, gvar_array_antest_sthrl, PointerTy_6); ConstantInt* const_int64_32 = ConstantInt::get(mod->getContext(), APInt(64, StringRef("12"), 10)); ConstantInt* const_int1_33 = ConstantInt::get(mod->getContext(), APInt(1, StringRef("0"), 10)); Constant* const_ptr_34 = ConstantExpr::getCast(Instruction::BitCast, gvar_array_antest_hehe, PointerTy_6); ConstantInt* const_int64_35 = ConstantInt::get(mod->getContext(), APInt(64, StringRef("8"), 10)); ConstantInt* const_int32_36 = ConstantInt::get(mod->getContext(), APInt(32, StringRef("21"), 10)); // Global Variable Definitions gvar_array_antest_sthrl->setInitializer(const_array_20); //alot sthrl astr都是用的ArrayTy_1,规定了数组大小 gvar_array_antest_hehe->setInitializer(const_array_24); // Function Definitions // Function: antest (func_antest) { BasicBlock* label_37 = BasicBlock::Create(mod->getContext(), "",func_antest,0); // Block (label_37) AllocaInst* ptr_abc = new AllocaInst(IntegerType::get(mod->getContext(), 32), "abc", label_37); ptr_abc->setAlignment(4); AllocaInst* ptr_abc1 = new AllocaInst(IntegerType::get(mod->getContext(), 32), "abc1", label_37); ptr_abc1->setAlignment(4); AllocaInst* ptr_abc2 = new AllocaInst(IntegerType::get(mod->getContext(), 32), "abc2", label_37); ptr_abc2->setAlignment(4); AllocaInst* ptr_antab = new AllocaInst(IntegerType::get(mod->getContext(), 32), "antab", label_37); ptr_antab->setAlignment(4); AllocaInst* ptr_antab3 = new AllocaInst(IntegerType::get(mod->getContext(), 32), "antab3", label_37); ptr_antab3->setAlignment(4); AllocaInst* ptr_antab4 = new AllocaInst(IntegerType::get(mod->getContext(), 32), "antab4", label_37); ptr_antab4->setAlignment(4); AllocaInst* ptr_asgnah = new AllocaInst(ArrayTy_1, "asgnah", label_37); ptr_asgnah->setAlignment(4); AllocaInst* ptr_sthrl = new AllocaInst(ArrayTy_1, "sthrl", label_37); ptr_sthrl->setAlignment(4); AllocaInst* ptr_hehe = new AllocaInst(ArrayTy_3, "hehe", label_37); ptr_hehe->setAlignment(4); StoreInst* void_38 = new StoreInst(const_int32_27, ptr_abc, false, label_37); void_38->setAlignment(4); StoreInst* void_39 = new StoreInst(const_int32_28, ptr_abc1, false, label_37); void_39->setAlignment(4); StoreInst* void_40 = new StoreInst(const_int32_29, ptr_antab, false, label_37); void_40->setAlignment(4); StoreInst* void_41 = new StoreInst(const_int32_30, ptr_antab4, false, label_37); void_41->setAlignment(4); CastInst* ptr_42 = new BitCastInst(ptr_sthrl, PointerTy_6, "", label_37); //ptr_sthrl是AllocaInst*,是在label37这个block中申到的存储空间地址, std::vector<Value*> void_43_params; void_43_params.push_back(ptr_42); void_43_params.push_back(const_ptr_31); void_43_params.push_back(const_int64_32); void_43_params.push_back(const_int32_19); void_43_params.push_back(const_int1_33); CallInst* void_43 = CallInst::Create(func_llvm_memcpy_p0i8_p0i8_i64, void_43_params, "", label_37); void_43->setCallingConv(CallingConv::C); void_43->setTailCall(false); AttributeSet void_43_PAL; void_43->setAttributes(void_43_PAL); CastInst* ptr_44 = new BitCastInst(ptr_hehe, PointerTy_6, "", label_37); std::vector<Value*> void_45_params; void_45_params.push_back(ptr_44); void_45_params.push_back(const_ptr_34); void_45_params.push_back(const_int64_35); void_45_params.push_back(const_int32_19); //6,5,4的4 void_45_params.push_back(const_int1_33); CallInst* void_45 = CallInst::Create(func_llvm_memcpy_p0i8_p0i8_i64, void_45_params, "", label_37); void_45->setCallingConv(CallingConv::C); void_45->setTailCall(false);//尾调用,因为C1暂时不支持返回,暂时无用 AttributeSet void_45_PAL; void_45->setAttributes(void_45_PAL); ReturnInst::Create(mod->getContext(), label_37); } // Function: testf (func_testf) { BasicBlock* label_47 = BasicBlock::Create(mod->getContext(), "",func_testf,0); // Block (label_47) AllocaInst* ptr_acb = new AllocaInst(IntegerType::get(mod->getContext(), 32), "acb", label_47); ptr_acb->setAlignment(4); CallInst* void_48 = CallInst::Create(func_antest, "", label_47); void_48->setCallingConv(CallingConv::C); void_48->setTailCall(false); AttributeSet void_48_PAL; void_48->setAttributes(void_48_PAL); LoadInst* int32_49 = new LoadInst(gvar_int32_a, "", false, label_47); int32_49->setAlignment(4); StoreInst* void_50 = new StoreInst(int32_49, ptr_acb, false, label_47); void_50->setAlignment(4); ReturnInst::Create(mod->getContext(), label_47); } // Function: main (func_main) { BasicBlock* label_52 = BasicBlock::Create(mod->getContext(), "",func_main,0); // Block (label_52) AllocaInst* ptr_a = new AllocaInst(IntegerType::get(mod->getContext(), 32), "a", label_52); ptr_a->setAlignment(4); StoreInst* void_53 = new StoreInst(const_int32_36, ptr_a, false, label_52); void_53->setAlignment(4); CallInst* void_54 = CallInst::Create(func_testf, "", label_52); void_54->setCallingConv(CallingConv::C); void_54->setTailCall(false); AttributeSet void_54_PAL; void_54->setAttributes(void_54_PAL); ReturnInst::Create(mod->getContext(), label_52); } return mod; }
Value *ABICallSignature::emitCall(GenIR &Reader, Value *Target, bool MayThrow, ArrayRef<Value *> Args, Value *IndirectionCell, bool IsJmp, Value **CallNode) const { assert(isa<llvm::Function>(Target) || Target->getType()->isIntegerTy(Reader.TargetPointerSizeInBits)); LLVMContext &Context = *Reader.JitContext->LLVMContext; // Compute the function type bool HasIndirectResult = Result.getKind() == ABIArgInfo::Indirect; bool HasIndirectionCell = IndirectionCell != nullptr; bool IsUnmanagedCall = Signature.getCallingConvention() != CORINFO_CALLCONV_DEFAULT; bool CallerHasSecretParameter = Reader.MethodSignature.hasSecretParameter(); bool IsJmpWithSecretParam = IsJmp && CallerHasSecretParameter; assert(((HasIndirectionCell ? 1 : 0) + (IsUnmanagedCall ? 1 : 0) + (IsJmpWithSecretParam ? 1 : 0)) <= 1); uint32_t NumSpecialArgs = 0; if (HasIndirectionCell || IsJmpWithSecretParam) { NumSpecialArgs = 1; } uint32_t NumExtraArgs = (HasIndirectResult ? 1 : 0) + NumSpecialArgs; const uint32_t NumArgs = getNumABIArgs() + NumExtraArgs; Value *ResultNode = nullptr; SmallVector<Type *, 16> ArgumentTypes(NumArgs); SmallVector<Value *, 16> Arguments(NumArgs); SmallVector<AttributeSet, 16> Attrs(NumArgs + 1); IRBuilder<> &Builder = *Reader.LLVMBuilder; // Check for calls with special args. // // Any special arguments are passed immediately preceeding the normal // arguments. The backend will place these arguments in the appropriate // registers according to the calling convention. Each special argument should // be machine-word-sized. if (HasIndirectionCell) { assert(IndirectionCell->getType()->isIntegerTy( Reader.TargetPointerSizeInBits)); ArgumentTypes[0] = IndirectionCell->getType(); Arguments[0] = IndirectionCell; } else if (IsJmpWithSecretParam) { Arguments[0] = Reader.secretParam(); ArgumentTypes[0] = Arguments[0]->getType(); } int32_t ResultIndex = -1; if (HasIndirectResult) { ResultIndex = (int32_t)NumSpecialArgs + (Signature.hasThis() ? 1 : 0); Type *ResultTy = Result.getType(); // Jmp target signature has to match the caller's signature. Since we type // the caller's indirect result parameters as managed pointers, jmp target's // indirect result parameters also have to be typed as managed pointers. ArgumentTypes[ResultIndex] = IsJmp ? Reader.getManagedPointerType(ResultTy) : Reader.getUnmanagedPointerType(ResultTy); if (IsJmp) { // When processing jmp, pass the pointer that we got from the caller // rather than a pointer to a copy in the current frame. Arguments[ResultIndex] = ResultNode = Reader.IndirectResult; } else { Arguments[ResultIndex] = ResultNode = Reader.createTemporary(ResultTy); } if (ResultTy->isStructTy()) { Reader.setValueRepresentsStruct(ResultNode); } } else { AttrBuilder RetAttrs; if (Result.getKind() == ABIArgInfo::ZeroExtend) { RetAttrs.addAttribute(Attribute::ZExt); } else if (Result.getKind() == ABIArgInfo::SignExtend) { RetAttrs.addAttribute(Attribute::SExt); } if (RetAttrs.hasAttributes()) { Attrs.push_back( AttributeSet::get(Context, AttributeSet::ReturnIndex, RetAttrs)); } } uint32_t I = NumSpecialArgs, J = 0; for (auto Arg : Args) { AttrBuilder ArgAttrs; if (ResultIndex >= 0 && I == (uint32_t)ResultIndex) { I++; } const ABIArgInfo &ArgInfo = this->Args[J]; Type *ArgType = Arg->getType(); switch (ArgInfo.getKind()) { case ABIArgInfo::Indirect: if (IsJmp) { // When processing jmp pass the pointer that we got from the caller // rather than a pointer to a copy in the current frame. Arguments[I] = Arg; ArgumentTypes[I] = ArgType; } else { Value *Temp = nullptr; if (Reader.doesValueRepresentStruct(Arg)) { StructType *ArgStructTy = cast<StructType>(ArgType->getPointerElementType()); ArgumentTypes[I] = ArgType; Temp = Reader.createTemporary(ArgStructTy); const bool IsVolatile = false; Reader.copyStructNoBarrier(ArgStructTy, Temp, Arg, IsVolatile); } else { ArgumentTypes[I] = ArgType->getPointerTo(); Temp = Reader.createTemporary(ArgType); Builder.CreateStore(Arg, Temp); } Arguments[I] = Temp; } break; case ABIArgInfo::Expand: { const bool IsResult = false; ArrayRef<ABIArgInfo::Expansion> Expansions = ArgInfo.getExpansions(); MutableArrayRef<Value *> Values = MutableArrayRef<Value *>(Arguments).slice(I, Expansions.size()); MutableArrayRef<Type *> Types = MutableArrayRef<Type *>(ArgumentTypes).slice(I, Expansions.size()); expand(Reader, ArgInfo.getExpansions(), Arg, Values, Types, IsResult); I += Expansions.size() - 1; break; } case ABIArgInfo::ZeroExtend: ArgAttrs.addAttribute(Attribute::ZExt); goto direct; case ABIArgInfo::SignExtend: ArgAttrs.addAttribute(Attribute::SExt); goto direct; case ABIArgInfo::Direct: { direct: Type *ArgTy = ArgInfo.getType(); Arg = coerce(Reader, ArgTy, Arg); if (ArgTy->isStructTy()) { assert(Arg->getType()->isPointerTy()); assert(Arg->getType()->getPointerElementType() == ArgTy); ArgTy = ArgTy->getPointerTo(); ArgAttrs.addAttribute(Attribute::ByVal); } else if (ArgTy->isVectorTy()) { assert(Arg->getType() == ArgTy); Value *Temp = Reader.createTemporary(ArgTy); Builder.CreateStore(Arg, Temp); Arg = Temp; ArgTy = ArgTy->getPointerTo(); ArgAttrs.addAttribute(Attribute::ByVal); } ArgumentTypes[I] = ArgTy; Arguments[I] = Arg; if (ArgAttrs.hasAttributes()) { const unsigned Idx = I + 1; // Add one to accomodate the return attrs. Attrs.push_back(AttributeSet::get(Context, Idx, ArgAttrs)); } } } I++, J++; } const bool IsVarArg = false; Type *FunctionTy = FunctionType::get(FuncResultType, ArgumentTypes, IsVarArg); Type *FunctionPtrTy = Reader.getUnmanagedPointerType(FunctionTy); // If we're passed a function value, we might need to update the type here // to match, since we didn't know the right type when we created the function. if (isa<llvm::Function>(Target)) { llvm::Function *TargetFunc = cast<llvm::Function>(Target); if (TargetFunc->getType() != FunctionPtrTy) { bool MutateType = false; // If we're going to Jmp to the target, don't mutate the type, // since we may have added parameters to satisfy the constraints // of LLVM's musttail that would cause this signature to diverge // from what we'd have come up with in a normal call to the target. if (!IsJmp) { // We shouldn't change our view of function types multiple times, // so only modify the type if it's the placeholder type we installed // in makeDirectCallTargetNode. Type *VoidType = Type::getVoidTy(Context); PointerType *PlaceholderTy = FunctionType::get(VoidType, false)->getPointerTo(); MutateType = TargetFunc->getType() == PlaceholderTy; } if (MutateType) { // Update the type now that we know the full set of normal // and special arguments. TargetFunc->mutateType(FunctionPtrTy); } else { // Cast to the type we need for this call Target = Builder.CreatePointerCast(Target, FunctionPtrTy); } } } else { Target = Builder.CreateIntToPtr(Target, FunctionPtrTy); } // The most straightforward way to satisfy the constraints imposed by the GC // on threads that are executing unmanaged code is to make the transition to // and from unmanaged code immediately preceeding and following the machine // call instruction, respectively. Unfortunately, there is no way to express // this in "standard" LLVM IR, hence the intrinsic. This intrinsic is also // a special GC statepoint that forces any GC pointers in callee-saved // registers to be spilled to the stack. CallSite Call; if (IsUnmanagedCall) { Call = emitUnmanagedCall(Reader, Target, MayThrow, Arguments); } else { Call = Reader.makeCall(Target, MayThrow, Arguments); } CallingConv::ID CC; if (HasIndirectionCell) { assert(Signature.getCallingConvention() == CORINFO_CALLCONV_DEFAULT); CC = CallingConv::CLR_VirtualDispatchStub; } else if (IsJmpWithSecretParam) { assert(Signature.getCallingConvention() == CORINFO_CALLCONV_DEFAULT); CC = CallingConv::CLR_SecretParameter; } else { bool Unused; CC = getLLVMCallingConv(getNormalizedCallingConvention(Signature), Unused); } Call.setCallingConv(CC); if (Attrs.size() > 0) { Call.setAttributes(AttributeSet::get(Context, Attrs)); } Value *TheCallInst = Call.getInstruction(); if (HasIndirectResult) { assert(ResultNode != nullptr); if (!Reader.doesValueRepresentStruct(ResultNode)) { ResultNode = Builder.CreateLoad(ResultNode); } } else { assert(ResultNode == nullptr); const CallArgType &SigResultType = Signature.getResultType(); Type *Ty = Reader.getType(SigResultType.CorType, SigResultType.Class); Value *CallResult = TheCallInst; if (!Ty->isVoidTy()) { if (Result.getKind() == ABIArgInfo::Expand) { assert(FuncResultType->isStructTy()); ResultNode = Reader.createTemporary(Ty, "CallResult"); Reader.setValueRepresentsStruct(ResultNode); Type *BytePtrTy = Type::getInt8PtrTy(Context, 0); Value *DestPtr = Builder.CreatePointerCast(ResultNode, BytePtrTy); assert(Result.getExpansions().size() == FuncResultType->getStructNumElements()); ArrayRef<ABIArgInfo::Expansion> Expansions = Result.getExpansions(); int32_t expansionCount = Expansions.size(); for (int32_t I = 0; I < expansionCount; I++) { Value *StoreVal = Builder.CreateExtractValue(CallResult, I); collapse(Reader, Expansions[I], StoreVal, DestPtr); } } else { ResultNode = coerce(Reader, Ty, CallResult); } } else { ResultNode = TheCallInst; } } *CallNode = TheCallInst; if (IsJmp) { cast<CallInst>(TheCallInst) ->setTailCallKind(CallInst::TailCallKind::TCK_MustTail); } return ResultNode; }
Function *ABIMethodSignature::createFunction(GenIR &Reader, Module &M) { // Compute the function type LLVMContext &Context = M.getContext(); bool HasIndirectResult = Result.getKind() == ABIArgInfo::Indirect; uint32_t NumExtraArgs = HasIndirectResult ? 1 : 0; const uint32_t NumArgs = getNumABIArgs() + NumExtraArgs; int32_t ResultIndex = -1; SmallVector<Type *, 16> ArgumentTypes(NumArgs); SmallVector<AttributeSet, 16> Attrs(NumArgs + 1); if (HasIndirectResult) { ResultIndex = Signature->hasThis() ? 1 : 0; Result.setIndex((uint32_t)ResultIndex); ArgumentTypes[ResultIndex] = Reader.getManagedPointerType(Result.getType()); } else { AttrBuilder RetAttrs; if (Result.getKind() == ABIArgInfo::ZeroExtend) { RetAttrs.addAttribute(Attribute::ZExt); } else if (Result.getKind() == ABIArgInfo::SignExtend) { RetAttrs.addAttribute(Attribute::SExt); } if (RetAttrs.hasAttributes()) { Attrs.push_back( AttributeSet::get(Context, AttributeSet::ReturnIndex, RetAttrs)); } } uint32_t I = 0; for (auto &Arg : Args) { AttrBuilder ArgAttrs; if (ResultIndex >= 0 && I == (uint32_t)ResultIndex) { I++; } switch (Arg.getKind()) { case ABIArgInfo::Indirect: ArgumentTypes[I] = Reader.getManagedPointerType(Arg.getType()); break; case ABIArgInfo::Expand: for (const ABIArgInfo::Expansion &Exp : Arg.getExpansions()) { ArgumentTypes[I++] = Exp.TheType; } I--; break; case ABIArgInfo::ZeroExtend: ArgAttrs.addAttribute(Attribute::ZExt); goto direct; case ABIArgInfo::SignExtend: ArgAttrs.addAttribute(Attribute::SExt); goto direct; case ABIArgInfo::Direct: { direct: Type *ArgTy = Arg.getType(); if (ArgTy->isStructTy()) { ArgTy = ArgTy->getPointerTo(); ArgAttrs.addAttribute(Attribute::ByVal); } ArgumentTypes[I] = ArgTy; if (ArgAttrs.hasAttributes()) { const unsigned Idx = I + 1; // Add one to accomodate the return attrs. Attrs.push_back(AttributeSet::get(Context, Idx, ArgAttrs)); } } } Arg.setIndex(I); I++; } const bool IsVarArg = false; FunctionType *FunctionTy = FunctionType::get(FuncResultType, ArgumentTypes, IsVarArg); Function *F = Function::Create(FunctionTy, Function::ExternalLinkage, M.getModuleIdentifier(), &M); // Use "param" for these initial parameter values. Numbering here // is strictly positional (hence includes implicit parameters). uint32_t N = 0; for (Function::arg_iterator Args = F->arg_begin(); Args != F->arg_end(); Args++) { Args->setName(Twine("param") + Twine(N++)); } CallingConv::ID CC = Signature->hasSecretParameter() ? CallingConv::CLR_SecretParameter : CallingConv::C; F->setCallingConv(CC); if (Attrs.size() > 0) { F->setAttributes(AttributeSet::get(Context, Attrs)); } F->setGC("coreclr"); return F; }
/// Deduce nocapture attributes for the SCC. static bool addArgumentAttrs(const SCCNodeSet &SCCNodes) { bool Changed = false; ArgumentGraph AG; AttrBuilder B; B.addAttribute(Attribute::NoCapture); // Check each function in turn, determining which pointer arguments are not // captured. for (Function *F : SCCNodes) { // Definitions with weak linkage may be overridden at linktime with // something that captures pointers, so treat them like declarations. if (F->isDeclaration() || F->mayBeOverridden()) continue; // Functions that are readonly (or readnone) and nounwind and don't return // a value can't capture arguments. Don't analyze them. if (F->onlyReadsMemory() && F->doesNotThrow() && F->getReturnType()->isVoidTy()) { for (Function::arg_iterator A = F->arg_begin(), E = F->arg_end(); A != E; ++A) { if (A->getType()->isPointerTy() && !A->hasNoCaptureAttr()) { A->addAttr(AttributeSet::get(F->getContext(), A->getArgNo() + 1, B)); ++NumNoCapture; Changed = true; } } continue; } for (Function::arg_iterator A = F->arg_begin(), E = F->arg_end(); A != E; ++A) { if (!A->getType()->isPointerTy()) continue; bool HasNonLocalUses = false; if (!A->hasNoCaptureAttr()) { ArgumentUsesTracker Tracker(SCCNodes); PointerMayBeCaptured(&*A, &Tracker); if (!Tracker.Captured) { if (Tracker.Uses.empty()) { // If it's trivially not captured, mark it nocapture now. A->addAttr( AttributeSet::get(F->getContext(), A->getArgNo() + 1, B)); ++NumNoCapture; Changed = true; } else { // If it's not trivially captured and not trivially not captured, // then it must be calling into another function in our SCC. Save // its particulars for Argument-SCC analysis later. ArgumentGraphNode *Node = AG[&*A]; for (SmallVectorImpl<Argument *>::iterator UI = Tracker.Uses.begin(), UE = Tracker.Uses.end(); UI != UE; ++UI) { Node->Uses.push_back(AG[*UI]); if (*UI != A) HasNonLocalUses = true; } } } // Otherwise, it's captured. Don't bother doing SCC analysis on it. } if (!HasNonLocalUses && !A->onlyReadsMemory()) { // Can we determine that it's readonly/readnone without doing an SCC? // Note that we don't allow any calls at all here, or else our result // will be dependent on the iteration order through the functions in the // SCC. SmallPtrSet<Argument *, 8> Self; Self.insert(&*A); Attribute::AttrKind R = determinePointerReadAttrs(&*A, Self); if (R != Attribute::None) { AttrBuilder B; B.addAttribute(R); A->addAttr(AttributeSet::get(A->getContext(), A->getArgNo() + 1, B)); Changed = true; R == Attribute::ReadOnly ? ++NumReadOnlyArg : ++NumReadNoneArg; } } } } // The graph we've collected is partial because we stopped scanning for // argument uses once we solved the argument trivially. These partial nodes // show up as ArgumentGraphNode objects with an empty Uses list, and for // these nodes the final decision about whether they capture has already been // made. If the definition doesn't have a 'nocapture' attribute by now, it // captures. for (scc_iterator<ArgumentGraph *> I = scc_begin(&AG); !I.isAtEnd(); ++I) { const std::vector<ArgumentGraphNode *> &ArgumentSCC = *I; if (ArgumentSCC.size() == 1) { if (!ArgumentSCC[0]->Definition) continue; // synthetic root node // eg. "void f(int* x) { if (...) f(x); }" if (ArgumentSCC[0]->Uses.size() == 1 && ArgumentSCC[0]->Uses[0] == ArgumentSCC[0]) { Argument *A = ArgumentSCC[0]->Definition; A->addAttr(AttributeSet::get(A->getContext(), A->getArgNo() + 1, B)); ++NumNoCapture; Changed = true; } continue; } bool SCCCaptured = false; for (auto I = ArgumentSCC.begin(), E = ArgumentSCC.end(); I != E && !SCCCaptured; ++I) { ArgumentGraphNode *Node = *I; if (Node->Uses.empty()) { if (!Node->Definition->hasNoCaptureAttr()) SCCCaptured = true; } } if (SCCCaptured) continue; SmallPtrSet<Argument *, 8> ArgumentSCCNodes; // Fill ArgumentSCCNodes with the elements of the ArgumentSCC. Used for // quickly looking up whether a given Argument is in this ArgumentSCC. for (auto I = ArgumentSCC.begin(), E = ArgumentSCC.end(); I != E; ++I) { ArgumentSCCNodes.insert((*I)->Definition); } for (auto I = ArgumentSCC.begin(), E = ArgumentSCC.end(); I != E && !SCCCaptured; ++I) { ArgumentGraphNode *N = *I; for (SmallVectorImpl<ArgumentGraphNode *>::iterator UI = N->Uses.begin(), UE = N->Uses.end(); UI != UE; ++UI) { Argument *A = (*UI)->Definition; if (A->hasNoCaptureAttr() || ArgumentSCCNodes.count(A)) continue; SCCCaptured = true; break; } } if (SCCCaptured) continue; for (unsigned i = 0, e = ArgumentSCC.size(); i != e; ++i) { Argument *A = ArgumentSCC[i]->Definition; A->addAttr(AttributeSet::get(A->getContext(), A->getArgNo() + 1, B)); ++NumNoCapture; Changed = true; } // We also want to compute readonly/readnone. With a small number of false // negatives, we can assume that any pointer which is captured isn't going // to be provably readonly or readnone, since by definition we can't // analyze all uses of a captured pointer. // // The false negatives happen when the pointer is captured by a function // that promises readonly/readnone behaviour on the pointer, then the // pointer's lifetime ends before anything that writes to arbitrary memory. // Also, a readonly/readnone pointer may be returned, but returning a // pointer is capturing it. Attribute::AttrKind ReadAttr = Attribute::ReadNone; for (unsigned i = 0, e = ArgumentSCC.size(); i != e; ++i) { Argument *A = ArgumentSCC[i]->Definition; Attribute::AttrKind K = determinePointerReadAttrs(A, ArgumentSCCNodes); if (K == Attribute::ReadNone) continue; if (K == Attribute::ReadOnly) { ReadAttr = Attribute::ReadOnly; continue; } ReadAttr = K; break; } if (ReadAttr != Attribute::None) { AttrBuilder B, R; B.addAttribute(ReadAttr); R.addAttribute(Attribute::ReadOnly).addAttribute(Attribute::ReadNone); for (unsigned i = 0, e = ArgumentSCC.size(); i != e; ++i) { Argument *A = ArgumentSCC[i]->Definition; // Clear out existing readonly/readnone attributes A->removeAttr(AttributeSet::get(A->getContext(), A->getArgNo() + 1, R)); A->addAttr(AttributeSet::get(A->getContext(), A->getArgNo() + 1, B)); ReadAttr == Attribute::ReadOnly ? ++NumReadOnlyArg : ++NumReadNoneArg; Changed = true; } } } return Changed; }
Function *ABIMethodSignature::createFunction(GenIR &Reader, Module &M) { // Compute the function type LLVMContext &Context = M.getContext(); bool HasIndirectResult = Result.getKind() == ABIArgInfo::Indirect; uint32_t NumExtraArgs = HasIndirectResult ? 1 : 0; const uint32_t NumArgs = Args.size() + NumExtraArgs; int32_t ResultIndex = -1; SmallVector<Type *, 16> ArgumentTypes(NumArgs); SmallVector<AttributeSet, 16> Attrs(NumArgs + 1); if (HasIndirectResult) { ResultIndex = Signature->hasThis() ? 1 : 0; Result.setIndex((uint32_t)ResultIndex); ArgumentTypes[ResultIndex] = Reader.getManagedPointerType(Result.getType()); } else { AttrBuilder RetAttrs; if (Result.getKind() == ABIArgInfo::ZeroExtend) { RetAttrs.addAttribute(Attribute::ZExt); } else if (Result.getKind() == ABIArgInfo::SignExtend) { RetAttrs.addAttribute(Attribute::SExt); } if (RetAttrs.hasAttributes()) { Attrs.push_back( AttributeSet::get(Context, AttributeSet::ReturnIndex, RetAttrs)); } } uint32_t I = 0; for (auto &Arg : Args) { AttrBuilder ArgAttrs; if (ResultIndex >= 0 && I == (uint32_t)ResultIndex) { I++; } if (Arg.getKind() == ABIArgInfo::Indirect) { // TODO: byval attribute support ArgumentTypes[I] = Reader.getManagedPointerType(Arg.getType()); } else { ArgumentTypes[I] = Arg.getType(); if (Arg.getKind() == ABIArgInfo::ZeroExtend) { ArgAttrs.addAttribute(Attribute::ZExt); } else if (Arg.getKind() == ABIArgInfo::SignExtend) { ArgAttrs.addAttribute(Attribute::SExt); } if (ArgAttrs.hasAttributes()) { const unsigned Idx = I + 1; // Add one to accomodate the return attrs. Attrs.push_back(AttributeSet::get(Context, Idx, ArgAttrs)); } } Arg.setIndex(I); I++; } const bool IsVarArg = false; FunctionType *FunctionTy = FunctionType::get(FuncResultType, ArgumentTypes, IsVarArg); Function *F = Function::Create(FunctionTy, Function::ExternalLinkage, M.getModuleIdentifier(), &M); // Use "param" for these initial parameter values. Numbering here // is strictly positional (hence includes implicit parameters). uint32_t N = 0; for (Function::arg_iterator Args = F->arg_begin(); Args != F->arg_end(); Args++) { Args->setName(Twine("param") + Twine(N++)); } CallingConv::ID CC; if (Signature->hasSecretParameter()) { assert((--F->arg_end())->getType()->isIntegerTy()); AttrBuilder SecretParamAttrs; SecretParamAttrs.addAttribute("CLR_SecretParameter"); Attrs.push_back( AttributeSet::get(Context, F->arg_size(), SecretParamAttrs)); CC = CallingConv::CLR_SecretParameter; } else { CC = CallingConv::C; } F->setCallingConv(CC); if (Attrs.size() > 0) { F->setAttributes(AttributeSet::get(Context, Attrs)); } if (Reader.JitContext->Options->DoInsertStatepoints) { F->setGC("coreclr"); } return F; }
Value *ABICallSignature::emitCall(GenIR &Reader, Value *Target, bool MayThrow, ArrayRef<Value *> Args, Value *IndirectionCell, Value **CallNode) const { assert(Target->getType()->isIntegerTy(Reader.TargetPointerSizeInBits)); LLVMContext &Context = *Reader.JitContext->LLVMContext; // Compute the function type bool HasIndirectResult = Result.getKind() == ABIArgInfo::Indirect; bool HasIndirectionCell = IndirectionCell != nullptr; bool IsUnmanagedCall = Signature.getCallingConvention() != CORINFO_CALLCONV_DEFAULT; assert(((HasIndirectionCell ? 1 : 0) + (IsUnmanagedCall ? 1 : 0)) <= 1); uint32_t NumSpecialArgs = 0; if (HasIndirectionCell) { NumSpecialArgs = 1; } uint32_t NumExtraArgs = (HasIndirectResult ? 1 : 0) + NumSpecialArgs; const uint32_t NumArgs = Args.size() + NumExtraArgs; Value *ResultNode = nullptr; SmallVector<Type *, 16> ArgumentTypes(NumArgs); SmallVector<Value *, 16> Arguments(NumArgs); SmallVector<AttributeSet, 16> Attrs(NumArgs + 1); IRBuilder<> &Builder = *Reader.LLVMBuilder; // Check for calls with special args. // // Any special arguments are passed immediately preceeding the normal // arguments. The backend will place these arguments in the appropriate // registers according to the calling convention. Each special argument should // be machine-word-sized. if (HasIndirectionCell) { assert(IndirectionCell->getType()->isIntegerTy( Reader.TargetPointerSizeInBits)); ArgumentTypes[0] = IndirectionCell->getType(); Arguments[0] = IndirectionCell; } int32_t ResultIndex = -1; if (HasIndirectResult) { ResultIndex = (int32_t)NumSpecialArgs + (Signature.hasThis() ? 1 : 0); Type *ResultTy = Result.getType(); ArgumentTypes[ResultIndex] = Reader.getUnmanagedPointerType(ResultTy); Arguments[ResultIndex] = ResultNode = Reader.createTemporary(ResultTy); if (ResultTy->isStructTy()) { Reader.setValueRepresentsStruct(ResultNode); } } else { AttrBuilder RetAttrs; if (Result.getKind() == ABIArgInfo::ZeroExtend) { RetAttrs.addAttribute(Attribute::ZExt); } else if (Result.getKind() == ABIArgInfo::SignExtend) { RetAttrs.addAttribute(Attribute::SExt); } if (RetAttrs.hasAttributes()) { Attrs.push_back( AttributeSet::get(Context, AttributeSet::ReturnIndex, RetAttrs)); } } uint32_t I = NumSpecialArgs, J = 0; for (auto Arg : Args) { AttrBuilder ArgAttrs; if (ResultIndex >= 0 && I == (uint32_t)ResultIndex) { I++; } const ABIArgInfo &ArgInfo = this->Args[J]; Type *ArgType = Arg->getType(); if (ArgInfo.getKind() == ABIArgInfo::Indirect) { // TODO: byval attribute support Value *Temp = nullptr; if (Reader.doesValueRepresentStruct(Arg)) { StructType *ArgStructTy = cast<StructType>(ArgType->getPointerElementType()); ArgumentTypes[I] = ArgType; Temp = Reader.createTemporary(ArgStructTy); const bool IsVolatile = false; Reader.copyStruct(ArgStructTy, Temp, Arg, IsVolatile); } else { ArgumentTypes[I] = ArgType->getPointerTo(); Temp = Reader.createTemporary(ArgType); Builder.CreateStore(Arg, Temp); } Arguments[I] = Temp; } else { ArgumentTypes[I] = ArgInfo.getType(); Arguments[I] = coerce(Reader, ArgInfo.getType(), Arg); if (ArgInfo.getKind() == ABIArgInfo::ZeroExtend) { ArgAttrs.addAttribute(Attribute::ZExt); } else if (ArgInfo.getKind() == ABIArgInfo::SignExtend) { ArgAttrs.addAttribute(Attribute::SExt); } if (ArgAttrs.hasAttributes()) { const unsigned Idx = I + 1; // Add one to accomodate the return attrs. Attrs.push_back(AttributeSet::get(Context, Idx, ArgAttrs)); } } I++, J++; } const bool IsVarArg = false; Type *FunctionTy = FunctionType::get(FuncResultType, ArgumentTypes, IsVarArg); Type *FunctionPtrTy = Reader.getUnmanagedPointerType(FunctionTy); Target = Builder.CreateIntToPtr(Target, FunctionPtrTy); // The most straightforward way to satisfy the constraints imposed by the GC // on threads that are executing unmanaged code is to make the transition to // and from unmanaged code immediately preceeding and following the machine // call instruction, respectively. Unfortunately, there is no way to express // this in "standard" LLVM IR, hence the intrinsic. This intrinsic is also // a special GC statepoint that forces any GC pointers in callee-saved // registers to be spilled to the stack. CallSite Call; Value *UnmanagedCallResult = nullptr; if (IsUnmanagedCall) { Call = emitUnmanagedCall(Reader, Target, MayThrow, Arguments, UnmanagedCallResult); } else { Call = Reader.makeCall(Target, MayThrow, Arguments); } CallingConv::ID CC; if (HasIndirectionCell) { assert(Signature.getCallingConvention() == CORINFO_CALLCONV_DEFAULT); CC = CallingConv::CLR_VirtualDispatchStub; } else { bool Unused; CC = getLLVMCallingConv(getNormalizedCallingConvention(Signature), Unused); } Call.setCallingConv(CC); if (Attrs.size() > 0) { Call.setAttributes(AttributeSet::get(Context, Attrs)); } if (ResultNode == nullptr) { assert(!HasIndirectResult); const CallArgType &SigResultType = Signature.getResultType(); Type *Ty = Reader.getType(SigResultType.CorType, SigResultType.Class); if (!Ty->isVoidTy()) { ResultNode = coerce(Reader, Ty, IsUnmanagedCall ? UnmanagedCallResult : Call.getInstruction()); } else { ResultNode = Call.getInstruction(); } } else { if (!Reader.doesValueRepresentStruct(ResultNode)) { ResultNode = Builder.CreateLoad(ResultNode); } } *CallNode = Call.getInstruction(); return ResultNode; }
bool PruneEH::runOnSCC(CallGraphSCC &SCC) { SmallPtrSet<CallGraphNode *, 8> SCCNodes; CallGraph &CG = getAnalysis<CallGraph>(); bool MadeChange = false; // Fill SCCNodes with the elements of the SCC. Used for quickly // looking up whether a given CallGraphNode is in this SCC. for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I != E; ++I) SCCNodes.insert(*I); // First pass, scan all of the functions in the SCC, simplifying them // according to what we know. for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I != E; ++I) if (Function *F = (*I)->getFunction()) MadeChange |= SimplifyFunction(F); // Next, check to see if any callees might throw or if there are any external // functions in this SCC: if so, we cannot prune any functions in this SCC. // Definitions that are weak and not declared non-throwing might be // overridden at linktime with something that throws, so assume that. // If this SCC includes the unwind instruction, we KNOW it throws, so // obviously the SCC might throw. // bool SCCMightUnwind = false, SCCMightReturn = false; for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); (!SCCMightUnwind || !SCCMightReturn) && I != E; ++I) { Function *F = (*I)->getFunction(); if (F == 0) { SCCMightUnwind = true; SCCMightReturn = true; } else if (F->isDeclaration() || F->mayBeOverridden()) { SCCMightUnwind |= !F->doesNotThrow(); SCCMightReturn |= !F->doesNotReturn(); } else { bool CheckUnwind = !SCCMightUnwind && !F->doesNotThrow(); bool CheckReturn = !SCCMightReturn && !F->doesNotReturn(); if (!CheckUnwind && !CheckReturn) continue; // Check to see if this function performs an unwind or calls an // unwinding function. for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) { if (CheckUnwind && isa<ResumeInst>(BB->getTerminator())) { // Uses unwind / resume! SCCMightUnwind = true; } else if (CheckReturn && isa<ReturnInst>(BB->getTerminator())) { SCCMightReturn = true; } // Invoke instructions don't allow unwinding to continue, so we are // only interested in call instructions. if (CheckUnwind && !SCCMightUnwind) for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I) if (CallInst *CI = dyn_cast<CallInst>(I)) { if (CI->doesNotThrow()) { // This call cannot throw. } else if (Function *Callee = CI->getCalledFunction()) { CallGraphNode *CalleeNode = CG[Callee]; // If the callee is outside our current SCC then we may // throw because it might. if (!SCCNodes.count(CalleeNode)) { SCCMightUnwind = true; break; } } else { // Indirect call, it might throw. SCCMightUnwind = true; break; } } if (SCCMightUnwind && SCCMightReturn) break; } } } // If the SCC doesn't unwind or doesn't throw, note this fact. if (!SCCMightUnwind || !SCCMightReturn) for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I != E; ++I) { AttrBuilder NewAttributes; if (!SCCMightUnwind) NewAttributes.addAttribute(Attributes::NoUnwind); if (!SCCMightReturn) NewAttributes.addAttribute(Attributes::NoReturn); Function *F = (*I)->getFunction(); const AttributeSet &PAL = F->getAttributes(); const AttributeSet &NPAL = PAL.addAttr(F->getContext(), ~0, Attributes::get(F->getContext(), NewAttributes)); if (PAL != NPAL) { MadeChange = true; F->setAttributes(NPAL); } } for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I != E; ++I) { // Convert any invoke instructions to non-throwing functions in this node // into call instructions with a branch. This makes the exception blocks // dead. if (Function *F = (*I)->getFunction()) MadeChange |= SimplifyFunction(F); } return MadeChange; }
Module* makeLLVMModule() { // Module Construction Module* mod = new Module("foo.ll", getGlobalContext()); mod->setDataLayout("e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"); mod->setTargetTriple("x86_64-unknown-linux-gnu"); // Type Definitions ArrayType* ArrayTy_0 = ArrayType::get(IntegerType::get(mod->getContext(), 8), 5); PointerType* PointerTy_1 = PointerType::get(ArrayTy_0, 0); std::vector<Type*>FuncTy_2_args; PointerType* PointerTy_3 = PointerType::get(IntegerType::get(mod->getContext(), 8), 0); FuncTy_2_args.push_back(PointerTy_3); FuncTy_2_args.push_back(IntegerType::get(mod->getContext(), 32)); FunctionType* FuncTy_2 = FunctionType::get( /*Result=*/Type::getVoidTy(mod->getContext()), /*Params=*/FuncTy_2_args, /*isVarArg=*/false); PointerType* PointerTy_4 = PointerType::get(PointerTy_3, 0); PointerType* PointerTy_5 = PointerType::get(IntegerType::get(mod->getContext(), 32), 0); std::vector<Type*>FuncTy_6_args; FunctionType* FuncTy_6 = FunctionType::get( /*Result=*/IntegerType::get(mod->getContext(), 32), /*Params=*/FuncTy_6_args, /*isVarArg=*/false); PointerType* PointerTy_7 = PointerType::get(FuncTy_2, 0); // Function Declarations Function* func_foo = mod->getFunction("foo"); if (!func_foo) { func_foo = Function::Create( /*Type=*/FuncTy_2, /*Linkage=*/GlobalValue::ExternalLinkage, /*Name=*/"foo", mod); func_foo->setCallingConv(CallingConv::C); } AttributeSet func_foo_PAL; { SmallVector<AttributeSet, 4> Attrs; AttributeSet PAS; { AttrBuilder B; B.addAttribute(Attribute::NoUnwind); B.addAttribute(Attribute::UWTable); PAS = AttributeSet::get(mod->getContext(), ~0U, B); } Attrs.push_back(PAS); func_foo_PAL = AttributeSet::get(mod->getContext(), Attrs); } func_foo->setAttributes(func_foo_PAL); Function* func_main = mod->getFunction("main"); if (!func_main) { func_main = Function::Create( /*Type=*/FuncTy_6, /*Linkage=*/GlobalValue::ExternalLinkage, /*Name=*/"main", mod); func_main->setCallingConv(CallingConv::C); } AttributeSet func_main_PAL; { SmallVector<AttributeSet, 4> Attrs; AttributeSet PAS; { AttrBuilder B; B.addAttribute(Attribute::NoUnwind); B.addAttribute(Attribute::UWTable); PAS = AttributeSet::get(mod->getContext(), ~0U, B); } Attrs.push_back(PAS); func_main_PAL = AttributeSet::get(mod->getContext(), Attrs); } func_main->setAttributes(func_main_PAL); // Global Variable Declarations GlobalVariable* gvar_array__str = new GlobalVariable(/*Module=*/*mod, /*Type=*/ArrayTy_0, /*isConstant=*/true, /*Linkage=*/GlobalValue::PrivateLinkage, /*Initializer=*/0, // has initializer, specified below /*Name=*/".str"); gvar_array__str->setAlignment(1); // Constant Definitions Constant *const_array_8 = ConstantDataArray::getString(mod->getContext(), "gogo", true); ConstantInt* const_int32_9 = ConstantInt::get(mod->getContext(), APInt(32, StringRef("1"), 10)); std::vector<Constant*> const_ptr_10_indices; ConstantInt* const_int32_11 = ConstantInt::get(mod->getContext(), APInt(32, StringRef("0"), 10)); const_ptr_10_indices.push_back(const_int32_11); const_ptr_10_indices.push_back(const_int32_11); Constant* const_ptr_10 = ConstantExpr::getGetElementPtr(gvar_array__str, const_ptr_10_indices); ConstantInt* const_int32_12 = ConstantInt::get(mod->getContext(), APInt(32, StringRef("3"), 10)); // Global Variable Definitions gvar_array__str->setInitializer(const_array_8); // Function Definitions // Function: foo (func_foo) { Function::arg_iterator args = func_foo->arg_begin(); Value* ptr_name = args++; ptr_name->setName("name"); Value* int32_count = args++; int32_count->setName("count"); BasicBlock* label_entry = BasicBlock::Create(mod->getContext(), "entry",func_foo,0); // Block entry (label_entry) AllocaInst* ptr_name_addr = new AllocaInst(PointerTy_3, "name.addr", label_entry); ptr_name_addr->setAlignment(8); AllocaInst* ptr_count_addr = new AllocaInst(IntegerType::get(mod->getContext(), 32), "count.addr", label_entry); ptr_count_addr->setAlignment(4); StoreInst* void_13 = new StoreInst(ptr_name, ptr_name_addr, false, label_entry); void_13->setAlignment(8); StoreInst* void_14 = new StoreInst(int32_count, ptr_count_addr, false, label_entry); void_14->setAlignment(4); ReturnInst::Create(mod->getContext(), label_entry); } // Function: main (func_main) { BasicBlock* label_entry_16 = BasicBlock::Create(mod->getContext(), "entry",func_main,0); // Block entry (label_entry_16) AllocaInst* ptr_myarg1 = new AllocaInst(PointerTy_3, "myarg1", label_entry_16); ptr_myarg1->setAlignment(8); AllocaInst* ptr_myarg2 = new AllocaInst(IntegerType::get(mod->getContext(), 32), "myarg2", label_entry_16); ptr_myarg2->setAlignment(4); StoreInst* void_17 = new StoreInst(const_ptr_10, ptr_myarg1, false, label_entry_16); void_17->setAlignment(8); StoreInst* void_18 = new StoreInst(const_int32_12, ptr_myarg2, false, label_entry_16); void_18->setAlignment(4); LoadInst* ptr_19 = new LoadInst(ptr_myarg1, "", false, label_entry_16); ptr_19->setAlignment(8); LoadInst* int32_20 = new LoadInst(ptr_myarg2, "", false, label_entry_16); int32_20->setAlignment(4); std::vector<Value*> void_21_params; void_21_params.push_back(ptr_19); void_21_params.push_back(int32_20); CallInst* void_21 = CallInst::Create(func_foo, void_21_params, "", label_entry_16); void_21->setCallingConv(CallingConv::C); void_21->setTailCall(false); AttributeSet void_21_PAL; void_21->setAttributes(void_21_PAL); ReturnInst::Create(mod->getContext(), const_int32_11, label_entry_16); } return mod; }
static void addExplicitArguments(std::vector<LLValue *> &args, AttrSet &attrs, IrFuncTy &irFty, LLFunctionType *callableTy, const std::vector<DValue *> &argvals, int numFormalParams) { // Number of arguments added to the LLVM type that are implicit on the // frontend side of things (this, context pointers, etc.) const size_t implicitLLArgCount = args.size(); // Number of formal arguments in the LLVM type (i.e. excluding varargs). const size_t formalLLArgCount = irFty.args.size(); // The number of explicit arguments in the D call expression (including // varargs), not all of which necessarily generate a LLVM argument. const size_t explicitDArgCount = argvals.size(); // construct and initialize an IrFuncTyArg object for each vararg std::vector<IrFuncTyArg *> optionalIrArgs; for (size_t i = numFormalParams; i < explicitDArgCount; i++) { Type *argType = argvals[i]->getType(); bool passByVal = gABI->passByVal(argType); AttrBuilder initialAttrs; if (passByVal) { initialAttrs.add(LLAttribute::ByVal); } else { initialAttrs.add(DtoShouldExtend(argType)); } optionalIrArgs.push_back(new IrFuncTyArg(argType, passByVal, initialAttrs)); optionalIrArgs.back()->parametersIdx = i; } // let the ABI rewrite the IrFuncTyArg objects gABI->rewriteVarargs(irFty, optionalIrArgs); const size_t explicitLLArgCount = formalLLArgCount + optionalIrArgs.size(); args.resize(implicitLLArgCount + explicitLLArgCount, static_cast<llvm::Value *>(nullptr)); // Iterate the explicit arguments from left to right in the D source, // which is the reverse of the LLVM order if irFty.reverseParams is true. for (size_t i = 0; i < explicitLLArgCount; ++i) { const bool isVararg = (i >= irFty.args.size()); IrFuncTyArg *irArg = nullptr; if (isVararg) { irArg = optionalIrArgs[i - numFormalParams]; } else { irArg = irFty.args[i]; } DValue *const argval = argvals[irArg->parametersIdx]; Type *const argType = argval->getType(); llvm::Value *llVal = nullptr; if (isVararg) { llVal = irFty.putParam(*irArg, argval); } else { llVal = irFty.putParam(i, argval); } const size_t llArgIdx = implicitLLArgCount + (irFty.reverseParams ? explicitLLArgCount - i - 1 : i); llvm::Type *const callableArgType = (isVararg ? nullptr : callableTy->getParamType(llArgIdx)); // Hack around LDC assuming structs and static arrays are in memory: // If the function wants a struct, and the argument value is a // pointer to a struct, load from it before passing it in. if (isaPointer(llVal) && DtoIsPassedByRef(argType) && ((!isVararg && !isaPointer(callableArgType)) || (isVararg && !irArg->byref && !irArg->isByVal()))) { Logger::println("Loading struct type for function argument"); llVal = DtoLoad(llVal); } // parameter type mismatch, this is hard to get rid of if (!isVararg && llVal->getType() != callableArgType) { IF_LOG { Logger::cout() << "arg: " << *llVal << '\n'; Logger::cout() << "expects: " << *callableArgType << '\n'; } if (isaStruct(llVal)) { llVal = DtoAggrPaint(llVal, callableArgType); } else { llVal = DtoBitCast(llVal, callableArgType); } } args[llArgIdx] = llVal; // +1 as index 0 contains the function attributes. attrs.add(llArgIdx + 1, irArg->attrs); if (isVararg) { delete irArg; } }