diff --git a/gen/declarations.cpp b/gen/declarations.cpp index 3d5f8e20e22..00f88473168 100644 --- a/gen/declarations.cpp +++ b/gen/declarations.cpp @@ -96,8 +96,7 @@ class CodegenVisitor : public Visitor { llvm::GlobalVariable *interfaceZ = ir->getClassInfoSymbol(); // Only define if not speculative. if (!isSpeculativeType(decl->type)) { - interfaceZ->setInitializer(ir->getClassInfoInit()); - setLinkage(decl, interfaceZ); + defineGlobal(interfaceZ, ir->getClassInfoInit(), decl); } } } @@ -186,21 +185,20 @@ class CodegenVisitor : public Visitor { } IrAggr *ir = getIrAggr(decl); - const auto lwc = DtoLinkage(decl); auto &initZ = ir->getInitSymbol(); auto initGlobal = llvm::cast(initZ); initZ = irs->setGlobalVarInitializer(initGlobal, ir->getDefaultInit()); - setLinkage(lwc, initGlobal); + setLinkage(decl, initGlobal); llvm::GlobalVariable *vtbl = ir->getVtblSymbol(); - vtbl->setInitializer(ir->getVtblInit()); - setLinkage(lwc, vtbl); + defineGlobal(vtbl, ir->getVtblInit(), decl); + + ir->defineInterfaceVtbls(); llvm::GlobalVariable *classZ = ir->getClassInfoSymbol(); if (!isSpeculativeType(decl->type)) { - classZ->setInitializer(ir->getClassInfoInit()); - setLinkage(lwc, classZ); + defineGlobal(classZ, ir->getClassInfoInit(), decl); } } } diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index 9e7f2dace47..6e97c1258fa 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -911,17 +911,12 @@ void DtoResolveVariable(VarDeclaration *vd) { // with a different type later, swap it out and replace any existing // uses with bitcasts to the previous type. - // We always start out with external linkage; any other type is set - // when actually defining it in VarDeclaration::codegen. - llvm::GlobalValue::LinkageTypes linkage = - llvm::GlobalValue::ExternalLinkage; - if (vd->llvmInternal == LLVMextern_weak) { - linkage = llvm::GlobalValue::ExternalWeakLinkage; - } - llvm::GlobalVariable *gvar = - getOrCreateGlobal(vd->loc, gIR->module, DtoMemType(vd->type), isLLConst, - linkage, nullptr, irMangle, vd->isThreadlocal()); + declareGlobal(vd->loc, gIR->module, DtoMemType(vd->type), irMangle, + isLLConst, vd->isThreadlocal()); + if (vd->llvmInternal == LLVMextern_weak) + gvar->setLinkage(llvm::GlobalValue::ExternalWeakLinkage); + auto varIr = getIrGlobal(vd); varIr->value = gvar; @@ -1751,19 +1746,32 @@ llvm::Constant *buildStringLiteralConstant(StringExp *se, bool zeroTerm) { return LLConstantArray::get(at, vals); } -llvm::GlobalVariable *getOrCreateGlobal(const Loc &loc, llvm::Module &module, - llvm::Type *type, bool isConstant, - llvm::GlobalValue::LinkageTypes linkage, - llvm::Constant *init, - llvm::StringRef name, - bool isThreadLocal) { - llvm::GlobalVariable *existing = module.getGlobalVariable(name, true); +static std::string llvmTypeToString(llvm::Type *type) { + std::string result; + llvm::raw_string_ostream stream(result); + stream << *type; + stream.flush(); + return result; +} + +llvm::GlobalVariable *declareGlobal(const Loc &loc, llvm::Module &module, + llvm::Type *type, + llvm::StringRef mangledName, + bool isConstant, bool isThreadLocal) { + llvm::GlobalVariable *existing = + module.getGlobalVariable(mangledName, /*AllowInternal=*/true); if (existing) { - if (existing->getType()->getElementType() != type) { + const auto existingType = existing->getType()->getElementType(); + if (existingType != type || existing->isConstant() != isConstant || + existing->isThreadLocal() != isThreadLocal) { + const auto existingTypeName = llvmTypeToString(existingType); + const auto newTypeName = llvmTypeToString(type); error(loc, "Global variable type does not match previous declaration with " "same mangled name: `%s`", - name.str().c_str()); + mangledName.str().c_str()); + errorSupplemental(loc, "Previous IR type: %s", existingTypeName.c_str()); + errorSupplemental(loc, "New IR type: %s", newTypeName.c_str()); fatal(); } return existing; @@ -1772,14 +1780,38 @@ llvm::GlobalVariable *getOrCreateGlobal(const Loc &loc, llvm::Module &module, // Use a command line option for the thread model. // On PPC there is only local-exec available - in this case just ignore the // command line. - const llvm::GlobalVariable::ThreadLocalMode tlsModel = + const auto tlsModel = isThreadLocal ? (global.params.targetTriple->getArch() == llvm::Triple::ppc ? llvm::GlobalVariable::LocalExecTLSModel : clThreadModel.getValue()) : llvm::GlobalVariable::NotThreadLocal; - return new llvm::GlobalVariable(module, type, isConstant, linkage, init, name, - nullptr, tlsModel); + + return new llvm::GlobalVariable(module, type, isConstant, + llvm::GlobalValue::ExternalLinkage, nullptr, + mangledName, nullptr, tlsModel); +} + +void defineGlobal(llvm::GlobalVariable *global, llvm::Constant *init, + Dsymbol *symbolForLinkage) { + assert(global->isDeclaration() && "Global variable already defined"); + assert(init); + global->setInitializer(init); + if (symbolForLinkage) + setLinkage(symbolForLinkage, global); +} + +llvm::GlobalVariable *defineGlobal(const Loc &loc, llvm::Module &module, + llvm::StringRef mangledName, + llvm::Constant *init, + llvm::GlobalValue::LinkageTypes linkage, + bool isConstant, bool isThreadLocal) { + assert(init); + auto global = declareGlobal(loc, module, init->getType(), mangledName, + isConstant, isThreadLocal); + defineGlobal(global, init, nullptr); + global->setLinkage(linkage); + return global; } FuncDeclaration *getParentFunc(Dsymbol *sym) { diff --git a/gen/llvmhelpers.h b/gen/llvmhelpers.h index 95c1bcddf4c..453d26e80d4 100644 --- a/gen/llvmhelpers.h +++ b/gen/llvmhelpers.h @@ -245,18 +245,29 @@ stringLiteralCacheForType(Type *charType); llvm::Constant *buildStringLiteralConstant(StringExp *se, bool zeroTerm); -/// Tries to create an LLVM global with the given properties. If a variable with -/// the same mangled name already exists, checks if the types match and returns -/// it instead. +/// Tries to declare an LLVM global. If a variable with the same mangled name +/// already exists, checks if the types match and returns it instead. /// /// Necessary to support multiple declarations with the same mangled name, as /// can be the case due to pragma(mangle). -llvm::GlobalVariable *getOrCreateGlobal(const Loc &loc, llvm::Module &module, - llvm::Type *type, bool isConstant, - llvm::GlobalValue::LinkageTypes linkage, - llvm::Constant *init, - llvm::StringRef name, - bool isThreadLocal = false); +llvm::GlobalVariable *declareGlobal(const Loc &loc, llvm::Module &module, + llvm::Type *type, + llvm::StringRef mangledName, + bool isConstant, + bool isThreadLocal = false); + +/// Defines an existing LLVM global, i.e., sets the initial value and finalizes +/// its linkage. +/// Asserts that a global isn't defined multiple times this way. +void defineGlobal(llvm::GlobalVariable *global, llvm::Constant *init, + Dsymbol *symbolForLinkage); + +/// Declares (if not already declared) & defines an LLVM global. +llvm::GlobalVariable *defineGlobal(const Loc &loc, llvm::Module &module, + llvm::StringRef mangledName, + llvm::Constant *init, + llvm::GlobalValue::LinkageTypes linkage, + bool isConstant, bool isThreadLocal = false); FuncDeclaration *getParentFunc(Dsymbol *sym); diff --git a/gen/modules.cpp b/gen/modules.cpp index 667112b2f70..d2cf8f80ccd 100644 --- a/gen/modules.cpp +++ b/gen/modules.cpp @@ -169,18 +169,15 @@ LLFunction *build_module_reference_and_ctor(const char *moduleMangle, // create the ModuleReference node for this module const auto thismrefIRMangle = getIRMangledModuleRefSymbolName(moduleMangle); - Loc loc; - LLGlobalVariable *thismref = getOrCreateGlobal( - loc, gIR->module, modulerefTy, false, LLGlobalValue::InternalLinkage, - thismrefinit, thismrefIRMangle); + LLGlobalVariable *thismref = + defineGlobal(Loc(), gIR->module, thismrefIRMangle, thismrefinit, + LLGlobalValue::InternalLinkage, false); // make sure _Dmodule_ref is declared const auto mrefIRMangle = getIRMangledVarName("_Dmodule_ref", LINKc); LLConstant *mref = gIR->module.getNamedGlobal(mrefIRMangle); LLType *modulerefPtrTy = getPtrToType(modulerefTy); if (!mref) { - mref = new LLGlobalVariable(gIR->module, modulerefPtrTy, false, - LLGlobalValue::ExternalLinkage, nullptr, - mrefIRMangle); + mref = declareGlobal(Loc(), gIR->module, modulerefPtrTy, mrefIRMangle, false); } mref = DtoBitCast(mref, getPtrToType(modulerefPtrTy)); @@ -218,9 +215,9 @@ llvm::Function *buildGetTLSAnchor() { // Create a dummmy TLS global private to this module. const auto one = llvm::ConstantInt::get(llvm::Type::getInt8Ty(gIR->context()), 1); - const auto anchor = getOrCreateGlobal( - Loc(), gIR->module, one->getType(), false, - llvm::GlobalValue::LinkOnceODRLinkage, one, "ldc.tls_anchor", true); + const auto anchor = defineGlobal(Loc(), gIR->module, "ldc.tls_anchor", one, + llvm::GlobalValue::LinkOnceODRLinkage, false, + /*isThreadLocal=*/true); anchor->setVisibility(llvm::GlobalValue::HiddenVisibility); anchor->setAlignment(16); @@ -358,11 +355,11 @@ void emitModuleRefToSection(RegistryStyle style, std::string moduleMangle, const auto thismrefIRMangle = getIRMangledModuleRefSymbolName(moduleMangle.c_str()); - auto thismref = new llvm::GlobalVariable( - gIR->module, moduleInfoPtrTy, - false, // FIXME: mRelocModel != llvm::Reloc::PIC_ - llvm::GlobalValue::LinkOnceODRLinkage, - DtoBitCast(thisModuleInfo, moduleInfoPtrTy), thismrefIRMangle); + auto thismref = defineGlobal(Loc(), gIR->module, thismrefIRMangle, + DtoBitCast(thisModuleInfo, moduleInfoPtrTy), + llvm::GlobalValue::LinkOnceODRLinkage, + false // FIXME: mRelocModel != llvm::Reloc::PIC_ + ); thismref->setSection(sectionName); gIR->usedArray.push_back(thismref); @@ -382,22 +379,19 @@ void emitModuleRefToSection(RegistryStyle style, std::string moduleMangle, const auto magicEndSymbolName = (style == RegistryStyle::sectionDarwin) ? "\1section$end$__DATA$.minfo" : "__stop___minfo"; - auto minfoBeg = new llvm::GlobalVariable(gIR->module, moduleInfoPtrTy, false, - llvm::GlobalValue::ExternalLinkage, - nullptr, magicBeginSymbolName); - auto minfoEnd = new llvm::GlobalVariable(gIR->module, moduleInfoPtrTy, false, - llvm::GlobalValue::ExternalLinkage, - nullptr, magicEndSymbolName); + auto minfoBeg = declareGlobal(Loc(), gIR->module, moduleInfoPtrTy, + magicBeginSymbolName, false); + auto minfoEnd = declareGlobal(Loc(), gIR->module, moduleInfoPtrTy, + magicEndSymbolName, false); minfoBeg->setVisibility(llvm::GlobalValue::HiddenVisibility); 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"); + auto dsoSlot = defineGlobal(Loc(), gIR->module, "ldc.dso_slot", + getNullPtr(getVoidPtrType()), + llvm::GlobalValue::LinkOnceODRLinkage, false); dsoSlot->setVisibility(llvm::GlobalValue::HiddenVisibility); // Okay, so the theory is easy: We want to have one global constructor and @@ -429,11 +423,10 @@ void emitModuleRefToSection(RegistryStyle style, std::string moduleMangle, // 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, + auto dsoInitialized = defineGlobal( + Loc(), gIR->module, "ldc.dso_initialized", llvm::ConstantInt::get(llvm::Type::getInt8Ty(gIR->context()), 0), - "ldc.dso_initialized"); + llvm::GlobalValue::LinkOnceODRLinkage, false); dsoInitialized->setVisibility(llvm::GlobalValue::HiddenVisibility); // There is no reason for this cast to void*, other than that removing it @@ -505,7 +498,7 @@ void addCoverageAnalysis(Module *m) { llvm::ConstantAggregateZero *zeroinitializer = llvm::ConstantAggregateZero::get(type); m->d_cover_valid = new llvm::GlobalVariable( - gIR->module, type, true, LLGlobalValue::InternalLinkage, + gIR->module, type, /*isConstant=*/true, LLGlobalValue::InternalLinkage, zeroinitializer, "_d_cover_valid"); LLConstant *idxs[] = {DtoConstUint(0), DtoConstUint(0)}; d_cover_valid_slice = diff --git a/gen/ms-cxx-helper.cpp b/gen/ms-cxx-helper.cpp index 061922d5914..577c7c8e336 100644 --- a/gen/ms-cxx-helper.cpp +++ b/gen/ms-cxx-helper.cpp @@ -165,9 +165,8 @@ llvm::StructType *getTypeDescriptorType(IRState &irs, llvm::GlobalVariable *getTypeDescriptor(IRState &irs, ClassDeclaration *cd) { if (cd->isCPPclass()) { const char *name = Target::cppTypeInfoMangle(cd); - return getOrCreateGlobal( - cd->loc, irs.module, getVoidPtrType(), /*isConstant=*/true, - LLGlobalValue::ExternalLinkage, /*init=*/nullptr, name); + return declareGlobal(cd->loc, irs.module, getVoidPtrType(), name, + /*isConstant=*/true); } auto classInfoPtr = getIrAggr(cd, true)->getClassInfoSymbol(); @@ -188,10 +187,13 @@ llvm::GlobalVariable *getTypeDescriptor(IRState &irs, ClassDeclaration *cd) { llvm::ConstantDataArray::getString(gIR->context(), TypeNameString)}; llvm::StructType *TypeDescriptorType = getTypeDescriptorType(irs, classInfoPtr, TypeNameString); - Var = new llvm::GlobalVariable( - gIR->module, TypeDescriptorType, /*Constant=*/false, - LLGlobalVariable::InternalLinkage, // getLinkageForRTTI(Type), - llvm::ConstantStruct::get(TypeDescriptorType, Fields), TypeDescName); + + const LinkageWithCOMDAT lwc = {LLGlobalVariable::LinkOnceODRLinkage, true}; + Var = defineGlobal(cd->loc, gIR->module, TypeDescName, + llvm::ConstantStruct::get(TypeDescriptorType, Fields), + lwc.first, /*isConstant=*/true); + setLinkage(lwc, Var); + return Var; } diff --git a/gen/trycatchfinally.cpp b/gen/trycatchfinally.cpp index 6adafb75f93..9b1f12885fe 100644 --- a/gen/trycatchfinally.cpp +++ b/gen/trycatchfinally.cpp @@ -161,31 +161,36 @@ void TryCatchScope::emitCatchBodies(IRState &irs, llvm::Value *ehPtrSlot) { LLGlobalVariable *ci; if (p.cd->isCPPclass()) { - const char *name = Target::cppTypeInfoMangle(p.cd); - auto cpp_ti = getOrCreateGlobal( - p.cd->loc, irs.module, getVoidPtrType(), /*isConstant=*/true, - LLGlobalValue::ExternalLinkage, /*init=*/nullptr, name); - - // Wrap std::type_info pointers inside a __cpp_type_info_ptr class instance so that - // the personality routine may differentiate C++ catch clauses from D ones. - OutBuffer mangleBuf; - mangleBuf.writestring("_D"); - mangleToBuffer(p.cd, &mangleBuf); - mangleBuf.printf("%d%s", 18, "_cpp_type_info_ptr"); - const auto wrapperMangle = getIRMangledVarName(mangleBuf.peekString(), LINKd); - - const auto cppTypeInfoPtrType = getCppTypeInfoPtrType(); - RTTIBuilder b(cppTypeInfoPtrType); - b.push(cpp_ti); - - auto wrapperType = llvm::cast( - static_cast(cppTypeInfoPtrType->ctype) - ->getMemoryLLType()); - auto wrapperInit = b.get_constant(wrapperType); - - ci = getOrCreateGlobal( - p.cd->loc, irs.module, wrapperType, /*isConstant=*/true, - LLGlobalValue::LinkOnceODRLinkage, wrapperInit, wrapperMangle); + // Wrap std::type_info pointers inside a __cpp_type_info_ptr class + // instance so that the personality routine may differentiate C++ catch + // clauses from D ones. + OutBuffer wrapperMangleBuf; + wrapperMangleBuf.writestring("_D"); + mangleToBuffer(p.cd, &wrapperMangleBuf); + wrapperMangleBuf.printf("%d%s", 18, "_cpp_type_info_ptr"); + const auto wrapperMangle = + getIRMangledVarName(wrapperMangleBuf.peekString(), LINKd); + + ci = irs.module.getGlobalVariable(wrapperMangle); + if (!ci) { + const char *name = Target::cppTypeInfoMangle(p.cd); + auto cpp_ti = + declareGlobal(p.cd->loc, irs.module, getVoidPtrType(), name, + /*isConstant=*/true); + + const auto cppTypeInfoPtrType = getCppTypeInfoPtrType(); + RTTIBuilder b(cppTypeInfoPtrType); + b.push(cpp_ti); + + auto wrapperType = llvm::cast( + static_cast(cppTypeInfoPtrType->ctype) + ->getMemoryLLType()); + auto wrapperInit = b.get_constant(wrapperType); + + ci = defineGlobal(p.cd->loc, irs.module, wrapperMangle, wrapperInit, + LLGlobalValue::LinkOnceODRLinkage, + /*isConstant=*/true); + } } else { ci = getIrAggr(p.cd)->getClassInfoSymbol(); } diff --git a/gen/typinf.cpp b/gen/typinf.cpp index ad37b4de578..1085b7bb251 100644 --- a/gen/typinf.cpp +++ b/gen/typinf.cpp @@ -623,18 +623,17 @@ void TypeInfoDeclaration_codegen(TypeInfoDeclaration *decl, IRState *p) { Logger::println("typeinfo mangle: %s", mangled); } + // Only declare the symbol if it isn't yet, otherwise the subtype of built-in + // TypeInfos (rt.typeinfo.*) may clash with the base type when compiling the + // rt.typeinfo.* modules. const auto irMangle = getIRMangledVarName(mangled, LINKd); - LLGlobalVariable *gvar = gIR->module.getGlobalVariable(irMangle); - if (gvar) { - assert(gvar->getType()->getContainedType(0)->isStructTy()); - } else { + llvm::GlobalVariable *gvar = gIR->module.getGlobalVariable(irMangle); + if (!gvar) { LLType *type = DtoType(decl->type)->getPointerElementType(); - // Create the symbol. We need to keep it mutable as the type is not declared - // as immutable on the D side, and e.g. synchronized() can be used on the + // We need to keep the symbol mutable as the type is not declared as + // immutable on the D side, and e.g. synchronized() can be used on the // implicit monitor. - gvar = - new LLGlobalVariable(gIR->module, type, false, - LLGlobalValue::ExternalLinkage, nullptr, irMangle); + gvar = declareGlobal(decl->loc, gIR->module, type, irMangle, false); } IrGlobal *irg = getIrGlobal(decl, true); diff --git a/ir/iraggr.cpp b/ir/iraggr.cpp index 8c66996b69a..fe7cc575a92 100644 --- a/ir/iraggr.cpp +++ b/ir/iraggr.cpp @@ -49,9 +49,8 @@ LLConstant *&IrAggr::getInitSymbol() { // create the initZ symbol const auto irMangle = getIRMangledInitSymbolName(aggrdecl); - auto initGlobal = - getOrCreateGlobal(aggrdecl->loc, gIR->module, getLLStructType(), true, - llvm::GlobalValue::ExternalLinkage, nullptr, irMangle); + auto initGlobal = declareGlobal(aggrdecl->loc, gIR->module, getLLStructType(), + irMangle, /*isConstant=*/true); initGlobal->setAlignment(DtoAlignment(type)); init = initGlobal; @@ -216,12 +215,9 @@ void IrAggr::addFieldInitializers( offset = aligned; } - // false when it's not okay to use functions from super classes - bool newinsts = (cd == aggrdecl->isClassDeclaration()); - size_t inter_idx = interfacesWithVtbls.size(); for (auto bc : *cd->vtblInterfaces) { - constants.push_back(getInterfaceVtbl(bc, newinsts, inter_idx)); + constants.push_back(getInterfaceVtblSymbol(bc, inter_idx)); offset += Target::ptrsize; inter_idx++; diff --git a/ir/iraggr.h b/ir/iraggr.h index 552b81a30a4..3bf720b8142 100644 --- a/ir/iraggr.h +++ b/ir/iraggr.h @@ -63,6 +63,9 @@ struct IrAggr { /// Builds the __vtblZ initializer constant lazily. llvm::Constant *getVtblInit(); + /// Defines all interface vtbls. + void defineInterfaceVtbls(); + /// Create the __ClassZ/__InterfaceZ symbol lazily. llvm::GlobalVariable *getClassInfoSymbol(); /// Builds the __ClassZ/__InterfaceZ initializer constant lazily. @@ -127,10 +130,12 @@ struct IrAggr { ////////////////////////////////////////////////////////////////////////// - /// Returns vtbl for interface implementation, creates it if not already - /// built. - llvm::GlobalVariable *getInterfaceVtbl(BaseClass *b, bool new_inst, - size_t interfaces_index); + /// Returns the vtbl for an interface implementation. + llvm::GlobalVariable *getInterfaceVtblSymbol(BaseClass *b, + size_t interfaces_index); + /// Defines the vtbl for an interface implementation. + void defineInterfaceVtbl(BaseClass *b, bool new_inst, + size_t interfaces_index); // FIXME make this a member instead friend llvm::Constant *DtoDefineClassInfo(ClassDeclaration *cd); diff --git a/ir/irclass.cpp b/ir/irclass.cpp index be98ff249fb..3188f9e492a 100644 --- a/ir/irclass.cpp +++ b/ir/irclass.cpp @@ -51,9 +51,8 @@ LLGlobalVariable *IrAggr::getVtblSymbol() { LLType *vtblTy = stripModifiers(type)->ctype->isClass()->getVtblType(); - vtbl = - getOrCreateGlobal(aggrdecl->loc, gIR->module, vtblTy, true, - llvm::GlobalValue::ExternalLinkage, nullptr, irMangle); + vtbl = declareGlobal(aggrdecl->loc, gIR->module, vtblTy, irMangle, + /*isConstant=*/true); return vtbl; } @@ -77,9 +76,8 @@ LLGlobalVariable *IrAggr::getClassInfoSymbol() { assert(tc && "invalid ClassInfo type"); // classinfos cannot be constants since they're used as locks for synchronized - classInfo = getOrCreateGlobal( - aggrdecl->loc, gIR->module, tc->getMemoryLLType(), false, - llvm::GlobalValue::ExternalLinkage, nullptr, irMangle); + classInfo = declareGlobal(aggrdecl->loc, gIR->module, tc->getMemoryLLType(), + irMangle, false); // Generate some metadata on this ClassInfo if it's for a class. ClassDeclaration *classdecl = aggrdecl->isClassDeclaration(); @@ -139,11 +137,8 @@ LLGlobalVariable *IrAggr::getInterfaceArraySymbol() { LLArrayType *array_type = llvm::ArrayType::get(InterfaceTy, n); - // We keep the global as external for now and only consider template linkage - // if we emit the initializer later. - classInterfacesArray = - getOrCreateGlobal(cd->loc, gIR->module, array_type, true, - llvm::GlobalValue::ExternalLinkage, nullptr, irMangle); + classInterfacesArray = declareGlobal(cd->loc, gIR->module, array_type, + irMangle, /*isConstant=*/true); return classInterfacesArray; } @@ -257,15 +252,48 @@ LLConstant *IrAggr::getClassInfoInit() { ////////////////////////////////////////////////////////////////////////////// -llvm::GlobalVariable *IrAggr::getInterfaceVtbl(BaseClass *b, bool new_instance, - size_t interfaces_index) { +llvm::GlobalVariable *IrAggr::getInterfaceVtblSymbol(BaseClass *b, + size_t interfaces_index) { auto it = interfaceVtblMap.find({b->sym, interfaces_index}); if (it != interfaceVtblMap.end()) { return it->second; } + ClassDeclaration *cd = aggrdecl->isClassDeclaration(); + assert(cd && "not a class aggregate"); + + llvm::Type *vtblType = LLArrayType::get(getVoidPtrType(), b->sym->vtbl.dim); + + // Thunk prefix + char thunkPrefix[16]; + int thunkLen = sprintf(thunkPrefix, "Thn%d_", b->offset); + char thunkPrefixLen[16]; + sprintf(thunkPrefixLen, "%d", thunkLen); + + OutBuffer mangledName; + mangledName.writestring("_D"); + mangleToBuffer(cd, &mangledName); + mangledName.writestring("11__interface"); + mangleToBuffer(b->sym, &mangledName); + mangledName.writestring(thunkPrefixLen); + mangledName.writestring(thunkPrefix); + mangledName.writestring("6__vtblZ"); + + const auto irMangle = getIRMangledVarName(mangledName.peekString(), LINKd); + + LLGlobalVariable *gvar = + declareGlobal(cd->loc, gIR->module, vtblType, irMangle, /*isConstant=*/true); + + // insert into the vtbl map + interfaceVtblMap.insert({{b->sym, interfaces_index}, gvar}); + + return gvar; +} + +void IrAggr::defineInterfaceVtbl(BaseClass *b, bool new_instance, + size_t interfaces_index) { IF_LOG Logger::println( - "Building vtbl for implementation of interface %s in class %s", + "Defining vtbl for implementation of interface %s in class %s", b->sym->toPrettyChars(), aggrdecl->toPrettyChars()); LOG_SCOPE; @@ -278,6 +306,9 @@ llvm::GlobalVariable *IrAggr::getInterfaceVtbl(BaseClass *b, bool new_instance, std::vector constants; constants.reserve(vtbl_array.dim); + char thunkPrefix[16]; + sprintf(thunkPrefix, "Thn%d_", b->offset); + const auto voidPtrTy = getVoidPtrType(); if (!b->sym->isCPPinterface()) { // skip interface info for CPP interfaces @@ -293,17 +324,11 @@ llvm::GlobalVariable *IrAggr::getInterfaceVtbl(BaseClass *b, bool new_instance, constants.push_back(DtoBitCast(c, voidPtrTy)); } - // Thunk prefix - char thunkPrefix[16]; - int thunkLen = sprintf(thunkPrefix, "Thn%d_", b->offset); - char thunkPrefixLen[16]; - sprintf(thunkPrefixLen, "%d", thunkLen); - // add virtual function pointers size_t n = vtbl_array.dim; for (size_t i = b->sym->vtblOffset(); i < n; i++) { - Dsymbol *dsym = static_cast(vtbl_array.data[i]); - if (dsym == nullptr) { + FuncDeclaration *fd = vtbl_array[i]; + if (!fd) { // FIXME // why is this null? // happens for mini/s.d @@ -311,9 +336,6 @@ llvm::GlobalVariable *IrAggr::getInterfaceVtbl(BaseClass *b, bool new_instance, continue; } - FuncDeclaration *fd = dsym->isFuncDeclaration(); - assert(fd && "vtbl entry not a function"); - assert((!fd->isAbstract() || fd->fbody) && "null symbol in interface implementation vtable"); @@ -444,27 +466,24 @@ llvm::GlobalVariable *IrAggr::getInterfaceVtbl(BaseClass *b, bool new_instance, llvm::Constant *vtbl_constant = LLConstantArray::get( LLArrayType::get(voidPtrTy, constants.size()), constants); - OutBuffer mangledName; - mangledName.writestring("_D"); - mangleToBuffer(cd, &mangledName); - mangledName.writestring("11__interface"); - mangleToBuffer(b->sym, &mangledName); - mangledName.writestring(thunkPrefixLen); - mangledName.writestring(thunkPrefix); - mangledName.writestring("6__vtblZ"); + // define the global + const auto gvar = getInterfaceVtblSymbol(b, interfaces_index); + defineGlobal(gvar, vtbl_constant, cd); +} - const auto irMangle = getIRMangledVarName(mangledName.peekString(), LINKd); +void IrAggr::defineInterfaceVtbls() { + const size_t n = interfacesWithVtbls.size(); + assert(n == stripModifiers(type)->ctype->isClass()->getNumInterfaceVtbls() && + "inconsistent number of interface vtables in this class"); - const auto lwc = DtoLinkage(cd); - LLGlobalVariable *GV = - getOrCreateGlobal(cd->loc, gIR->module, vtbl_constant->getType(), true, - lwc.first, vtbl_constant, irMangle); - setLinkage(lwc, GV); + for (size_t i = 0; i < n; ++i) { + auto baseClass = interfacesWithVtbls[i]; - // insert into the vtbl map - interfaceVtblMap.insert({{b->sym, interfaces_index}, GV}); + // false when it's not okay to use functions from super classes + bool newinsts = (baseClass->sym == aggrdecl->isClassDeclaration()); - return GV; + defineInterfaceVtbl(baseClass, newinsts, i); + } } bool IrAggr::isPacked() const { @@ -552,8 +571,7 @@ LLConstant *IrAggr::getClassInfoInterfaces() { // create and apply initializer LLConstant *arr = LLConstantArray::get(array_type, constants); auto ciarr = getInterfaceArraySymbol(); - ciarr->setInitializer(arr); - setLinkage(cd, ciarr); + defineGlobal(ciarr, arr, cd); // return null, only baseclass provide interfaces if (cd->vtblInterfaces->dim == 0) { diff --git a/ir/irmodule.cpp b/ir/irmodule.cpp index 8d2eee839df..3d936029d0f 100644 --- a/ir/irmodule.cpp +++ b/ir/irmodule.cpp @@ -11,6 +11,7 @@ #include "module.h" #include "gen/llvm.h" #include "gen/irstate.h" +#include "gen/llvmhelpers.h" #include "gen/mangling.h" #include "gen/tollvm.h" #include "ir/irdsymbol.h" @@ -25,9 +26,9 @@ llvm::GlobalVariable *IrModule::moduleInfoSymbol() { const auto irMangle = getIRMangledModuleInfoSymbolName(M); - moduleInfoVar = new llvm::GlobalVariable( - gIR->module, llvm::StructType::create(gIR->context()), false, - llvm::GlobalValue::ExternalLinkage, nullptr, irMangle); + moduleInfoVar = + declareGlobal(Loc(), gIR->module, + llvm::StructType::create(gIR->context()), irMangle, false); return moduleInfoVar; }