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,14 @@ 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 +110,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 +270,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; } 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/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/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-NEXT: 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-NEXT: nop +; STATIC: blr + +; CHECK-LABEL: @weak_local_function_caller +; CHECK: bl weak_local_function +; CHECK-NEXT: 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-NEXT: nop +; STATIC: blr + +; CHECK-LABEL: @external_local_function_caller +; CHECK: bl external_local_function +; CHECK-NEXT: 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-preemption.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/darwin-preemption.ll @@ -0,0 +1,251 @@ +; 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 + +; 32 bits + +; 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_DNP %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 +; DARWIN32: leal {{_?}}strong_default_global-L{{.*}}$pb(%eax), %eax +; DARWIN32_S: movl ${{_?}}strong_default_global, %eax +; DARWIN32_DNP: 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 +; DARWIN32: movl L_weak_default_global$non_lazy_ptr-L{{.*}}$pb(%eax), %eax +; DARWIN32_S: movl ${{_?}}weak_default_global, %eax +; DARWIN32_DNP: 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 +; DARWIN32: movl L_external_default_global$non_lazy_ptr-L{{.*}}$pb(%eax), %eax +; DARWIN32_S: movl ${{_?}}external_default_global, %eax +; DARWIN32_DNP: movl L_external_default_global$non_lazy_ptr, %eax + +@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 +; DARWIN32: leal _strong_local_global-L{{.*}}$pb(%eax), %eax +; DARWIN32_S: movl ${{_?}}strong_local_global, %eax +; DARWIN32_DNP: movl ${{_?}}strong_local_global, %eax + +@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 +; DARWIN32: leal _weak_local_global-L{{.}}$pb(%eax), %eax +; DARWIN32_S: movl ${{_?}}weak_local_global, %eax +; DARWIN32_DNP: movl ${{_?}}weak_local_global, %eax + +@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 +; DARWIN32: movl L_external_local_global$non_lazy_ptr-L{{.*}}$pb(%eax), %eax +; DARWIN32_S: movl ${{_?}}external_local_global, %eax +; DARWIN32_DNP: movl ${{_?}}external_local_global, %eax + +@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 +; DARWIN32: movl L_strong_preemptable_global$non_lazy_ptr-L{{.*}}$pb(%eax), %eax +; DARWIN32_S: movl L_strong_preemptable_global$non_lazy_ptr, %eax +; DARWIN32_DNP: movl L_strong_preemptable_global$non_lazy_ptr, %eax + +@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 +; DARWIN32: movl L_weak_preemptable_global$non_lazy_ptr-L{{.*}}$pb(%eax), %eax +; DARWIN32_S: movl L_weak_preemptable_global$non_lazy_ptr, %eax +; DARWIN32_DNP: movl L_weak_preemptable_global$non_lazy_ptr, %eax + +@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 +; DARWIN32: movl L_external_preemptable_global$non_lazy_ptr-L{{.*}}$pb(%eax), %eax +; DARWIN32_S: movl L_external_preemptable_global$non_lazy_ptr, %eax +; DARWIN32_DNP: 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 +; DARWIN32: leal _strong_default_alias-L{{.*}}$pb(%eax), %eax +; DARWIN32_S: movl ${{_?}}strong_default_alias, %eax +; DARWIN32_DNP: 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 +; DARWIN32: movl L_weak_default_alias$non_lazy_ptr-L{{.*}}$pb(%eax), %eax +; DARWIN32_S: movl ${{_?}}weak_default_alias, %eax +; DARWIN32_DNP: movl L_weak_default_alias$non_lazy_ptr, %eax + +@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 +; DARWIN32: leal _strong_local_alias-L{{.*}}$pb(%eax), %eax +; DARWIN32_S: movl ${{_?}}strong_local_alias, %eax +; DARWIN32_DNP: movl ${{_?}}strong_local_alias, %eax + +@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 +; DARWIN32: leal _weak_local_alias-L{{.*}}$pb(%eax), %eax +; DARWIN32_S: movl ${{_?}}weak_local_alias, %eax +; DARWIN32_DNP: movl ${{_?}}weak_local_alias, %eax + +@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 +; DARWIN32: movl L_strong_preemptable_alias$non_lazy_ptr-L{{.*}}$pb(%eax), %eax +; DARWIN32_S: movl L_strong_preemptable_alias$non_lazy_ptr, %eax +; DARWIN32_DNP: movl L_strong_preemptable_alias$non_lazy_ptr, %eax + +@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 +; DARWIN32: movl L_weak_preemptable_alias$non_lazy_ptr-L{{.*}}$pb(%eax), %eax +; DARWIN32_S: movl L_weak_preemptable_alias$non_lazy_ptr, %eax +; DARWIN32_DNP: 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 +; DARWIN32: leal _strong_default_function-L{{.*}}$pb(%eax), %eax +; DARWIN32_S: movl ${{_?}}strong_default_function, %eax +; DARWIN32_DNP: 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 +; DARWIN32: movl L_weak_default_function$non_lazy_ptr-L{{.*}}$pb(%eax), %eax +; DARWIN32_S: movl ${{_?}}weak_default_function, %eax +; DARWIN32_DNP: 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 +; DARWIN32: movl L_external_default_function$non_lazy_ptr-L{{.*}}$pb(%eax), %eax +; DARWIN32_S: movl ${{_?}}external_default_function, %eax +; DARWIN32_DNP: movl L_external_default_function$non_lazy_ptr, %eax + +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 +; DARWIN32: leal _strong_local_function-L{{.*}}$pb(%eax), %eax +; DARWIN32_S: movl ${{_?}}strong_local_function, %eax +; DARWIN32_DNP: movl ${{_?}}strong_local_function, %eax + +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 +; DARWIN32: leal _weak_local_function-L{{.*}}$pb(%eax), %eax +; DARWIN32_S: movl ${{_?}}weak_local_function, %eax +; DARWIN32_DNP: movl ${{_?}}weak_local_function, %eax + +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 +; DARWIN32: movl L_external_local_function$non_lazy_ptr-L{{.*}}$pb(%eax), %eax +; DARWIN32_S: movl ${{_?}}external_local_function, %eax +; DARWIN32_DNP: movl ${{_?}}external_local_function, %eax + +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 +; DARWIN32: movl L_strong_preemptable_function$non_lazy_ptr-L{{.*}}$pb(%eax), %eax +; DARWIN32_S: movl L_strong_preemptable_function$non_lazy_ptr, %eax +; DARWIN32_DNP: movl L_strong_preemptable_function$non_lazy_ptr, %eax + +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 +; DARWIN32: movl L_weak_preemptable_function$non_lazy_ptr-L{{.*}}$pb(%eax), %eax +; DARWIN32_S: movl L_weak_preemptable_function$non_lazy_ptr, %eax +; DARWIN32_DNP: movl L_weak_preemptable_function$non_lazy_ptr, %eax + +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 +; DARWIN32: movl L_external_preemptable_function$non_lazy_ptr-L{{.*}}$pb(%eax), %eax +; DARWIN32_S: movl L_external_preemptable_function$non_lazy_ptr, %eax +; DARWIN32_DNP: movl L_external_preemptable_function$non_lazy_ptr, %eax Index: test/CodeGen/X86/linux-preemption.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/linux-preemption.ll @@ -0,0 +1,225 @@ +; 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 + +; 32 bits + +; RUN: llc -mtriple i386-pc-linux \ +; RUN: -relocation-model=pic < %s | FileCheck --check-prefix=CHECK32 %s + +; globals + +@strong_default_global = global i32 42 +define i32* @get_strong_default_global() { + ret i32* @strong_default_global +} +; CHECK: movq {{_?}}strong_default_global@GOTPCREL(%rip), %rax +; STATIC: movl ${{_?}}strong_default_global, %eax +; CHECK32: movl {{_?}}strong_default_global@GOT(%eax), %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: movl ${{_?}}weak_default_global, %eax +; CHECK32: movl {{_?}}weak_default_global@GOT(%eax), %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: movl ${{_?}}external_default_global, %eax +; CHECK32: movl {{_?}}external_default_global@GOT(%eax), %eax + +@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 +; STATIC: movl ${{_?}}strong_local_global, %eax +; CHECK32: leal {{_?}}strong_local_global@GOTOFF(%eax), %eax + +@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 +; STATIC: movl ${{_?}}weak_local_global, %eax +; CHECK32: leal {{_?}}weak_local_global@GOTOFF(%eax), %eax + +@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 +; STATIC: movl ${{_?}}external_local_global, %eax +; CHECK32: leal {{_?}}external_local_global@GOTOFF(%eax), %eax + + +@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 +; STATIC: movq {{_?}}strong_preemptable_global@GOTPCREL, %rax +; CHECK32: movl {{_?}}strong_preemptable_global@GOT(%eax), %eax + +@weak_preemptable_global = weak dso_preemptable global i32 42 +define i32* @get_weak_preemptable_global() { + ret i32* @weak_preemptable_global +} +; CHECK ;ADD_LABEL_BACK; movq {{_?}}weak_preemptable_global@GOTPCREL(%rip), %rax +; STATIC ;ADD_LABEL_BACK; movq {{_?}}weak_preemptable_global@GOTPCREL, %rax +; CHECK32 ;ADD_LABEL_BACK; movl {{_?}}weak_preemptable_global@GOT(%eax), %eax + +@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 +; STATIC: movq {{_?}}external_preemptable_global@GOTPCREL, %rax +; CHECK32: movl {{_?}}external_preemptable_global@GOT(%eax), %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: movq {{_?}}strong_default_alias@GOTPCREL(%rip), %rax +; STATIC: movl ${{_?}}strong_default_alias, %eax +; CHECK32: movl {{_?}}strong_default_alias@GOT(%eax), %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: movl ${{_?}}weak_default_alias, %eax +; CHECK32: movl {{_?}}weak_default_alias@GOT(%eax), %eax + +@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 +; STATIC: movl ${{_?}}strong_local_alias, %eax +; CHECK32: leal {{_?}}strong_local_alias@GOTOFF(%eax), %eax + +@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 +; STATIC: movl ${{_?}}weak_local_alias, %eax +; CHECK32: leal {{_?}}weak_local_alias@GOTOFF(%eax), %eax + + +@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 +; STATIC: movq {{_?}}strong_preemptable_alias@GOTPCREL, %rax +; CHECK32: movl {{_?}}strong_preemptable_alias@GOT(%eax), %eax + +@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 +; STATIC: movq {{_?}}weak_preemptable_alias@GOTPCREL, %rax +; CHECK32: movl {{_?}}weak_preemptable_alias@GOT(%eax), %eax + +; functions + +define void @strong_default_function() { + ret void +} +define void()* @get_strong_default_function() { + ret void()* @strong_default_function +} +; CHECK: movq {{_?}}strong_default_function@GOTPCREL(%rip), %rax +; STATIC: movl ${{_?}}strong_default_function, %eax +; CHECK32: movl {{_?}}strong_default_function@GOT(%eax), %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: movl ${{_?}}weak_default_function, %eax +; CHECK32: movl {{_?}}weak_default_function@GOT(%eax), %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: movl ${{_?}}external_default_function, %eax +; CHECK32: movl {{_?}}external_default_function@GOT(%eax), %eax + +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 +; STATIC: movl ${{_?}}strong_local_function, %eax +; CHECK32: leal {{_?}}strong_local_function@GOTOFF(%eax), %eax + +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 +; STATIC: movl ${{_?}}weak_local_function, %eax +; CHECK32: leal {{_?}}weak_local_function@GOTOFF(%eax), %eax + +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 +; STATIC: movl ${{_?}}external_local_function, %eax +; CHECK32: leal {{_?}}external_local_function@GOTOFF(%eax), %eax + + +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 +; STATIC: movq {{_?}}strong_preemptable_function@GOTPCREL, %rax +; CHECK32: movl {{_?}}strong_preemptable_function@GOT(%eax), %eax + +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 +; STATIC: movq {{_?}}weak_preemptable_function@GOTPCREL, %rax +; CHECK32: movl {{_?}}weak_preemptable_function@GOT(%eax), %eax + +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 +; STATIC: movq {{_?}}external_preemptable_function@GOTPCREL, %rax +; CHECK32: movl {{_?}}external_preemptable_function@GOT(%eax), %eax Index: test/CodeGen/X86/win32-preemption.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/win32-preemption.ll @@ -0,0 +1,236 @@ +; 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-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 +} +; COFF: leaq {{_?}}strong_default_global(%rip), %rax +; COFF_S: movl $strong_default_global, %eax +; COFF32: movl ${{_?}}strong_default_global, %eax + +@weak_default_global = weak global i32 42 +define i32* @get_weak_default_global() { + ret i32* @weak_default_global +} +; COFF: leaq weak_default_global(%rip), %rax +; COFF_S: movl ${{_?}}weak_default_global, %eax +; COFF32: movl ${{_?}}_weak_default_global, %eax + +@external_default_global = external global i32 +define i32* @get_external_default_global() { + ret i32* @external_default_global +} +; COFF: leaq external_default_global(%rip), %rax +; COFF_S: movl ${{_?}}external_default_global, %eax +; COFF32: movl ${{_?}}external_default_global, %eax + + +@strong_local_global = dso_local global i32 42 +define i32* @get_strong_local_global() { + ret i32* @strong_local_global +} +; COFF: leaq {{_?}}strong_local_global(%rip), %rax +; COFF_S: movl ${{_?}}strong_local_global, %eax +; COFF32: movl ${{_?}}strong_local_global, %eax + +@weak_local_global = weak dso_local global i32 42 +define i32* @get_weak_local_global() { + ret i32* @weak_local_global +} +; COFF: leaq {{_?}}weak_local_global(%rip), %rax +; COFF_S: movl ${{_?}}weak_local_global, %eax +; COFF32: movl ${{_?}}weak_local_global, %eax + +@external_local_global = external dso_local global i32 +define i32* @get_external_local_global() { + ret i32* @external_local_global +} +; COFF: leaq {{_?}}external_local_global(%rip), %rax +; COFF_S: movl ${{_?}}external_local_global, %eax +; COFF32: movl ${{_?}}external_local_global, %eax + + +@strong_preemptable_global = dso_preemptable global i32 42 +define i32* @get_strong_preemptable_global() { + ret i32* @strong_preemptable_global +} +; COFF: movq __imp_strong_preemptable_global(%rip), %rax +; COFF_S: movq __imp_strong_preemptable_global, %rax +; COFF32: movl __imp__strong_preemptable_global, %eax + +@weak_preemptable_global = weak dso_preemptable global i32 42 +define i32* @get_weak_preemptable_global() { + ret i32* @weak_preemptable_global +} +; COFF: movq __imp_weak_preemptable_global(%rip), %rax +; COFF_S: movq __imp_weak_preemptable_global, %rax +; COFF32: movl __imp__weak_preemptable_global, %eax + +@external_preemptable_global = external dso_preemptable global i32 +define i32* @get_external_preemptable_global() { + ret i32* @external_preemptable_global +} +; COFF: movq __imp_external_preemptable_global(%rip), %rax +; COFF_S: movq __imp_external_preemptable_global, %rax +; COFF32: movl __imp__external_preemptable_global, %eax + + +; aliases +@aliasee = global i32 42 + +@strong_default_alias = alias i32, i32* @aliasee +define i32* @get_strong_default_alias() { + ret i32* @strong_default_alias +} +; COFF: leaq {{_?}}strong_default_alias(%rip), %rax +; COFF_S: movl ${{_?}}strong_default_alias, %eax +; COFF32: movl ${{_?}}strong_default_alias, %eax + +@weak_default_alias = weak alias i32, i32* @aliasee +define i32* @get_weak_default_alias() { + ret i32* @weak_default_alias +} +; COFF: leaq weak_default_alias(%rip), %rax +; COFF_S: movl ${{_?}}weak_default_alias, %eax +; COFF32: movl ${{_?}}weak_default_alias, %eax + + +@strong_local_alias = dso_local alias i32, i32* @aliasee +define i32* @get_strong_local_alias() { + ret i32* @strong_local_alias +} +; COFF: leaq {{_?}}strong_local_alias(%rip), %rax +; COFF_S: movl ${{_?}}strong_local_alias, %eax +; COFF32: movl ${{_?}}strong_local_alias, %eax + +@weak_local_alias = weak dso_local alias i32, i32* @aliasee +define i32* @get_weak_local_alias() { + ret i32* @weak_local_alias +} +; COFF: leaq {{_?}}weak_local_alias(%rip), %rax +; COFF_S: movl ${{_?}}weak_local_alias, %eax +; COFF32: movl ${{_?}}weak_local_alias, %eax + + +@strong_preemptable_alias = dso_preemptable alias i32, i32* @aliasee +define i32* @get_strong_preemptable_alias() { + ret i32* @strong_preemptable_alias +} +; COFF: movq __imp_strong_preemptable_alias(%rip), %rax +; COFF_S: movq __imp_strong_preemptable_alias, %rax +; COFF32: movl __imp__strong_preemptable_alias, %eax + +@weak_preemptable_alias = weak dso_preemptable alias i32, i32* @aliasee +define i32* @get_weak_preemptable_alias() { + ret i32* @weak_preemptable_alias +} +; COFF: movq __imp_weak_preemptable_alias(%rip), %rax +; COFF_S: movq __imp_weak_preemptable_alias, %rax +; COFF32: movl __imp__weak_preemptable_alias, %eax + + +; functions + +define void @strong_default_function() { + ret void +} +define void()* @get_strong_default_function() { + ret void()* @strong_default_function +} +; COFF: leaq {{_?}}strong_default_function(%rip), %rax +; COFF_S: movl ${{_?}}strong_default_function, %eax +; COFF32: movl ${{_?}}strong_default_function, %eax + +define weak void @weak_default_function() { + ret void +} +define void()* @get_weak_default_function() { + ret void()* @weak_default_function +} +; COFF: leaq weak_default_function(%rip), %rax +; COFF_S: movl ${{_?}}weak_default_function, %eax +; COFF32: movl ${{_?}}weak_default_function, %eax + +declare void @external_default_function() +define void()* @get_external_default_function() { + ret void()* @external_default_function +} +; COFF: leaq external_default_function(%rip), %rax +; COFF_S: movl $external_default_function, %eax +; COFF32: movl ${{_?}}external_default_function, %eax + + +define dso_local void @strong_local_function() { + ret void +} +define void()* @get_strong_local_function() { + ret void()* @strong_local_function +} +; COFF: leaq {{_?}}strong_local_function(%rip), %rax +; COFF_S: movl ${{_?}}strong_local_function, %eax +; COFF32: movl ${{_?}}strong_local_function, %eax + +define weak dso_local void @weak_local_function() { + ret void +} +define void()* @get_weak_local_function() { + ret void()* @weak_local_function +} +; COFF: leaq {{_?}}weak_local_function(%rip), %rax +; COFF_S: movl ${{_?}}weak_local_function, %eax +; COFF32: movl $_weak_local_function, %eax + +declare dso_local void @external_local_function() +define void()* @get_external_local_function() { + ret void()* @external_local_function +} +; COFF: leaq {{_?}}external_local_function(%rip), %rax +; COFF_S: movl ${{_?}}external_local_function, %eax +; COFF32: movl ${{_?}}external_local_function, %eax + + +define dso_preemptable void @strong_preemptable_function() { + ret void +} +define void()* @get_strong_preemptable_function() { + ret void()* @strong_preemptable_function +} +; COFF: __imp_strong_preemptable_function(%rip), %rax +; COFF_S: __imp_strong_preemptable_function, %rax +; COFF32: __imp__strong_preemptable_function, %eax + +define weak dso_preemptable void @weak_preemptable_function() { + ret void +} +define void()* @get_weak_preemptable_function() { + ret void()* @weak_preemptable_function +} +; COFF: movq __imp_weak_preemptable_function(%rip), %rax +; COFF_S: movq __imp_weak_preemptable_function, %rax +; COFF32: movl __imp__weak_preemptable_function, %eax + +declare dso_preemptable void @external_preemptable_function() +define void()* @get_external_preemptable_function() { + ret void()* @external_preemptable_function +} +; COFF: movq __imp_external_preemptable_function(%rip), %rax +; COFF_S: movq __imp_external_preemptable_function, %rax +; COFF32: movl __imp__external_preemptable_function, %eax