[AsmPrinter][TLOF] ARM64 MachO support for replacing GOT equivalents
authorBruno Cardoso Lopes <bruno.cardoso@gmail.com>
Fri, 6 Mar 2015 13:48:45 +0000 (13:48 +0000)
committerBruno Cardoso Lopes <bruno.cardoso@gmail.com>
Fri, 6 Mar 2015 13:48:45 +0000 (13:48 +0000)
Follow up r230264 and add ARM64 support for replacing global GOT
equivalent symbol accesses by references to the GOT entry for the final
symbol instead, example:

-- before

   .globl  _foo
  _foo:
   .long   42

   .globl  _gotequivalent
  _gotequivalent:
   .quad   _foo

   .globl  _delta
  _delta:
   .long   _gotequivalent-_delta

-- after

   .globl  _foo
  _foo:
   .long   42

   .globl  _delta
  Ltmp3:
   .long _foo@GOT-Ltmp3

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

include/llvm/Target/TargetLoweringObjectFile.h
lib/CodeGen/AsmPrinter/AsmPrinter.cpp
lib/Target/AArch64/AArch64TargetObjectFile.cpp
lib/Target/AArch64/AArch64TargetObjectFile.h
lib/Target/X86/X86TargetObjectFile.cpp
lib/Target/X86/X86TargetObjectFile.h
test/MC/MachO/cstexpr-gotpcrel-64.ll [new file with mode: 0644]
test/MC/X86/cstexpr-gotpcrel.ll [deleted file]

index 57c2606edfa4444ad1a1c0f83577eda270f93a9d..b121fc6bce3b1ae9b4ce2e2201219e30913c13bf 100644 (file)
@@ -43,12 +43,14 @@ class TargetLoweringObjectFile : public MCObjectFileInfo {
 
 protected:
   bool SupportIndirectSymViaGOTPCRel;
+  bool SupportGOTPCRelWithOffset;
 
 public:
   MCContext &getContext() const { return *Ctx; }
 
   TargetLoweringObjectFile() : MCObjectFileInfo(), Ctx(nullptr), DL(nullptr),
-                               SupportIndirectSymViaGOTPCRel(false) {}
+                               SupportIndirectSymViaGOTPCRel(false),
+                               SupportGOTPCRelWithOffset(true) {}
 
   virtual ~TargetLoweringObjectFile();
 
@@ -168,9 +170,16 @@ public:
     return SupportIndirectSymViaGOTPCRel;
   }
 
+  /// \brief Target GOT "PC"-relative relocation supports encoding an additional
+  /// binary expression with an offset?
+  bool supportGOTPCRelWithOffset() const {
+    return SupportGOTPCRelWithOffset;
+  }
+
   /// \brief Get the target specific PC relative GOT entry relocation
   virtual const MCExpr *getIndirectSymViaGOTPCRel(const MCSymbol *Sym,
-                                                  int64_t Offset) const {
+                                                  int64_t Offset,
+                                                  MCStreamer &Streamer) const {
     return nullptr;
   }
 
