diff --git a/llvm/include/llvm/Target/TargetLoweringObjectFile.h b/llvm/include/llvm/Target/TargetLoweringObjectFile.h index 57c2606edfa4..b121fc6bce3b 100644 --- a/llvm/include/llvm/Target/TargetLoweringObjectFile.h +++ b/llvm/include/llvm/Target/TargetLoweringObjectFile.h @@ -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; } diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index 569863315ac8..22eae785c782 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -2084,9 +2084,13 @@ static void handleIndirectSymViaGOTPCRel(AsmPrinter &AP, const MCExpr **ME, // // gotpcrelcst := + // + // Only encode 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(GV->getOperand(0)); const MCSymbol *FinalSym = AP.getSymbol(FinalGV); *ME = AP.getObjFileLowering().getIndirectSymViaGOTPCRel(FinalSym, - GOTPCRelCst); + GOTPCRelCst, + AP.OutStreamer); // Update GOT equivalent usage information --NumUses; diff --git a/llvm/lib/Target/AArch64/AArch64TargetObjectFile.cpp b/llvm/lib/Target/AArch64/AArch64TargetObjectFile.cpp index 4069038dffe7..3c0a3428ff39 100644 --- a/llvm/lib/Target/AArch64/AArch64TargetObjectFile.cpp +++ b/llvm/lib/Target/AArch64/AArch64TargetObjectFile.cpp @@ -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()); +} diff --git a/llvm/lib/Target/AArch64/AArch64TargetObjectFile.h b/llvm/lib/Target/AArch64/AArch64TargetObjectFile.h index 2e595f91961a..067fda5952b5 100644 --- a/llvm/lib/Target/AArch64/AArch64TargetObjectFile.h +++ b/llvm/lib/Target/AArch64/AArch64TargetObjectFile.h @@ -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 diff --git a/llvm/lib/Target/X86/X86TargetObjectFile.cpp b/llvm/lib/Target/X86/X86TargetObjectFile.cpp index 16ce73658833..15a5fddd8629 100644 --- a/llvm/lib/Target/X86/X86TargetObjectFile.cpp +++ b/llvm/lib/Target/X86/X86TargetObjectFile.cpp @@ -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+. diff --git a/llvm/lib/Target/X86/X86TargetObjectFile.h b/llvm/lib/Target/X86/X86TargetObjectFile.h index a92c122838e3..3c7caabdfdca 100644 --- a/llvm/lib/Target/X86/X86TargetObjectFile.h +++ b/llvm/lib/Target/X86/X86TargetObjectFile.h @@ -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/llvm/test/MC/X86/cstexpr-gotpcrel.ll b/llvm/test/MC/MachO/cstexpr-gotpcrel-64.ll similarity index 58% rename from llvm/test/MC/X86/cstexpr-gotpcrel.ll rename to llvm/test/MC/MachO/cstexpr-gotpcrel-64.ll index 82da87090479..56862fe50738 100644 --- a/llvm/test/MC/X86/cstexpr-gotpcrel.ll +++ b/llvm/test/MC/MachO/cstexpr-gotpcrel-64.ll @@ -1,6 +1,9 @@ ; RUN: llc -mtriple=x86_64-apple-darwin %s -o %t -; RUN: FileCheck %s < %t -; RUN: FileCheck %s -check-prefix=GOT-EQUIV < %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. @@ -8,9 +11,15 @@ %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 +; 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 @@ -21,35 +30,54 @@ ; 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 +; 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] [ -; CHECK-LABEL: _table +; X86-LABEL: _table +; ARM-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 + +; 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)} }, -; CHECK: .long 5 -; CHECK-NOT: _extgotequiv-(_table+32) -; CHECK-NEXT: .long _extfoo@GOTPCREL+4 +; 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 -; CHECK: .long 5 -; CHECK-NOT: _extgotequiv-(_table+44) -; CHECK-NEXT: .long _extfoo@GOTPCREL+28 +; 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)) @@ -58,14 +86,22 @@ ], align 16 ; Test multiple uses of GOT equivalents. -; CHECK-LABEL: _delta -; CHECK: .long _extfoo@GOTPCREL+4 + +; 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) -; CHECK-LABEL: _deltaplus: -; CHECK: .long _localfoo@GOTPCREL+59 +; 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)