[ARM] [Windows] Use COFF stubs for calls to extern_weak functions
authorMartin Storsjö <martin@martin.st>
Thu, 19 Dec 2019 12:00:44 +0000 (14:00 +0200)
committerMartin Storsjö <martin@martin.st>
Mon, 23 Dec 2019 10:13:49 +0000 (12:13 +0200)
As the extern_weak target might be missing, resolving to the absolute
address zero, we can't use the normal direct PC-relative branch
instructions (as that would result in relocations out of range).

Instead check the shouldAssumeDSOLocal method and load the address
from a COFF stub.

This matches what was done for X86 in 6bf108d77a3c.

Differential Revision: https://reviews.llvm.org/D71720

llvm/lib/Target/ARM/ARMISelLowering.cpp
llvm/test/CodeGen/ARM/tail-call-weak.ll

index 0b4d39e..bfc78a9 100644 (file)
@@ -2356,12 +2356,14 @@ ARMTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
       } else if (Subtarget->isTargetCOFF()) {
         assert(Subtarget->isTargetWindows() &&
                "Windows is the only supported COFF target");
-        unsigned TargetFlags = GV->hasDLLImportStorageClass()
-                                   ? ARMII::MO_DLLIMPORT
-                                   : ARMII::MO_NO_FLAG;
+        unsigned TargetFlags = ARMII::MO_NO_FLAG;
+        if (GV->hasDLLImportStorageClass())
+          TargetFlags = ARMII::MO_DLLIMPORT;
+        else if (!TM.shouldAssumeDSOLocal(*GV->getParent(), GV))
+          TargetFlags = ARMII::MO_COFFSTUB;
         Callee = DAG.getTargetGlobalAddress(GV, dl, PtrVt, /*offset=*/0,
                                             TargetFlags);
-        if (GV->hasDLLImportStorageClass())
+        if (TargetFlags & (ARMII::MO_DLLIMPORT | ARMII::MO_COFFSTUB))
           Callee =
               DAG.getLoad(PtrVt, dl, DAG.getEntryNode(),
                           DAG.getNode(ARMISD::Wrapper, dl, PtrVt, Callee),
index e0117df..04ba510 100644 (file)
@@ -5,14 +5,17 @@
 declare i8* @f()
 declare extern_weak i8* @g(i8*)
 
-; weak symbol resolution occurs statically in PE/COFF, ensure that we permit
-; tail calls on weak externals when targeting a COFF environment.
 define void @test() {
   %call = tail call i8* @f()
   %call1 = tail call i8* @g(i8* %call)
   ret void
 }
 
-; CHECK-COFF: b g
+; CHECK-COFF: movw r0, :lower16:.refptr.g
+; CHECK-COFF: movt r0, :upper16:.refptr.g
+; CHECK-COFF: ldr r4, [r0]
+; CHECK-COFF: mov r1, r4
+; CHECK-COFF: bx r1
+
 ; CHECK-OTHER: bl {{_?}}g