Index: include/llvm/IR/GlobalValue.h =================================================================== --- include/llvm/IR/GlobalValue.h +++ include/llvm/IR/GlobalValue.h @@ -73,6 +73,12 @@ DLLExportStorageClass = 2 ///< Function to be accessible from DLL. }; + enum DSO_Location { + DSO_Default = 0, + DSO_Local, + DSO_Preemptable + }; + protected: GlobalValue(Type *Ty, ValueTy VTy, Use *Ops, unsigned NumOps, LinkageTypes Linkage, const Twine &Name, unsigned AddressSpace) @@ -80,13 +86,13 @@ ValueType(Ty), Linkage(Linkage), Visibility(DefaultVisibility), UnnamedAddrVal(unsigned(UnnamedAddr::None)), DllStorageClass(DefaultStorageClass), ThreadLocal(NotThreadLocal), - HasLLVMReservedName(false), IntID((Intrinsic::ID)0U), Parent(nullptr) { + HasLLVMReservedName(false), DSOLocation(DSO_Default), IntID((Intrinsic::ID)0U), Parent(nullptr) { setName(Name); } Type *ValueType; - static const unsigned GlobalValueSubClassDataBits = 18; + static const unsigned GlobalValueSubClassDataBits = 16; // All bitfields use unsigned as the underlying type so that MSVC will pack // them. @@ -103,11 +109,13 @@ /// Function::intrinsicID() returns Intrinsic::not_intrinsic. unsigned HasLLVMReservedName : 1; + unsigned DSOLocation : 2; + private: friend class Constant; // Give subclasses access to what otherwise would be wasted padding. - // (18 + 4 + 2 + 2 + 2 + 3 + 1) == 32. + // (16 + 4 + 2 + 2 + 2 + 3 + 1 + 2) == 32. unsigned SubClassData : GlobalValueSubClassDataBits; void destroyConstantImpl(); @@ -261,6 +269,16 @@ Type *getValueType() const { return ValueType; } + void setDSOLocation(DSO_Location Location) { DSOLocation = Location; } + + bool hasExplicitDSOLocation() const { + return DSOLocation != DSO_Default; + } + + DSO_Location getDSOLocation(void) const { + return DSO_Location(DSOLocation); + } + static LinkageTypes getLinkOnceLinkage(bool ODR) { return ODR ? LinkOnceODRLinkage : LinkOnceAnyLinkage; } @@ -277,6 +295,7 @@ static bool isLinkOnceODRLinkage(LinkageTypes Linkage) { return Linkage == LinkOnceODRLinkage; } + static bool isLinkOnceLinkage(LinkageTypes Linkage) { return Linkage == LinkOnceAnyLinkage || Linkage == LinkOnceODRLinkage; } Index: lib/AsmParser/LLLexer.cpp =================================================================== --- lib/AsmParser/LLLexer.cpp +++ lib/AsmParser/LLLexer.cpp @@ -494,6 +494,9 @@ KEYWORD(declare); KEYWORD(define); KEYWORD(global); KEYWORD(constant); + KEYWORD(dso_local); + KEYWORD(dso_preemptable); + KEYWORD(private); KEYWORD(internal); KEYWORD(available_externally); Index: lib/AsmParser/LLParser.h =================================================================== --- lib/AsmParser/LLParser.h +++ lib/AsmParser/LLParser.h @@ -235,7 +235,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); @@ -277,13 +279,13 @@ 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, GlobalVariable::UnnamedAddr 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, GlobalVariable::UnnamedAddr UnnamedAddr); bool parseComdat(); Index: lib/AsmParser/LLParser.cpp =================================================================== --- lib/AsmParser/LLParser.cpp +++ lib/AsmParser/LLParser.cpp @@ -503,18 +503,19 @@ } bool HasLinkage; - unsigned Linkage, Visibility, DLLStorageClass; + unsigned Linkage, DSOLocation, Visibility, DLLStorageClass; GlobalVariable::ThreadLocalMode TLM; GlobalVariable::UnnamedAddr 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); } @@ -529,19 +530,20 @@ Lex.Lex(); bool HasLinkage; - unsigned Linkage, Visibility, DLLStorageClass; + unsigned Linkage, DSOLocation, Visibility, DLLStorageClass; GlobalVariable::ThreadLocalMode TLM; GlobalVariable::UnnamedAddr 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); } @@ -709,10 +711,12 @@ /// /// Everything through OptionalUnnamedAddr has already been parsed. /// -bool LLParser::parseIndirectSymbol( - const std::string &Name, LocTy NameLoc, unsigned L, unsigned Visibility, - unsigned DLLStorageClass, GlobalVariable::ThreadLocalMode TLM, - GlobalVariable::UnnamedAddr UnnamedAddr) { +bool LLParser::parseIndirectSymbol(const std::string &Name, LocTy NameLoc, + unsigned L, unsigned DSOLocation, + unsigned Visibility, + unsigned DLLStorageClass, + GlobalVariable::ThreadLocalMode TLM, + GlobalVariable::UnnamedAddr UnnamedAddr) { bool IsAlias; if (Lex.getKind() == lltok::kw_alias) IsAlias = true; @@ -800,6 +804,7 @@ (GlobalValue::LinkageTypes)Linkage, Name, Aliasee, /*Parent*/ nullptr)); GA->setThreadLocalMode(TLM); + GA->setDSOLocation((GlobalValue::DSO_Location)DSOLocation); GA->setVisibility((GlobalValue::VisibilityTypes)Visibility); GA->setDLLStorageClass((GlobalValue::DLLStorageClassTypes)DLLStorageClass); GA->setUnnamedAddr(UnnamedAddr); @@ -846,7 +851,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, GlobalVariable::UnnamedAddr UnnamedAddr) { if (!isValidVisibilityForLinkage(Visibility, Linkage)) @@ -921,6 +927,7 @@ GV->setInitializer(Init); GV->setConstant(IsConstant); GV->setLinkage((GlobalValue::LinkageTypes)Linkage); + GV->setDSOLocation((GlobalValue::DSO_Location)DSOLocation); GV->setVisibility((GlobalValue::VisibilityTypes)Visibility); GV->setDLLStorageClass((GlobalValue::DLLStorageClassTypes)DLLStorageClass); GV->setExternallyInitialized(IsExternallyInitialized); @@ -1595,16 +1602,43 @@ /// ::= 'extern_weak' /// ::= 'external' bool LLParser::ParseOptionalLinkage(unsigned &Res, bool &HasLinkage, + unsigned &DSOLocation, unsigned &Visibility, unsigned &DLLStorageClass) { Res = parseOptionalLinkageAux(Lex.getKind(), HasLinkage); if (HasLinkage) Lex.Lex(); + ParseOptionalDSOLocation(DSOLocation); ParseOptionalVisibility(Visibility); ParseOptionalDLLStorageClass(DLLStorageClass); + + if (DSOLocation == GlobalValue::DSO_Preemptable && + Visibility != GlobalValue::DefaultVisibility) { + return Error(Lex.getLoc(), "dso_location and visibility mismatch"); + } else if (DSOLocation == GlobalValue::DSO_Local && + DLLStorageClass == GlobalValue::DLLImportStorageClass) { + return Error(Lex.getLoc(), "dso_location and DLL-StorageClass mismatch"); + } + return false; } +void LLParser::ParseOptionalDSOLocation(unsigned &DSOLocation) { + switch (Lex.getKind()) { + default: + DSOLocation = GlobalValue::DSO_Default; + break; + case lltok::kw_dso_local: + DSOLocation = GlobalValue::DSO_Local; + break; + case lltok::kw_dso_preemptable: + DSOLocation = GlobalValue::DSO_Preemptable; + break; + } + if (DSOLocation != GlobalValue::DSO_Default) + Lex.Lex(); +} + /// ParseOptionalVisibility /// ::= /*empty*/ /// ::= 'default' @@ -4665,7 +4699,7 @@ // Parse the linkage. LocTy LinkageLoc = Lex.getLoc(); unsigned Linkage; - + unsigned DSOLocation; unsigned Visibility; unsigned DLLStorageClass; AttrBuilder RetAttrs; @@ -4673,7 +4707,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; @@ -4836,6 +4871,7 @@ NumberedVals.push_back(Fn); Fn->setLinkage((GlobalValue::LinkageTypes)Linkage); + Fn->setDSOLocation((GlobalValue::DSO_Location)DSOLocation); Fn->setVisibility((GlobalValue::VisibilityTypes)Visibility); Fn->setDLLStorageClass((GlobalValue::DLLStorageClassTypes)DLLStorageClass); Fn->setCallingConv(CC); Index: lib/AsmParser/LLToken.h =================================================================== --- lib/AsmParser/LLToken.h +++ lib/AsmParser/LLToken.h @@ -45,6 +45,9 @@ kw_global, kw_constant, + kw_dso_local, + kw_dso_preemptable, + kw_private, kw_internal, kw_linkonce, Index: lib/Target/PowerPC/PPCISelLowering.cpp =================================================================== --- lib/Target/PowerPC/PPCISelLowering.cpp +++ lib/Target/PowerPC/PPCISelLowering.cpp @@ -4232,6 +4232,37 @@ } static bool +isCodeModelMediumOrLarge(CodeModel::Model CM, const Triple& TT) { + switch (CM) { + case CodeModel::Medium: + case CodeModel::Large: + return true; + case CodeModel::Default: + return !TT.isOSDarwin() && + (TT.getArch() == Triple::ppc64 || TT.getArch() == Triple::ppc64le); + default: + return false; + } +} + +static bool +shouldAssumeDifferentTOC(const Function *Caller, SDValue Callee, + const TargetMachine &TM) { + if (isCodeModelMediumOrLarge(TM.getCodeModel(), TM.getTargetTriple())) { + GlobalAddressSDNode *G = dyn_cast(Callee); + if (!G) + return true; + + return !TM.shouldAssumeDSOLocal(*Caller->getParent(), G->getGlobal()); + } + + // Check if Callee resides in the same section, because for Small codemodel, + // we could end up with multiple TOCs in the same module. + // ref: https://bugzilla.mozilla.org/show_bug.cgi?id=973977 + return !resideInSameSection(Caller, Callee, TM); +} + +static bool needStackSlotPassParameters(const PPCSubtarget &Subtarget, const SmallVectorImpl &Outs) { assert(Subtarget.isSVR4ABI() && Subtarget.isPPC64()); @@ -4927,7 +4958,7 @@ // any other variadic arguments). Ops.insert(std::next(Ops.begin()), AddTOC); } else if (CallOpc == PPCISD::CALL && - !resideInSameSection(MF.getFunction(), Callee, DAG.getTarget())) { + shouldAssumeDifferentTOC(MF.getFunction(), Callee, DAG.getTarget())) { // Otherwise insert NOP for non-local calls. CallOpc = PPCISD::CALL_NOP; } Index: lib/Target/TargetMachine.cpp =================================================================== --- lib/Target/TargetMachine.cpp +++ lib/Target/TargetMachine.cpp @@ -123,6 +123,10 @@ Reloc::Model RM = getRelocationModel(); const Triple &TT = getTargetTriple(); + // If the GlobalValue has an explicit dso location, respect it. + if(GV && GV->hasExplicitDSOLocation()) + return GV->getDSOLocation() == GlobalValue::DSO_Local; + // DLLImport explicitly marks the GV as external. if (GV && GV->hasDLLImportStorageClass()) return false; Index: test/CodeGen/PowerPC/ppc64-blnop.ll =================================================================== --- test/CodeGen/PowerPC/ppc64-blnop.ll +++ test/CodeGen/PowerPC/ppc64-blnop.ll @@ -74,7 +74,7 @@ ; CHECK-LABEL: wo_hcaller: ; CHECK: bl wo_hcallee -; CHECK-NEXT: nop +; CHECK-NOT: nop } define weak_odr protected void @wo_pcallee(%class.T* %this, i8* %c) { ret void } @@ -84,7 +84,7 @@ ; CHECK-LABEL: wo_pcaller: ; CHECK: bl wo_pcallee -; CHECK-NEXT: nop +; CHECK-NOT: nop } define weak_odr void @wo_callee(%class.T* %this, i8* %c) { ret void } @@ -104,7 +104,7 @@ ; CHECK-LABEL: w_pcaller: ; CHECK: bl w_pcallee -; CHECK-NEXT: nop +; CHECK-NOT: nop } define weak hidden void @w_hcallee(i8* %ptr) { ret void } @@ -114,7 +114,7 @@ ; CHECK-LABEL: w_hcaller: ; CHECK: bl w_hcallee -; CHECK-NEXT: nop +; CHECK-NOT: nop } define weak void @w_callee(i8* %ptr) { ret void } Index: test/CodeGen/PowerPC/ppc64-calls.ll =================================================================== --- test/CodeGen/PowerPC/ppc64-calls.ll +++ test/CodeGen/PowerPC/ppc64-calls.ll @@ -21,13 +21,14 @@ ret void } -; Calls to weak function requires a TOC restore 'nop' because they -; may be overridden in a different module. +; Calls to a weak function don't require a TOC restore when compiling with +; the static relocation model and the default codemodel (Medium), since the exe +; will have a single TOC and callee definition must also be in the exe. define void @test_weak() nounwind readnone { ; CHECK-LABEL: test_weak: tail call void @foo_weak() nounwind ; CHECK: bl foo -; CHECK-NEXT: nop +; CHECK-NOT: nop ret void } Index: test/CodeGen/PowerPC/preemption.ll =================================================================== --- /dev/null +++ test/CodeGen/PowerPC/preemption.ll @@ -0,0 +1,301 @@ +; RUN: llc -mtriple powerpc64le-unkown-gnu-linux < %s | FileCheck %s +; RUN: llc -mtriple powerpc64le-unkown-gnu-linux -relocation-model=static \ +; RUN: < %s | FileCheck --check-prefix=STATIC %s +; RUN: llc -mtriple powerpc64le-unkown-gnu-linux -relocation-model=pic \ +; RUN: < %s | FileCheck %s + +; globals + +@strong_default = global i32 55 +define i32* @get_strong_default() #0 { + ret i32* @strong_default + +; STATIC-LABEL: @get_strong_default +; STATIC: addis 3, 2, strong_default@toc@ha +; STATIC: addi 3, 3, strong_default@toc@l +; STATIC: blr + +; CHECK-LABEL: @get_strong_default +; CHECK: addis 3, 2, .LC0@toc@ha +; CHECK: ld 3, .LC0@toc@l(3) +; CHECK: blr +} + +@weak_default = weak global i32 55 +define i32* @get_weak_default() #0 { + ret i32* @weak_default + +; STATIC-LABEL: @get_weak_default +; STATIC: addis 3, 2, weak_default@toc@ha +; STATIC: addi 3, 3, weak_default@toc@l +; STATIC: blr + +; CHECK-LABEL: @get_weak_default +; CHECK: addis 3, 2, .LC1@toc@ha +; CHECK: ld 3, .LC1@toc@l(3) +; CHECK: blr +} + +@external_default_global = external global i32 +define i32* @get_external_default_global() { + ret i32* @external_default_global + +; STATIC-LABEL: @get_external_default_global +; STATIC: addis 3, 2, .LC0@toc@ha +; STATIC: ld 3, .LC0@toc@l(3) +; STATIC: blr + +; CHECK-LABEL: @get_external_default_global +; CHECK: addis 3, 2, .LC2@toc@ha +; CHECK: ld 3, .LC2@toc@l(3) +; CHECK: blr +} + + +@strong_local_global = dso_local global i32 55 +define i32* @get_strong_local_global() { + ret i32* @strong_local_global + +; STATIC-LABEL: @get_strong_local_global +; STATIC: addis 3, 2, strong_local_global@toc@ha +; STATIC: addi 3, 3, strong_local_global@toc@l +; STATIC: blr + +; CHECK-LABEL: @get_strong_local_global +; CHECK: addis 3, 2, strong_local_global@toc@ha +; CHECK: addi 3, 3, strong_local_global@toc@l +; CHECK: blr +} + +@weak_local_global = weak dso_local global i32 42 +define i32* @get_weak_local_global() { + ret i32* @weak_local_global + +; STATIC-LABEL: @get_weak_local_global +; STATIC: addis 3, 2, weak_local_global@toc@ha +; STATIC: addi 3, 3, weak_local_global@toc@l +; STATIC: blr + +; CHECK-LABEL: @get_weak_local_global +; CHECK: addis 3, 2, weak_local_global@toc@ha +; CHECK: addi 3, 3, weak_local_global@toc@l +; CHECK: blr +} + +@external_local_global = external dso_local global i32 +define i32* @get_external_local_global() { + ret i32* @external_local_global +; STATIC-LABEL: @get_external_local_global +; STATIC: addis 3, 2, external_local_global@toc@ha +; STATIC: addi 3, 3, external_local_global@toc@l +; STATIC: blr + +; CHECK-LABEL: @get_external_local_global +; CHECK: addis 3, 2, external_local_global@toc@ha +; CHECK: addi 3, 3, external_local_global@toc@l +; CHECK: blr +} + +@strong_preemptable_global = dso_preemptable global i32 42 +define i32* @get_strong_preemptable_global() { + ret i32* @strong_preemptable_global + +; STATIC-LABEL: @get_strong_preemptable_global +; STATIC: addis 3, 2, .LC1@toc@ha +; STATIC: ld 3, .LC1@toc@l(3) +; STATIC: blr + +; CHECK-LABEL: @get_strong_preemptable_global +; CHECK: addis 3, 2, .LC3@toc@ha +; CHECK: ld 3, .LC3@toc@l(3) +; CHECK: blr +} + +@weak_preemptable_global = weak dso_preemptable global i32 42 +define i32* @get_weak_preemptable_global() { + ret i32* @weak_preemptable_global + +; STATIC-LABEL: @get_weak_preemptable_global +; STATIC: addis 3, 2, .LC2@toc@ha +; STATIC: ld 3, .LC2@toc@l(3) +; STATIC: blr + +; CHECK-LABEL: @get_weak_preemptable_global +; CHECK: addis 3, 2, .LC4@toc@ha +; CHECK: ld 3, .LC4@toc@l(3) +; CHECK: blr +} + +@external_preemptable_global = external dso_preemptable global i32 +define i32* @get_external_preemptable_global() { + ret i32* @external_preemptable_global + +; STATIC-LABEL: @get_external_preemptable_global +; STATIC: addis 3, 2, .LC3@toc@ha +; STATIC: ld 3, .LC3@toc@l(3) +; STATIC: blr + +; CHECK-LABEL: @get_external_preemptable_global +; CHECK: addis 3, 2, .LC5@toc@ha +; CHECK: ld 3, .LC5@toc@l(3) +; CHECK: blr +} + +; functions +define signext i32 @strong_default_function(i32 %i) { + ret i32 %i +} +define signext i32 @strong_default_function_caller(i32 %i) { + %call = notail call signext i32 @strong_default_function(i32 signext %i) + ret i32 %call + +; STATIC-LABEL: @strong_default_function_caller +; STATIC: bl strong_default_function +; STATIC-NOT: nop +; STATIC: blr + +; CHECK-LABEL: @strong_default_function_caller +; CHECK: bl strong_default_function +; CHECK-NEXT: nop +; CHECK: blr +} + +define weak signext i32 @weak_default_function(i32 %i) { + ret i32 %i +} +define signext i32 @weak_default_function_caller(i32 %i) { + %call = notail call signext i32 @weak_default_function(i32 signext %i) + ret i32 %call + +; STATIC-LABEL: @weak_default_function_caller +; STATIC: bl weak_default_function +; STATIC-NOT: nop +; STATIC: blr + +; CHECK-LABEL: @weak_default_function_caller +; CHECK: bl weak_default_function +; CHECK-NEXT: nop +; CHECK: blr +} + + +declare i32 @external_default_function(i32 %i) +define i32 @external_default_function_caller(i32 %i) { + %call = notail call signext i32 @external_default_function(i32 signext %i) + ret i32 %call + +; STATIC-LABEL: @external_default_function_caller +; STATIC: bl external_default_function +; STATIC-NEXT: nop +; STATIC: blr + +; CHECK-LABEL: @external_default_function_caller +; CHECK: bl external_default_function +; CHECK-NEXT: nop +; CHECK: blr +} + +define dso_local signext i32 @strong_local_function(i32 %i) { + ret i32 %i +} +define signext i32 @strong_local_function_caller(i32 %i) { + %call = notail call signext i32 @strong_local_function(i32 signext %i) + ret i32 %call + +; STATIC-LABEL: @strong_local_function_caller +; STATIC: bl strong_local_function +; STATIC-NOT: nop +; STATIC: blr + +; CHECK-LABEL: @strong_local_function_caller +; CHECK: bl strong_local_function +; CHECK-NOT: nop +; CHECK: blr +} + +define weak dso_local signext i32 @weak_local_function(i32 %i) { + ret i32 %i +} +define signext i32 @weak_local_function_caller(i32 %i) { + %call = notail call signext i32 @weak_local_function(i32 signext %i) + ret i32 %call + +; STATIC-LABEL: @weak_local_function_caller +; STATIC: bl weak_local_function +; STATIC-NOT: nop +; STATIC: blr + +; CHECK-LABEL: @weak_local_function_caller +; CHECK: bl weak_local_function +; CHECK-NOT: nop +; CHECK: blr +} + +declare dso_local i32 @external_local_function(i32 %i) +define i32 @external_local_function_caller(i32 %i) { + %call = notail call signext i32 @external_local_function(i32 signext %i) + ret i32 %call + +; STATIC-LABEL: @external_local_function_caller +; STATIC: bl external_local_function +; STATIC-NOT: nop +; STATIC: blr + +; CHECK-LABEL: @external_local_function_caller +; CHECK: bl external_local_function +; CHECK-NOT: nop +; CHECK: blr +} + +define dso_preemptable signext i32 @strong_preemptable_function(i32 %i) { + ret i32 %i +} +define signext i32 @strong_preemptable_function_caller(i32 %i) { + %call = notail call signext i32 @strong_preemptable_function(i32 signext %i) + ret i32 %call + +; STATIC-LABEL: @strong_preemptable_function_caller +; STATIC: bl strong_preemptable_function +; STATIC-NEXT: nop +; STATIC: blr + +; CHECK-LABEL: @strong_preemptable_function_caller +; CHECK: bl strong_preemptable_function +; CHECK-NEXT: nop +; CHECK: blr +} + +define weak dso_preemptable signext i32 @weak_preemptable_function(i32 %i) { + ret i32 %i +} +define signext i32 @weak_preemptable_function_caller(i32 %i) { + %call = notail call signext i32 @weak_preemptable_function(i32 signext %i) + ret i32 %call + +; STATIC-LABEL: @weak_preemptable_function_caller +; STATIC: bl weak_preemptable_function +; STATIC-NEXT: nop +; STATIC: blr + +; CHECK-LABEL: @weak_preemptable_function_caller +; CHECK: bl weak_preemptable_function +; CHECK-NEXT: nop +; CHECK: blr +} + +declare dso_preemptable i32 @external_preemptable_function(i32 %i) +define i32 @external_preemptable_function_caller(i32 %i) { + %call = notail call signext i32 @external_preemptable_function(i32 signext %i) + ret i32 %call + +; STATIC-LABEL: @external_preemptable_function_caller +; STATIC: bl external_preemptable_function +; STATIC-NEXT: nop +; STATIC: blr + +; CHECK-LABEL: @external_preemptable_function_caller +; CHECK: bl external_preemptable_function +; CHECK-NEXT: nop +; CHECK: blr +} + Index: test/CodeGen/X86/darwin-preemptible.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/darwin-preemptible.ll @@ -0,0 +1,179 @@ +; 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 + + +; 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 = dso_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 dso_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 dso_local global i32 +define i32* @get_external_local_global() { + ret i32* @external_local_global +} +; CHECK: leaq _external_local_global(%rip), %rax + + +@strong_preemptable_global = dso_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 dso_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 dso_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 = dso_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 dso_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 = dso_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 dso_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 dso_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 dso_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 dso_local void @external_local_function() +define void()* @get_external_local_function() { + ret void()* @external_local_function +} +; CHECK: leaq _external_local_function(%rip), %rax + + +define dso_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 dso_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 dso_preemptable void @external_preemptable_function() +define void()* @get_external_preemptable_function() { + ret void()* @external_preemptable_function +} +; CHECK: movq _external_preemptable_function@GOTPCREL(%rip), %rax +