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/X86Subtarget.cpp =================================================================== --- lib/Target/X86/X86Subtarget.cpp +++ lib/Target/X86/X86Subtarget.cpp @@ -78,7 +78,7 @@ // 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) + if (!GV->shouldAssumeDSOLocal()) return X86II::MO_GOTPCREL; } else if (!isTargetWin64()) { assert(isTargetELF() && "Unknown rip-relative target"); Index: test/CodeGen/X86/preemption.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/preemption.ll @@ -0,0 +1,172 @@ +; RUN: llc -mtriple x86_64-apple-darwin < %s | FileCheck %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 + +@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 + +@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 + + +@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 + +@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 + +@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 + + +@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 + +@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 + +@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 + + +; 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 + +@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 + + +@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 + +@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 + + +@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 + +@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 + + +; 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 + +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 + +declare void @external_default_function() +define void()* @get_external_default_function() { + ret void()* @external_default_function +} +; CHECK: movq _external_default_function@GOTPCREL(%rip), %rax + + +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 + +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 + +declare local void @external_local_function() +define void()* @get_external_local_function() { + ret void()* @external_local_function +} +; CHECK: leaq _external_local_function(%rip), %rax + + +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 + +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 + +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