index 569863315ac8ac0645d7949241ebbf37bb038d0b..22eae785c782f55055caffbdad545e209a1fc938 100644 (file)
@@ -2084,9 +2084,13 @@ static void handleIndirectSymViaGOTPCRel(AsmPrinter &AP, const MCExpr **ME,
   //
   //    gotpcrelcst := <offset from @foo base> + <cst>
   //
+  // Only encode <cst> if the target supports it.
+  //
   int64_t GOTPCRelCst = Offset + MV.getConstant();
   if (GOTPCRelCst < 0)
     return;
+  if (!AP.getObjFileLowering().supportGOTPCRelWithOffset() && GOTPCRelCst != 0)
+    return;
 
   // Emit the GOT PC relative to replace the got equivalent global, i.e.:
   //
@@ -2110,7 +2114,8 @@ static void handleIndirectSymViaGOTPCRel(AsmPrinter &AP, const MCExpr **ME,
   const GlobalValue *FinalGV = dyn_cast<GlobalValue>(GV->getOperand(0));
   const MCSymbol *FinalSym = AP.getSymbol(FinalGV);
   *ME = AP.getObjFileLowering().getIndirectSymViaGOTPCRel(FinalSym,
-                                                          GOTPCRelCst);
+                                                          GOTPCRelCst,
+                                                          AP.OutStreamer);
 
   // Update GOT equivalent usage information
   --NumUses;
index 4069038dffe70fe343f97237b718ec075a93c95a..3c0a3428ff394c09c059dde87f3a0c5a07f19d25 100644 (file)
@@ -23,6 +23,12 @@ void AArch64_ELFTargetObjectFile::Initialize(MCContext &Ctx,
   InitializeELF(TM.Options.UseInitArray);
 }
 
+AArch64_MachoTargetObjectFile::AArch64_MachoTargetObjectFile()
+  : TargetLoweringObjectFileMachO() {
+  SupportIndirectSymViaGOTPCRel = true;
+  SupportGOTPCRelWithOffset = false;
+}
+
 const MCExpr *AArch64_MachoTargetObjectFile::getTTypeGlobalReference(
     const GlobalValue *GV, unsigned Encoding, Mangler &Mang,
     const TargetMachine &TM, MachineModuleInfo *MMI,
@@ -50,3 +56,15 @@ MCSymbol *AArch64_MachoTargetObjectFile::getCFIPersonalitySymbol(
     MachineModuleInfo *MMI) const {
   return TM.getSymbol(GV, Mang);
 }
+
+const MCExpr *AArch64_MachoTargetObjectFile::getIndirectSymViaGOTPCRel(
+    const MCSymbol *Sym, int64_t Offset, MCStreamer &Streamer) const {
+  // On ARM64 Darwin, we can reference symbols with foo@GOT-., which
+  // is an indirect pc-relative reference.
+  const MCExpr *Res =
+      MCSymbolRefExpr::Create(Sym, MCSymbolRefExpr::VK_GOT, getContext());
+  MCSymbol *PCSym = getContext().CreateTempSymbol();
+  Streamer.EmitLabel(PCSym);
+  const MCExpr *PC = MCSymbolRefExpr::Create(PCSym, getContext());
+  return MCBinaryExpr::CreateSub(Res, PC, getContext());
+}
index 2e595f91961a2ef54d9e49cbb4fa509c34f3b06a..067fda5952b506a7ecdbfc9e58ef22654af63520 100644 (file)
@@ -24,6 +24,8 @@ class AArch64_ELFTargetObjectFile : public TargetLoweringObjectFileELF {
 /// AArch64_MachoTargetObjectFile - This TLOF implementation is used for Darwin.
 class AArch64_MachoTargetObjectFile : public TargetLoweringObjectFileMachO {
 public:
+  AArch64_MachoTargetObjectFile();
+
   const MCExpr *getTTypeGlobalReference(const GlobalValue *GV,
                                         unsigned Encoding, Mangler &Mang,
                                         const TargetMachine &TM,
@@ -33,6 +35,10 @@ public:
   MCSymbol *getCFIPersonalitySymbol(const GlobalValue *GV, Mangler &Mang,
                                     const TargetMachine &TM,
                                     MachineModuleInfo *MMI) const override;
+
+  const MCExpr *
+    getIndirectSymViaGOTPCRel(const MCSymbol *Sym, int64_t Offset,
+                              MCStreamer &Streamer) const override;
 };
 
 } // end namespace llvm
index 16ce736588338c0e9bdb92c36222ce4b2c0f6392..15a5fddd8629c46be29d9b427c85a33c5d4ef813 100644 (file)
@@ -52,7 +52,7 @@ MCSymbol *X86_64MachoTargetObjectFile::getCFIPersonalitySymbol(
 }
 
 const MCExpr *X86_64MachoTargetObjectFile::getIndirectSymViaGOTPCRel(
-    const MCSymbol *Sym, int64_t Offset) const {
+    const MCSymbol *Sym, int64_t Offset, MCStreamer &Streamer) const {
   // On Darwin/X86-64, we need to use foo@GOTPCREL+4 to access the got entry
   // from a data section. In case there's an additional offset, then use
   // foo@GOTPCREL+4+<offset>.
index a92c122838e312a1131d533142455024d87da6e1..3c7caabdfdcac5579289cc94b315048dd5e92778 100644 (file)
@@ -34,8 +34,8 @@ namespace llvm {
                                       MachineModuleInfo *MMI) const override;
 
     const MCExpr *
-      getIndirectSymViaGOTPCRel(const MCSymbol *Sym,
-                                int64_t Offset) const override;
+      getIndirectSymViaGOTPCRel(const MCSymbol *Sym, int64_t Offset,
+                                MCStreamer &Streamer) const override;
   };
 
   /// \brief This implemenatation is used for X86 ELF targets that don't
diff --git a/test/MC/MachO/cstexpr-gotpcrel-64.ll b/test/MC/MachO/cstexpr-gotpcrel-64.ll
new file mode 100644 (file)
index 0000000..56862fe
--- /dev/null
@@ -0,0 +1,114 @@
+; RUN: llc -mtriple=x86_64-apple-darwin %s -o %t
+; RUN:  FileCheck %s -check-prefix=X86 < %t
+; RUN:  FileCheck %s -check-prefix=X86-GOT-EQUIV < %t
+; RUN: llc -mtriple=arm64-apple-darwin %s -o %t
+; RUN:  FileCheck %s -check-prefix=ARM < %t
+; RUN:  FileCheck %s -check-prefix=ARM-GOT-EQUIV < %t
+
+; GOT equivalent globals references can be replaced by the GOT entry of the
+; final symbol instead.
+
+%struct.data = type { i32, %struct.anon }
+%struct.anon = type { i32, i32 }
+
+; Check that these got equivalent symbols are never emitted on x86-64 and
+; emitted on ARM64. Since ARM64 does not support encoding an extra offset with
+; @GOT, we still need to emit the equivalents for use by such IR constructs.
+
+; X86-GOT-EQUIV-NOT: L_localgotequiv
+; X86-GOT-EQUIV-NOT: l_extgotequiv
+
+; ARM-GOT-EQUIV-LABEL: l_extgotequiv:
+; ARM-GOT-EQUIV-LABEL: l_localgotequiv:
+@localfoo = global i32 42
+@localgotequiv = private unnamed_addr constant i32* @localfoo
+
+@extfoo = external global i32
+@extgotequiv = private unnamed_addr constant i32* @extfoo
+
+; Don't replace GOT equivalent usage within instructions and emit the GOT
+; equivalent since it can't be replaced by the GOT entry. @bargotequiv is
+; used by an instruction inside @t0.
+;
+; X86: l_bargotequiv:
+; X86-NEXT:  .quad   _extbar
+; ARM: l_bargotequiv:
+; ARM-NEXT:  .quad   _extbar
+@extbar = external global i32
+@bargotequiv = private unnamed_addr constant i32* @extbar
+
+@table = global [4 x %struct.data] [
+; X86-LABEL: _table
+; ARM-LABEL: _table
+  %struct.data { i32 1, %struct.anon { i32 2, i32 3 } },
+; Test GOT equivalent usage inside nested constant arrays.
+
+; X86: .long   5
+; X86-NOT: .long   _localgotequiv-(_table+20)
+; X86-NEXT: .long   _localfoo@GOTPCREL+4
+
+; ARM: .long   5
+; ARM-NOT: .long   _localgotequiv-(_table+20)
+; ARM-NEXT: Ltmp1:
+; ARM-NEXT: .long _localfoo@GOT-Ltmp1
+  %struct.data { i32 4, %struct.anon { i32 5,
+    i32 trunc (i64 sub (i64 ptrtoint (i32** @localgotequiv to i64),
+                        i64 ptrtoint (i32* getelementptr inbounds ([4 x %struct.data]* @table, i32 0, i64 1, i32 1, i32 1) to i64))
+                        to i32)}
+  },
+; X86: .long   5
+; X86-NOT: _extgotequiv-(_table+32)
+; X86-NEXT: .long   _extfoo@GOTPCREL+4
+
+; ARM: .long   5
+; ARM-NOT: _extgotequiv-(_table+32)
+; ARM-NEXT: Ltmp2:
+; ARM-NEXT: _extfoo@GOT-Ltmp2
+  %struct.data { i32 4, %struct.anon { i32 5,
+    i32 trunc (i64 sub (i64 ptrtoint (i32** @extgotequiv to i64),
+                        i64 ptrtoint (i32* getelementptr inbounds ([4 x %struct.data]* @table, i32 0, i64 2, i32 1, i32 1) to i64))
+                        to i32)}
+  },
+; Test support for arbitrary constants into the GOTPCREL offset, which is
+; supported on x86-64 but not on ARM64
+
+; X86: .long   5
+; X86-NOT: _extgotequiv-(_table+44)
+; X86-NEXT: .long   _extfoo@GOTPCREL+28
+
+; ARM: .long   5
+; ARM-NEXT: .long (l_extgotequiv-(_table+44))+24
+  %struct.data { i32 4, %struct.anon { i32 5,
+    i32 add (i32 trunc (i64 sub (i64 ptrtoint (i32** @extgotequiv to i64),
+                                 i64 ptrtoint (i32* getelementptr inbounds ([4 x %struct.data]* @table, i32 0, i64 3, i32 1, i32 1) to i64))
+                                 to i32), i32 24)}
+  }
+], align 16
+
+; Test multiple uses of GOT equivalents.
+
+; X86-LABEL: _delta
+; X86: .long   _extfoo@GOTPCREL+4
+
+; ARM-LABEL: _delta
+; ARM: Ltmp3:
+; ARM-NEXT:  .long _extfoo@GOT-Ltmp3
+@delta = global i32 trunc (i64 sub (i64 ptrtoint (i32** @extgotequiv to i64),
+                                    i64 ptrtoint (i32* @delta to i64))
+                           to i32)
+
+; X86-LABEL: _deltaplus:
+; X86: .long   _localfoo@GOTPCREL+59
+
+; ARM-LABEL: _deltaplus:
+; ARM: .long  (l_localgotequiv-_deltaplus)+55
+@deltaplus = global i32 add (i32 trunc (i64 sub (i64 ptrtoint (i32** @localgotequiv to i64),
+                                        i64 ptrtoint (i32* @deltaplus to i64))
+                                        to i32), i32 55)
+
+define i32 @t0(i32 %a) {
+  %x = add i32 trunc (i64 sub (i64 ptrtoint (i32** @bargotequiv to i64),
+                               i64 ptrtoint (i32 (i32)* @t0 to i64))
+                           to i32), %a
+  ret i32 %x
+}
diff --git a/test/MC/X86/cstexpr-gotpcrel.ll b/test/MC/X86/cstexpr-gotpcrel.ll
deleted file mode 100644 (file)
index 82da870..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-; RUN: llc -mtriple=x86_64-apple-darwin %s -o %t
-; RUN: FileCheck %s < %t
-; RUN: FileCheck %s -check-prefix=GOT-EQUIV < %t
-
-; GOT equivalent globals references can be replaced by the GOT entry of the
-; final symbol instead.
-
-%struct.data = type { i32, %struct.anon }
-%struct.anon = type { i32, i32 }
-
-; Check that these got equivalent symbols are never emitted or used
-; GOT-EQUIV-NOT: _localgotequiv
-; GOT-EQUIV-NOT: _extgotequiv
-@localfoo = global i32 42
-@localgotequiv = private unnamed_addr constant i32* @localfoo
-
-@extfoo = external global i32
-@extgotequiv = private unnamed_addr constant i32* @extfoo
-
-; Don't replace GOT equivalent usage within instructions and emit the GOT
-; equivalent since it can't be replaced by the GOT entry. @bargotequiv is
-; used by an instruction inside @t0.
-;
-; CHECK: l_bargotequiv:
-; CHECK-NEXT:  .quad   _extbar
-@extbar = external global i32
-@bargotequiv = private unnamed_addr constant i32* @extbar
-
-@table = global [4 x %struct.data] [
-; CHECK-LABEL: _table
-  %struct.data { i32 1, %struct.anon { i32 2, i32 3 } },
-; Test GOT equivalent usage inside nested constant arrays.
-; CHECK: .long   5
-; CHECK-NOT: .long   _localgotequiv-(_table+20)
-; CHECK-NEXT: .long   _localfoo@GOTPCREL+4
-  %struct.data { i32 4, %struct.anon { i32 5,
-    i32 trunc (i64 sub (i64 ptrtoint (i32** @localgotequiv to i64),
-                        i64 ptrtoint (i32* getelementptr inbounds ([4 x %struct.data]* @table, i32 0, i64 1, i32 1, i32 1) to i64))
-                        to i32)}
-  },
-; CHECK: .long   5
-; CHECK-NOT: _extgotequiv-(_table+32)
-; CHECK-NEXT: .long   _extfoo@GOTPCREL+4
-  %struct.data { i32 4, %struct.anon { i32 5,
-    i32 trunc (i64 sub (i64 ptrtoint (i32** @extgotequiv to i64),
-                        i64 ptrtoint (i32* getelementptr inbounds ([4 x %struct.data]* @table, i32 0, i64 2, i32 1, i32 1) to i64))
-                        to i32)}
-  },
-; Test support for arbitrary constants into the GOTPCREL offset
-; CHECK: .long   5
-; CHECK-NOT: _extgotequiv-(_table+44)
-; CHECK-NEXT: .long   _extfoo@GOTPCREL+28
-  %struct.data { i32 4, %struct.anon { i32 5,
-    i32 add (i32 trunc (i64 sub (i64 ptrtoint (i32** @extgotequiv to i64),
-                                 i64 ptrtoint (i32* getelementptr inbounds ([4 x %struct.data]* @table, i32 0, i64 3, i32 1, i32 1) to i64))
-                                 to i32), i32 24)}
-  }
-], align 16
-
-; Test multiple uses of GOT equivalents.
-; CHECK-LABEL: _delta
-; CHECK: .long   _extfoo@GOTPCREL+4
-@delta = global i32 trunc (i64 sub (i64 ptrtoint (i32** @extgotequiv to i64),
-                                    i64 ptrtoint (i32* @delta to i64))
-                           to i32)
-
-; CHECK-LABEL: _deltaplus:
-; CHECK: .long   _localfoo@GOTPCREL+59
-@deltaplus = global i32 add (i32 trunc (i64 sub (i64 ptrtoint (i32** @localgotequiv to i64),
-                                        i64 ptrtoint (i32* @deltaplus to i64))
-                                        to i32), i32 55)
-
-define i32 @t0(i32 %a) {
-  %x = add i32 trunc (i64 sub (i64 ptrtoint (i32** @bargotequiv to i64),
-                               i64 ptrtoint (i32 (i32)* @t0 to i64))
-                           to i32), %a
-  ret i32 %x
-}