static void build_module_ref(std::string moduleMangle, llvm::Constant *thisModuleInfo) { // Build the ModuleInfo reference and bracketing symbols. llvm::Type *const moduleInfoPtrTy = DtoPtrToType(Module::moduleinfo->type); std::string thismrefname = "_D"; thismrefname += moduleMangle; thismrefname += "11__moduleRefZ"; auto thismref = new llvm::GlobalVariable( gIR->module, moduleInfoPtrTy, false, // FIXME: mRelocModel != llvm::Reloc::PIC_ llvm::GlobalValue::LinkOnceODRLinkage, DtoBitCast(thisModuleInfo, moduleInfoPtrTy), thismrefname); thismref->setSection(".minfo"); gIR->usedArray.push_back(thismref); }
// helper function that returns the static default initializer of a variable LLConstant* get_default_initializer(VarDeclaration* vd, Initializer* init) { if (init) { return DtoConstInitializer(init->loc, vd->type, init); } if (vd->init) { return DtoConstInitializer(vd->init->loc, vd->type, vd->init); } if (vd->type->size(vd->loc) == 0) { // We need to be able to handle void[0] struct members even if void has // no default initializer. return llvm::ConstantPointerNull::get(DtoPtrToType(vd->type)); } return DtoConstExpInit(vd->loc, vd->type, vd->type->defaultInit(vd->loc)); }
DValue *DtoAAIndex(Loc &loc, Type *type, DValue *aa, DValue *key, bool lvalue) { // D2: // call: // extern(C) void* _aaGetY(AA* aa, TypeInfo aati, size_t valuesize, void* // pkey) // or // extern(C) void* _aaInX(AA aa*, TypeInfo keyti, void* pkey) // first get the runtime function llvm::Function *func = getRuntimeFunction( loc, gIR->module, lvalue ? "_aaGetY" : "_aaInX"); LLFunctionType *funcTy = func->getFunctionType(); // aa param LLValue *aaval = lvalue ? aa->getLVal() : aa->getRVal(); aaval = DtoBitCast(aaval, funcTy->getParamType(0)); // pkey param LLValue *pkey = makeLValue(loc, key); pkey = DtoBitCast(pkey, funcTy->getParamType(lvalue ? 3 : 2)); // call runtime LLValue *ret; if (lvalue) { LLValue *rawAATI = DtoTypeInfoOf(aa->type->unSharedOf()->mutableOf(), false); LLValue *castedAATI = DtoBitCast(rawAATI, funcTy->getParamType(1)); LLValue *valsize = DtoConstSize_t(getTypePaddedSize(DtoType(type))); ret = gIR->CreateCallOrInvoke(func, aaval, castedAATI, valsize, pkey, "aa.index") .getInstruction(); } else { LLValue *keyti = DtoBitCast(to_keyti(aa), funcTy->getParamType(1)); ret = gIR->CreateCallOrInvoke(func, aaval, keyti, pkey, "aa.index") .getInstruction(); } // cast return value LLType *targettype = DtoPtrToType(type); if (ret->getType() != targettype) { ret = DtoBitCast(ret, targettype); } // Only check bounds for rvalues ('aa[key]'). // Lvalue use ('aa[key] = value') auto-adds an element. if (!lvalue && gIR->emitArrayBoundsChecks()) { llvm::BasicBlock *failbb = llvm::BasicBlock::Create( gIR->context(), "aaboundscheckfail", gIR->topfunc()); llvm::BasicBlock *okbb = llvm::BasicBlock::Create(gIR->context(), "aaboundsok", gIR->topfunc()); LLValue *nullaa = LLConstant::getNullValue(ret->getType()); LLValue *cond = gIR->ir->CreateICmpNE(nullaa, ret, "aaboundscheck"); gIR->ir->CreateCondBr(cond, okbb, failbb); // set up failbb to call the array bounds error runtime function gIR->scope() = IRScope(failbb); llvm::Function *errorfn = getRuntimeFunction(loc, gIR->module, "_d_arraybounds"); gIR->CreateCallOrInvoke( errorfn, DtoModuleFileName(gIR->func()->decl->getModule(), loc), DtoConstUint(loc.linnum)); // the function does not return gIR->ir->CreateUnreachable(); // if ok, proceed in okbb gIR->scope() = IRScope(okbb); } return new DVarValue(type, ret); }
DValue *DtoNestedVariable(Loc &loc, Type *astype, VarDeclaration *vd, bool byref) { IF_LOG Logger::println("DtoNestedVariable for %s @ %s", vd->toChars(), loc.toChars()); LOG_SCOPE; //////////////////////////////////// // Locate context value Dsymbol *vdparent = vd->toParent2(); assert(vdparent); IrFunction *irfunc = gIR->func(); // Check whether we can access the needed frame FuncDeclaration *fd = irfunc->decl; while (fd && fd != vdparent) { fd = getParentFunc(fd); } if (!fd) { error(loc, "function `%s` cannot access frame of function `%s`", irfunc->decl->toPrettyChars(), vdparent->toPrettyChars()); return new DLValue(astype, llvm::UndefValue::get(DtoPtrToType(astype))); } // is the nested variable in this scope? if (vdparent == irfunc->decl) { return makeVarDValue(astype, vd); } // get the nested context LLValue *ctx = nullptr; bool skipDIDeclaration = false; auto currentCtx = gIR->funcGen().nestedVar; if (currentCtx) { Logger::println("Using own nested context of current function"); ctx = currentCtx; } else if (irfunc->decl->isMember2()) { Logger::println( "Current function is member of nested class, loading vthis"); AggregateDeclaration *cd = irfunc->decl->isMember2(); LLValue *val = irfunc->thisArg; if (cd->isClassDeclaration()) { val = DtoLoad(val); } ctx = DtoLoad(DtoGEPi(val, 0, getVthisIdx(cd), ".vthis")); skipDIDeclaration = true; } else { Logger::println("Regular nested function, loading context arg"); ctx = DtoLoad(irfunc->nestArg); } assert(ctx); IF_LOG { Logger::cout() << "Context: " << *ctx << '\n'; } DtoCreateNestedContextType(vdparent->isFuncDeclaration()); assert(isIrLocalCreated(vd)); //////////////////////////////////// // Extract variable from nested context const auto frameType = LLPointerType::getUnqual(irfunc->frameType); IF_LOG { Logger::cout() << "casting to: " << *irfunc->frameType << '\n'; } LLValue *val = DtoBitCast(ctx, frameType); IrLocal *const irLocal = getIrLocal(vd); const auto vardepth = irLocal->nestedDepth; const auto funcdepth = irfunc->depth; IF_LOG { Logger::cout() << "Variable: " << vd->toChars() << '\n'; Logger::cout() << "Variable depth: " << vardepth << '\n'; Logger::cout() << "Function: " << irfunc->decl->toChars() << '\n'; Logger::cout() << "Function depth: " << funcdepth << '\n'; } if (vardepth == funcdepth) { // This is not always handled above because functions without // variables accessed by nested functions don't create new frames. IF_LOG Logger::println("Same depth"); } else { // Load frame pointer and index that... IF_LOG Logger::println("Lower depth"); val = DtoGEPi(val, 0, vardepth); IF_LOG Logger::cout() << "Frame index: " << *val << '\n'; val = DtoAlignedLoad( val, (std::string(".frame.") + vdparent->toChars()).c_str()); IF_LOG Logger::cout() << "Frame: " << *val << '\n'; } const auto idx = irLocal->nestedIndex; assert(idx != -1 && "Nested context not yet resolved for variable."); LLSmallVector<int64_t, 2> dwarfAddrOps; LLValue *gep = DtoGEPi(val, 0, idx, vd->toChars()); val = gep; IF_LOG { Logger::cout() << "Addr: " << *val << '\n'; Logger::cout() << "of type: " << *val->getType() << '\n'; } const bool isRefOrOut = vd->isRef() || vd->isOut(); if (isSpecialRefVar(vd)) { // Handled appropriately by makeVarDValue() and EmitLocalVariable(), pass // storage of pointer (reference lvalue). } else if (byref || isRefOrOut) { val = DtoAlignedLoad(val); // ref/out variables get a reference-debuginfo-type in EmitLocalVariable(); // pass the GEP as reference lvalue in that case. if (!isRefOrOut) gIR->DBuilder.OpDeref(dwarfAddrOps); IF_LOG { Logger::cout() << "Was byref, now: " << *irLocal->value << '\n'; Logger::cout() << "of type: " << *irLocal->value->getType() << '\n'; } }
LLType *type(Type *dty, LLType *t) override { return DtoPtrToType(dty); }
static void build_dso_registry_calls(std::string moduleMangle, llvm::Constant *thisModuleInfo) { // Build the ModuleInfo reference and bracketing symbols. llvm::Type *const moduleInfoPtrTy = DtoPtrToType(Module::moduleinfo->type); // Order is important here: We must create the symbols in the // bracketing sections right before/after the ModuleInfo reference // so that they end up in the correct order in the object file. auto minfoBeg = new llvm::GlobalVariable(gIR->module, moduleInfoPtrTy, false, // FIXME: mRelocModel != llvm::Reloc::PIC_ llvm::GlobalValue::LinkOnceODRLinkage, getNullPtr(moduleInfoPtrTy), "_minfo_beg"); minfoBeg->setSection(".minfo_beg"); minfoBeg->setVisibility(llvm::GlobalValue::HiddenVisibility); std::string thismrefname = "_D"; thismrefname += moduleMangle; thismrefname += "11__moduleRefZ"; auto thismref = new llvm::GlobalVariable( gIR->module, moduleInfoPtrTy, false, // FIXME: mRelocModel != llvm::Reloc::PIC_ llvm::GlobalValue::LinkOnceODRLinkage, DtoBitCast(thisModuleInfo, moduleInfoPtrTy), thismrefname); thismref->setSection(".minfo"); gIR->usedArray.push_back(thismref); auto minfoEnd = new llvm::GlobalVariable(gIR->module, moduleInfoPtrTy, false, // FIXME: mRelocModel != llvm::Reloc::PIC_ llvm::GlobalValue::LinkOnceODRLinkage, getNullPtr(moduleInfoPtrTy), "_minfo_end"); minfoEnd->setSection(".minfo_end"); minfoEnd->setVisibility(llvm::GlobalValue::HiddenVisibility); // Build the ctor to invoke _d_dso_registry. // This is the DSO slot for use by the druntime implementation. auto dsoSlot = new llvm::GlobalVariable(gIR->module, getVoidPtrType(), false, llvm::GlobalValue::LinkOnceODRLinkage, getNullPtr(getVoidPtrType()), "ldc.dso_slot"); dsoSlot->setVisibility(llvm::GlobalValue::HiddenVisibility); // Okay, so the theory is easy: We want to have one global constructor and // destructor per object (i.e. executable/shared library) that calls // _d_dso_registry with the respective DSO record. However, there are a // couple of issues that make this harder than necessary: // // 1) The natural way to implement the "one-per-image" part would be to // emit a weak reference to a weak function into a .ctors.<somename> // section (llvm.global_ctors doesn't support the necessary // functionality, so we'd use our knowledge of the linker script to work // around that). But as of LLVM 3.4, emitting a symbol both as weak and // into a custom section is not supported by the MC layer. Thus, we have // to use a normal ctor/dtor and manually ensure that we only perform // the call once. This is done by introducing ldc.dso_initialized. // // 2) To make sure the .minfo section isn't removed by the linker when // using --gc-sections, we need to keep a reference to it around in // _every_ object file (as --gc-sections works per object file). The // natural place for this is the ctor, where we just load a reference // on the stack after the DSO record (to ensure LLVM doesn't optimize // it out). However, this way, we need to have at least one ctor // instance per object file be pulled into the final executable. We // do this here by making the module mangle string part of its name, // even thoguht this is slightly wasteful on -singleobj builds. // // It might be a better idea to simply use a custom linker script (using // INSERT AFTER… so as to still keep the default one) to avoid all these // problems. This would mean that it is no longer safe to link D objects // directly using e.g. "g++ dcode.o cppcode.o", though. auto dsoInitialized = new llvm::GlobalVariable( gIR->module, llvm::Type::getInt8Ty(gIR->context()), false, llvm::GlobalValue::LinkOnceODRLinkage, llvm::ConstantInt::get(llvm::Type::getInt8Ty(gIR->context()), 0), "ldc.dso_initialized"); dsoInitialized->setVisibility(llvm::GlobalValue::HiddenVisibility); // There is no reason for this cast to void*, other than that removing it // seems to trigger a bug in the llvm::Linker (at least on LLVM 3.4) // causing it to not merge the %object.ModuleInfo types properly. This // manifests itself in a type mismatch assertion being triggered on the // minfoUsedPointer store in the ctor as soon as the optimizer runs. llvm::Value *minfoRefPtr = DtoBitCast(thismref, getVoidPtrType()); std::string ctorName = "ldc.dso_ctor."; ctorName += moduleMangle; llvm::Function *dsoCtor = llvm::Function::Create( llvm::FunctionType::get(llvm::Type::getVoidTy(gIR->context()), false), llvm::GlobalValue::LinkOnceODRLinkage, ctorName, &gIR->module); dsoCtor->setVisibility(llvm::GlobalValue::HiddenVisibility); build_dso_ctor_dtor_body(dsoCtor, dsoInitialized, dsoSlot, minfoBeg, minfoEnd, minfoRefPtr, false); llvm::appendToGlobalCtors(gIR->module, dsoCtor, 65535); std::string dtorName = "ldc.dso_dtor."; dtorName += moduleMangle; llvm::Function *dsoDtor = llvm::Function::Create( llvm::FunctionType::get(llvm::Type::getVoidTy(gIR->context()), false), llvm::GlobalValue::LinkOnceODRLinkage, dtorName, &gIR->module); dsoDtor->setVisibility(llvm::GlobalValue::HiddenVisibility); build_dso_ctor_dtor_body(dsoDtor, dsoInitialized, dsoSlot, minfoBeg, minfoEnd, minfoRefPtr, true); llvm::appendToGlobalDtors(gIR->module, dsoDtor, 65535); }
LLType* type(Type* dty, LLType* t) { return DtoPtrToType(dty); }
DSpecialRefValue::DSpecialRefValue(Type *t, LLValue *v) : DLValue(v, t) { assert(v->getType() == DtoPtrToType(t)->getPointerTo()); }
DLValue::DLValue(Type *t, LLValue *v) : DValue(t, v) { // v may be an addrspace qualified pointer so strip it before doing a pointer // equality check. assert(t->toBasetype()->ty == Ttuple || stripAddrSpaces(v->getType()) == DtoPtrToType(t)); }
LLType *type(Type *t) override { return DtoPtrToType(t); }