rnk created this revision.
rnk added reviewers: smeenai, mstorsjo.
Herald added subscribers: cfe-commits, hiraditya.
Herald added projects: clang, LLVM.

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


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D61615

Files:
  clang/lib/CodeGen/CodeGenModule.cpp
  clang/test/CodeGen/dso-local-executable.c
  llvm/lib/Target/TargetMachine.cpp
  llvm/lib/Target/X86/X86FastISel.cpp
  llvm/lib/Target/X86/X86ISelLowering.cpp
  llvm/lib/Target/X86/X86Subtarget.cpp
  llvm/test/CodeGen/X86/extern_weak.ll

Index: llvm/test/CodeGen/X86/extern_weak.ll
===================================================================
--- llvm/test/CodeGen/X86/extern_weak.ll
+++ llvm/test/CodeGen/X86/extern_weak.ll
@@ -1,13 +1,64 @@
-; RUN: llc < %s -mtriple=i686-apple-darwin | grep weak_reference | count 2
+; 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
 
-@Y = global i32 (i8*)* @X               ; <i32 (i8*)**> [#uses=0]
-
-declare extern_weak i32 @X(i8*)
+declare extern_weak void @foo(...)
 
 define void @bar() {
-        tail call void (...) @foo( )
-        ret void
+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
 }
 
-declare extern_weak void @foo(...)
+; 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
 
Index: llvm/lib/Target/X86/X86Subtarget.cpp
===================================================================
--- llvm/lib/Target/X86/X86Subtarget.cpp
+++ llvm/lib/Target/X86/X86Subtarget.cpp
@@ -176,10 +176,13 @@
   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);
Index: llvm/lib/Target/X86/X86ISelLowering.cpp
===================================================================
--- llvm/lib/Target/X86/X86ISelLowering.cpp
+++ llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -3967,10 +3967,10 @@
       Callee = DAG.getTargetGlobalAddress(
           GV, dl, getPointerTy(DAG.getDataLayout()), G->getOffset(), OpFlags);
 
-      if (OpFlags == X86II::MO_GOTPCREL) {
+      if (OpFlags == X86II::MO_GOTPCREL || OpFlags == X86II::MO_COFFSTUB) {
         // Add a wrapper.
-        Callee = DAG.getNode(X86ISD::WrapperRIP, dl,
-          getPointerTy(DAG.getDataLayout()), Callee);
+        Callee = DAG.getNode(getGlobalWrapperKind(), dl,
+                             getPointerTy(DAG.getDataLayout()), Callee);
         // Add extra indirection
         Callee = DAG.getLoad(
             getPointerTy(DAG.getDataLayout()), dl, DAG.getEntryNode(), Callee,
@@ -3985,9 +3985,9 @@
     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 (OpFlags == X86II::MO_GOTPCREL || OpFlags == X86II::MO_COFFSTUB) {
+      Callee = DAG.getNode(getGlobalWrapperKind(), dl,
+                           getPointerTy(DAG.getDataLayout()), Callee);
       Callee = DAG.getLoad(
           getPointerTy(DAG.getDataLayout()), dl, DAG.getEntryNode(), Callee,
           MachinePointerInfo::getGOT(DAG.getMachineFunction()));
Index: llvm/lib/Target/X86/X86FastISel.cpp
===================================================================
--- llvm/lib/Target/X86/X86FastISel.cpp
+++ llvm/lib/Target/X86/X86FastISel.cpp
@@ -3503,8 +3503,9 @@
 
     // 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);
Index: llvm/lib/Target/TargetMachine.cpp
===================================================================
--- llvm/lib/Target/TargetMachine.cpp
+++ llvm/lib/Target/TargetMachine.cpp
@@ -144,6 +144,12 @@
       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
Index: clang/test/CodeGen/dso-local-executable.c
===================================================================
--- clang/test/CodeGen/dso-local-executable.c
+++ 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()
Index: clang/lib/CodeGen/CodeGenModule.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenModule.cpp
+++ clang/lib/CodeGen/CodeGenModule.cpp
@@ -763,6 +763,13 @@
         !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
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to