Index: include/llvm/IR/GlobalValue.h =================================================================== --- include/llvm/IR/GlobalValue.h +++ include/llvm/IR/GlobalValue.h @@ -67,13 +67,7 @@ protected: GlobalValue(Type *Ty, ValueTy VTy, Use *Ops, unsigned NumOps, - LinkageTypes Linkage, const Twine &Name, unsigned AddressSpace) - : Constant(PointerType::get(Ty, AddressSpace), VTy, Ops, NumOps), - ValueType(Ty), Linkage(Linkage), Visibility(DefaultVisibility), - UnnamedAddr(0), DllStorageClass(DefaultStorageClass), - ThreadLocal(NotThreadLocal), IntID((Intrinsic::ID)0U), Parent(nullptr) { - setName(Name); - } + LinkageTypes Linkage, const Twine &Name, unsigned AddressSpace); Type *ValueType; // All bitfields use unsigned as the underlying type so that MSVC will pack @@ -85,7 +79,20 @@ unsigned ThreadLocal : 3; // Is this symbol "Thread Local", if so, what is // the desired model? - static const unsigned GlobalValueSubClassDataBits = 19; + + // Normally a definition can be preempted at runtime iff it can be preempted + // at static link time. That is not always the case. For example, in ELF weak + // symbols in the main binary cannot be preempted and regular symbols in + // shared libraries can. + // + // This bit is set when we want to mark the runtime preemption as being + // different from the link time one. + // + // FIXME: Merge dllimport into this. For COFF a dllimport is not assumed + // local, everything else is. + unsigned FlipDSOLocal : 1; + + static const unsigned GlobalValueSubClassDataBits = 18; private: // Give subclasses access to what otherwise would be wasted padding. @@ -153,6 +160,9 @@ unsigned getAlignment() const; + void setFlipDSOLocal(bool V); + bool shouldAssumeDSOLocal() const; + bool hasUnnamedAddr() const { return UnnamedAddr; } void setUnnamedAddr(bool Val) { UnnamedAddr = Val; } Index: lib/AsmParser/LLLexer.cpp =================================================================== --- lib/AsmParser/LLLexer.cpp +++ lib/AsmParser/LLLexer.cpp @@ -498,6 +498,9 @@ KEYWORD(declare); KEYWORD(define); KEYWORD(global); KEYWORD(constant); + KEYWORD(local); + KEYWORD(preemptable); + KEYWORD(private); KEYWORD(internal); KEYWORD(available_externally); Index: lib/AsmParser/LLParser.h =================================================================== --- lib/AsmParser/LLParser.h +++ lib/AsmParser/LLParser.h @@ -233,7 +233,9 @@ bool ParseOptionalParamAttrs(AttrBuilder &B); bool ParseOptionalReturnAttrs(AttrBuilder &B); bool ParseOptionalLinkage(unsigned &Linkage, bool &HasLinkage, - unsigned &Visibility, unsigned &DLLStorageClass); + unsigned &DSOLocation, unsigned &Visibility, + unsigned &DLLStorageClass); + void parseOptionalDSOLocation(unsigned &DSOLocation); void ParseOptionalVisibility(unsigned &Visibility); void ParseOptionalDLLStorageClass(unsigned &DLLStorageClass); bool ParseOptionalCallingConv(unsigned &CC); @@ -273,12 +275,12 @@ bool ParseUnnamedGlobal(); bool ParseNamedGlobal(); bool ParseGlobal(const std::string &Name, LocTy Loc, unsigned Linkage, - bool HasLinkage, unsigned Visibility, + bool HasLinkage, unsigned DSOLocation, unsigned Visibility, unsigned DLLStorageClass, GlobalVariable::ThreadLocalMode TLM, bool UnnamedAddr); bool parseIndirectSymbol(const std::string &Name, LocTy Loc, - unsigned Linkage, unsigned Visibility, - unsigned DLLStorageClass, + unsigned Linkage, unsigned DSOLocation, + unsigned Visibility, unsigned DLLStorageClass, GlobalVariable::ThreadLocalMode TLM, bool UnnamedAddr); bool parseComdat(); Index: lib/AsmParser/LLParser.cpp =================================================================== --- lib/AsmParser/LLParser.cpp +++ lib/AsmParser/LLParser.cpp @@ -451,18 +451,19 @@ } bool HasLinkage; - unsigned Linkage, Visibility, DLLStorageClass; + unsigned Linkage, DSOLocation, Visibility, DLLStorageClass; GlobalVariable::ThreadLocalMode TLM; bool UnnamedAddr; - if (ParseOptionalLinkage(Linkage, HasLinkage, Visibility, DLLStorageClass) || + if (ParseOptionalLinkage(Linkage, HasLinkage, DSOLocation, Visibility, + DLLStorageClass) || ParseOptionalThreadLocal(TLM) || parseOptionalUnnamedAddr(UnnamedAddr)) return true; if (Lex.getKind() != lltok::kw_alias && Lex.getKind() != lltok::kw_ifunc) - return ParseGlobal(Name, NameLoc, Linkage, HasLinkage, Visibility, - DLLStorageClass, TLM, UnnamedAddr); + return ParseGlobal(Name, NameLoc, Linkage, HasLinkage, DSOLocation, + Visibility, DLLStorageClass, TLM, UnnamedAddr); - return parseIndirectSymbol(Name, NameLoc, Linkage, Visibility, + return parseIndirectSymbol(Name, NameLoc, Linkage, DSOLocation, Visibility, DLLStorageClass, TLM, UnnamedAddr); } @@ -477,19 +478,20 @@ Lex.Lex(); bool HasLinkage; - unsigned Linkage, Visibility, DLLStorageClass; + unsigned Linkage, DSOLocation, Visibility, DLLStorageClass; GlobalVariable::ThreadLocalMode TLM; bool UnnamedAddr; if (ParseToken(lltok::equal, "expected '=' in global variable") || - ParseOptionalLinkage(Linkage, HasLinkage, Visibility, DLLStorageClass) || + ParseOptionalLinkage(Linkage, HasLinkage, DSOLocation, Visibility, + DLLStorageClass) || ParseOptionalThreadLocal(TLM) || parseOptionalUnnamedAddr(UnnamedAddr)) return true; if (Lex.getKind() != lltok::kw_alias && Lex.getKind() != lltok::kw_ifunc) - return ParseGlobal(Name, NameLoc, Linkage, HasLinkage, Visibility, - DLLStorageClass, TLM, UnnamedAddr); + return ParseGlobal(Name, NameLoc, Linkage, HasLinkage, DSOLocation, + Visibility, DLLStorageClass, TLM, UnnamedAddr); - return parseIndirectSymbol(Name, NameLoc, Linkage, Visibility, + return parseIndirectSymbol(Name, NameLoc, Linkage, DSOLocation, Visibility, DLLStorageClass, TLM, UnnamedAddr); } @@ -647,6 +649,33 @@ (GlobalValue::VisibilityTypes)V == GlobalValue::DefaultVisibility; } +enum DSOLocation { DSO_Default, DSO_Local, DSO_Preemptable }; + +void LLParser::parseOptionalDSOLocation(unsigned &DSOLocation) { + switch (Lex.getKind()) { + default: + DSOLocation = DSO_Default; + break; + case lltok::kw_local: + DSOLocation = DSO_Local; + break; + case lltok::kw_preemptable: + DSOLocation = DSO_Preemptable; + break; + } + if (DSOLocation != DSO_Default) + Lex.Lex(); +} + +static void setDSOLocation(GlobalValue &GV, unsigned int Location) { + if (Location == DSO_Default) + return; + bool StrongDef = GV.isStrongDefinitionForLinker(); + if ((StrongDef && Location == DSO_Preemptable) || + (!StrongDef && Location == DSO_Local)) + GV.setFlipDSOLocal(true); +} + /// parseIndirectSymbol: /// ::= GlobalVar '=' OptionalLinkage OptionalVisibility /// OptionalDLLStorageClass OptionalThreadLocal @@ -658,7 +687,8 @@ /// Everything through OptionalUnnamedAddr has already been parsed. /// bool LLParser::parseIndirectSymbol(const std::string &Name, LocTy NameLoc, - unsigned L, unsigned Visibility, + unsigned L, unsigned DSOLocation, + unsigned Visibility, unsigned DLLStorageClass, GlobalVariable::ThreadLocalMode TLM, bool UnnamedAddr) { @@ -753,6 +783,8 @@ GA->setDLLStorageClass((GlobalValue::DLLStorageClassTypes)DLLStorageClass); GA->setUnnamedAddr(UnnamedAddr); + setDSOLocation(*GA, DSOLocation); + if (Name.empty()) NumberedVals.push_back(GA.get()); @@ -795,7 +827,8 @@ /// bool LLParser::ParseGlobal(const std::string &Name, LocTy NameLoc, unsigned Linkage, bool HasLinkage, - unsigned Visibility, unsigned DLLStorageClass, + unsigned DSOLocation, unsigned Visibility, + unsigned DLLStorageClass, GlobalVariable::ThreadLocalMode TLM, bool UnnamedAddr) { if (!isValidVisibilityForLinkage(Visibility, Linkage)) @@ -876,6 +909,8 @@ GV->setThreadLocalMode(TLM); GV->setUnnamedAddr(UnnamedAddr); + setDSOLocation(*GV, DSOLocation); + // Parse attributes on the global. while (Lex.getKind() == lltok::comma) { Lex.Lex(); @@ -1530,13 +1565,18 @@ /// ::= 'extern_weak' /// ::= 'external' bool LLParser::ParseOptionalLinkage(unsigned &Res, bool &HasLinkage, - unsigned &Visibility, + unsigned &DSOLocation, unsigned &Visibility, unsigned &DLLStorageClass) { Res = parseOptionalLinkageAux(Lex.getKind(), HasLinkage); if (HasLinkage) Lex.Lex(); + parseOptionalDSOLocation(DSOLocation); ParseOptionalVisibility(Visibility); ParseOptionalDLLStorageClass(DLLStorageClass); + if (Visibility != GlobalValue::DefaultVisibility && + DSOLocation == DSO_Preemptable) + return Error(Lex.getLoc(), "foo"); + return false; } @@ -4474,7 +4514,7 @@ // Parse the linkage. LocTy LinkageLoc = Lex.getLoc(); unsigned Linkage; - + unsigned DSOLocation; unsigned Visibility; unsigned DLLStorageClass; AttrBuilder RetAttrs; @@ -4482,7 +4522,8 @@ bool HasLinkage; Type *RetType = nullptr; LocTy RetTypeLoc = Lex.getLoc(); - if (ParseOptionalLinkage(Linkage, HasLinkage, Visibility, DLLStorageClass) || + if (ParseOptionalLinkage(Linkage, HasLinkage, DSOLocation, Visibility, + DLLStorageClass) || ParseOptionalCallingConv(CC) || ParseOptionalReturnAttrs(RetAttrs) || ParseType(RetType, RetTypeLoc, true /*void allowed*/)) return true; @@ -4685,6 +4726,14 @@ ArgList[i].Name + "'"); } + if (DSOLocation != DSO_Default) { + bool StrongDef = isDefine && !Fn->hasAvailableExternallyLinkage() && + !Fn->isWeakForLinker(); + if ((StrongDef && DSOLocation == DSO_Preemptable) || + (!StrongDef && DSOLocation == DSO_Local)) + Fn->setFlipDSOLocal(true); + } + if (isDefine) return false; Index: lib/AsmParser/LLToken.h =================================================================== --- lib/AsmParser/LLToken.h +++ lib/AsmParser/LLToken.h @@ -45,6 +45,9 @@ kw_global, kw_constant, + kw_local, + kw_preemptable, + kw_private, kw_internal, kw_linkonce, Index: lib/IR/Globals.cpp =================================================================== --- lib/IR/Globals.cpp +++ lib/IR/Globals.cpp @@ -28,6 +28,32 @@ // GlobalValue Class //===----------------------------------------------------------------------===// +GlobalValue::GlobalValue(Type *Ty, ValueTy VTy, Use *Ops, unsigned NumOps, + LinkageTypes Linkage, const Twine &Name, + unsigned AddressSpace) + : Constant(PointerType::get(Ty, AddressSpace), VTy, Ops, NumOps), + ValueType(Ty), Linkage(Linkage), Visibility(DefaultVisibility), + UnnamedAddr(0), DllStorageClass(DefaultStorageClass), + ThreadLocal(NotThreadLocal), IntID((Intrinsic::ID)0U), Parent(nullptr) { + setName(Name); + FlipDSOLocal = false; +} + +void GlobalValue::setFlipDSOLocal(bool V) { FlipDSOLocal = V; } + +bool GlobalValue::shouldAssumeDSOLocal() const { + if (getVisibility() != DefaultVisibility) { + assert(!FlipDSOLocal); + return true; + } + + bool Default = isStrongDefinitionForLinker(); + + if (FlipDSOLocal) + return !Default; + return Default; +} + bool GlobalValue::isMaterializable() const { if (const Function *F = dyn_cast(this)) return F->isMaterializable(); Index: lib/Target/X86/X86ISelLowering.cpp =================================================================== --- lib/Target/X86/X86ISelLowering.cpp +++ lib/Target/X86/X86ISelLowering.cpp @@ -12688,8 +12688,9 @@ Result = DAG.getTargetGlobalAddress(GV, dl, PtrVT, 0, OpFlags); } - if (Subtarget.isPICStyleRIPRel() && - (M == CodeModel::Small || M == CodeModel::Kernel)) + if (OpFlags == X86II::MO_GOTPCREL || + (Subtarget.isPICStyleRIPRel() && + (M == CodeModel::Small || M == CodeModel::Kernel))) Result = DAG.getNode(X86ISD::WrapperRIP, dl, PtrVT, Result); else Result = DAG.getNode(X86ISD::Wrapper, dl, PtrVT, Result); Index: lib/Target/X86/X86InstrInfo.cpp =================================================================== --- lib/Target/X86/X86InstrInfo.cpp +++ lib/Target/X86/X86InstrInfo.cpp @@ -7347,8 +7347,6 @@ CGBR() : MachineFunctionPass(ID) {} bool runOnMachineFunction(MachineFunction &MF) override { - const X86TargetMachine *TM = - static_cast(&MF.getTarget()); const X86Subtarget &STI = MF.getSubtarget(); // Don't do anything if this is 64-bit as 64-bit PIC @@ -7356,10 +7354,6 @@ if (STI.is64Bit()) return false; - // Only emit a global base reg in PIC mode. - if (TM->getRelocationModel() != Reloc::PIC_) - return false; - X86MachineFunctionInfo *X86FI = MF.getInfo(); unsigned GlobalBaseReg = X86FI->getGlobalBaseReg(); @@ -7375,7 +7369,7 @@ const X86InstrInfo *TII = STI.getInstrInfo(); unsigned PC; - if (STI.isPICStyleGOT()) + if (STI.isTargetELF()) PC = RegInfo.createVirtualRegister(&X86::GR32RegClass); else PC = GlobalBaseReg; @@ -7386,7 +7380,7 @@ // If we're using vanilla 'GOT' PIC style, we should use relative addressing // not to pc, but to _GLOBAL_OFFSET_TABLE_ external. - if (STI.isPICStyleGOT()) { + if (STI.isTargetELF()) { // Generate addl $__GLOBAL_OFFSET_TABLE_ + [.-piclabel], %some_register BuildMI(FirstMBB, MBBI, DL, TII->get(X86::ADD32ri), GlobalBaseReg) .addReg(PC).addExternalSymbol("_GLOBAL_OFFSET_TABLE_", Index: lib/Target/X86/X86Subtarget.cpp =================================================================== --- lib/Target/X86/X86Subtarget.cpp +++ lib/Target/X86/X86Subtarget.cpp @@ -61,94 +61,53 @@ /// how we should reference it in a non-pcrel context. unsigned char X86Subtarget:: 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->hasDLLImportStorageClass()) - return X86II::MO_DLLIMPORT; - - bool isDef = GV->isStrongDefinitionForLinker(); + // Large model never uses stubs. + if (TM.getCodeModel() == CodeModel::Large) + return X86II::MO_NO_FLAG; - // X86-64 in PIC mode. - if (isPICStyleRIPRel()) { - // Large model never uses stubs. - if (TM.getCodeModel() == CodeModel::Large) + if (GV->shouldAssumeDSOLocal()) { + // 64 bits can use %rip addressing for anything local. + if (is64Bit()) return X86II::MO_NO_FLAG; - if (isTargetDarwin()) { - // If symbol visibility is hidden, the extra load is not needed if - // target is x86-64 or the symbol is definitely defined in the current - // translation unit. - if (GV->hasDefaultVisibility() && !isDef) - return X86II::MO_GOTPCREL; - } else if (!isTargetWin64()) { - assert(isTargetELF() && "Unknown rip-relative target"); - - // Extra load is needed for all externally visible globals except with - // PIE as the definition of the global in an executable is not - // overridden. - - if (!GV->hasLocalLinkage() && GV->hasDefaultVisibility() && - !isGlobalDefinedInPIE(GV, TM)) - return X86II::MO_GOTPCREL; - } - - return X86II::MO_NO_FLAG; - } - - if (isPICStyleGOT()) { // 32-bit ELF targets. - // Extra load is needed for all externally visible globals except with - // PIE as the definition of the global in an executable is not overridden. + // If this is for a position dependent executable, the static linker can + // figure it out. + if (TM.getRelocationModel() == Reloc::Static || + TM.getRelocationModel() == Reloc::DynamicNoPIC) + return X86II::MO_NO_FLAG; - if (GV->hasLocalLinkage() || GV->hasHiddenVisibility() || - isGlobalDefinedInPIE(GV, TM)) - return X86II::MO_GOTOFF; - return X86II::MO_GOT; - } + // The COFF dynamic linker just patches the executable sections. + if (isTargetCOFF()) + return X86II::MO_NO_FLAG; - if (isPICStyleStubPIC()) { // Darwin/32 in PIC mode. - // Determine whether we have a stub reference and/or whether the reference - // is relative to the PIC base or not. + if (isTargetDarwin()) { + // 32 bit macho has no relocation for a-b if a is undefined, even if + // b is in the same section that is being relocated. + // This means we have to use o load even for GVs that are known to be + // local to the dso. + if (GV->isDeclarationForLinker() || GV->hasCommonLinkage()) + return X86II::MO_DARWIN_NONLAZY_PIC_BASE; - // If this is a strong reference to a definition, it is definitely not - // through a stub. - if (isDef) return X86II::MO_PIC_BASE_OFFSET; - - // Unless we have a symbol with hidden visibility, we have to go through a - // normal $non_lazy_ptr stub because this symbol might be resolved late. - if (!GV->hasHiddenVisibility()) // $non_lazy_ptr reference. - return X86II::MO_DARWIN_NONLAZY_PIC_BASE; - - // If symbol visibility is hidden, we have a stub for common symbol - // references and external declarations. - if (GV->isDeclarationForLinker() || GV->hasCommonLinkage()) { - // $non_lazy_ptr reference. - return X86II::MO_DARWIN_NONLAZY_PIC_BASE; } - // Otherwise, no stub. - return X86II::MO_PIC_BASE_OFFSET; + return X86II::MO_GOTOFF; } - if (isPICStyleStubNoDynamic()) { // Darwin/32 in -mdynamic-no-pic mode. - // Determine whether we have a stub reference. + if (isTargetCOFF()) + return X86II::MO_DLLIMPORT; - // If this is a strong reference to a definition, it is definitely not - // through a stub. - if (isDef) - return X86II::MO_NO_FLAG; + if (is64Bit()) + return X86II::MO_GOTPCREL; - // Unless we have a symbol with hidden visibility, we have to go through a - // normal $non_lazy_ptr stub because this symbol might be resolved late. - if (!GV->hasHiddenVisibility()) // Non-hidden $non_lazy_ptr reference. + if (isTargetDarwin()) { + if (TM.getRelocationModel() == Reloc::Static || + TM.getRelocationModel() == Reloc::DynamicNoPIC) return X86II::MO_DARWIN_NONLAZY; - - // Otherwise, no stub. - return X86II::MO_NO_FLAG; + return X86II::MO_DARWIN_NONLAZY_PIC_BASE; } - // Direct static reference to global. - return X86II::MO_NO_FLAG; + return X86II::MO_GOT; } unsigned char X86Subtarget::classifyGlobalFunctionReference( Index: test/CodeGen/X86/preemption.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/preemption.ll @@ -0,0 +1,422 @@ +; RUN: llc -mtriple x86_64-apple-darwin \ +; RUN: -relocation-model=default < %s | FileCheck %s +; RUN: llc -mtriple x86_64-apple-darwin \ +; RUN: -relocation-model=static < %s | FileCheck %s +; RUN: llc -mtriple x86_64-apple-darwin \ +; RUN: -relocation-model=pic < %s | FileCheck %s +; RUN: llc -mtriple x86_64-apple-darwin \ +; RUN: -relocation-model=dynamic-no-pic < %s | FileCheck %s + +; RUN: llc -mtriple x86_64-pc-linux \ +; RUN: -relocation-model=default < %s | FileCheck --check-prefix=STATIC %s +; RUN: llc -mtriple x86_64-pc-linux \ +; RUN: -relocation-model=static < %s | FileCheck --check-prefix=STATIC %s +; RUN: llc -mtriple x86_64-pc-linux \ +; RUN: -relocation-model=pic < %s | FileCheck %s +; RUN: llc -mtriple x86_64-pc-linux \ +; RUN: -relocation-model=dynamic-no-pic < %s | FileCheck %s + +; RUN: llc -mtriple x86_64-pc-win32 \ +; RUN: -relocation-model=default < %s | FileCheck --check-prefix=COFF %s +; RUN: llc -mtriple x86_64-pc-win32 \ +; RUN: -relocation-model=static < %s | FileCheck --check-prefix=COFF_S %s +; RUN: llc -mtriple x86_64-pc-win32 \ +; RUN: -relocation-model=pic < %s | FileCheck --check-prefix=COFF %s +; RUN: llc -mtriple x86_64-pc-win32 \ +; RUN: -relocation-model=dynamic-no-pic < %s | FileCheck --check-prefix=COFF %s + + +; 32 bits + +; RUN: llc -mtriple i386-apple-darwin \ +; RUN: -relocation-model=default < %s | FileCheck --check-prefix=DARWIN32_S %s +; RUN: llc -mtriple i386-apple-darwin \ +; RUN: -relocation-model=static < %s | FileCheck --check-prefix=DARWIN32_S %s +; RUN: llc -mtriple i386-apple-darwin \ +; RUN: -relocation-model=pic < %s | FileCheck --check-prefix=DARWIN32 %s +; RUN: llc -mtriple i386-apple-darwin \ +; RUN: -relocation-model=dynamic-no-pic < %s | \ +; RUN: FileCheck --check-prefix=DARWIN32_S %s + +; RUN: llc -mtriple i386-pc-linux \ +; RUN: -relocation-model=default < %s | FileCheck --check-prefix=STATIC32 %s +; RUN: llc -mtriple i386-pc-linux \ +; RUN: -relocation-model=static < %s | FileCheck --check-prefix=STATIC32 %s +; RUN: llc -mtriple i386-pc-linux \ +; RUN: -relocation-model=pic < %s | FileCheck --check-prefix=CHECK32 %s +; RUN: llc -mtriple i386-pc-linux \ +; RUN: -relocation-model=dynamic-no-pic < %s | \ +; RUN: FileCheck --check-prefix=STATIC32 %s + +; RUN: llc -mtriple i386-pc-win32 \ +; RUN: -relocation-model=default < %s | FileCheck --check-prefix=COFF32 %s +; RUN: llc -mtriple i386-pc-win32 \ +; RUN: -relocation-model=static < %s | FileCheck --check-prefix=COFF32 %s +; RUN: llc -mtriple i386-pc-win32 \ +; RUN: -relocation-model=pic < %s | FileCheck --check-prefix=COFF32 %s +; RUN: llc -mtriple i386-pc-win32 \ +; RUN: -relocation-model=dynamic-no-pic < %s | \ +; RUN: FileCheck --check-prefix=COFF32 %s + +; globals + +@strong_default_global = global i32 42 +define i32* @get_strong_default_global() { + ret i32* @strong_default_global +} +; CHECK: leaq {{_?}}strong_default_global(%rip), %rax +; STATIC: movl ${{_?}}strong_default_global, %eax +; COFF: leaq {{_?}}strong_default_global(%rip), %rax +; COFF_S: movl $strong_default_global, %eax +; CHECK32: leal {{_?}}strong_default_global@GOTOFF(%eax), %eax +; STATIC32: movl ${{_?}}strong_default_global, %eax +; COFF32: movl ${{_?}}strong_default_global, %eax +; DARWIN32: leal {{_?}}strong_default_global-L{{.*}}$pb(%eax), %eax +; DARWIN32_S: movl ${{_?}}strong_default_global, %eax + +@weak_default_global = weak global i32 42 +define i32* @get_weak_default_global() { + ret i32* @weak_default_global +} +; CHECK: movq {{_?}}weak_default_global@GOTPCREL(%rip), %rax +; STATIC: movq {{_?}}weak_default_global@GOTPCREL(%rip), %rax +; COFF: movq __imp_weak_default_global(%rip), %rax +; COFF_S: movq __imp_weak_default_global, %rax +; CHECK32: movl {{_?}}weak_default_global@GOT(%eax), %eax +; STATIC32: movl {{_?}}weak_default_global@GOT(%eax), %eax +; COFF32: movl __imp__weak_default_global, %eax +; DARWIN32: movl L_weak_default_global$non_lazy_ptr-L{{.*}}$pb(%eax), %eax +; DARWIN32_S: movl L_weak_default_global$non_lazy_ptr, %eax + +@external_default_global = external global i32 +define i32* @get_external_default_global() { + ret i32* @external_default_global +} +; CHECK: movq {{_?}}external_default_global@GOTPCREL(%rip), %rax +; STATIC: movq {{_?}}external_default_global@GOTPCREL(%rip), %rax +; COFF: movq __imp_external_default_global(%rip), %rax +; COFF_S: movq __imp_external_default_global, %rax +; CHECK32: movl {{_?}}external_default_global@GOT(%eax), %eax +; STATIC32: movl {{_?}}external_default_global@GOT(%eax), %eax +; COFF32: movl __imp__external_default_global, %eax +; DARWIN32: movl L_external_default_global$non_lazy_ptr-L{{.*}}$pb(%eax), %eax +; DARWIN32_S: movl L_external_default_global$non_lazy_ptr, %eax + + +@strong_local_global = local global i32 42 +define i32* @get_strong_local_global() { + ret i32* @strong_local_global +} +; CHECK: leaq {{_?}}strong_local_global(%rip), %rax +; STATIC: movl ${{_?}}strong_local_global, %eax +; COFF: leaq {{_?}}strong_local_global(%rip), %rax +; COFF_S: movl ${{_?}}strong_local_global, %eax +; CHECK32: leal {{_?}}strong_local_global@GOTOFF(%eax), %eax +; STATIC32: movl ${{_?}}strong_local_global, %eax +; COFF32: movl ${{_?}}strong_local_global, %eax +; DARWIN32: leal _strong_local_global-L{{.*}}$pb(%eax), %eax +; DARWIN32_S: movl ${{_?}}strong_local_global, %eax + +@weak_local_global = weak local global i32 42 +define i32* @get_weak_local_global() { + ret i32* @weak_local_global +} +; CHECK: leaq {{_?}}weak_local_global(%rip), %rax +; STATIC: movl ${{_?}}weak_local_global, %eax +; COFF: leaq {{_?}}weak_local_global(%rip), %rax +; COFF_S: movl ${{_?}}weak_local_global, %eax +; CHECK32: leal {{_?}}weak_local_global@GOTOFF(%eax), %eax +; STATIC32: movl ${{_?}}weak_local_global, %eax +; COFF32: movl ${{_?}}weak_local_global, %eax +; DARWIN32: leal _weak_local_global-L{{.}}$pb(%eax), %eax +; DARWIN32_S: movl ${{_?}}weak_local_global, %eax + +@external_local_global = external local global i32 +define i32* @get_external_local_global() { + ret i32* @external_local_global +} +; CHECK: leaq {{_?}}external_local_global(%rip), %rax +; STATIC: movl ${{_?}}external_local_global, %eax +; COFF: leaq {{_?}}external_local_global(%rip), %rax +; COFF_S: movl ${{_?}}external_local_global, %eax +; CHECK32: leal {{_?}}external_local_global@GOTOFF(%eax), %eax +; STATIC32: movl ${{_?}}external_local_global, %eax +; COFF32: movl ${{_?}}external_local_global, %eax +; DARWIN32: movl L_external_local_global$non_lazy_ptr-L{{.*}}$pb(%eax), %eax +; DARWIN32_S: movl ${{_?}}external_local_global, %eax + + +@strong_preemptable_global = preemptable global i32 42 +define i32* @get_strong_preemptable_global() { + ret i32* @strong_preemptable_global +} +; CHECK: movq {{_?}}strong_preemptable_global@GOTPCREL(%rip), %rax +; STATIC: movq {{_?}}strong_preemptable_global@GOTPCREL(%rip), %rax +; COFF: movq __imp_strong_preemptable_global(%rip), %rax +; COFF_S: movq __imp_strong_preemptable_global, %rax +; CHECK32: movl {{_?}}strong_preemptable_global@GOT(%eax), %eax +; STATIC32: movl {{_?}}strong_preemptable_global@GOT(%eax), %eax +; COFF32: movl __imp__strong_preemptable_global, %eax +; DARWIN32: movl L_strong_preemptable_global$non_lazy_ptr-L{{.*}}$pb(%eax), %eax +; DARWIN32_S: movl L_strong_preemptable_global$non_lazy_ptr, %eax + +@weak_preemptable_global = weak preemptable global i32 42 +define i32* @get_weak_preemptable_global() { + ret i32* @weak_preemptable_global +} +; CHECK: movq {{_?}}weak_preemptable_global@GOTPCREL(%rip), %rax +; STATIC: movq {{_?}}weak_preemptable_global@GOTPCREL(%rip), %rax +; COFF: movq __imp_weak_preemptable_global(%rip), %rax +; COFF_S: movq __imp_weak_preemptable_global, %rax +; CHECK32: movl {{_?}}weak_preemptable_global@GOT(%eax), %eax +; STATIC32: movl {{_?}}weak_preemptable_global@GOT(%eax), %eax +; COFF32: movl __imp__weak_preemptable_global, %eax +; DARWIN32: movl L_weak_preemptable_global$non_lazy_ptr-L{{.*}}$pb(%eax), %eax +; DARWIN32_S: movl L_weak_preemptable_global$non_lazy_ptr, %eax + +@external_preemptable_global = external preemptable global i32 +define i32* @get_external_preemptable_global() { + ret i32* @external_preemptable_global +} +; CHECK: movq {{_?}}external_preemptable_global@GOTPCREL(%rip), %rax +; STATIC: movq {{_?}}external_preemptable_global@GOTPCREL(%rip), %rax +; COFF: movq __imp_external_preemptable_global(%rip), %rax +; COFF_S: movq __imp_external_preemptable_global, %rax +; CHECK32: movl {{_?}}external_preemptable_global@GOT(%eax), %eax +; STATIC32: movl {{_?}}external_preemptable_global@GOT(%eax), %eax +; COFF32: movl __imp__external_preemptable_global, %eax +; DARWIN32: movl L_external_preemptable_global$non_lazy_ptr-L{{.*}}$pb(%eax), %eax +; DARWIN32_S: movl L_external_preemptable_global$non_lazy_ptr, %eax + + +; aliases +@aliasee = global i32 42 + +@strong_default_alias = alias i32, i32* @aliasee +define i32* @get_strong_default_alias() { + ret i32* @strong_default_alias +} +; CHECK: leaq {{_?}}strong_default_alias(%rip), %rax +; STATIC: movl ${{_?}}strong_default_alias, %eax +; COFF: leaq {{_?}}strong_default_alias(%rip), %rax +; COFF_S: movl ${{_?}}strong_default_alias, %eax +; CHECK32: leal {{_?}}strong_default_alias@GOTOFF(%eax), %eax +; STATIC32: movl ${{_?}}strong_default_alias, %eax +; COFF32: movl ${{_?}}strong_default_alias, %eax +; DARWIN32: leal _strong_default_alias-L{{.*}}$pb(%eax), %eax +; DARWIN32_S: movl ${{_?}}strong_default_alias, %eax + +@weak_default_alias = weak alias i32, i32* @aliasee +define i32* @get_weak_default_alias() { + ret i32* @weak_default_alias +} +; CHECK: movq {{_?}}weak_default_alias@GOTPCREL(%rip), %rax +; STATIC: movq {{_?}}weak_default_alias@GOTPCREL(%rip), %rax +; COFF: movq __imp_weak_default_alias(%rip), %rax +; COFF_S: movq __imp_weak_default_alias, %rax +; CHECK32: movl {{_?}}weak_default_alias@GOT(%eax), %eax +; STATIC32: movl {{_?}}weak_default_alias@GOT(%eax), %eax +; COFF32: movl __imp__weak_default_alias, %eax +; DARWIN32: movl L_weak_default_alias$non_lazy_ptr-L{{.*}}$pb(%eax), %eax +; DARWIN32_S: movl L_weak_default_alias$non_lazy_ptr, %eax + + +@strong_local_alias = local alias i32, i32* @aliasee +define i32* @get_strong_local_alias() { + ret i32* @strong_local_alias +} +; CHECK: leaq {{_?}}strong_local_alias(%rip), %rax +; STATIC: movl ${{_?}}strong_local_alias, %eax +; COFF: leaq {{_?}}strong_local_alias(%rip), %rax +; COFF_S: movl ${{_?}}strong_local_alias, %eax +; CHECK32: leal {{_?}}strong_local_alias@GOTOFF(%eax), %eax +; STATIC32: movl ${{_?}}strong_local_alias, %eax +; COFF32: movl ${{_?}}strong_local_alias, %eax +; DARWIN32: leal _strong_local_alias-L{{.*}}$pb(%eax), %eax +; DARWIN32_S: movl ${{_?}}strong_local_alias, %eax + +@weak_local_alias = weak local alias i32, i32* @aliasee +define i32* @get_weak_local_alias() { + ret i32* @weak_local_alias +} +; CHECK: leaq {{_?}}weak_local_alias(%rip), %rax +; STATIC: movl ${{_?}}weak_local_alias, %eax +; COFF: leaq {{_?}}weak_local_alias(%rip), %rax +; COFF_S: movl ${{_?}}weak_local_alias, %eax +; CHECK32: leal {{_?}}weak_local_alias@GOTOFF(%eax), %eax +; STATIC32: movl ${{_?}}weak_local_alias, %eax +; COFF32: movl ${{_?}}weak_local_alias, %eax +; DARWIN32: leal _weak_local_alias-L{{.*}}$pb(%eax), %eax +; DARWIN32_S: movl ${{_?}}weak_local_alias, %eax + + +@strong_preemptable_alias = preemptable alias i32, i32* @aliasee +define i32* @get_strong_preemptable_alias() { + ret i32* @strong_preemptable_alias +} +; CHECK: movq {{_?}}strong_preemptable_alias@GOTPCREL(%rip), %rax +; STATIC: movq {{_?}}strong_preemptable_alias@GOTPCREL(%rip), %rax +; COFF: movq __imp_strong_preemptable_alias(%rip), %rax +; COFF_S: movq __imp_strong_preemptable_alias, %rax +; CHECK32: movl {{_?}}strong_preemptable_alias@GOT(%eax), %eax +; STATIC32: movl {{_?}}strong_preemptable_alias@GOT(%eax), %eax +; COFF32: movl __imp__strong_preemptable_alias, %eax +; DARWIN32: movl L_strong_preemptable_alias$non_lazy_ptr-L{{.*}}$pb(%eax), %eax +; DARWIN32_S: movl L_strong_preemptable_alias$non_lazy_ptr, %eax + +@weak_preemptable_alias = weak preemptable alias i32, i32* @aliasee +define i32* @get_weak_preemptable_alias() { + ret i32* @weak_preemptable_alias +} +; CHECK: movq {{_?}}weak_preemptable_alias@GOTPCREL(%rip), %rax +; STATIC: movq {{_?}}weak_preemptable_alias@GOTPCREL(%rip), %rax +; COFF: movq __imp_weak_preemptable_alias(%rip), %rax +; COFF_S: movq __imp_weak_preemptable_alias, %rax +; CHECK32: movl {{_?}}weak_preemptable_alias@GOT(%eax), %eax +; STATIC32: movl {{_?}}weak_preemptable_alias@GOT(%eax), %eax +; COFF32: movl __imp__weak_preemptable_alias, %eax +; DARWIN32: movl L_weak_preemptable_alias$non_lazy_ptr-L{{.*}}$pb(%eax), %eax +; DARWIN32_S: movl L_weak_preemptable_alias$non_lazy_ptr, %eax + + +; functions + +define void @strong_default_function() { + ret void +} +define void()* @get_strong_default_function() { + ret void()* @strong_default_function +} +; CHECK: leaq {{_?}}strong_default_function(%rip), %rax +; STATIC: movl ${{_?}}strong_default_function, %eax +; COFF: leaq {{_?}}strong_default_function(%rip), %rax +; COFF_S: movl ${{_?}}strong_default_function, %eax +; CHECK32: leal {{_?}}strong_default_function@GOTOFF(%eax), %eax +; STATIC32: movl ${{_?}}strong_default_function, %eax +; COFF32: movl ${{_?}}strong_default_function, %eax +; DARWIN32: leal _strong_default_function-L{{.*}}$pb(%eax), %eax +; DARWIN32_S: movl ${{_?}}strong_default_function, %eax + +define weak void @weak_default_function() { + ret void +} +define void()* @get_weak_default_function() { + ret void()* @weak_default_function +} +; CHECK: movq {{_?}}weak_default_function@GOTPCREL(%rip), %rax +; STATIC: movq {{_?}}weak_default_function@GOTPCREL(%rip), %rax +; COFF: movq __imp_weak_default_function(%rip), %rax +; COFF_S: movq __imp_weak_default_function, %rax +; CHECK32: movl {{_?}}weak_default_function@GOT(%eax), %eax +; STATIC32: movl {{_?}}weak_default_function@GOT(%eax), %eax +; COFF32: movl __imp__weak_default_function, %eax +; DARWIN32: movl L_weak_default_function$non_lazy_ptr-L{{.*}}$pb(%eax), %eax +; DARWIN32_S: movl L_weak_default_function$non_lazy_ptr, %eax + +declare void @external_default_function() +define void()* @get_external_default_function() { + ret void()* @external_default_function +} +; CHECK: movq {{_?}}external_default_function@GOTPCREL(%rip), %rax +; STATIC: movq {{_?}}external_default_function@GOTPCREL(%rip), %rax +; COFF: __imp_external_default_function(%rip), %rax +; COFF_S: __imp_external_default_function, %rax +; CHECK32: movl {{_?}}external_default_function@GOT(%eax), %eax +; STATIC32: movl {{_?}}external_default_function@GOT(%eax), %eax +; COFF32: __imp__external_default_function, %eax +; DARWIN32: movl L_external_default_function$non_lazy_ptr-L{{.*}}$pb(%eax), %eax +; DARWIN32_S: movl L_external_default_function$non_lazy_ptr, %eax + + +define local void @strong_local_function() { + ret void +} +define void()* @get_strong_local_function() { + ret void()* @strong_local_function +} +; CHECK: leaq {{_?}}strong_local_function(%rip), %rax +; STATIC: movl ${{_?}}strong_local_function, %eax +; COFF: leaq {{_?}}strong_local_function(%rip), %rax +; COFF_S: movl ${{_?}}strong_local_function, %eax +; CHECK32: leal {{_?}}strong_local_function@GOTOFF(%eax), %eax +; STATIC32: movl ${{_?}}strong_local_function, %eax +; COFF32: movl ${{_?}}strong_local_function, %eax +; DARWIN32: leal _strong_local_function-L{{.*}}$pb(%eax), %eax +; DARWIN32_S: movl ${{_?}}strong_local_function, %eax + +define weak local void @weak_local_function() { + ret void +} +define void()* @get_weak_local_function() { + ret void()* @weak_local_function +} +; CHECK: leaq {{_?}}weak_local_function(%rip), %rax +; STATIC: movl ${{_?}}weak_local_function, %eax +; COFF: leaq {{_?}}weak_local_function(%rip), %rax +; COFF_S: movl ${{_?}}weak_local_function, %eax +; CHECK32: leal {{_?}}weak_local_function@GOTOFF(%eax), %eax +; STATIC32: movl ${{_?}}weak_local_function, %eax +; COFF32: movl $_weak_local_function, %eax +; DARWIN32: leal _weak_local_function-L{{.*}}$pb(%eax), %eax +; DARWIN32_S: movl ${{_?}}weak_local_function, %eax + +declare local void @external_local_function() +define void()* @get_external_local_function() { + ret void()* @external_local_function +} +; CHECK: leaq {{_?}}external_local_function(%rip), %rax +; STATIC: movl ${{_?}}external_local_function, %eax +; COFF: leaq {{_?}}external_local_function(%rip), %rax +; COFF_S: movl ${{_?}}external_local_function, %eax +; CHECK32: leal {{_?}}external_local_function@GOTOFF(%eax), %eax +; STATIC32: movl ${{_?}}external_local_function, %eax +; COFF32: movl ${{_?}}external_local_function, %eax +; DARWIN32: movl L_external_local_function$non_lazy_ptr-L{{.*}}$pb(%eax), %eax +; DARWIN32_S: movl ${{_?}}external_local_function, %eax + + +define preemptable void @strong_preemptable_function() { + ret void +} +define void()* @get_strong_preemptable_function() { + ret void()* @strong_preemptable_function +} +; CHECK: movq {{_?}}strong_preemptable_function@GOTPCREL(%rip), %rax +; STATIC: movq {{_?}}strong_preemptable_function@GOTPCREL(%rip), %rax +; COFF: __imp_strong_preemptable_function(%rip), %rax +; COFF_S: __imp_strong_preemptable_function, %rax +; CHECK32: movl {{_?}}strong_preemptable_function@GOT(%eax), %eax +; STATIC32: movl {{_?}}strong_preemptable_function@GOT(%eax), %eax +; COFF32: __imp__strong_preemptable_function, %eax +; DARWIN32: movl L_strong_preemptable_function$non_lazy_ptr-L{{.*}}$pb(%eax), %eax +; DARWIN32_S: movl L_strong_preemptable_function$non_lazy_ptr, %eax + +define weak preemptable void @weak_preemptable_function() { + ret void +} +define void()* @get_weak_preemptable_function() { + ret void()* @weak_preemptable_function +} +; CHECK: movq {{_?}}weak_preemptable_function@GOTPCREL(%rip), %rax +; STATIC: movq {{_?}}weak_preemptable_function@GOTPCREL(%rip), %rax +; COFF: movq __imp_weak_preemptable_function(%rip), %rax +; COFF_S: movq __imp_weak_preemptable_function, %rax +; CHECK32: movl {{_?}}weak_preemptable_function@GOT(%eax), %eax +; STATIC32: movl {{_?}}weak_preemptable_function@GOT(%eax), %eax +; COFF32: movl __imp__weak_preemptable_function, %eax +; DARWIN32: movl L_weak_preemptable_function$non_lazy_ptr-L{{.*}}$pb(%eax), %eax +; DARWIN32_S: movl L_weak_preemptable_function$non_lazy_ptr, %eax + +declare preemptable void @external_preemptable_function() +define void()* @get_external_preemptable_function() { + ret void()* @external_preemptable_function +} +; CHECK: movq {{_?}}external_preemptable_function@GOTPCREL(%rip), %rax +; STATIC: movq {{_?}}external_preemptable_function@GOTPCREL(%rip), %rax +; COFF: movq __imp_external_preemptable_function(%rip), %rax +; COFF_S: movq __imp_external_preemptable_function, %rax +; CHECK32: movl {{_?}}external_preemptable_function@GOT(%eax), %eax +; STATIC32: movl {{_?}}external_preemptable_function@GOT(%eax), %eax +; COFF32: movl __imp__external_preemptable_function, %eax +; DARWIN32: movl L_external_preemptable_function$non_lazy_ptr-L{{.*}}$pb(%eax), %eax +; DARWIN32_S: movl L_external_preemptable_function$non_lazy_ptr, %eax