llvm::GlobalValue::LinkageTypes DtoExternalLinkage(Dsymbol* sym) { if (needsTemplateLinkage(sym)) return templateLinkage; else if (isAvailableExternally(sym) && mustDefineSymbol(sym)) return llvm::GlobalValue::AvailableExternallyLinkage; else return llvm::GlobalValue::ExternalLinkage; }
void DtoResolveStruct(StructDeclaration* sd) { // Make sure to resolve each struct type exactly once. if (sd->ir.resolved) return; sd->ir.resolved = true; Logger::println("Resolving struct type: %s (%s)", sd->toChars(), sd->loc.toChars()); LOG_SCOPE; // make sure type exists DtoType(sd->type); // if it's a forward declaration, all bets are off. The type should be enough if (sd->sizeok != 1) return; // create the IrAggr IrAggr* irstruct = new IrAggr(sd); sd->ir.irStruct = irstruct; // Set up our field metadata. for (ArrayIter<VarDeclaration> it(sd->fields); !it.done(); it.next()) { VarDeclaration* vd = it.get(); assert(!vd->ir.irField); (void)new IrField(vd); } // perform definition bool emitGlobalData = mustDefineSymbol(sd); if (emitGlobalData) { // emit the initZ symbol LLGlobalVariable* initZ = irstruct->getInitSymbol(); // set initZ initializer initZ->setInitializer(irstruct->getDefaultInit()); } // emit members if (sd->members) { for (ArrayIter<Dsymbol> it(sd->members); !it.done(); it.next()) { it.get()->codegen(Type::sir); } } if (emitGlobalData) { // emit typeinfo DtoTypeInfoOf(sd->type); } }
void VarDeclaration::codegen(Ir* p) { Logger::print("VarDeclaration::codegen(): %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; if (type->ty == Terror) { error("had semantic errors when compiling"); return; } // just forward aliases if (aliassym) { Logger::println("alias sym"); toAlias()->codegen(p); return; } // output the parent aggregate first if (AggregateDeclaration* ad = isMember()) ad->codegen(p); // global variable // taken from dmd2/structs if (isDataseg() || (storage_class & (STCconst | STCimmutable) && init)) { Logger::println("data segment"); #if 0 // TODO: assert(!(storage_class & STCmanifest) && "manifest constant being codegen'd!"); #endif // don't duplicate work if (this->ir.resolved) return; this->ir.resolved = true; this->ir.declared = true; this->ir.irGlobal = new IrGlobal(this); Logger::println("parent: %s (%s)", parent->toChars(), parent->kind()); // not sure why this is only needed for d2 bool _isconst = isConst() && init; Logger::println("Creating global variable"); assert(!ir.initialized); ir.initialized = gIR->dmodule; std::string _name(mangle()); LLType *_type = DtoConstInitializerType(type, init); // create the global variable #if LDC_LLVM_VER >= 302 // FIXME: clang uses a command line option for the thread model LLGlobalVariable* gvar = new LLGlobalVariable(*gIR->module, _type, _isconst, DtoLinkage(this), NULL, _name, 0, isThreadlocal() ? LLGlobalVariable::GeneralDynamicTLSModel : LLGlobalVariable::NotThreadLocal); #else LLGlobalVariable* gvar = new LLGlobalVariable(*gIR->module, _type, _isconst, DtoLinkage(this), NULL, _name, 0, isThreadlocal()); #endif this->ir.irGlobal->value = gvar; // Set the alignment (it is important not to use type->alignsize because // VarDeclarations can have an align() attribute independent of the type // as well). if (alignment != STRUCTALIGN_DEFAULT) gvar->setAlignment(alignment); if (Logger::enabled()) Logger::cout() << *gvar << '\n'; // if this global is used from a nested function, this is necessary or // optimization could potentially remove the global (if it's the only use) if (nakedUse) gIR->usedArray.push_back(DtoBitCast(gvar, getVoidPtrType())); // assign the initializer if (!(storage_class & STCextern) && mustDefineSymbol(this)) { if (Logger::enabled()) { Logger::println("setting initializer"); Logger::cout() << "global: " << *gvar << '\n'; #if 0 Logger::cout() << "init: " << *initVal << '\n'; #endif } // build the initializer LLConstant *initVal = DtoConstInitializer(loc, type, init); // set the initializer assert(!ir.irGlobal->constInit); ir.irGlobal->constInit = initVal; gvar->setInitializer(initVal); // do debug info DtoDwarfGlobalVariable(gvar, this); } } }
void DtoResolveStruct(StructDeclaration* sd) { // don't do anything if already been here if (sd->ir.resolved) return; // make sure above works :P sd->ir.resolved = true; // log what we're doing Logger::println("Resolving struct type: %s (%s)", sd->toChars(), sd->loc.toChars()); LOG_SCOPE; // make sure type exists DtoType(sd->type); // if it's a forward declaration, all bets are off. The type should be enough if (sd->sizeok != 1) return; // create the IrStruct IrStruct* irstruct = new IrStruct(sd); sd->ir.irStruct = irstruct; // make sure all fields really get their ir field ArrayIter<VarDeclaration> it(sd->fields); for (; !it.done(); it.next()) { VarDeclaration* vd = it.get(); if (vd->ir.irField == NULL) { new IrField(vd); } else { IF_LOG Logger::println("struct field already exists!!!"); } } // perform definition bool needs_def = mustDefineSymbol(sd); if (needs_def) { // emit the initZ symbol LLGlobalVariable* initZ = irstruct->getInitSymbol(); // set initZ initializer initZ->setInitializer(irstruct->getDefaultInit()); } // emit members if (sd->members) { ArrayIter<Dsymbol> it(*sd->members); while (!it.done()) { Dsymbol* member = it.get(); if (member) member->codegen(Type::sir); it.next(); } } if (needs_def) { // emit typeinfo DtoTypeInfoOf(sd->type); } }
void DtoResolveClass(ClassDeclaration* cd) { // make sure the base classes are processed first ArrayIter<BaseClass> base_iter(cd->baseclasses); while (base_iter.more()) { BaseClass* bc = base_iter.get(); if (bc) { bc->base->codegen(Type::sir); } base_iter.next(); } if (cd->ir.resolved) return; cd->ir.resolved = true; Logger::println("DtoResolveClass(%s): %s", cd->toPrettyChars(), cd->loc.toChars()); LOG_SCOPE; // make sure type exists DtoType(cd->type); // create IrStruct assert(cd->ir.irStruct == NULL); IrStruct* irstruct = new IrStruct(cd); cd->ir.irStruct = irstruct; // make sure all fields really get their ir field ArrayIter<VarDeclaration> it(cd->fields); for (; !it.done(); it.next()) { VarDeclaration* vd = it.get(); if (vd->ir.irField == NULL) { new IrField(vd); } else { IF_LOG Logger::println("class field already exists!!!"); } } bool needs_def = mustDefineSymbol(cd); // emit the ClassZ symbol LLGlobalVariable* ClassZ = irstruct->getClassInfoSymbol(); // emit the interfaceInfosZ symbol if necessary if (cd->vtblInterfaces && cd->vtblInterfaces->dim > 0) irstruct->getInterfaceArraySymbol(); // initializer is applied when it's built // interface only emit typeinfo and classinfo if (cd->isInterfaceDeclaration()) { irstruct->initializeInterface(); } else { // emit the initZ symbol LLGlobalVariable* initZ = irstruct->getInitSymbol(); // emit the vtblZ symbol LLGlobalVariable* vtblZ = irstruct->getVtblSymbol(); // perform definition if (needs_def) { // set symbol initializers initZ->setInitializer(irstruct->getDefaultInit()); vtblZ->setInitializer(irstruct->getVtblInit()); } } // emit members if (cd->members) { ArrayIter<Dsymbol> it(*cd->members); while (!it.done()) { Dsymbol* member = it.get(); if (member) member->codegen(Type::sir); it.next(); } } if (needs_def) { // emit typeinfo DtoTypeInfoOf(cd->type); // define classinfo ClassZ->setInitializer(irstruct->getClassInfoInit()); } }
void VarDeclaration::codegen(Ir* p) { Logger::print("VarDeclaration::codegen(): %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; if (type->ty == Terror) { error("had semantic errors when compiling"); return; } // just forward aliases if (aliassym) { Logger::println("alias sym"); toAlias()->codegen(p); return; } // output the parent aggregate first if (AggregateDeclaration* ad = isMember()) ad->codegen(p); // global variable if (isDataseg() || (storage_class & (STCconst | STCimmutable) && init)) { Logger::println("data segment"); #if 0 // TODO: assert(!(storage_class & STCmanifest) && "manifest constant being codegen'd!"); #endif // don't duplicate work if (this->ir.resolved) return; this->ir.resolved = true; this->ir.declared = true; this->ir.irGlobal = new IrGlobal(this); Logger::println("parent: %s (%s)", parent->toChars(), parent->kind()); const bool isLLConst = isConst() && init; const llvm::GlobalValue::LinkageTypes llLinkage = DtoLinkage(this); assert(!ir.initialized); ir.initialized = gIR->dmodule; std::string llName(mangle()); // Since the type of a global must exactly match the type of its // initializer, we cannot know the type until after we have emitted the // latter (e.g. in case of unions, …). However, it is legal for the // initializer to refer to the address of the variable. Thus, we first // create a global with the generic type (note the assignment to // this->ir.irGlobal->value!), and in case we also do an initializer // with a different type later, swap it out and replace any existing // uses with bitcasts to the previous type. llvm::GlobalVariable* gvar = getOrCreateGlobal(loc, *gIR->module, i1ToI8(DtoType(type)), isLLConst, llLinkage, 0, llName, isThreadlocal()); this->ir.irGlobal->value = gvar; // Check if we are defining or just declaring the global in this module. if (!(storage_class & STCextern) && mustDefineSymbol(this)) { // Build the initializer. Might use this->ir.irGlobal->value! LLConstant *initVal = DtoConstInitializer(loc, type, init); // In case of type mismatch, swap out the variable. if (initVal->getType() != gvar->getType()->getElementType()) { llvm::GlobalVariable* newGvar = getOrCreateGlobal(loc, *gIR->module, initVal->getType(), isLLConst, llLinkage, 0, "", // We take on the name of the old global below. isThreadlocal()); newGvar->takeName(gvar); llvm::Constant* newValue = llvm::ConstantExpr::getBitCast(newGvar, gvar->getType()); gvar->replaceAllUsesWith(newValue); gvar->eraseFromParent(); gvar = newGvar; this->ir.irGlobal->value = newGvar; } // Now, set the initializer. assert(!ir.irGlobal->constInit); ir.irGlobal->constInit = initVal; gvar->setInitializer(initVal); // Also set up the edbug info. DtoDwarfGlobalVariable(gvar, this); } // Set the alignment (it is important not to use type->alignsize because // VarDeclarations can have an align() attribute independent of the type // as well). if (alignment != STRUCTALIGN_DEFAULT) gvar->setAlignment(alignment); // If this global is used from a naked function, we need to create an // artificial "use" for it, or it could be removed by the optimizer if // the only reference to it is in inline asm. if (nakedUse) gIR->usedArray.push_back(DtoBitCast(gvar, getVoidPtrType())); if (Logger::enabled()) Logger::cout() << *gvar << '\n'; } }
LLGlobalValue::LinkageTypes DtoLinkage(Dsymbol* sym) { const bool mustDefine = mustDefineSymbol(sym); // global/static variable if (VarDeclaration* vd = sym->isVarDeclaration()) { if (mustDefine) { IF_LOG Logger::println("Variable %savailable externally: %s", (vd->availableExternally ? "" : "not "), vd->toChars()); } // generated by inlining semantics run if (vd->availableExternally && mustDefine) return llvm::GlobalValue::AvailableExternallyLinkage; // template if (needsTemplateLinkage(sym)) return templateLinkage; // Currently, we have to consider all variables, even function-local // statics, to be external, as CTFE might cause template functions // instances to be semantic3'd that occur within the body of a function // from an imported module. Consequently, a copy of them is codegen'd // in the importing module, even if they might reference a static in a // function in the imported module (e.g. via an alias parameter). // // A fix for this would be to track instantiations/semantic3 runs made // solely for CTFE purposes in a way similar to how the extra inlining // semantic runs are handled. // // LDC_FIXME: Can this also occur for functions? Find a better solution. if (true || vd->storage_class & STCextern) return llvm::GlobalValue::ExternalLinkage; } else if (FuncDeclaration* fdecl = sym->isFuncDeclaration()) { if (mustDefine) { IF_LOG Logger::println("Function %savailable externally: %s", (fdecl->availableExternally ? "" : "not "), fdecl->toChars()); } assert(fdecl->type->ty == Tfunction); TypeFunction* ft = static_cast<TypeFunction*>(fdecl->type); // intrinsics are always external if (fdecl->llvmInternal == LLVMintrinsic) return llvm::GlobalValue::ExternalLinkage; // Mark functions generated by an inlining semantic run as // available_externally. Naked functions are turned into module-level // inline asm and are thus declaration-only as far as the LLVM IR level // is concerned. if (fdecl->availableExternally && mustDefine && !fdecl->naked) return llvm::GlobalValue::AvailableExternallyLinkage; // array operations are always template linkage if (fdecl->isArrayOp == 1) return templateLinkage; // template instances should have weak linkage // but only if there's a body, and it's not naked // otherwise we make it external if (needsTemplateLinkage(fdecl) && fdecl->fbody && !fdecl->naked) return templateLinkage; // extern(C) functions are always external if (ft->linkage == LINKc) return llvm::GlobalValue::ExternalLinkage; // If a function without a body is nested in another // function, we cannot use internal linkage for that // function (see below about nested functions) // FIXME: maybe there is a better way without emission // of needless symbols? if (!fdecl->fbody) return llvm::GlobalValue::ExternalLinkage; } // class else if (ClassDeclaration* cd = sym->isClassDeclaration()) { if (mustDefine) { IF_LOG Logger::println("Class %savailable externally: %s", (cd->availableExternally ? "" : "not "), vd->toChars()); } // generated by inlining semantics run if (cd->availableExternally && mustDefine) return llvm::GlobalValue::AvailableExternallyLinkage; // template if (needsTemplateLinkage(cd)) return templateLinkage; } else { llvm_unreachable("not global/function"); } // If the function needs to be defined in the current module, check if it // is a nested function and we can declare it as internal. bool canInternalize = mustDefine; // Nested naked functions and the implicitly generated __require/__ensure // functions for in/out contracts cannot be internalized. The reason // for the latter is that contract functions, despite being nested, can be // referenced from other D modules e.g. in the case of contracts on // interface methods (where __require/__ensure are emitted to the module // where the interface is declared, but an actual interface implementation // can be in a completely different place). if (canInternalize) { if (FuncDeclaration* fd = sym->isFuncDeclaration()) { if ((fd->naked != 0) || (fd->ident == Id::require) || (fd->ident == Id::ensure)) { canInternalize = false; } } } // Any symbol nested in a function that cannot be inlined can't be // referenced directly from outside that function, so we can give // such symbols internal linkage. This holds even if nested indirectly, // such as member functions of aggregates nested in functions. // // Note: This must be checked after things like template member-ness or // symbols nested in templates would get duplicated for each module, // breaking things like // --- // int counter(T)() { static int i; return i++; }" // --- // if instances get emitted in multiple object files because they'd use // different instances of 'i'. // TODO: Check if we are giving away too much inlining potential due to // canInline being overly conservative here. if (canInternalize) { for (Dsymbol* parent = sym->parent; parent ; parent = parent->parent) { FuncDeclaration *fd = parent->isFuncDeclaration(); if (fd && !fd->canInline(fd->needThis(), false, false)) { // We also cannot internalize nested functions which are // leaked to the outside via a templated return type, because // that type will also be codegen'd in any caller modules (see // GitHub issue #131). // Since we can't easily determine if this is really the case // here, just don't internalize it if the parent returns a // template at all, to be safe. TypeFunction* tf = static_cast<TypeFunction*>(fd->type); if (!DtoIsTemplateInstance(tf->next->toDsymbol(fd->scope))) return llvm::GlobalValue::InternalLinkage; } } } // default to external linkage return llvm::GlobalValue::ExternalLinkage; }