void TryCatchFinallyScopes::runCleanups(CleanupCursor sourceScope, CleanupCursor targetScope, llvm::BasicBlock *continueWith) { #if LDC_LLVM_VER >= 308 if (useMSVCEH()) { runCleanupCopies(sourceScope, targetScope, continueWith); return; } #endif assert(targetScope <= sourceScope); if (targetScope == sourceScope) { // No cleanups to run, just branch to the next block. irs.ir->CreateBr(continueWith); return; } // Insert the unconditional branch to the first cleanup block. irs.ir->CreateBr(cleanupScopes[sourceScope - 1].beginBlock()); // Update all the control flow in the cleanups to make sure we end up where // we want. for (CleanupCursor i = sourceScope; i-- > targetScope;) { llvm::BasicBlock *nextBlock = (i > targetScope) ? cleanupScopes[i - 1].beginBlock() : continueWith; cleanupScopes[i].run(irs, irs.scopebb(), nextBlock); } }
void TryCatchFinallyScopes::popTryCatch() { tryCatchScopes.pop_back(); if (useMSVCEH()) { #if LDC_LLVM_VER >= 308 assert(isCatchSwitchBlock(cleanupScopes.back().beginBlock())); #endif popCleanups(currentCleanupScope() - 1); } else { landingPadsPerCleanupScope[currentCleanupScope()].pop_back(); } }
void TryCatchFinallyScopes::pushTryCatch(TryCatchStatement *stmt, llvm::BasicBlock *endbb) { TryCatchScope scope(irs, getOrCreateEhPtrSlot(), stmt, endbb); // Only after emitting all the catch bodies, register the catch scopes. // This is so that (re)throwing inside a catch does not match later // catches. tryCatchScopes.push_back(scope); if (!useMSVCEH()) landingPadsPerCleanupScope[currentCleanupScope()].push_back(nullptr); }
CleanupScope::CleanupScope(llvm::BasicBlock *beginBlock, llvm::BasicBlock *endBlock) { #if LDC_LLVM_VER >= 308 if (useMSVCEH()) { findSuccessors(blocks, beginBlock, endBlock); return; } #endif blocks.push_back(beginBlock); if (endBlock != beginBlock) blocks.push_back(endBlock); }
TryCatchScope::TryCatchScope(IRState &irs, llvm::Value *ehPtrSlot, TryCatchStatement *stmt, llvm::BasicBlock *endbb) : stmt(stmt), endbb(endbb) { assert(stmt->catches); cleanupScope = irs.funcGen().scopes.currentCleanupScope(); catchesNonExceptions = std::any_of(stmt->catches->begin(), stmt->catches->end(), [](Catch *c) { for (auto cd = c->type->toBasetype()->isClassHandle(); cd; cd = isClassDeclarationOrNull(cd->baseClass)) { // CALYPSO if (cd == ClassDeclaration::exception) return false; } return true; }); #if LDC_LLVM_VER >= 308 if (useMSVCEH()) { emitCatchBodiesMSVC(irs, ehPtrSlot); return; } #endif emitCatchBodies(irs, ehPtrSlot); }
llvm::BasicBlock *TryCatchFinallyScopes::emitLandingPad() { #if LDC_LLVM_VER >= 308 if (useMSVCEH()) { assert(currentCleanupScope() > 0); return emitLandingPadMSVC(currentCleanupScope() - 1); } #endif // save and rewrite scope IRScope savedIRScope = irs.scope(); // insert landing pads at the end of the function, in emission order, // to improve human-readability of the IR llvm::BasicBlock *beginBB = irs.insertBBBefore(nullptr, "landingPad"); irs.scope() = IRScope(beginBB); llvm::LandingPadInst *landingPad = createLandingPadInst(irs); // Stash away the exception object pointer and selector value into their // stack slots. llvm::Value *ehPtr = DtoExtractValue(landingPad, 0); irs.ir->CreateStore(ehPtr, getOrCreateEhPtrSlot()); llvm::Value *ehSelector = DtoExtractValue(landingPad, 1); if (!ehSelectorSlot) ehSelectorSlot = DtoRawAlloca(ehSelector->getType(), 0, "eh.selector"); irs.ir->CreateStore(ehSelector, ehSelectorSlot); // Add landingpad clauses, emit finallys and 'if' chain to catch the // exception. CleanupCursor lastCleanup = currentCleanupScope(); for (auto it = tryCatchScopes.rbegin(), end = tryCatchScopes.rend(); it != end; ++it) { const auto &tryCatchScope = *it; // Insert any cleanups in between the previous (inner-more) try-catch scope // and this one. const auto newCleanup = tryCatchScope.getCleanupScope(); assert(lastCleanup >= newCleanup); if (lastCleanup > newCleanup) { landingPad->setCleanup(true); llvm::BasicBlock *afterCleanupBB = irs.insertBB(beginBB->getName() + llvm::Twine(".after.cleanup")); runCleanups(lastCleanup, newCleanup, afterCleanupBB); irs.scope() = IRScope(afterCleanupBB); lastCleanup = newCleanup; } for (const auto &cb : tryCatchScope.getCatchBlocks()) { // Add the ClassInfo reference to the landingpad instruction so it is // emitted to the EH tables. landingPad->addClause(cb.classInfoPtr); llvm::BasicBlock *mismatchBB = irs.insertBB(beginBB->getName() + llvm::Twine(".mismatch")); // "Call" llvm.eh.typeid.for, which gives us the eh selector value to // compare the landing pad selector value with. llvm::Value *ehTypeId = irs.ir->CreateCall(GET_INTRINSIC_DECL(eh_typeid_for), DtoBitCast(cb.classInfoPtr, getVoidPtrType())); // Compare the selector value from the unwinder against the expected // one and branch accordingly. irs.ir->CreateCondBr( irs.ir->CreateICmpEQ(irs.ir->CreateLoad(ehSelectorSlot), ehTypeId), cb.bodyBB, mismatchBB, cb.branchWeights); irs.scope() = IRScope(mismatchBB); } } // No catch matched. Execute all finallys and resume unwinding. auto resumeUnwindBlock = getOrCreateResumeUnwindBlock(); if (lastCleanup > 0) { landingPad->setCleanup(true); runCleanups(lastCleanup, 0, resumeUnwindBlock); } else if (!tryCatchScopes.empty()) { // Directly convert the last mismatch branch into a branch to the // unwind resume block. irs.scopebb()->replaceAllUsesWith(resumeUnwindBlock); irs.scopebb()->eraseFromParent(); } else { irs.ir->CreateBr(resumeUnwindBlock); } irs.scope() = savedIRScope; return beginBB; }
llvm::BasicBlock *CleanupScope::run(IRState &irs, llvm::BasicBlock *sourceBlock, llvm::BasicBlock *continueWith) { #if LDC_LLVM_VER >= 308 if (useMSVCEH()) return runCopying(irs, sourceBlock, continueWith); #endif if (exitTargets.empty() || (exitTargets.size() == 1 && exitTargets[0].branchTarget == continueWith)) { // We didn't need a branch selector before and still don't need one. assert(!branchSelector); // Set up the unconditional branch at the end of the cleanup if we have // not done so already. if (exitTargets.empty()) { exitTargets.emplace_back(continueWith); llvm::BranchInst::Create(continueWith, endBlock()); } exitTargets.front().sourceBlocks.push_back(sourceBlock); return beginBlock(); } // We need a branch selector if we are here... if (!branchSelector) { // ... and have not created one yet, so do so now. branchSelector = new llvm::AllocaInst(llvm::Type::getInt32Ty(irs.context()), #if LDC_LLVM_VER >= 500 irs.module.getDataLayout().getAllocaAddrSpace(), #endif llvm::Twine("branchsel.") + beginBlock()->getName(), irs.topallocapoint()); // Now we also need to store 0 to it to keep the paths that go to the // only existing branch target the same. for (auto bb : exitTargets.front().sourceBlocks) { new llvm::StoreInst(DtoConstUint(0), branchSelector, bb->getTerminator()); } // And convert the BranchInst to the existing branch target to a // SelectInst so we can append the other cases to it. endBlock()->getTerminator()->eraseFromParent(); llvm::Value *sel = new llvm::LoadInst(branchSelector, "", endBlock()); llvm::SwitchInst::Create( sel, exitTargets[0].branchTarget, 1, // Expected number of branches, only for pre-allocating. endBlock()); } // If we already know this branch target, figure out the branch selector // value and simply insert the store into the source block (prior to the // last instruction, which is the branch to the first cleanup). for (unsigned i = 0; i < exitTargets.size(); ++i) { CleanupExitTarget &t = exitTargets[i]; if (t.branchTarget == continueWith) { new llvm::StoreInst(DtoConstUint(i), branchSelector, sourceBlock->getTerminator()); // Note: Strictly speaking, keeping this up to date would not be // needed right now, because we never to any optimizations that // require changes to the source blocks after the initial conversion // from one to two branch targets. Keeping this around for now to // ease future development, but may be removed to save some work. t.sourceBlocks.push_back(sourceBlock); return beginBlock(); } } // We don't know this branch target yet, so add it to the SwitchInst... llvm::ConstantInt *const selectorVal = DtoConstUint(exitTargets.size()); llvm::cast<llvm::SwitchInst>(endBlock()->getTerminator()) ->addCase(selectorVal, continueWith); // ... insert the store into the source block... new llvm::StoreInst(selectorVal, branchSelector, sourceBlock->getTerminator()); // ... and keep track of it (again, this is unnecessary right now as // discussed in the above note). exitTargets.emplace_back(continueWith); exitTargets.back().sourceBlocks.push_back(sourceBlock); return beginBlock(); }
static void buildRuntimeModule() { Logger::println("building runtime module"); M = new llvm::Module("ldc internal runtime", gIR->context()); Type *voidTy = Type::tvoid; Type *boolTy = Type::tbool; Type *ubyteTy = Type::tuns8; Type *intTy = Type::tint32; Type *uintTy = Type::tuns32; Type *ulongTy = Type::tuns64; Type *sizeTy = Type::tsize_t; Type *dcharTy = Type::tdchar; Type *voidPtrTy = Type::tvoidptr; Type *voidArrayTy = Type::tvoid->arrayOf(); Type *voidArrayPtrTy = voidArrayTy->pointerTo(); Type *stringTy = Type::tchar->arrayOf(); Type *wstringTy = Type::twchar->arrayOf(); Type *dstringTy = Type::tdchar->arrayOf(); // Ensure that the declarations exist before creating llvm types for them. ensureDecl(ClassDeclaration::object, "Object"); ensureDecl(Type::typeinfoclass, "TypeInfo_Class"); ensureDecl(Type::dtypeinfo, "DTypeInfo"); ensureDecl(Type::typeinfoassociativearray, "TypeInfo_AssociativeArray"); ensureDecl(Module::moduleinfo, "ModuleInfo"); Type *objectTy = ClassDeclaration::object->type; Type *classInfoTy = Type::typeinfoclass->type; Type *typeInfoTy = Type::dtypeinfo->type; Type *aaTypeInfoTy = Type::typeinfoassociativearray->type; Type *moduleInfoPtrTy = Module::moduleinfo->type->pointerTo(); // The AA type is a struct that only contains a ptr Type *aaTy = voidPtrTy; ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // Construct some attribute lists used below (possibly multiple times) AttrSet NoAttrs, Attr_NoAlias(NoAttrs, llvm::AttributeSet::ReturnIndex, llvm::Attribute::NoAlias), Attr_NoUnwind(NoAttrs, llvm::AttributeSet::FunctionIndex, llvm::Attribute::NoUnwind), Attr_ReadOnly(NoAttrs, llvm::AttributeSet::FunctionIndex, llvm::Attribute::ReadOnly), Attr_Cold(NoAttrs, llvm::AttributeSet::FunctionIndex, llvm::Attribute::Cold), Attr_Cold_NoReturn(Attr_Cold, llvm::AttributeSet::FunctionIndex, llvm::Attribute::NoReturn), Attr_ReadOnly_NoUnwind(Attr_ReadOnly, llvm::AttributeSet::FunctionIndex, llvm::Attribute::NoUnwind), Attr_ReadOnly_1_NoCapture(Attr_ReadOnly, 1, llvm::Attribute::NoCapture), Attr_ReadOnly_1_3_NoCapture(Attr_ReadOnly_1_NoCapture, 3, llvm::Attribute::NoCapture), Attr_ReadOnly_NoUnwind_1_NoCapture(Attr_ReadOnly_1_NoCapture, ~0U, llvm::Attribute::NoUnwind), Attr_ReadNone(NoAttrs, ~0U, llvm::Attribute::ReadNone), Attr_1_NoCapture(NoAttrs, 1, llvm::Attribute::NoCapture), Attr_NoAlias_1_NoCapture(Attr_1_NoCapture, 0, llvm::Attribute::NoAlias), Attr_1_2_NoCapture(Attr_1_NoCapture, 2, llvm::Attribute::NoCapture), Attr_1_3_NoCapture(Attr_1_NoCapture, 3, llvm::Attribute::NoCapture), Attr_1_4_NoCapture(Attr_1_NoCapture, 4, llvm::Attribute::NoCapture); ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // void _d_assert(string file, uint line) // void _d_arraybounds(string file, uint line) createFwdDecl(LINKc, Type::tvoid, {"_d_assert", "_d_arraybounds"}, {stringTy, uintTy}, {}, Attr_Cold_NoReturn); // void _d_assert_msg(string msg, string file, uint line) createFwdDecl(LINKc, voidTy, {"_d_assert_msg"}, {stringTy, stringTy, uintTy}, {}, Attr_Cold_NoReturn); // void _d_assertm(immutable(ModuleInfo)* m, uint line) // void _d_array_bounds(immutable(ModuleInfo)* m, uint line) // void _d_switch_error(immutable(ModuleInfo)* m, uint line) createFwdDecl( LINKc, voidTy, {"_d_assertm", "_d_array_bounds", "_d_switch_error"}, {moduleInfoPtrTy, uintTy}, {STCimmutable, 0}, Attr_Cold_NoReturn); ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // void* _d_allocmemory(size_t sz) createFwdDecl(LINKc, voidPtrTy, {"_d_allocmemory"}, {sizeTy}, {}, Attr_NoAlias); // void* _d_allocmemoryT(TypeInfo ti) createFwdDecl(LINKc, voidPtrTy, {"_d_allocmemoryT"}, {typeInfoTy}, {}, Attr_NoAlias); // void[] _d_newarrayT (const TypeInfo ti, size_t length) // void[] _d_newarrayiT(const TypeInfo ti, size_t length) // void[] _d_newarrayU (const TypeInfo ti, size_t length) createFwdDecl(LINKc, voidArrayTy, {"_d_newarrayT", "_d_newarrayiT", "_d_newarrayU"}, {typeInfoTy, sizeTy}, {STCconst, 0}); // void[] _d_newarraymTX (const TypeInfo ti, size_t[] dims) // void[] _d_newarraymiTX(const TypeInfo ti, size_t[] dims) createFwdDecl(LINKc, voidArrayTy, {"_d_newarraymTX", "_d_newarraymiTX"}, {typeInfoTy, sizeTy->arrayOf()}, {STCconst, 0}); // void[] _d_arraysetlengthT (const TypeInfo ti, size_t newlength, void[]* p) // void[] _d_arraysetlengthiT(const TypeInfo ti, size_t newlength, void[]* p) createFwdDecl(LINKc, voidArrayTy, {"_d_arraysetlengthT", "_d_arraysetlengthiT"}, {typeInfoTy, sizeTy, voidArrayPtrTy}, {STCconst, 0, 0}); // byte[] _d_arrayappendcTX(const TypeInfo ti, ref byte[] px, size_t n) createFwdDecl(LINKc, voidArrayTy, {"_d_arrayappendcTX"}, {typeInfoTy, voidArrayTy, sizeTy}, {STCconst, STCref, 0}); // void[] _d_arrayappendT(const TypeInfo ti, ref byte[] x, byte[] y) createFwdDecl(LINKc, voidArrayTy, {"_d_arrayappendT"}, {typeInfoTy, voidArrayTy, voidArrayTy}, {STCconst, STCref, 0}); // void[] _d_arrayappendcd(ref byte[] x, dchar c) // void[] _d_arrayappendwd(ref byte[] x, dchar c) createFwdDecl(LINKc, voidArrayTy, {"_d_arrayappendcd", "_d_arrayappendwd"}, {voidArrayTy, dcharTy}, {STCref, 0}); // byte[] _d_arraycatT(const TypeInfo ti, byte[] x, byte[] y) createFwdDecl(LINKc, voidArrayTy, {"_d_arraycatT"}, {typeInfoTy, voidArrayTy, voidArrayTy}, {STCconst, 0, 0}); // void[] _d_arraycatnTX(const TypeInfo ti, byte[][] arrs) createFwdDecl(LINKc, voidArrayTy, {"_d_arraycatnTX"}, {typeInfoTy, voidArrayTy->arrayOf()}, {STCconst, 0}); // Object _d_newclass(const ClassInfo ci) createFwdDecl(LINKc, objectTy, {"_d_newclass"}, {classInfoTy}, {STCconst}, Attr_NoAlias); // void* _d_newitemT (TypeInfo ti) // void* _d_newitemiT(TypeInfo ti) createFwdDecl(LINKc, voidPtrTy, {"_d_newitemT", "_d_newitemiT"}, {typeInfoTy}, {0}, Attr_NoAlias); // void _d_delarray_t(void[]* p, const TypeInfo_Struct ti) createFwdDecl(LINKc, voidTy, {"_d_delarray_t"}, {voidArrayPtrTy, Type::typeinfostruct->type}, {0, STCconst}); // void _d_delmemory(void** p) // void _d_delinterface(void** p) createFwdDecl(LINKc, voidTy, {"_d_delmemory", "_d_delinterface"}, {voidPtrTy->pointerTo()}); // void _d_callfinalizer(void* p) createFwdDecl(LINKc, voidTy, {"_d_callfinalizer"}, {voidPtrTy}); // D2: void _d_delclass(Object* p) createFwdDecl(LINKc, voidTy, {"_d_delclass"}, {objectTy->pointerTo()}); // void _d_delstruct(void** p, TypeInfo_Struct inf) createFwdDecl(LINKc, voidTy, {"_d_delstruct"}, {voidPtrTy->pointerTo(), Type::typeinfostruct->type}); ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // array slice copy when assertions are on! // void _d_array_slice_copy(void* dst, size_t dstlen, void* src, size_t // srclen) createFwdDecl(LINKc, voidTy, {"_d_array_slice_copy"}, {voidPtrTy, sizeTy, voidPtrTy, sizeTy}, {}, Attr_1_3_NoCapture); //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // int _aApplycd1(in char[] aa, dg_t dg) // int _aApplyRcd1(in char[] aa, dg_t dg) #define STR_APPLY1(TY, a, b) \ { \ const std::string prefix = "_aApply"; \ std::string fname1 = prefix + (a) + '1', fname2 = prefix + (b) + '1', \ fname3 = prefix + 'R' + (a) + '1', \ fname4 = prefix + 'R' + (b) + '1'; \ createFwdDecl(LINKc, sizeTy, {fname1, fname2, fname3, fname4}, \ {TY, rt_dg1()}); \ } STR_APPLY1(stringTy, "cw", "cd") STR_APPLY1(wstringTy, "wc", "wd") STR_APPLY1(dstringTy, "dc", "dw") #undef STR_APPLY1 // int _aApplycd2(in char[] aa, dg2_t dg) // int _aApplyRcd2(in char[] aa, dg2_t dg) #define STR_APPLY2(TY, a, b) \ { \ const std::string prefix = "_aApply"; \ std::string fname1 = prefix + (a) + '2', fname2 = prefix + (b) + '2', \ fname3 = prefix + 'R' + (a) + '2', \ fname4 = prefix + 'R' + (b) + '2'; \ createFwdDecl(LINKc, sizeTy, {fname1, fname2, fname3, fname4}, \ {TY, rt_dg2()}); \ } STR_APPLY2(stringTy, "cw", "cd") STR_APPLY2(wstringTy, "wc", "wd") STR_APPLY2(dstringTy, "dc", "dw") #undef STR_APPLY2 ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // fixes the length for dynamic array casts // size_t _d_array_cast_len(size_t len, size_t elemsz, size_t newelemsz) createFwdDecl(LINKc, sizeTy, {"_d_array_cast_len"}, {sizeTy, sizeTy, sizeTy}, {}, Attr_ReadNone); ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // void[] _d_arrayassign_l(TypeInfo ti, void[] src, void[] dst, void* ptmp) // void[] _d_arrayassign_r(TypeInfo ti, void[] src, void[] dst, void* ptmp) createFwdDecl(LINKc, voidArrayTy, {"_d_arrayassign_l", "_d_arrayassign_r"}, {typeInfoTy, voidArrayTy, voidArrayTy, voidPtrTy}); // void[] _d_arrayctor(TypeInfo ti, void[] from, void[] to) createFwdDecl(LINKc, voidArrayTy, {"_d_arrayctor"}, {typeInfoTy, voidArrayTy, voidArrayTy}); // void* _d_arraysetassign(void* p, void* value, int count, TypeInfo ti) // void* _d_arraysetctor(void* p, void* value, int count, TypeInfo ti) createFwdDecl(LINKc, voidPtrTy, {"_d_arraysetassign", "_d_arraysetctor"}, {voidPtrTy, voidPtrTy, intTy, typeInfoTy}, {}, Attr_NoAlias); ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // cast interface // void* _d_interface_cast(void* p, ClassInfo c) createFwdDecl(LINKc, voidPtrTy, {"_d_interface_cast"}, {voidPtrTy, classInfoTy}, {}, Attr_ReadOnly_NoUnwind); // dynamic cast // void* _d_dynamic_cast(Object o, ClassInfo c) createFwdDecl(LINKc, voidPtrTy, {"_d_dynamic_cast"}, {objectTy, classInfoTy}, {}, Attr_ReadOnly_NoUnwind); ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // char[] _adReverseChar(char[] a) // char[] _adSortChar(char[] a) createFwdDecl(LINKc, stringTy, {"_adReverseChar", "_adSortChar"}, {stringTy}); // wchar[] _adReverseWchar(wchar[] a) // wchar[] _adSortWchar(wchar[] a) createFwdDecl(LINKc, wstringTy, {"_adReverseWchar", "_adSortWchar"}, {wstringTy}); // void[] _adReverse(void[] a, size_t szelem) createFwdDecl(LINKc, wstringTy, {"_adReverse"}, {voidArrayTy, sizeTy}, {}, Attr_NoUnwind); // int _adEq2(void[] a1, void[] a2, TypeInfo ti) // int _adCmp2(void[] a1, void[] a2, TypeInfo ti) createFwdDecl(LINKc, intTy, {"_adEq2", "_adCmp2"}, {voidArrayTy, voidArrayTy, typeInfoTy}, {}, Attr_ReadOnly); // int _adCmpChar(void[] a1, void[] a2) createFwdDecl(LINKc, intTy, {"_adCmpChar"}, {voidArrayTy, voidArrayTy}, {}, Attr_ReadOnly_NoUnwind); // void[] _adSort(void[] a, TypeInfo ti) createFwdDecl(LINKc, voidArrayTy, {"_adSort"}, {voidArrayTy, typeInfoTy}); ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // size_t _aaLen(in AA aa) createFwdDecl(LINKc, sizeTy, {"_aaLen"}, {aaTy}, {STCin}, Attr_ReadOnly_NoUnwind_1_NoCapture); // void* _aaGetY(AA* aa, const TypeInfo aati, in size_t valuesize, // in void* pkey) createFwdDecl(LINKc, voidPtrTy, {"_aaGetY"}, {aaTy->pointerTo(), aaTypeInfoTy, sizeTy, voidPtrTy}, {0, STCconst, STCin, STCin}, Attr_1_4_NoCapture); // inout(void)* _aaInX(inout AA aa, in TypeInfo keyti, in void* pkey) // FIXME: "inout" storageclass is not applied to return type createFwdDecl(LINKc, voidPtrTy, {"_aaInX"}, {aaTy, typeInfoTy, voidPtrTy}, {STCin | STCout, STCin, STCin}, Attr_ReadOnly_1_3_NoCapture); // bool _aaDelX(AA aa, in TypeInfo keyti, in void* pkey) createFwdDecl(LINKc, boolTy, {"_aaDelX"}, {aaTy, typeInfoTy, voidPtrTy}, {0, STCin, STCin}, Attr_1_3_NoCapture); // inout(void[]) _aaValues(inout AA aa, in size_t keysize, // in size_t valuesize, const TypeInfo tiValueArray) createFwdDecl( LINKc, voidArrayTy, {"_aaValues"}, {aaTy, sizeTy, sizeTy, typeInfoTy}, {STCin | STCout, STCin, STCin, STCconst}, Attr_ReadOnly_1_3_NoCapture); // void* _aaRehash(AA* paa, in TypeInfo keyti) createFwdDecl(LINKc, voidPtrTy, {"_aaRehash"}, {aaTy->pointerTo(), typeInfoTy}, {0, STCin}); // inout(void[]) _aaKeys(inout AA aa, in size_t keysize, // const TypeInfo tiKeyArray) createFwdDecl(LINKc, voidArrayTy, {"_aaKeys"}, {aaTy, sizeTy, typeInfoTy}, {STCin | STCout, STCin, STCconst}, Attr_NoAlias_1_NoCapture); // int _aaApply(AA aa, in size_t keysize, dg_t dg) createFwdDecl(LINKc, intTy, {"_aaApply"}, {aaTy, sizeTy, rt_dg1()}, {0, STCin, 0}, Attr_1_NoCapture); // int _aaApply2(AA aa, in size_t keysize, dg2_t dg) createFwdDecl(LINKc, intTy, {"_aaApply2"}, {aaTy, sizeTy, rt_dg2()}, {0, STCin, 0}, Attr_1_NoCapture); // int _aaEqual(in TypeInfo tiRaw, in AA e1, in AA e2) createFwdDecl(LINKc, intTy, {"_aaEqual"}, {typeInfoTy, aaTy, aaTy}, {STCin, STCin, STCin}, Attr_1_2_NoCapture); // AA _d_assocarrayliteralTX(const TypeInfo_AssociativeArray ti, // void[] keys, void[] values) createFwdDecl(LINKc, aaTy, {"_d_assocarrayliteralTX"}, {aaTypeInfoTy, voidArrayTy, voidArrayTy}, {STCconst, 0, 0}); ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // void _moduleCtor() // void _moduleDtor() createFwdDecl(LINKc, voidTy, {"_moduleCtor", "_moduleDtor"}, {}); ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // void _d_throw_exception(Object e) createFwdDecl(LINKc, voidTy, {"_d_throw_exception"}, {objectTy}); ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // int _d_switch_string(char[][] table, char[] ca) createFwdDecl(LINKc, intTy, {"_d_switch_string"}, {stringTy->arrayOf(), stringTy}, {}, Attr_ReadOnly); // int _d_switch_ustring(wchar[][] table, wchar[] ca) createFwdDecl(LINKc, intTy, {"_d_switch_ustring"}, {wstringTy->arrayOf(), wstringTy}, {}, Attr_ReadOnly); // int _d_switch_dstring(dchar[][] table, dchar[] ca) createFwdDecl(LINKc, intTy, {"_d_switch_dstring"}, {dstringTy->arrayOf(), dstringTy}, {}, Attr_ReadOnly); ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // int _d_eh_personality(...) { if (global.params.targetTriple->isWindowsMSVCEnvironment()) { const char *fname = useMSVCEH() ? "__CxxFrameHandler3" : "_d_eh_personality"; // (ptr ExceptionRecord, ptr EstablisherFrame, ptr ContextRecord, // ptr DispatcherContext) createFwdDecl(LINKc, intTy, {fname}, {voidPtrTy, voidPtrTy, voidPtrTy, voidPtrTy}); } else if (global.params.targetTriple->getArch() == llvm::Triple::arm) { // (int state, ptr ucb, ptr context) createFwdDecl(LINKc, intTy, {"_d_eh_personality"}, {intTy, voidPtrTy, voidPtrTy}); } else { // (int ver, int actions, ulong eh_class, ptr eh_info, ptr context) createFwdDecl(LINKc, intTy, {"_d_eh_personality"}, {intTy, intTy, ulongTy, voidPtrTy, voidPtrTy}); } } if (useMSVCEH()) { // _d_enter_cleanup(ptr frame) createFwdDecl(LINKc, boolTy, {"_d_enter_cleanup"}, {voidPtrTy}); // _d_leave_cleanup(ptr frame) createFwdDecl(LINKc, voidTy, {"_d_leave_cleanup"}, {voidPtrTy}); // Object _d_eh_enter_catch(ptr exception, ClassInfo catchType) createFwdDecl(LINKc, objectTy, {"_d_eh_enter_catch"}, {voidPtrTy, classInfoTy}, {}); } else { // void _d_eh_resume_unwind(ptr) createFwdDecl(LINKc, voidTy, {"_d_eh_resume_unwind"}, {voidPtrTy}); // Object _d_eh_enter_catch(ptr) createFwdDecl(LINKc, objectTy, {"_d_eh_enter_catch"}, {voidPtrTy}, {}, Attr_NoUnwind); } ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // void invariant._d_invariant(Object o) createFwdDecl( LINKd, voidTy, {gABI->mangleFunctionForLLVM("_D9invariant12_d_invariantFC6ObjectZv", LINKd)}, {objectTy}); // void _d_dso_registry(CompilerDSOData* data) llvm::StringRef fname("_d_dso_registry"); LLType *LLvoidTy = LLType::getVoidTy(gIR->context()); LLType *LLvoidPtrPtrTy = getPtrToType(getPtrToType(LLvoidTy)); LLType *moduleInfoPtrPtrTy = getPtrToType(getPtrToType(DtoType(Module::moduleinfo->type))); llvm::StructType *dsoDataTy = llvm::StructType::get(DtoSize_t(), // version LLvoidPtrPtrTy, // slot moduleInfoPtrPtrTy, // _minfo_beg moduleInfoPtrPtrTy, // _minfo_end NULL); llvm::Type *types[] = {getPtrToType(dsoDataTy)}; llvm::FunctionType *fty = llvm::FunctionType::get(LLvoidTy, types, false); llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M); ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // extern (C) void _d_cover_register2(string filename, size_t[] valid, // uint[] data, ubyte minPercent) if (global.params.cov) { createFwdDecl(LINKc, voidTy, {"_d_cover_register2"}, {stringTy, sizeTy->arrayOf(), uintTy->arrayOf(), ubyteTy}); } if (global.params.hasObjectiveC) { assert(global.params.targetTriple->isOSDarwin()); // The types of these functions don't really matter because they are always // bitcast to correct signature before calling. Type* objectPtrTy = voidPtrTy; Type* selectorPtrTy = voidPtrTy; Type* realTy = Type::tfloat80; // id objc_msgSend(id self, SEL op, ...) // Function called early and/or often, so lazy binding isn't worthwhile. createFwdDecl(LINKc, objectPtrTy, {"objc_msgSend"}, {objectPtrTy, selectorPtrTy}, {}, AttrSet(NoAttrs, ~0U, llvm::Attribute::NonLazyBind)); switch (global.params.targetTriple->getArch()) { case llvm::Triple::x86_64: // creal objc_msgSend_fp2ret(id self, SEL op, ...) createFwdDecl(LINKc, Type::tcomplex80, {"objc_msgSend_fp2ret"}, {objectPtrTy, selectorPtrTy}); // fall-thru case llvm::Triple::x86: // x86_64 real return only, x86 float, double, real return // real objc_msgSend_fpret(id self, SEL op, ...) createFwdDecl(LINKc, realTy, {"objc_msgSend_fpret"}, {objectPtrTy, selectorPtrTy}); // fall-thru case llvm::Triple::arm: case llvm::Triple::thumb: // used when return value is aggregate via a hidden sret arg // void objc_msgSend_stret(T *sret_arg, id self, SEL op, ...) createFwdDecl(LINKc, voidTy, {"objc_msgSend_stret"}, {objectPtrTy, selectorPtrTy}); break; default: break; } } }