Index: docs/LangRef.rst =================================================================== --- docs/LangRef.rst +++ docs/LangRef.rst @@ -279,23 +279,6 @@ visible, meaning that it participates in linkage and can be used to resolve external symbol references. -The next two types of linkage are targeted for Microsoft Windows -platform only. They are designed to support importing (exporting) -symbols from (to) DLLs (Dynamic Link Libraries). - -``dllimport`` - "``dllimport``" linkage causes the compiler to reference a function - or variable via a global pointer to a pointer that is set up by the - DLL exporting the symbol. On Microsoft Windows targets, the pointer - name is formed by combining ``__imp_`` and the function or variable - name. -``dllexport`` - "``dllexport``" linkage causes the compiler to provide a global - pointer to a pointer in a DLL, so that it can be referenced with the - ``dllimport`` attribute. On Microsoft Windows targets, the pointer - name is formed by combining ``__imp_`` and the function or variable - name. - For example, since the "``.LC0``" variable is defined to be internal, if another module defined a "``.LC0``" variable and was linked with this one, one of the two would be renamed, preventing a collision. Since @@ -525,6 +508,9 @@ iterate over them as an array, alignment padding would break this iteration. +Globals can be marked as ``dllimport`` or ``dllexport``. Please refer to +the function attributes with the same name for more information. + For example, the following defines a global in a numbered address space with an initializer, section, and alignment: @@ -539,6 +525,12 @@ @G = thread_local(initialexec) global i32 0, align 4 +The following example defines a global that is imported from a DLL: + +.. code-block:: llvm + + @G = external global i32, dllimport + .. _functionstructure: Functions @@ -828,6 +820,16 @@ computing edge weights, basic blocks post-dominated by a cold function call are also considered to be cold; and, thus, given low weight. +``dllimport`` + "``dllimport``" causes the compiler to reference the function via a + global pointer to a pointer that is set up by the DLL exporting the + symbol. On Microsoft Windows targets, the pointer name is formed by + combining ``__imp_`` and the function or variable name. +``dllexport`` + "``dllexport``" causes the compiler to provide a global pointer to a + pointer in a DLL, so that it can be referenced with the ``dllimport`` + attribute. On Microsoft Windows targets, the pointer name is formed + by combining ``__imp_`` and the function or variable name. ``nonlazybind`` This attribute suppresses lazy symbol binding for the function. This may make calls to the function faster, at the cost of extra program Index: include/llvm-c/Core.h =================================================================== --- include/llvm-c/Core.h +++ include/llvm-c/Core.h @@ -281,8 +281,6 @@ LLVMInternalLinkage, /**< Rename collisions when linking (static functions) */ LLVMPrivateLinkage, /**< Like Internal, but omit from symbol table */ - LLVMDLLImportLinkage, /**< Function to be imported from DLL */ - LLVMDLLExportLinkage, /**< Function to be accessible from DLL */ LLVMExternalWeakLinkage,/**< ExternalWeak linkage description */ LLVMGhostLinkage, /**< Obsolete */ LLVMCommonLinkage, /**< Tentative definitions */ Index: include/llvm/IR/Attributes.h =================================================================== --- include/llvm/IR/Attributes.h +++ include/llvm/IR/Attributes.h @@ -71,6 +71,8 @@ ///< nobuiltin attribute on its declaration. ByVal, ///< Pass structure by value Cold, ///< Marks function as being in a cold path. + DLLExport, ///< Export this function from DLL + DLLImport, ///< Import this function from DLL InlineHint, ///< Source said inlining was desirable InReg, ///< Force argument to be passed in register MinSize, ///< Function must be optimized for size first Index: include/llvm/IR/GlobalValue.h =================================================================== --- include/llvm/IR/GlobalValue.h +++ include/llvm/IR/GlobalValue.h @@ -43,8 +43,6 @@ PrivateLinkage, ///< Like Internal, but omit from symbol table. LinkerPrivateLinkage, ///< Like Private, but linker removes. LinkerPrivateWeakLinkage, ///< Like LinkerPrivate, but weak. - DLLImportLinkage, ///< Function to be imported from DLL - DLLExportLinkage, ///< Function to be accessible from DLL. ExternalWeakLinkage,///< ExternalWeak linkage description. CommonLinkage ///< Tentative definitions. }; @@ -92,7 +90,7 @@ return Visibility == ProtectedVisibility; } void setVisibility(VisibilityTypes V) { Visibility = V; } - + bool hasSection() const { return !Section.empty(); } const std::string &getSection() const { return Section; } void setSection(StringRef S) { Section = S; } @@ -152,12 +150,6 @@ return isInternalLinkage(Linkage) || isPrivateLinkage(Linkage) || isLinkerPrivateLinkage(Linkage) || isLinkerPrivateWeakLinkage(Linkage); } - static bool isDLLImportLinkage(LinkageTypes Linkage) { - return Linkage == DLLImportLinkage; - } - static bool isDLLExportLinkage(LinkageTypes Linkage) { - return Linkage == DLLExportLinkage; - } static bool isExternalWeakLinkage(LinkageTypes Linkage) { return Linkage == ExternalWeakLinkage; } @@ -219,8 +211,6 @@ return isLinkerPrivateWeakLinkage(Linkage); } bool hasLocalLinkage() const { return isLocalLinkage(Linkage); } - bool hasDLLImportLinkage() const { return isDLLImportLinkage(Linkage); } - bool hasDLLExportLinkage() const { return isDLLExportLinkage(Linkage); } bool hasExternalWeakLinkage() const { return isExternalWeakLinkage(Linkage); } bool hasCommonLinkage() const { return isCommonLinkage(Linkage); } Index: include/llvm/IR/GlobalVariable.h =================================================================== --- include/llvm/IR/GlobalVariable.h +++ include/llvm/IR/GlobalVariable.h @@ -48,6 +48,7 @@ // can change from its initial // value before global // initializers are run? + unsigned dllStorageClass : 2; // DLL storage class public: // allocate space for exactly one operand @@ -63,6 +64,13 @@ LocalExecTLSModel }; + /// @brief Storage classes of global values for PE targets. + enum DLLStorageClassTypes { + DefaultStorageClass = 0, + DLLImportStorageClass = 1, ///< Function to be imported from DLL + DLLExportStorageClass = 2 ///< Function to be accessible from DLL. + }; + /// GlobalVariable ctor - If a parent module is specified, the global is /// automatically inserted into the end of the specified modules global list. GlobalVariable(Type *Ty, bool isConstant, LinkageTypes Linkage, @@ -167,6 +175,17 @@ return static_cast(threadLocalMode); } + DLLStorageClassTypes getDLLStorageClass() const { + return DLLStorageClassTypes(dllStorageClass); + } + bool hasDLLImportStorageClass() const { + return dllStorageClass == DLLImportStorageClass; + } + bool hasDLLExportStorageClass() const { + return dllStorageClass == DLLExportStorageClass; + } + void setDLLStorageClass(DLLStorageClassTypes C) { dllStorageClass = C; } + bool isExternallyInitialized() const { return isExternallyInitializedConstant; } Index: lib/AsmParser/LLParser.cpp =================================================================== --- lib/AsmParser/LLParser.cpp +++ lib/AsmParser/LLParser.cpp @@ -250,9 +250,7 @@ case lltok::kw_linkonce_odr: // OptionalLinkage case lltok::kw_linkonce_odr_auto_hide: // OptionalLinkage case lltok::kw_appending: // OptionalLinkage - case lltok::kw_dllexport: // OptionalLinkage case lltok::kw_common: // OptionalLinkage - case lltok::kw_dllimport: // OptionalLinkage case lltok::kw_extern_weak: // OptionalLinkage case lltok::kw_external: { // OptionalLinkage unsigned Linkage, Visibility; @@ -725,8 +723,7 @@ // If the linkage is specified and is external, then no initializer is // present. Constant *Init = 0; - if (!HasLinkage || (Linkage != GlobalValue::DLLImportLinkage && - Linkage != GlobalValue::ExternalWeakLinkage && + if (!HasLinkage || (Linkage != GlobalValue::ExternalWeakLinkage && Linkage != GlobalValue::ExternalLinkage)) { if (ParseGlobalValue(Ty, Init)) return true; @@ -792,6 +789,12 @@ unsigned Alignment; if (ParseOptionalAlignment(Alignment)) return true; GV->setAlignment(Alignment); + } else if (Lex.getKind() == lltok::kw_dllimport) { + Lex.Lex(); + GV->setDLLStorageClass(GlobalVariable::DLLImportStorageClass); + } else if (Lex.getKind() == lltok::kw_dllexport) { + Lex.Lex(); + GV->setDLLStorageClass(GlobalVariable::DLLExportStorageClass); } else { TokError("unknown global variable property!"); } @@ -911,6 +914,8 @@ case lltok::kw_alwaysinline: B.addAttribute(Attribute::AlwaysInline); break; case lltok::kw_builtin: B.addAttribute(Attribute::Builtin); break; case lltok::kw_cold: B.addAttribute(Attribute::Cold); break; + case lltok::kw_dllexport: B.addAttribute(Attribute::DLLExport); break; + case lltok::kw_dllimport: B.addAttribute(Attribute::DLLImport); break; case lltok::kw_inlinehint: B.addAttribute(Attribute::InlineHint); break; case lltok::kw_minsize: B.addAttribute(Attribute::MinSize); break; case lltok::kw_naked: B.addAttribute(Attribute::Naked); break; @@ -1270,9 +1275,7 @@ /// ::= 'linkonce_odr_auto_hide' /// ::= 'available_externally' /// ::= 'appending' -/// ::= 'dllexport' /// ::= 'common' -/// ::= 'dllimport' /// ::= 'extern_weak' /// ::= 'external' bool LLParser::ParseOptionalLinkage(unsigned &Res, bool &HasLinkage) { @@ -1297,9 +1300,7 @@ Res = GlobalValue::AvailableExternallyLinkage; break; case lltok::kw_appending: Res = GlobalValue::AppendingLinkage; break; - case lltok::kw_dllexport: Res = GlobalValue::DLLExportLinkage; break; case lltok::kw_common: Res = GlobalValue::CommonLinkage; break; - case lltok::kw_dllimport: Res = GlobalValue::DLLImportLinkage; break; case lltok::kw_extern_weak: Res = GlobalValue::ExternalWeakLinkage; break; case lltok::kw_external: Res = GlobalValue::ExternalLinkage; break; } @@ -2935,7 +2936,6 @@ switch ((GlobalValue::LinkageTypes)Linkage) { case GlobalValue::ExternalLinkage: break; // always ok. - case GlobalValue::DLLImportLinkage: case GlobalValue::ExternalWeakLinkage: if (isDefine) return Error(LinkageLoc, "invalid linkage for function definition"); @@ -2950,7 +2950,6 @@ case GlobalValue::LinkOnceODRAutoHideLinkage: case GlobalValue::WeakAnyLinkage: case GlobalValue::WeakODRLinkage: - case GlobalValue::DLLExportLinkage: if (!isDefine) return Error(LinkageLoc, "invalid linkage for function declaration"); break; Index: lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- lib/Bitcode/Reader/BitcodeReader.cpp +++ lib/Bitcode/Reader/BitcodeReader.cpp @@ -77,8 +77,6 @@ case 2: return GlobalValue::AppendingLinkage; case 3: return GlobalValue::InternalLinkage; case 4: return GlobalValue::LinkOnceAnyLinkage; - case 5: return GlobalValue::DLLImportLinkage; - case 6: return GlobalValue::DLLExportLinkage; case 7: return GlobalValue::ExternalWeakLinkage; case 8: return GlobalValue::CommonLinkage; case 9: return GlobalValue::PrivateLinkage; Index: lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- lib/Bitcode/Writer/BitcodeWriter.cpp +++ lib/Bitcode/Writer/BitcodeWriter.cpp @@ -397,8 +397,6 @@ case GlobalValue::AppendingLinkage: return 2; case GlobalValue::InternalLinkage: return 3; case GlobalValue::LinkOnceAnyLinkage: return 4; - case GlobalValue::DLLImportLinkage: return 5; - case GlobalValue::DLLExportLinkage: return 6; case GlobalValue::ExternalWeakLinkage: return 7; case GlobalValue::CommonLinkage: return 8; case GlobalValue::PrivateLinkage: return 9; Index: lib/CodeGen/AsmPrinter/AsmPrinter.cpp =================================================================== --- lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -240,7 +240,6 @@ OutStreamer.EmitSymbolAttribute(GVSym, MCSA_Weak); } break; - case GlobalValue::DLLExportLinkage: case GlobalValue::AppendingLinkage: // FIXME: appending linkage variables should go into a section of // their name or something. For now, just emit them as external. Index: lib/ExecutionEngine/ExecutionEngine.cpp =================================================================== --- lib/ExecutionEngine/ExecutionEngine.cpp +++ lib/ExecutionEngine/ExecutionEngine.cpp @@ -1199,9 +1199,7 @@ } // If the existing global is strong, never replace it. - if (GVEntry->hasExternalLinkage() || - GVEntry->hasDLLImportLinkage() || - GVEntry->hasDLLExportLinkage()) + if (GVEntry->hasExternalLinkage()) continue; // Otherwise, we know it's linkonce/weak, replace it if this is a strong Index: lib/IR/AsmWriter.cpp =================================================================== --- lib/IR/AsmWriter.cpp +++ lib/IR/AsmWriter.cpp @@ -1399,8 +1399,6 @@ case GlobalValue::WeakODRLinkage: Out << "weak_odr "; break; case GlobalValue::CommonLinkage: Out << "common "; break; case GlobalValue::AppendingLinkage: Out << "appending "; break; - case GlobalValue::DLLImportLinkage: Out << "dllimport "; break; - case GlobalValue::DLLExportLinkage: Out << "dllexport "; break; case GlobalValue::ExternalWeakLinkage: Out << "extern_weak "; break; case GlobalValue::AvailableExternallyLinkage: Out << "available_externally "; @@ -1472,6 +1470,12 @@ if (GV->getAlignment()) Out << ", align " << GV->getAlignment(); + switch (GV->getDLLStorageClass()) { + case GlobalVariable::DefaultStorageClass: break; + case GlobalVariable::DLLImportStorageClass: Out << ", dllimport"; break; + case GlobalVariable::DLLExportStorageClass: Out << ", dllexport"; break; + } + printInfoComment(*GV); } Index: lib/IR/Attributes.cpp =================================================================== --- lib/IR/Attributes.cpp +++ lib/IR/Attributes.cpp @@ -161,6 +161,10 @@ return "builtin"; if (hasAttribute(Attribute::ByVal)) return "byval"; + if (hasAttribute(Attribute::DLLExport)) + return "dllexport"; + if (hasAttribute(Attribute::DLLImport)) + return "dllimport"; if (hasAttribute(Attribute::InlineHint)) return "inlinehint"; if (hasAttribute(Attribute::InReg)) @@ -402,6 +406,8 @@ case Attribute::Returned: return 1ULL << 39; case Attribute::Cold: return 1ULL << 40; case Attribute::Builtin: return 1ULL << 41; + case Attribute::DLLExport: return 1ULL << 42; + case Attribute::DLLImport: return 1ULL << 43; } llvm_unreachable("Unsupported attribute type"); } Index: lib/IR/Core.cpp =================================================================== --- lib/IR/Core.cpp +++ lib/IR/Core.cpp @@ -1126,10 +1126,6 @@ return LLVMLinkerPrivateLinkage; case GlobalValue::LinkerPrivateWeakLinkage: return LLVMLinkerPrivateWeakLinkage; - case GlobalValue::DLLImportLinkage: - return LLVMDLLImportLinkage; - case GlobalValue::DLLExportLinkage: - return LLVMDLLExportLinkage; case GlobalValue::ExternalWeakLinkage: return LLVMExternalWeakLinkage; case GlobalValue::CommonLinkage: @@ -1179,12 +1175,6 @@ case LLVMLinkerPrivateWeakLinkage: GV->setLinkage(GlobalValue::LinkerPrivateWeakLinkage); break; - case LLVMDLLImportLinkage: - GV->setLinkage(GlobalValue::DLLImportLinkage); - break; - case LLVMDLLExportLinkage: - GV->setLinkage(GlobalValue::DLLExportLinkage); - break; case LLVMExternalWeakLinkage: GV->setLinkage(GlobalValue::ExternalWeakLinkage); break; Index: lib/IR/Globals.cpp =================================================================== --- lib/IR/Globals.cpp +++ lib/IR/Globals.cpp @@ -91,7 +91,8 @@ OperandTraits::op_begin(this), InitVal != 0, Link, Name), isConstantGlobal(constant), threadLocalMode(TLMode), - isExternallyInitializedConstant(isExternallyInitialized) { + isExternallyInitializedConstant(isExternallyInitialized), + dllStorageClass(DefaultStorageClass) { if (InitVal) { assert(InitVal->getType() == Ty && "Initializer should be the same type as the GlobalVariable!"); @@ -112,7 +113,8 @@ OperandTraits::op_begin(this), InitVal != 0, Link, Name), isConstantGlobal(constant), threadLocalMode(TLMode), - isExternallyInitializedConstant(isExternallyInitialized) { + isExternallyInitializedConstant(isExternallyInitialized), + dllStorageClass(DefaultStorageClass) { if (InitVal) { assert(InitVal->getType() == Ty && "Initializer should be the same type as the GlobalVariable!"); Index: lib/IR/Verifier.cpp =================================================================== --- lib/IR/Verifier.cpp +++ lib/IR/Verifier.cpp @@ -388,16 +388,12 @@ Assert1(!GV.isDeclaration() || GV.isMaterializable() || GV.hasExternalLinkage() || - GV.hasDLLImportLinkage() || GV.hasExternalWeakLinkage() || (isa(GV) && (GV.hasLocalLinkage() || GV.hasWeakLinkage())), - "Global is external, but doesn't have external or dllimport or weak linkage!", + "Global is external, but doesn't have external or weak linkage!", &GV); - Assert1(!GV.hasDLLImportLinkage() || GV.isDeclaration(), - "Global is marked as dllimport, but not external", &GV); - Assert1(!GV.hasAppendingLinkage() || isa(GV), "Only global variables can have appending linkage!", &GV); @@ -427,8 +423,7 @@ &GV); } } else { - Assert1(GV.hasExternalLinkage() || GV.hasDLLImportLinkage() || - GV.hasExternalWeakLinkage(), + Assert1(GV.hasExternalLinkage() || GV.hasExternalWeakLinkage(), "invalid linkage type for global declaration", &GV); } @@ -473,6 +468,11 @@ } } + Assert1(!GV.hasDLLImportStorageClass() || GV.isDeclaration() || + GV.getLinkage() == GlobalValue::ExternalLinkage || + GV.getLinkage() == GlobalValue::AvailableExternallyLinkage, + "Global is marked as dllimport, but not external", &GV); + visitGlobalValue(GV); } @@ -694,7 +694,9 @@ I->getKindAsEnum() == Attribute::NoDuplicate || I->getKindAsEnum() == Attribute::Builtin || I->getKindAsEnum() == Attribute::NoBuiltin || - I->getKindAsEnum() == Attribute::Cold) { + I->getKindAsEnum() == Attribute::Cold || + I->getKindAsEnum() == Attribute::DLLImport || + I->getKindAsEnum() == Attribute::DLLExport) { if (!isFunction) { CheckFailed("Attribute '" + I->getAsString() + "' only applies to functions!", V); @@ -833,6 +835,12 @@ Attrs.hasAttribute(AttributeSet::FunctionIndex, Attribute::AlwaysInline)), "Attributes 'noinline and alwaysinline' are incompatible!", V); + + Assert1(!(Attrs.hasAttribute(AttributeSet::FunctionIndex, + Attribute::DLLImport) && + Attrs.hasAttribute(AttributeSet::FunctionIndex, + Attribute::DLLExport)), + "Attributes 'dllimport and dllexport' are incompatible!", V); } bool Verifier::VerifyAttributeCount(AttributeSet Attrs, unsigned Params) { @@ -924,8 +932,7 @@ if (F.isMaterializable()) { // Function has a body somewhere we can't see. } else if (F.isDeclaration()) { - Assert1(F.hasExternalLinkage() || F.hasDLLImportLinkage() || - F.hasExternalWeakLinkage(), + Assert1(F.hasExternalLinkage() || F.hasExternalWeakLinkage(), "invalid linkage type for function declaration", &F); } else { // Verify that this function (which has a body) is not named "llvm.*". It @@ -951,6 +958,10 @@ if (F.hasAddressTaken(&U)) Assert1(0, "Invalid user of intrinsic instruction!", U); } + + Assert1(!F.hasFnAttribute(Attribute::DLLImport) || F.isDeclaration() || + F.getLinkage() == GlobalValue::AvailableExternallyLinkage, + "Function is marked as dllimport, but not external.", &F); } // verifyBasicBlock - Verify that a basic block is well formed... Index: lib/Linker/LinkModules.cpp =================================================================== --- lib/Linker/LinkModules.cpp +++ lib/Linker/LinkModules.cpp @@ -509,6 +509,16 @@ return false; } +static bool hasDLLImport(const GlobalValue *G) { + if (const GlobalVariable *GV = dyn_cast(G)) + return GV->hasDLLImportStorageClass(); + + if (const Function *F = dyn_cast(G)) + return F->hasFnAttribute(Attribute::DLLImport); + + return false; +} + Value *ValueMaterializerTy::materializeValueFor(Value *V) { Function *SF = dyn_cast(V); if (!SF) @@ -538,12 +548,12 @@ bool SrcIsDeclaration = Src->isDeclaration() && !Src->isMaterializable(); bool DestIsDeclaration = Dest->isDeclaration(); - + if (SrcIsDeclaration) { // If Src is external or if both Src & Dest are external.. Just link the // external globals, we aren't adding anything. - if (Src->hasDLLImportLinkage()) { - // If one of GVs has DLLImport linkage, result should be dllimport'ed. + if (hasDLLImport(Src)) { + // If one of GVs is marked as DLLImport, result should be dllimport'ed. if (DestIsDeclaration) { LinkFromSrc = true; LT = Src->getLinkage(); @@ -556,7 +566,7 @@ LinkFromSrc = false; LT = Dest->getLinkage(); } - } else if (DestIsDeclaration && !Dest->hasDLLImportLinkage()) { + } else if (DestIsDeclaration && !hasDLLImport(Dest)) { // If Dest is external but Src is not: LinkFromSrc = true; LT = Src->getLinkage(); @@ -583,10 +593,8 @@ LT = GlobalValue::ExternalLinkage; } } else { - assert((Dest->hasExternalLinkage() || Dest->hasDLLImportLinkage() || - Dest->hasDLLExportLinkage() || Dest->hasExternalWeakLinkage()) && - (Src->hasExternalLinkage() || Src->hasDLLImportLinkage() || - Src->hasDLLExportLinkage() || Src->hasExternalWeakLinkage()) && + assert((Dest->hasExternalLinkage() || Dest->hasExternalWeakLinkage()) && + (Src->hasExternalLinkage() || Src->hasExternalWeakLinkage()) && "Unexpected linkage type!"); return emitError("Linking globals named '" + Src->getName() + "': symbol multiply defined!"); Index: lib/Target/CppBackend/CPPBackend.cpp =================================================================== --- lib/Target/CppBackend/CPPBackend.cpp +++ lib/Target/CppBackend/CPPBackend.cpp @@ -301,10 +301,6 @@ Out << "GlobalValue::AppendingLinkage"; break; case GlobalValue::ExternalLinkage: Out << "GlobalValue::ExternalLinkage"; break; - case GlobalValue::DLLImportLinkage: - Out << "GlobalValue::DLLImportLinkage"; break; - case GlobalValue::DLLExportLinkage: - Out << "GlobalValue::DLLExportLinkage"; break; case GlobalValue::ExternalWeakLinkage: Out << "GlobalValue::ExternalWeakLinkage"; break; case GlobalValue::CommonLinkage: @@ -510,6 +506,8 @@ HANDLE_ATTR(UWTable); HANDLE_ATTR(NonLazyBind); HANDLE_ATTR(MinSize); + HANDLE_ATTR(DLLExport); + HANDLE_ATTR(DLLImport); #undef HANDLE_ATTR if (attrs.contains(Attribute::StackAlignment)) { Index: lib/Target/Mangler.cpp =================================================================== --- lib/Target/Mangler.cpp +++ lib/Target/Mangler.cpp @@ -17,6 +17,7 @@ #include "llvm/IR/DataLayout.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Function.h" +#include "llvm/IR/GlobalVariable.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" #include "llvm/Target/TargetMachine.h" @@ -237,6 +238,14 @@ MCSymbol *Mangler::getSymbol(const GlobalValue *GV) { SmallString<60> NameStr; getNameWithPrefix(NameStr, GV, false); + + if (const GlobalVariable *Var = dyn_cast(GV)) { + if (Var->hasDLLImportStorageClass()) { + const char *Prefix = "__imp_"; + NameStr.insert(NameStr.begin(), Prefix, Prefix+strlen(Prefix)); + } + } + return Context.GetOrCreateSymbol(NameStr.str()); } Index: lib/Target/X86/X86AsmPrinter.cpp =================================================================== --- lib/Target/X86/X86AsmPrinter.cpp +++ lib/Target/X86/X86AsmPrinter.cpp @@ -644,14 +644,29 @@ static_cast(getObjFileLowering()); for (Module::const_iterator I = M.begin(), E = M.end(); I != E; ++I) - if (I->hasDLLExportLinkage()) + if (I->hasFnAttribute(Attribute::DLLExport)) DLLExportedFns.push_back(Mang->getSymbol(I)); for (Module::const_global_iterator I = M.global_begin(), E = M.global_end(); I != E; ++I) - if (I->hasDLLExportLinkage()) + if (I->hasDLLExportStorageClass()) DLLExportedGlobals.push_back(Mang->getSymbol(I)); + for (Module::const_alias_iterator I = M.alias_begin(), E = M.alias_end(); + I != E; ++I) { + const GlobalValue *GV = I->getAliasedGlobal(); + while (const GlobalAlias *A = dyn_cast(GV)) + GV = A->getAliasedGlobal(); + + if (const Function *F = dyn_cast(GV)) { + if (F->hasFnAttribute(Attribute::DLLExport)) + DLLExportedFns.push_back(Mang->getSymbol(I)); + } else if (const GlobalVariable *V = dyn_cast(GV)) { + if (V->hasDLLExportStorageClass()) + DLLExportedGlobals.push_back(Mang->getSymbol(I)); + } + } + // Output linker support code for dllexported globals on windows. if (!DLLExportedGlobals.empty() || !DLLExportedFns.empty()) { OutStreamer.SwitchSection(TLOFCOFF.getDrectveSection()); Index: lib/Target/X86/X86FastISel.cpp =================================================================== --- lib/Target/X86/X86FastISel.cpp +++ lib/Target/X86/X86FastISel.cpp @@ -635,15 +635,21 @@ (AM.Base.Reg != 0 || AM.IndexReg != 0)) return false; - // Can't handle DLLImport. - if (GV->hasDLLImportLinkage()) - return false; - - // Can't handle TLS. - if (const GlobalVariable *GVar = dyn_cast(GV)) + if (const GlobalVariable *GVar = dyn_cast(GV)) { + // Can't handle TLS. if (GVar->isThreadLocal()) return false; + // Can't handle DLLImport. + if (GVar->hasDLLImportStorageClass()) + return false; + } + + if (const Function *F = dyn_cast(GV)) + // Can't handle DLLImport. + if (F->hasFnAttribute(Attribute::DLLImport)) + return false; + // Okay, we've committed to selecting this global. Set up the basic address. AM.GV = GV; Index: lib/Target/X86/X86ISelLowering.cpp =================================================================== --- lib/Target/X86/X86ISelLowering.cpp +++ lib/Target/X86/X86ISelLowering.cpp @@ -2271,6 +2271,16 @@ return Chain; } +static bool hasDLLImport(const GlobalValue *G) { + if (const GlobalVariable *GV = dyn_cast(G)) + return GV->hasDLLImportStorageClass(); + + if (const Function *F = dyn_cast(G)) + return F->hasFnAttribute(Attribute::DLLImport); + + return false; +} + SDValue X86TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, SmallVectorImpl &InVals) const { @@ -2567,7 +2577,7 @@ // We should use extra load for direct calls to dllimported functions in // non-JIT mode. const GlobalValue *GV = G->getGlobal(); - if (!GV->hasDLLImportLinkage()) { + if (!hasDLLImport(GV)) { unsigned char OpFlags = 0; bool ExtraLoad = false; unsigned WrapperKind = ISD::DELETED_NODE; Index: lib/Target/X86/X86Subtarget.cpp =================================================================== --- lib/Target/X86/X86Subtarget.cpp +++ lib/Target/X86/X86Subtarget.cpp @@ -17,6 +17,7 @@ #include "llvm/IR/Attributes.h" #include "llvm/IR/Function.h" #include "llvm/IR/GlobalValue.h" +#include "llvm/IR/GlobalVariable.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Host.h" @@ -48,6 +49,16 @@ return X86II::MO_NO_FLAG; } +static bool hasDLLImport(const GlobalValue *G) { + if (const GlobalVariable *GV = dyn_cast(G)) + return GV->hasDLLImportStorageClass(); + + if (const Function *F = dyn_cast(G)) + return F->hasFnAttribute(Attribute::DLLImport); + + return false; +} + /// ClassifyGlobalReference - Classify a global variable reference for the /// current subtarget according to how we should reference it in a non-pcrel /// context. @@ -55,7 +66,7 @@ ClassifyGlobalReference(const GlobalValue *GV, const TargetMachine &TM) const { // DLLImport only exists on windows, it is implemented as a load from a // DLLIMPORT stub. - if (GV->hasDLLImportLinkage()) + if (hasDLLImport(GV)) return X86II::MO_DLLIMPORT; // Determine whether this is a reference to a definition or a declaration. Index: lib/Target/XCore/XCoreAsmPrinter.cpp =================================================================== --- lib/Target/XCore/XCoreAsmPrinter.cpp +++ lib/Target/XCore/XCoreAsmPrinter.cpp @@ -133,10 +133,6 @@ case GlobalValue::InternalLinkage: case GlobalValue::PrivateLinkage: break; - case GlobalValue::DLLImportLinkage: - llvm_unreachable("DLLImport linkage is not supported by this target!"); - case GlobalValue::DLLExportLinkage: - llvm_unreachable("DLLExport linkage is not supported by this target!"); default: llvm_unreachable("Unknown linkage type!"); } Index: test/CodeGen/X86/dll-linkage.ll =================================================================== --- test/CodeGen/X86/dll-linkage.ll +++ /dev/null @@ -1,14 +0,0 @@ -; RUN: llc < %s -mtriple=i386-pc-mingw32 | FileCheck %s - -; RUN: llc < %s -mtriple=i386-pc-mingw32 -O0 | FileCheck %s -check-prefix=FAST -; PR6275 - -declare dllimport void @foo() - -define void @bar() nounwind { -; CHECK: calll *__imp__foo -; FAST: movl __imp__foo, [[R:%[a-z]{3}]] -; FAST: calll *[[R]] - call void @foo() - ret void -} Index: test/CodeGen/X86/dllexport-x86_64.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/dllexport-x86_64.ll @@ -0,0 +1,85 @@ +; RUN: llc -mtriple x86_64-pc-win32 < %s | FileCheck %s + +; CHECK: .text + +; CHECK: .globl f1 +define void @f1() dllexport { + ret void +} + +; CHECK: .globl f2 +define void @f2() unnamed_addr dllexport { + ret void +} + +; CHECK: .section +; CHECK: .linkonce discard +; CHECK: .globl lnk1 +define linkonce_odr void @lnk1() dllexport { + ret void +} + +; CHECK: .section +; CHECK: .linkonce discard +; CHECK: .globl lnk2 +define linkonce_odr void @lnk2() alwaysinline dllexport { + ret void +} + +; CHECK: .section +; CHECK: .linkonce discard +; CHECK: .globl weak1 +define weak_odr void @weak1() dllexport { + ret void +} + + +; CHECK: .data + +; CHECK: .globl Var1 +@Var1 = global i32 1, align 4, dllexport + +; CHECK: .globl Var2 +@Var2 = unnamed_addr constant i32 1, dllexport + +; CHECK: .comm Var3 +@Var3 = common global i32 0, align 4, dllexport + +; CHECK: .section +; CHECK: .linkonce discard +; CHECK: .globl WeakVar1 +@WeakVar1 = weak_odr global i32 1, align 4, dllexport + +; CHECK: .section +; CHECK: .linkonce discard +; CHECK: .globl WeakVar2 +@WeakVar2 = weak_odr unnamed_addr constant i32 1, dllexport + + +; CHECK: .globl alias +; CHECK: alias = f1 +@alias = alias void()* @f1 + +; CHECK: .globl alias2 +; CHECK: alias2 = alias +@alias2 = alias void()* @alias + +; CHECK: .weak weak_alias +; CHECK: weak_alias = f1 +@weak_alias = alias weak_odr void()* @f1 + + +; CHECK: .section .drectve +; CHECK: /EXPORT:Var1,DATA +; CHECK: /EXPORT:Var2,DATA +; CHECK: /EXPORT:Var3,DATA +; CHECK: /EXPORT:WeakVar1,DATA +; CHECK: /EXPORT:WeakVar2,DATA +; CHECK: /EXPORT:f1 +; CHECK: /EXPORT:f2 +; CHECK: /EXPORT:lnk1 +; CHECK: /EXPORT:lnk2 +; CHECK: /EXPORT:weak1 +; CHECK: /EXPORT:alias +; CHECK: /EXPORT:alias2 +; CHECK: /EXPORT:weak_alias Index: test/CodeGen/X86/dllexport.ll =================================================================== --- test/CodeGen/X86/dllexport.ll +++ test/CodeGen/X86/dllexport.ll @@ -1,12 +1,103 @@ -; RUN: llc < %s | FileCheck %s -; PR2936 +; RUN: llc -mtriple i386-pc-win32 < %s | FileCheck %s -target triple = "i386-pc-mingw32" +; CHECK: .text -define dllexport x86_fastcallcc i32 @foo() nounwind { -entry: +; CHECK: .globl _f1 +define void @f1() dllexport { + ret void +} + +; CHECK: .globl _f2 +define void @f2() unnamed_addr dllexport { + ret void +} + +; CHECK: .globl _stdfun@0 +define x86_stdcallcc void @stdfun() nounwind dllexport { + ret void +} + +; CHECK: .globl @fastfun@0 +define x86_fastcallcc i32 @fastfun() nounwind dllexport { ret i32 0 } +; CHECK: .globl _thisfun +define x86_thiscallcc void @thisfun() nounwind dllexport { + ret void +} + +; CHECK: .section +; CHECK: .linkonce discard +; CHECK: .globl _lnk1 +define linkonce_odr void @lnk1() dllexport { + ret void +} + +; CHECK: .section +; CHECK: .linkonce discard +; CHECK: .globl _lnk2 +define linkonce_odr void @lnk2() alwaysinline dllexport { + ret void +} + +; CHECK: .section +; CHECK: .linkonce discard +; CHECK: .globl _weak1 +define weak_odr void @weak1() dllexport { + ret void +} + + +; CHECK: .data + +; CHECK: .globl _Var1 +@Var1 = global i32 1, align 4, dllexport + +; CHECK: .globl _Var2 +@Var2 = unnamed_addr constant i32 1, dllexport + +; CHECK: .comm _Var3 +@Var3 = common global i32 0, align 4, dllexport + +; CHECK: .section +; CHECK: .linkonce discard +; CHECK: .globl _WeakVar1 +@WeakVar1 = weak_odr global i32 1, align 4, dllexport + +; CHECK: .section +; CHECK: .linkonce discard +; CHECK: .globl _WeakVar2 +@WeakVar2 = weak_odr unnamed_addr constant i32 1, dllexport + + +; CHECK: .globl _alias +; CHECK: _alias = _f1 +@alias = alias void()* @f1 + +; CHECK: .globl _alias2 +; CHECK: alias2 = _alias +@alias2 = alias void()* @alias + +; CHECK: .weak _weak_alias +; CHECK: _weak_alias = _f1 +@weak_alias = alias weak_odr void()* @f1 + + ; CHECK: .section .drectve -; CHECK: -export:@foo@0 +; CHECK: /EXPORT:_Var1,DATA +; CHECK: /EXPORT:_Var2,DATA +; CHECK: /EXPORT:_Var3,DATA +; CHECK: /EXPORT:_WeakVar1,DATA +; CHECK: /EXPORT:_WeakVar2,DATA +; CHECK: /EXPORT:_f1 +; CHECK: /EXPORT:_f2 +; CHECK: /EXPORT:_stdfun@0 +; CHECK: /EXPORT:@fastfun@0 +; CHECK: /EXPORT:_thisfun +; CHECK: /EXPORT:_lnk1 +; CHECK: /EXPORT:_lnk2 +; CHECK: /EXPORT:_weak1 +; CHECK: /EXPORT:_alias +; CHECK: /EXPORT:_alias2 +; CHECK: /EXPORT:_weak_alias Index: test/CodeGen/X86/dllimport-x86_64.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/dllimport-x86_64.ll @@ -0,0 +1,54 @@ +; RUN: llc -mtriple x86_64-pc-win32 < %s | FileCheck %s +; RUN: llc -mtriple x86_64-pc-mingw32 < %s | FileCheck %s +; +; RUN: llc -mtriple x86_64-pc-mingw32 -O0 < %s | FileCheck %s -check-prefix=FAST +; PR6275 +; +; RUN: opt -mtriple x86_64-pc-win32 -std-compile-opts -S < %s | FileCheck %s -check-prefix=OPT + +@Var1 = external global i32, dllimport +@Var2 = available_externally unnamed_addr constant i32 1, dllimport + +declare void @fun() dllimport + +define available_externally void @inline1() dllimport { + ret void +} + +define available_externally void @inline2() alwaysinline dllimport { + ret void +} + +declare void @dummy(...) + +define void @use() nounwind { +; CHECK: callq *__imp_fun(%rip) +; FAST: movq __imp_fun(%rip), [[R:%[a-z]{3}]] +; FAST: callq *[[R]] + call void @fun() + +; CHECK: callq *__imp_inline1(%rip) +; CHECK: callq *__imp_inline2(%rip) + call void @inline1() + call void @inline2() + +; available_externally uses go away +; OPT-NOT: call void @inline1() +; OPT-NOT: call void @inline2() +; OPT-NOT: load i32* @Var2 +; OPT: call void (...)* @dummy(i32 %1, i32 1) + +; CHECK-DAG: movq __imp_Var1(%rip), [[R1:%[a-z]{3}]] +; CHECK-DAG: movq __imp_Var2(%rip), [[R2:%[a-z]{3}]] + %1 = load i32* @Var1 + %2 = load i32* @Var2 + call void(...)* @dummy(i32 %1, i32 %2) + + ret void +} + + +; CHECK: .globl _ZTC1C0_1B +; CHECK: .quad __imp__ZTI1B +@_ZTI1B = external constant i8*, dllimport +@_ZTC1C0_1B = constant [1 x i8**] [i8** @_ZTI1B] Index: test/CodeGen/X86/dllimport.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/dllimport.ll @@ -0,0 +1,65 @@ +; RUN: llc -mtriple i386-pc-win32 < %s | FileCheck %s +; RUN: llc -mtriple i386-pc-mingw32 < %s | FileCheck %s +; +; RUN: llc -mtriple i386-pc-mingw32 -O0 < %s | FileCheck %s -check-prefix=FAST +; PR6275 +; +; RUN: opt -mtriple i386-pc-win32 -std-compile-opts -S < %s | FileCheck %s -check-prefix=OPT + +@Var1 = external global i32, dllimport +@Var2 = available_externally unnamed_addr constant i32 1, dllimport + +declare void @fun() dllimport + +define available_externally void @inline1() dllimport { + ret void +} + +define available_externally void @inline2() alwaysinline dllimport { + ret void +} + +declare x86_stdcallcc void @stdfun() nounwind dllimport +declare x86_fastcallcc void @fastfun() nounwind dllimport +declare x86_thiscallcc void @thisfun() nounwind dllimport + +declare void @dummy(...) + +define void @use() nounwind { +; CHECK: calll *__imp__fun +; FAST: movl __imp__fun, [[R:%[a-z]{3}]] +; FAST: calll *[[R]] + call void @fun() + +; CHECK: calll *__imp__inline1 +; CHECK: calll *__imp__inline2 + call void @inline1() + call void @inline2() + +; CHECK: calll *__imp__stdfun@0 +; CHECK: calll *__imp_@fastfun@0 +; CHECK: calll *__imp__thisfun + call void @stdfun() + call void @fastfun() + call void @thisfun() + +; available_externally uses go away +; OPT-NOT: call void @inline1() +; OPT-NOT: call void @inline2() +; OPT-NOT: load i32* @Var2 +; OPT: call void (...)* @dummy(i32 %1, i32 1) + +; CHECK-DAG: movl __imp__Var1, [[R1:%[a-z]{3}]] +; CHECK-DAG: movl __imp__Var2, [[R2:%[a-z]{3}]] + %1 = load i32* @Var1 + %2 = load i32* @Var2 + call void(...)* @dummy(i32 %1, i32 %2) + + ret void +} + + +; CHECK: .globl __ZTC1C0_1B +; CHECK: .long __imp___ZTI1B +@_ZTI1B = external constant i8*, dllimport +@_ZTC1C0_1B = constant [1 x i8**] [i8** @_ZTI1B] Index: test/MC/COFF/linker-options.ll =================================================================== --- test/MC/COFF/linker-options.ll +++ test/MC/COFF/linker-options.ll @@ -9,7 +9,7 @@ !llvm.module.flags = !{ !0 } -define dllexport void @foo() { +define void @foo() dllexport { ret void }