Index: lib/CodeGen/AsmPrinter/AsmPrinter.cpp =================================================================== --- lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -2243,6 +2243,45 @@ AP.GlobalGOTEquivs[GOTEquivSym] = std::make_pair(GV, NumUses); } +/// \brief Transform a not absolute MCExpr `something - foo + N` to +/// PC-relative `something - . + M` if we're based on `foo`. +static void handleRelativeSymViaPCRel(AsmPrinter &AP, const MCExpr **ME, + const Constant *BaseCst, + uint64_t Offset) { + MCValue MV; + if (!(*ME)->evaluateAsRelocatable(MV, nullptr, nullptr) || MV.isAbsolute()) + return; + const MCSymbolRefExpr *SymA = MV.getSymA(); + if (!SymA) + return; + + const GlobalValue *BaseGV = dyn_cast_or_null(BaseCst); + if (!BaseGV) + return; + + const MCSymbol *BaseSym = AP.getSymbol(BaseGV); + const MCSymbolRefExpr *SymB = MV.getSymB(); + + if (!SymB || BaseSym != &SymB->getSymbol()) + return; + + int64_t PCRelCst = Offset + MV.getConstant(); + + // Emit a local symbol for the current position to base the rewritten + // reference on. + MCSymbol *PCSym = AP.OutContext.createTempSymbol(); + AP.OutStreamer->EmitLabel(PCSym); + + const MCExpr *PCSymRef = MCSymbolRefExpr::create(PCSym, AP.OutContext); + const MCExpr *PCRelRef + = MCBinaryExpr::createSub(SymA, PCSymRef, AP.OutContext); + if (PCRelCst != 0) { + const MCExpr *Cst = MCConstantExpr::create(PCRelCst, AP.OutContext); + PCRelRef = MCBinaryExpr::createAdd(PCRelRef, Cst, AP.OutContext); + } + *ME = PCRelRef; +} + static void emitGlobalConstantImpl(const DataLayout &DL, const Constant *CV, AsmPrinter &AP, const Constant *BaseCV, uint64_t Offset) { @@ -2320,6 +2359,9 @@ if (AP.getObjFileLowering().supportIndirectSymViaGOTPCRel()) handleIndirectSymViaGOTPCRel(AP, &ME, BaseCV, Offset); + if (BaseCV) + handleRelativeSymViaPCRel(AP, &ME, BaseCV, Offset); + AP.OutStreamer->EmitValue(ME, Size); } Index: test/MC/COFF/cross-section-relative.ll =================================================================== --- test/MC/COFF/cross-section-relative.ll +++ test/MC/COFF/cross-section-relative.ll @@ -11,13 +11,21 @@ ;;;; cross-section relative relocations -; CHECK: .quad (g3-t1)+4 +; CHECK: t1: +; CHECK-NEXT: [[PC:\.Ltmp.*]]: +; CHECK-NEXT: .quad (g3-[[PC]])+4 @t1 = global i64 add(i64 sub(i64 ptrtoint(i32* @g3 to i64), i64 ptrtoint(i64* @t1 to i64)), i64 4), section ".fix" -; CHECK: .quad g3-t2 +; CHECK: t2: +; CHECK-NEXT: [[PC:\.Ltmp.*]]: +; CHECK-NEXT: .quad g3-[[PC]] @t2 = global i64 sub(i64 ptrtoint(i32* @g3 to i64), i64 ptrtoint(i64* @t2 to i64)), section ".fix" -; CHECK: .quad (g3-t3)-4 +; CHECK: t3: +; CHECK-NEXT: [[PC:\.Ltmp.*]]: +; CHECK-NEXT: .quad (g3-[[PC]])-4 @t3 = global i64 sub(i64 sub(i64 ptrtoint(i32* @g3 to i64), i64 ptrtoint(i64* @t3 to i64)), i64 4), section ".fix" -; CHECK: .long g3-t4 +; CHECK: t4: +; CHECK-NEXT: [[PC:\.Ltmp.*]]: +; CHECK: .long g3-[[PC]] @t4 = global i32 trunc(i64 sub(i64 ptrtoint(i32* @g3 to i64), i64 ptrtoint(i32* @t4 to i64)) to i32), section ".fix" ;;;; image base relocation @@ -29,7 +37,9 @@ %struct.EEType = type { [2 x i8], i64, i32} -; CHECK: .long g3-(t6+16) +; CHECK: t6: +; CHECK: [[PC:\.Ltmp.*]]: +; CHECK: .long g3-[[PC]] @t6 = global %struct.EEType { [2 x i8] c"\01\02", i64 256, Index: test/MC/ELF/cstexpr-pcrel.ll =================================================================== --- /dev/null +++ test/MC/ELF/cstexpr-pcrel.ll @@ -0,0 +1,15 @@ +; RUN: llc -mtriple=x86_64-pc-linux %s -o %t +; RUN: FileCheck %s < %t + +; CHECK-LABEL: {{^}}foo: +; CHECK-NEXT: [[PC1:\.Ltmp.*]]: +; CHECK-NEXT: .long .Lbar-[[PC1]] +; CHECK-NEXT: [[PC2:\.Ltmp.*]]: +; CHECK-NEXT: .long (.Lbar-[[PC2]])+4 +; CHECK-NEXT: [[PC3:\.Ltmp.*]]: +; CHECK-NEXT: .long .Lbar-.Ltmp2 + +@foo = linkonce_odr constant [3 x i32] [i32 trunc (i64 sub (i64 ptrtoint ([5 x i8]* @bar to i64), i64 ptrtoint ([3 x i32]* @foo to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint ([5 x i8]* @bar to i64), i64 ptrtoint ([3 x i32]* @foo to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint ([5 x i8]* @bar to i64), i64 ptrtoint (i32* getelementptr ([3 x i32], [3 x i32]* @foo, i32 0, i32 2) to i64)) to i32)] + +@bar = private unnamed_addr constant [5 x i8] c"abcd\00" + Index: test/MC/MachO/AArch64/cstexpr-gotpcrel.ll =================================================================== --- test/MC/MachO/AArch64/cstexpr-gotpcrel.ll +++ test/MC/MachO/AArch64/cstexpr-gotpcrel.ll @@ -49,7 +49,8 @@ ; supported on x86-64 but not on ARM64 ; CHECK: .long 5 -; CHECK-NEXT: .long (l_extgotequiv-(_table+44))+24 +; CHECK-NEXT: Ltmp3: +; CHECK-NEXT: .long (l_extgotequiv-Ltmp3)+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], [4 x %struct.data]* @table, i32 0, i64 3, i32 1, i32 1) to i64)) @@ -60,14 +61,15 @@ ; Test multiple uses of GOT equivalents. ; CHECK-LABEL: _delta -; CHECK: Ltmp3: -; CHECK-NEXT: .long _extfoo@GOT-Ltmp3 +; CHECK: Ltmp4: +; CHECK-NEXT: .long _extfoo@GOT-Ltmp4 @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 (l_localgotequiv-_deltaplus)+55 +; CHECK-NEXT: Ltmp5: +; CHECK: .long (l_localgotequiv-Ltmp5)+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) Index: test/MC/MachO/ARM/cstexpr-gotpcrel.ll =================================================================== --- test/MC/MachO/ARM/cstexpr-gotpcrel.ll +++ test/MC/MachO/ARM/cstexpr-gotpcrel.ll @@ -31,23 +31,26 @@ %struct.data { i32 1, %struct.anon { i32 2, i32 3 } }, ; Test GOT equivalent usage inside nested constant arrays. ; CHECK: .long 5 -; CHECK-NOT: l_localgotequiv-(_table+20) -; CHECK-NEXT: L_localfoo$non_lazy_ptr-(_table+20) +; CHECK-NEXT: Ltmp0: +; CHECK-NOT: l_localgotequiv-Ltmp0 +; CHECK-NEXT: L_localfoo$non_lazy_ptr-Ltmp0 %struct.data { i32 4, %struct.anon { i32 5, i32 sub (i32 ptrtoint (i32** @localgotequiv to i32), i32 ptrtoint (i32* getelementptr inbounds ([4 x %struct.data], [4 x %struct.data]* @table, i32 0, i32 1, i32 1, i32 1) to i32))} }, ; CHECK: .long 5 -; CHECK-NOT: l_extgotequiv-(_table+32) -; CHECK-NEXT: L_extfoo$non_lazy_ptr-(_table+32) +; CHECK-NEXT: Ltmp1: +; CHECK-NOT: l_extgotequiv-Ltmp1 +; CHECK-NEXT: L_extfoo$non_lazy_ptr-Ltmp1 %struct.data { i32 4, %struct.anon { i32 5, i32 sub (i32 ptrtoint (i32** @extgotequiv to i32), i32 ptrtoint (i32* getelementptr inbounds ([4 x %struct.data], [4 x %struct.data]* @table, i32 0, i32 2, i32 1, i32 1) to i32))} }, ; Test support for arbitrary constants into the GOTPCREL offset ; CHECK: .long 5 -; CHECK-NOT: (l_extgotequiv-(_table+44))+24 -; CHECK-NEXT: L_extfoo$non_lazy_ptr-(_table+20) +; CHECK-NEXT: Ltmp2: +; CHECK-NOT: (l_extgotequiv-Ltmp2)+24 +; CHECK-NEXT: (L_extfoo$non_lazy_ptr-Ltmp2)+24 %struct.data { i32 4, %struct.anon { i32 5, i32 add (i32 sub (i32 ptrtoint (i32** @extgotequiv to i32), i32 ptrtoint (i32* getelementptr inbounds ([4 x %struct.data], [4 x %struct.data]* @table, i32 0, i32 3, i32 1, i32 1) to i32)), @@ -56,13 +59,15 @@ ], align 16 ; Test multiple uses of GOT equivalents. -; CHECK-LABEL: _delta -; CHECK: .long L_extfoo$non_lazy_ptr-_delta +; CHECK-LABEL: _delta: +; CHECK-NEXT: Ltmp3: +; CHECK-NEXT: .long L_extfoo$non_lazy_ptr-Ltmp3 @delta = global i32 sub (i32 ptrtoint (i32** @extgotequiv to i32), i32 ptrtoint (i32* @delta to i32)) ; CHECK-LABEL: _deltaplus: -; CHECK: .long L_localfoo$non_lazy_ptr-(_deltaplus-55) +; CHECK-NEXT: Ltmp4: +; CHECK-NEXT: .long (L_localfoo$non_lazy_ptr-Ltmp4)+55 @deltaplus = global i32 add (i32 sub (i32 ptrtoint (i32** @localgotequiv to i32), i32 ptrtoint (i32* @deltaplus to i32)), i32 55) Index: test/MC/MachO/cstexpr-gotpcrel-32.ll =================================================================== --- test/MC/MachO/cstexpr-gotpcrel-32.ll +++ test/MC/MachO/cstexpr-gotpcrel-32.ll @@ -30,24 +30,27 @@ ; 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: l_localgotequiv-(_table+20) -; CHECK-NEXT: L_localfoo$non_lazy_ptr-(_table+20) +; CHECK: .long 5 +; CHECK-NEXT: Ltmp0: +; CHECK-NOT: l_localgotequiv-Ltmp0 +; CHECK-NEXT: L_localfoo$non_lazy_ptr-Ltmp0 %struct.data { i32 4, %struct.anon { i32 5, i32 sub (i32 ptrtoint (i32** @localgotequiv to i32), i32 ptrtoint (i32* getelementptr inbounds ([4 x %struct.data], [4 x %struct.data]* @table, i32 0, i32 1, i32 1, i32 1) to i32))} }, -; CHECK: .long 5 -; CHECK-NOT: l_extgotequiv-(_table+32) -; CHECK-NEXT: L_extfoo$non_lazy_ptr-(_table+32) +; CHECK: .long 5 +; CHECK-NEXT: Ltmp1: +; CHECK-NOT: l_extgotequiv-Ltmp1 +; CHECK-NEXT: L_extfoo$non_lazy_ptr-Ltmp1 %struct.data { i32 4, %struct.anon { i32 5, i32 sub (i32 ptrtoint (i32** @extgotequiv to i32), i32 ptrtoint (i32* getelementptr inbounds ([4 x %struct.data], [4 x %struct.data]* @table, i32 0, i32 2, i32 1, i32 1) to i32))} }, ; Test support for arbitrary constants into the GOTPCREL offset -; CHECK: .long 5 -; CHECK-NOT: (l_extgotequiv-(_table+44))+24 -; CHECK-NEXT: L_extfoo$non_lazy_ptr-(_table+20) +; CHECK: .long 5 +; CHECK-NEXT: Ltmp2: +; CHECK-NOT: (l_extgotequiv-Ltmp2)+24 +; CHECK-NEXT: (L_extfoo$non_lazy_ptr-Ltmp2)+24 %struct.data { i32 4, %struct.anon { i32 5, i32 add (i32 sub (i32 ptrtoint (i32** @extgotequiv to i32), i32 ptrtoint (i32* getelementptr inbounds ([4 x %struct.data], [4 x %struct.data]* @table, i32 0, i32 3, i32 1, i32 1) to i32)), @@ -56,13 +59,15 @@ ], align 16 ; Test multiple uses of GOT equivalents. -; CHECK-LABEL: _delta -; CHECK: .long L_extfoo$non_lazy_ptr-_delta +; CHECK-LABEL: _delta: +; CHECK-NEXT: Ltmp3: +; CHECK-NEXT: .long L_extfoo$non_lazy_ptr-Ltmp3 @delta = global i32 sub (i32 ptrtoint (i32** @extgotequiv to i32), i32 ptrtoint (i32* @delta to i32)) ; CHECK-LABEL: _deltaplus: -; CHECK: .long L_localfoo$non_lazy_ptr-(_deltaplus-55) +; CHECK-NEXT: Ltmp4: +; CHECK-NEXT: .long (L_localfoo$non_lazy_ptr-Ltmp4)+55 @deltaplus = global i32 add (i32 sub (i32 ptrtoint (i32** @localgotequiv to i32), i32 ptrtoint (i32* @deltaplus to i32)), i32 55)