forked from OSchip/llvm-project
[COFF] Use COFF stubs for extern_weak functions
Summary: A COFF stub indirects the reference to a symbol through memory. A .refptr.$sym global variable pointer is created to refer to $sym. Typically mingw uses these for external global variable declarations, but we can use them for weak function declarations as well. Updates the dso_local classification to add a special case for extern_weak symbols on COFF in both clang and LLVM. Fixes PR37598 Reviewers: smeenai, mstorsjo Subscribers: hiraditya, cfe-commits, llvm-commits Tags: #clang, #llvm Differential Revision: https://reviews.llvm.org/D61615 llvm-svn: 360207
This commit is contained in:
parent
e088d03b9c
commit
6bf108d77a
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -144,6 +144,12 @@ bool TargetMachine::shouldAssumeDSOLocal(const Module &M,
|
|||
isa<GlobalVariable>(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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()));
|
||||
|
|
|
@ -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<Function>(GV);
|
||||
|
|
|
@ -1,13 +1,64 @@
|
|||
; RUN: llc < %s -mtriple=i686-apple-darwin | grep weak_reference | count 2
|
||||
|
||||
@Y = global i32 (i8*)* @X ; <i32 (i8*)**> [#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 ; <i32 (i8*)**> [#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
|
||||
|
||||
|
|
Loading…
Reference in New Issue