Implement external weak (ELF) symbols on AArch64
authorTim Northover <Tim.Northover@arm.com>
Wed, 6 Feb 2013 16:43:33 +0000 (16:43 +0000)
committerTim Northover <Tim.Northover@arm.com>
Wed, 6 Feb 2013 16:43:33 +0000 (16:43 +0000)
Weakly defined symbols should evaluate to 0 if they're undefined at
link-time. This is impossible to do with the usual address generation
patterns, so we should use a literal pool entry to materlialise the
address.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@174518 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/AArch64/AArch64ISelLowering.cpp
lib/Target/AArch64/AArch64InstrInfo.td
test/CodeGen/AArch64/extern-weak.ll [new file with mode: 0644]

index e2e472fa9f81a9fb295079e2ab98a8ff81fc3a62..071b432998b826565bfdc70d3085680df180d1cb 100644 (file)
@@ -1863,7 +1863,7 @@ AArch64TargetLowering::LowerGlobalAddressELF(SDValue Op,
   // TableGen doesn't have easy access to the CodeModel or RelocationModel, so
   // we make that distinction here.
 
-  // We support the static, small memory model for now.
+  // We support the small memory model for now.
   assert(getTargetMachine().getCodeModel() == CodeModel::Small);
 
   EVT PtrVT = getPointerTy();
@@ -1871,6 +1871,18 @@ AArch64TargetLowering::LowerGlobalAddressELF(SDValue Op,
   const GlobalAddressSDNode *GN = cast<GlobalAddressSDNode>(Op);
   const GlobalValue *GV = GN->getGlobal();
   unsigned Alignment = GV->getAlignment();
+  Reloc::Model RelocM = getTargetMachine().getRelocationModel();
+
+  if (GV->isWeakForLinker() && RelocM == Reloc::Static) {
+    // Weak symbols can't use ADRP/ADD pair since they should evaluate to
+    // zero when undefined. In PIC mode the GOT can take care of this, but in
+    // absolute mode we use a constant pool load.
+    return DAG.getLoad(PtrVT, dl, DAG.getEntryNode(),
+                       DAG.getConstantPool(GV, GN->getValueType(0)),
+                       MachinePointerInfo::getConstantPool(),
+                       /*isVolatile=*/ false,  /*isNonTemporal=*/ true,
+                       /*isInvariant=*/ true, 8);
+  }
 
   if (Alignment == 0) {
     const PointerType *GVPtrTy = cast<PointerType>(GV->getType());
@@ -1886,7 +1898,6 @@ AArch64TargetLowering::LowerGlobalAddressELF(SDValue Op,
   }
 
   unsigned char HiFixup, LoFixup;
-  Reloc::Model RelocM = getTargetMachine().getRelocationModel();
   bool UseGOT = Subtarget->GVIsIndirectSymbol(GV, RelocM);
 
   if (UseGOT) {
index 538d4bdb325118ac3630ae0c0f993c3a0d30c897..a9ff02ae0a197a6d663942e110ffdd2ae1e81fc9 100644 (file)
@@ -2409,8 +2409,10 @@ class A64I_LDRlitSimple<bits<2> opc, bit v, RegisterClass OutReg,
                  "ldr\t$Rt, $Imm19", patterns, NoItinerary>;
 
 let mayLoad = 1 in {
-  def LDRw_lit : A64I_LDRlitSimple<0b00, 0b0, GPR32>;
-  def LDRx_lit : A64I_LDRlitSimple<0b01, 0b0, GPR64>;
+  def LDRw_lit : A64I_LDRlitSimple<0b00, 0b0, GPR32,
+                              [(set (i32 GPR32:$Rt), (load constpool:$Imm19))]>;
+  def LDRx_lit : A64I_LDRlitSimple<0b01, 0b0, GPR64,
+                              [(set (i64 GPR64:$Rt), (load constpool:$Imm19))]>;
 }
 
 def LDRs_lit  : A64I_LDRlitSimple<0b00, 0b1, FPR32,
diff --git a/test/CodeGen/AArch64/extern-weak.ll b/test/CodeGen/AArch64/extern-weak.ll
new file mode 100644 (file)
index 0000000..54baab2
--- /dev/null
@@ -0,0 +1,13 @@
+; RUN: llc -mtriple=aarch64-none-linux-gnu -o - < %s | FileCheck %s
+
+declare extern_weak i32 @var()
+
+define i32()* @foo() {
+; The usual ADRP/ADD pair can't be used for a weak reference because it must
+; evaluate to 0 if the symbol is undefined. We use a litpool entry.
+  ret i32()* @var
+; CHECK: ldr x0, .LCPI0_0
+
+; CHECK: .LCPI0_0:
+; CHECK-NEXT: .xword var
+}