diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index b490fa0faf2e..40e18e6e350f 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -763,6 +763,13 @@ static bool shouldAssumeDSOLocal(const CodeGenModule &CGM, !GV->isThreadLocal()) return false; } + + // On COFF, don't mark 'extern_weak' symbols as DSO local. If these symbols + // remain unresolved in the link, they can be resolved to zero, which is + // outside the current DSO. + if (TT.isOSBinFormatCOFF() && GV->hasExternalWeakLinkage()) + return false; + // Every other GV is local on COFF. // Make an exception for windows OS in the triple: Some firmware builds use // *-win32-macho triples. This (accidentally?) produced windows relocations diff --git a/clang/test/CodeGen/dso-local-executable.c b/clang/test/CodeGen/dso-local-executable.c index 36fd4d0d0396..13e11158300f 100644 --- a/clang/test/CodeGen/dso-local-executable.c +++ b/clang/test/CodeGen/dso-local-executable.c @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -triple x86_64-pc-win32 -emit-llvm %s -o - | FileCheck -allow-deprecated-dag-overlap --check-prefix=COFF %s // COFF-DAG: @bar = external dso_local global i32 -// COFF-DAG: @weak_bar = extern_weak dso_local global i32 +// COFF-DAG: @weak_bar = extern_weak global i32 // COFF-DAG: declare dso_local void @foo() // COFF-DAG: @baz = dso_local global i32 42 // COFF-DAG: define dso_local i32* @zed() diff --git a/llvm/lib/Target/TargetMachine.cpp b/llvm/lib/Target/TargetMachine.cpp index 7a1e01bdab67..5b2bdc37af88 100644 --- a/llvm/lib/Target/TargetMachine.cpp +++ b/llvm/lib/Target/TargetMachine.cpp @@ -144,6 +144,12 @@ bool TargetMachine::shouldAssumeDSOLocal(const Module &M, isa(GV)) return false; + // On COFF, don't mark 'extern_weak' symbols as DSO local. If these symbols + // remain unresolved in the link, they can be resolved to zero, which is + // outside the current DSO. + if (TT.isOSBinFormatCOFF() && GV && GV->hasExternalWeakLinkage()) + return false; + // Every other GV is local on COFF. // Make an exception for windows OS in the triple: Some firmware builds use // *-win32-macho triples. This (accidentally?) produced windows relocations diff --git a/llvm/lib/Target/X86/X86FastISel.cpp b/llvm/lib/Target/X86/X86FastISel.cpp index 80dcd74a5d21..6fca1acb0092 100644 --- a/llvm/lib/Target/X86/X86FastISel.cpp +++ b/llvm/lib/Target/X86/X86FastISel.cpp @@ -3503,8 +3503,9 @@ bool X86FastISel::fastLowerCall(CallLoweringInfo &CLI) { // This will be a direct call, or an indirect call through memory for // NonLazyBind calls or dllimport calls. - bool NeedLoad = - OpFlags == X86II::MO_DLLIMPORT || OpFlags == X86II::MO_GOTPCREL; + bool NeedLoad = OpFlags == X86II::MO_DLLIMPORT || + OpFlags == X86II::MO_GOTPCREL || + OpFlags == X86II::MO_COFFSTUB; unsigned CallOpc = NeedLoad ? (Is64Bit ? X86::CALL64m : X86::CALL32m) : (Is64Bit ? X86::CALL64pcrel32 : X86::CALLpcrel32); diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp index 56f02c412aef..26619571821e 100644 --- a/llvm/lib/Target/X86/X86ISelLowering.cpp +++ b/llvm/lib/Target/X86/X86ISelLowering.cpp @@ -3969,10 +3969,10 @@ X86TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, Callee = DAG.getTargetGlobalAddress( GV, dl, getPointerTy(DAG.getDataLayout()), G->getOffset(), OpFlags); - if (OpFlags == X86II::MO_GOTPCREL) { + if (isGlobalStubReference(OpFlags)) { // Add a wrapper. - Callee = DAG.getNode(X86ISD::WrapperRIP, dl, - getPointerTy(DAG.getDataLayout()), Callee); + Callee = DAG.getNode(getGlobalWrapperKind(GV, OpFlags), dl, + getPointerTy(DAG.getDataLayout()), Callee); // Add extra indirection Callee = DAG.getLoad( getPointerTy(DAG.getDataLayout()), dl, DAG.getEntryNode(), Callee, @@ -3987,9 +3987,9 @@ X86TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, Callee = DAG.getTargetExternalSymbol( S->getSymbol(), getPointerTy(DAG.getDataLayout()), OpFlags); - if (OpFlags == X86II::MO_GOTPCREL) { - Callee = DAG.getNode(X86ISD::WrapperRIP, dl, - getPointerTy(DAG.getDataLayout()), Callee); + if (isGlobalStubReference(OpFlags)) { + Callee = DAG.getNode(getGlobalWrapperKind(nullptr, OpFlags), dl, + getPointerTy(DAG.getDataLayout()), Callee); Callee = DAG.getLoad( getPointerTy(DAG.getDataLayout()), dl, DAG.getEntryNode(), Callee, MachinePointerInfo::getGOT(DAG.getMachineFunction())); diff --git a/llvm/lib/Target/X86/X86Subtarget.cpp b/llvm/lib/Target/X86/X86Subtarget.cpp index 177fde45911a..d5bb56603df9 100644 --- a/llvm/lib/Target/X86/X86Subtarget.cpp +++ b/llvm/lib/Target/X86/X86Subtarget.cpp @@ -176,10 +176,13 @@ X86Subtarget::classifyGlobalFunctionReference(const GlobalValue *GV, if (TM.shouldAssumeDSOLocal(M, GV)) return X86II::MO_NO_FLAG; + // Functions on COFF can be non-DSO local for two reasons: + // - They are marked dllimport + // - They are extern_weak, and a stub is needed if (isTargetCOFF()) { - assert(GV->hasDLLImportStorageClass() && - "shouldAssumeDSOLocal gave inconsistent answer"); - return X86II::MO_DLLIMPORT; + if (GV->hasDLLImportStorageClass()) + return X86II::MO_DLLIMPORT; + return X86II::MO_COFFSTUB; } const Function *F = dyn_cast_or_null(GV); diff --git a/llvm/test/CodeGen/X86/extern_weak.ll b/llvm/test/CodeGen/X86/extern_weak.ll index c2ff09f21e80..2e6be5e0249c 100644 --- a/llvm/test/CodeGen/X86/extern_weak.ll +++ b/llvm/test/CodeGen/X86/extern_weak.ll @@ -1,13 +1,64 @@ -; RUN: llc < %s -mtriple=i686-apple-darwin | grep weak_reference | count 2 - -@Y = global i32 (i8*)* @X ; [#uses=0] - -declare extern_weak i32 @X(i8*) - -define void @bar() { - tail call void (...) @foo( ) - ret void -} +; RUN: llc < %s -mtriple=i686-apple-darwin | FileCheck %s --check-prefix=DARWIN +; RUN: llc < %s -mtriple=i686-windows-msvc | FileCheck %s --check-prefix=WIN32 +; RUN: llc < %s -mtriple=x86_64-windows-msvc | FileCheck %s --check-prefix=WIN64 declare extern_weak void @foo(...) +define void @bar() { +entry: + br i1 icmp ne (void (...)* @foo, void (...)* null), label %if.then, label %if.end + +if.then: + tail call void (...) @foo( ) + ret void + +if.end: + ret void +} + +; DARWIN-LABEL: _bar: +; DARWIN: cmpl $0, L_foo$non_lazy_ptr +; DARWIN: jmp _foo ## TAILCALL + +; WIN32-LABEL: _bar: +; WIN32: cmpl $0, .refptr._foo +; WIN32: jmpl *.refptr._foo + +; WIN64-LABEL: bar: +; WIN64: cmpq $0, .refptr.foo(%rip) +; WIN64: jmpq *.refptr.foo + + +declare extern_weak i32 @X(i8*) + +@Y = global i32 (i8*)* @X ; [#uses=0] + +; DARWIN-LABEL: _Y: +; DARWIN: .long _X + +; WIN32-LABEL: _Y: +; WIN32: .long _X + +; WIN64-LABEL: Y: +; WIN64: .quad X + + +; DARWIN: .weak_reference _foo +; DARWIN: .weak_reference _X + +; WIN32: .section .rdata$.refptr._foo,"dr",discard,.refptr._foo +; WIN32: .globl .refptr._foo +; WIN32: .refptr._foo: +; WIN32: .long _foo + +; WIN32: .weak _foo +; WIN32: .weak _X + +; WIN64: .section .rdata$.refptr.foo,"dr",discard,.refptr.foo +; WIN64: .globl .refptr.foo +; WIN64: .refptr.foo: +; WIN64: .quad foo + +; WIN64: .weak foo +; WIN64: .weak X +