[lld] r360112 - [PPC64] toc-indirect to toc-relative relaxation

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Mon May 6 21:26:05 PDT 2019


Author: maskray
Date: Mon May  6 21:26:05 2019
New Revision: 360112

URL: http://llvm.org/viewvc/llvm-project?rev=360112&view=rev
Log:
[PPC64] toc-indirect to toc-relative relaxation

This is based on D54720 by Sean Fertile.

When accessing a global symbol which is not defined in the translation unit,
compilers will generate instructions that load the address from the toc entry.

If the symbol is defined, non-preemptable, and addressable with a 32-bit
signed offset from the toc pointer, the address can be computed
directly. e.g.

    addis 3, 2, .LC0 at toc@ha  # R_PPC64_TOC16_HA
    ld    3, .LC0 at toc@l(3)   # R_PPC64_TOC16_LO_DS, load the address from a .toc entry
    ld/lwa 3, 0(3)           # load the value from the address

    .section .toc,"aw", at progbits
    .LC0: .tc var[TC],var

can be relaxed to

    addis 3,2,var at toc@ha     # this may be relaxed to a nop,
    addi  3,3,var at toc@l      # then this becomes addi 3,2,var at toc
    ld/lwa 3, 0(3)           # load the value from the address

We can delete the test ppc64-got-indirect.s as its purpose is covered by
newly added ppc64-toc-relax.s and ppc64-toc-relax-constants.s

Reviewed By: ruiu, sfertile

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

Added:
    lld/trunk/test/ELF/Inputs/ppc64-toc-relax-shared.s
    lld/trunk/test/ELF/Inputs/ppc64-toc-relax.s
    lld/trunk/test/ELF/ppc64-toc-relax-constants.s
    lld/trunk/test/ELF/ppc64-toc-relax-jumptable.s
    lld/trunk/test/ELF/ppc64-toc-relax.s
Removed:
    lld/trunk/test/ELF/ppc64-got-indirect.s
Modified:
    lld/trunk/ELF/Arch/PPC64.cpp
    lld/trunk/ELF/Arch/X86_64.cpp
    lld/trunk/ELF/InputSection.cpp
    lld/trunk/ELF/Relocations.cpp
    lld/trunk/ELF/Relocations.h
    lld/trunk/ELF/Target.cpp
    lld/trunk/ELF/Target.h
    lld/trunk/test/ELF/ppc64-func-entry-points.s
    lld/trunk/test/ELF/ppc64-relocs.s

Modified: lld/trunk/ELF/Arch/PPC64.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Arch/PPC64.cpp?rev=360112&r1=360111&r2=360112&view=diff
==============================================================================
--- lld/trunk/ELF/Arch/PPC64.cpp (original)
+++ lld/trunk/ELF/Arch/PPC64.cpp Mon May  6 21:26:05 2019
@@ -103,6 +103,88 @@ bool elf::isPPC64SmallCodeModelTocReloc(
   return Type == R_PPC64_TOC16 || Type == R_PPC64_TOC16_DS;
 }
 
+// Find the R_PPC64_ADDR64 in .rela.toc with matching offset.
+template <typename ELFT>
+static std::pair<Defined *, int64_t>
+getRelaTocSymAndAddend(InputSectionBase *TocSec, uint64_t Offset) {
+  if (TocSec->NumRelocations == 0)
+    return {};
+
+  // .rela.toc contains exclusively R_PPC64_ADDR64 relocations sorted by
+  // r_offset: 0, 8, 16, etc. For a given Offset, Offset / 8 gives us the
+  // relocation index in most cases.
+  //
+  // In rare cases a TOC entry may store a constant that doesn't need an
+  // R_PPC64_ADDR64, the corresponding r_offset is therefore missing. Offset / 8
+  // points to a relocation with larger r_offset. Do a linear probe then.
+  // Constants are extremely uncommon in .toc and the extra number of array
+  // accesses can be seen as a small constant.
+  ArrayRef<typename ELFT::Rela> Relas = TocSec->template relas<ELFT>();
+  uint64_t Index = std::min<uint64_t>(Offset / 8, Relas.size() - 1);
+  for (;;) {
+    if (Relas[Index].r_offset == Offset) {
+      Symbol &Sym = TocSec->getFile<ELFT>()->getRelocTargetSym(Relas[Index]);
+      return {dyn_cast<Defined>(&Sym), getAddend<ELFT>(Relas[Index])};
+    }
+    if (Relas[Index].r_offset < Offset || Index == 0)
+      break;
+    --Index;
+  }
+  return {};
+}
+
+// When accessing a symbol defined in another translation unit, compilers
+// reserve a .toc entry, allocate a local label and generate toc-indirect
+// instuctions:
+//
+//   addis 3, 2, .LC0 at toc@ha  # R_PPC64_TOC16_HA
+//   ld    3, .LC0 at toc@l(3)   # R_PPC64_TOC16_LO_DS, load the address from a .toc entry
+//   ld/lwa 3, 0(3)           # load the value from the address
+//
+//   .section .toc,"aw", at progbits
+//   .LC0: .tc var[TC],var
+//
+// If var is defined, non-preemptable and addressable with a 32-bit signed
+// offset from the toc base, the address of var can be computed by adding an
+// offset to the toc base, saving a load.
+//
+//   addis 3,2,var at toc@ha     # this may be relaxed to a nop,
+//   addi  3,3,var at toc@l      # then this becomes addi 3,2,var at toc
+//   ld/lwa 3, 0(3)           # load the value from the address
+//
+// Returns true if the relaxation is performed.
+bool elf::tryRelaxPPC64TocIndirection(RelType Type, const Relocation &Rel,
+                                      uint8_t *BufLoc) {
+  assert(Config->TocOptimize);
+  if (Rel.Addend < 0)
+    return false;
+
+  // If the symbol is not the .toc section, this isn't a toc-indirection.
+  Defined *DefSym = dyn_cast<Defined>(Rel.Sym);
+  if (!DefSym || !DefSym->isSection() || DefSym->Section->Name != ".toc")
+    return false;
+
+  Defined *D;
+  int64_t Addend;
+  auto *TocISB = cast<InputSectionBase>(DefSym->Section);
+  std::tie(D, Addend) =
+      Config->IsLE ? getRelaTocSymAndAddend<ELF64LE>(TocISB, Rel.Addend)
+                   : getRelaTocSymAndAddend<ELF64BE>(TocISB, Rel.Addend);
+
+  // Only non-preemptable defined symbols can be relaxed.
+  if (!D || D->IsPreemptible)
+    return false;
+
+  // Two instructions can materialize a 32-bit signed offset from the toc base.
+  uint64_t TocRelative = D->getVA(Addend) - getPPC64TocBase();
+  if (!isInt<32>(TocRelative))
+    return false;
+
+  // Add PPC64TocOffset that will be subtracted by relocateOne().
+  Target->relaxGot(BufLoc, Type, TocRelative + PPC64TocOffset);
+  return true;
+}
+
 namespace {
 class PPC64 final : public TargetInfo {
 public:
@@ -121,6 +203,7 @@ public:
   bool inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const override;
   RelExpr adjustRelaxExpr(RelType Type, const uint8_t *Data,
                           RelExpr Expr) const override;
+  void relaxGot(uint8_t *Loc, RelType Type, uint64_t Val) const override;
   void relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
   void relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
   void relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
@@ -270,6 +353,27 @@ uint32_t PPC64::calcEFlags() const {
   return 2;
 }
 
+void PPC64::relaxGot(uint8_t *Loc, RelType Type, uint64_t Val) const {
+  switch (Type) {
+  case R_PPC64_TOC16_HA:
+    // Convert "addis reg, 2, .LC0 at toc@h" to "addis reg, 2, var at toc@h" or "nop".
+    relocateOne(Loc, Type, Val);
+    break;
+  case R_PPC64_TOC16_LO_DS: {
+    // Convert "ld reg, .LC0 at toc@l(reg)" to "addi reg, reg, var at toc@l" or
+    // "addi reg, 2, var at toc".
+    uint32_t Instr = readInstrFromHalf16(Loc);
+    if (getPrimaryOpCode(Instr) != LD)
+      error("expected a 'ld' for got-indirect to toc-relative relaxing");
+    writeInstrFromHalf16(Loc, (Instr & 0x03FFFFFF) | 0x38000000);
+    relocateOne(Loc, R_PPC64_TOC16_LO, Val);
+    break;
+  }
+  default:
+    llvm_unreachable("unexpected relocation type");
+  }
+}
+
 void PPC64::relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
   // Reference: 3.7.4.2 of the 64-bit ELF V2 abi supplement.
   // The general dynamic code sequence for a global `x` will look like:
@@ -439,11 +543,12 @@ RelExpr PPC64::getRelExpr(RelType Type,
     return R_GOT_OFF;
   case R_PPC64_TOC16:
   case R_PPC64_TOC16_DS:
-  case R_PPC64_TOC16_HA:
   case R_PPC64_TOC16_HI:
   case R_PPC64_TOC16_LO:
-  case R_PPC64_TOC16_LO_DS:
     return R_GOTREL;
+  case R_PPC64_TOC16_HA:
+  case R_PPC64_TOC16_LO_DS:
+    return Config->TocOptimize ? R_PPC64_RELAX_TOC : R_GOTREL;
   case R_PPC64_TOC:
     return R_PPC_TOC;
   case R_PPC64_REL14:

Modified: lld/trunk/ELF/Arch/X86_64.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Arch/X86_64.cpp?rev=360112&r1=360111&r2=360112&view=diff
==============================================================================
--- lld/trunk/ELF/Arch/X86_64.cpp (original)
+++ lld/trunk/ELF/Arch/X86_64.cpp Mon May  6 21:26:05 2019
@@ -38,7 +38,7 @@ public:
 
   RelExpr adjustRelaxExpr(RelType Type, const uint8_t *Data,
                           RelExpr Expr) const override;
-  void relaxGot(uint8_t *Loc, uint64_t Val) const override;
+  void relaxGot(uint8_t *Loc, RelType Type, uint64_t Val) const override;
   void relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
   void relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
   void relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
@@ -453,7 +453,7 @@ static void relaxGotNoPic(uint8_t *Loc,
   write32le(Loc, Val);
 }
 
-void X86_64::relaxGot(uint8_t *Loc, uint64_t Val) const {
+void X86_64::relaxGot(uint8_t *Loc, RelType Type, uint64_t Val) const {
   const uint8_t Op = Loc[-2];
   const uint8_t ModRm = Loc[-1];
 

Modified: lld/trunk/ELF/InputSection.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.cpp?rev=360112&r1=360111&r2=360112&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.cpp (original)
+++ lld/trunk/ELF/InputSection.cpp Mon May  6 21:26:05 2019
@@ -631,6 +631,7 @@ static uint64_t getRelocTargetVA(const I
   case R_GOTPLTONLY_PC:
     return In.GotPlt->getVA() + A - P;
   case R_GOTREL:
+  case R_PPC64_RELAX_TOC:
     return Sym.getVA(A) - In.Got->getVA();
   case R_GOTPLTREL:
     return Sym.getVA(A) - In.GotPlt->getVA();
@@ -894,7 +895,11 @@ void InputSectionBase::relocateAlloc(uin
     switch (Expr) {
     case R_RELAX_GOT_PC:
     case R_RELAX_GOT_PC_NOPIC:
-      Target->relaxGot(BufLoc, TargetVA);
+      Target->relaxGot(BufLoc, Type, TargetVA);
+      break;
+    case R_PPC64_RELAX_TOC:
+      if (!tryRelaxPPC64TocIndirection(Type, Rel, BufLoc))
+        Target->relocateOne(BufLoc, Type, TargetVA);
       break;
     case R_RELAX_TLS_IE_TO_LE:
       Target->relaxTlsIeToLe(BufLoc, Type, TargetVA);

Modified: lld/trunk/ELF/Relocations.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Relocations.cpp?rev=360112&r1=360111&r2=360112&view=diff
==============================================================================
--- lld/trunk/ELF/Relocations.cpp (original)
+++ lld/trunk/ELF/Relocations.cpp Mon May  6 21:26:05 2019
@@ -383,7 +383,7 @@ static bool needsGot(RelExpr Expr) {
 // file (PC, or GOT for example).
 static bool isRelExpr(RelExpr Expr) {
   return oneof<R_PC, R_GOTREL, R_GOTPLTREL, R_MIPS_GOTREL, R_PPC_CALL,
-               R_PPC_CALL_PLT, R_AARCH64_PAGE_PC, R_RELAX_GOT_PC>(Expr);
+               R_PPC64_RELAX_TOC, R_PPC_CALL_PLT, R_AARCH64_PAGE_PC, R_RELAX_GOT_PC>(Expr);
 }
 
 // Returns true if a given relocation can be computed at link-time.
@@ -403,7 +403,7 @@ static bool isStaticLinkTimeConstant(Rel
             R_MIPS_GOT_OFF32, R_MIPS_GOT_GP_PC, R_MIPS_TLSGD,
             R_AARCH64_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC, R_GOTPLTONLY_PC,
             R_PLT_PC, R_TLSGD_GOT, R_TLSGD_GOTPLT, R_TLSGD_PC, R_PPC_CALL_PLT,
-            R_TLSDESC_CALL, R_AARCH64_TLSDESC_PAGE, R_HINT, R_TLSLD_HINT,
+            R_PPC64_RELAX_TOC, R_TLSDESC_CALL, R_AARCH64_TLSDESC_PAGE, R_HINT, R_TLSLD_HINT,
             R_TLSIE_HINT>(E))
     return true;
 
@@ -1079,7 +1079,7 @@ static void scanReloc(InputSectionBase &
   // The 4 types that relative GOTPLT are all x86 and x86-64 specific.
   if (oneof<R_GOTPLTONLY_PC, R_GOTPLTREL, R_GOTPLT, R_TLSGD_GOTPLT>(Expr)) {
     In.GotPlt->HasGotPltOffRel = true;
-  } else if (oneof<R_GOTONLY_PC, R_GOTREL, R_PPC_TOC>(Expr)) {
+  } else if (oneof<R_GOTONLY_PC, R_GOTREL, R_PPC_TOC, R_PPC64_RELAX_TOC>(Expr)) {
     In.Got->HasGotOffRel = true;
   }
 
@@ -1240,8 +1240,10 @@ static void scanRelocs(InputSectionBase
   for (auto I = Rels.begin(), End = Rels.end(); I != End;)
     scanReloc<ELFT>(Sec, GetOffset, I, End);
 
-  // Sort relocations by offset to binary search for R_RISCV_PCREL_HI20
-  if (Config->EMachine == EM_RISCV)
+  // Sort relocations by offset for more efficient searching for
+  // R_RISCV_PCREL_HI20 and R_PPC64_ADDR64.
+  if (Config->EMachine == EM_RISCV ||
+      (Config->EMachine == EM_PPC64 && Sec.Name == ".toc"))
     llvm::stable_sort(Sec.Relocations,
                       [](const Relocation &LHS, const Relocation &RHS) {
                         return LHS.Offset < RHS.Offset;

Modified: lld/trunk/ELF/Relocations.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Relocations.h?rev=360112&r1=360111&r2=360112&view=diff
==============================================================================
--- lld/trunk/ELF/Relocations.h (original)
+++ lld/trunk/ELF/Relocations.h Mon May  6 21:26:05 2019
@@ -93,6 +93,7 @@ enum RelExpr {
   R_PPC_CALL,
   R_PPC_CALL_PLT,
   R_PPC_TOC,
+  R_PPC64_RELAX_TOC,
   R_RISCV_PC_INDIRECT,
 };
 

Modified: lld/trunk/ELF/Target.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Target.cpp?rev=360112&r1=360111&r2=360112&view=diff
==============================================================================
--- lld/trunk/ELF/Target.cpp (original)
+++ lld/trunk/ELF/Target.cpp Mon May  6 21:26:05 2019
@@ -149,7 +149,7 @@ RelExpr TargetInfo::adjustRelaxExpr(RelT
   return Expr;
 }
 
-void TargetInfo::relaxGot(uint8_t *Loc, uint64_t Val) const {
+void TargetInfo::relaxGot(uint8_t *Loc, RelType Type, uint64_t Val) const {
   llvm_unreachable("Should not have claimed to be relaxable");
 }
 

Modified: lld/trunk/ELF/Target.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Target.h?rev=360112&r1=360111&r2=360112&view=diff
==============================================================================
--- lld/trunk/ELF/Target.h (original)
+++ lld/trunk/ELF/Target.h Mon May  6 21:26:05 2019
@@ -124,7 +124,7 @@ public:
 
   virtual RelExpr adjustRelaxExpr(RelType Type, const uint8_t *Data,
                                   RelExpr Expr) const;
-  virtual void relaxGot(uint8_t *Loc, uint64_t Val) const;
+  virtual void relaxGot(uint8_t *Loc, RelType Type, uint64_t Val) const;
   virtual void relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const;
   virtual void relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const;
   virtual void relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const;
@@ -164,8 +164,11 @@ static inline std::string getErrorLocati
   return getErrorPlace(Loc).Loc;
 }
 
-// In the PowerPC64 Elf V2 abi a function can have 2 entry points.  The first is
-// a global entry point (GEP) which typically is used to intiailzie the TOC
+bool tryRelaxPPC64TocIndirection(RelType Type, const Relocation &Rel,
+                                 uint8_t *BufLoc);
+
+// In the PowerPC64 Elf V2 abi a function can have 2 entry points.  The first
+// is a global entry point (GEP) which typically is used to initialize the TOC
 // pointer in general purpose register 2.  The second is a local entry
 // point (LEP) which bypasses the TOC pointer initialization code. The
 // offset between GEP and LEP is encoded in a function's st_other flags.

Added: lld/trunk/test/ELF/Inputs/ppc64-toc-relax-shared.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/Inputs/ppc64-toc-relax-shared.s?rev=360112&view=auto
==============================================================================
--- lld/trunk/test/ELF/Inputs/ppc64-toc-relax-shared.s (added)
+++ lld/trunk/test/ELF/Inputs/ppc64-toc-relax-shared.s Mon May  6 21:26:05 2019
@@ -0,0 +1,7 @@
+.data
+
+.type shared, at object
+.globl shared
+shared:
+  .long 8
+  .size shared, 4

Added: lld/trunk/test/ELF/Inputs/ppc64-toc-relax.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/Inputs/ppc64-toc-relax.s?rev=360112&view=auto
==============================================================================
--- lld/trunk/test/ELF/Inputs/ppc64-toc-relax.s (added)
+++ lld/trunk/test/ELF/Inputs/ppc64-toc-relax.s Mon May  6 21:26:05 2019
@@ -0,0 +1,15 @@
+.data
+
+.globl default, hidden
+.hidden hidden
+
+default:
+hidden:
+  .long 0
+
+.space 65532
+
+.globl hidden2
+.hidden hidden2
+hidden2:
+  .long 0

Modified: lld/trunk/test/ELF/ppc64-func-entry-points.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/ppc64-func-entry-points.s?rev=360112&r1=360111&r2=360112&view=diff
==============================================================================
--- lld/trunk/test/ELF/ppc64-func-entry-points.s (original)
+++ lld/trunk/test/ELF/ppc64-func-entry-points.s Mon May  6 21:26:05 2019
@@ -75,6 +75,6 @@ glob:
 // CHECK: foo_external_diff:
 // CHECK-NEXT: 10010080:       {{.*}}     addis 2, 12, 1
 // CHECK-NEXT: 10010084:       {{.*}}     addi 2, 2, 32640
-// CHECK-NEXT: 10010088:       {{.*}}     nop
+// CHECK-NEXT: 10010088:       {{.*}}     addis 5, 2, 1
 // CHECK: foo_external_same:
 // CHECK-NEXT: 100100b0:       {{.*}}     add 3, 4, 3

Removed: lld/trunk/test/ELF/ppc64-got-indirect.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/ppc64-got-indirect.s?rev=360111&view=auto
==============================================================================
--- lld/trunk/test/ELF/ppc64-got-indirect.s (original)
+++ lld/trunk/test/ELF/ppc64-got-indirect.s (removed)
@@ -1,121 +0,0 @@
-# REQUIRES: ppc
-
-# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
-# RUN: llvm-readobj -r %t.o | FileCheck -check-prefix=RELOCS-LE %s
-# RUN: ld.lld %t.o -o %t2
-# RUN: llvm-objdump -D %t2 | FileCheck %s --check-prefix=CHECK-LE
-# RUN: llvm-objdump -D %t2 | FileCheck %s
-
-# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
-# RUN: llvm-readobj -r %t.o | FileCheck -check-prefix=RELOCS-BE %s
-# RUN: ld.lld %t.o -o %t2
-# RUN: llvm-objdump -D %t2 | FileCheck %s --check-prefix=CHECK-BE
-# RUN: llvm-objdump -D %t2 | FileCheck %s
-
-# Make sure we calculate the offset correctly for a got-indirect access to a
-# global variable as described by the PPC64 ELF V2 abi.
-  .text
-  .abiversion 2
-  .globl  _start                    # -- Begin function _start
-  .p2align  4
-  .type  _start, at function
-_start:                                   # @_start
-.Lfunc_begin0:
-.Lfunc_gep0:
-  addis 2, 12, .TOC.-.Lfunc_gep0 at ha
-  addi 2, 2, .TOC.-.Lfunc_gep0 at l
-.Lfunc_lep0:
-  .localentry  _start, .Lfunc_lep0-.Lfunc_gep0
-# %bb.0:                                # %entry
-  addis 3, 2, .LC0 at toc@ha
-  ld 3, .LC0 at toc@l(3)
-  li 4, 0
-  stw 4, -12(1)
-  li 0,1
-        lwa 3, 0(3)
-  sc
-  .long  0
-  .quad  0
-.Lfunc_end0:
-  .size  _start, .Lfunc_end0-.Lfunc_begin0
-                                        # -- End function
-  .section  .toc,"aw", at progbits
-.LC0:
-  .tc glob[TC],glob
-  .type  glob, at object            # @glob
-  .data
-  .globl  glob
-  .p2align  2
-glob:
-  .long  55                      # 0x37
-  .size  glob, 4
-
-# Verify the relocations emitted for glob are through the .toc
-
-# RELOCS-LE: Relocations [
-# RELOCS-LE:  .rela.text {
-# RELOCS-LE:     0x0 R_PPC64_REL16_HA .TOC. 0x0
-# RELOCS-LE:     0x4 R_PPC64_REL16_LO .TOC. 0x4
-# RELOCS-LE:     0x8 R_PPC64_TOC16_HA .toc 0x0
-# RELOCS-LE:     0xC R_PPC64_TOC16_LO_DS .toc 0x0
-# RELOCS-LE:   }
-# RELOCS-LE:   .rela.toc {
-# RELOCS-LE:     0x0 R_PPC64_ADDR64 glob 0x0
-# RELOCS-LE:   }
-
-# RELOCS-BE: Relocations [
-# RELOCS-BE:  .rela.text {
-# RELOCS-BE:    0x2 R_PPC64_REL16_HA .TOC. 0x2
-# RELOCS-BE:    0x6 R_PPC64_REL16_LO .TOC. 0x6
-# RELOCS-BE:    0xA R_PPC64_TOC16_HA .toc 0x0
-# RELOCS-BE:    0xE R_PPC64_TOC16_LO_DS .toc 0x0
-# RELOCS-BE:  }
-# RELOCS-BE:  .rela.toc {
-# RELOCS-BE:    0x0 R_PPC64_ADDR64 glob 0x0
-# RELOCS-BE:  }
-# RELOCS-BE:]
-
-# Verify that the global variable access is done through the correct
-# toc entry:
-# r2 = .TOC. = 0x10038000.
-# r3 = r2 - 32760 = 0x10030008 -> .toc entry for glob.
-
-# CHECK: _start:
-# CHECK-NEXT: 10010000:  {{.*}}   addis 2, 12, 2
-# CHECK-NEXT: 10010004:  {{.*}}   addi 2, 2, -32768
-# CHECK-NEXT: 10010008:  {{.*}}   nop
-# CHECK-NEXT: 1001000c:  {{.*}}   ld 3, -32760(2)
-# CHECK: 1001001c:  {{.*}}   lwa 3, 0(3)
-
-# CHECK-LE: Disassembly of section .got:
-# CHECK-LE-EMPTY:
-# CHECK-LE-NEXT: .got:
-# CHECK-LE-NEXT: 10020000:       00 80 02 10
-# CHECK-LE-NEXT: 10020004:       00 00 00 00
-
-# Verify that .toc comes right after .got
-# CHECK-LE: Disassembly of section .toc:
-# CHECK-LE-EMPTY:
-# CHECK-LE: 10020008:       00 00 03 10
-
-# CHECK-LE: Disassembly of section .data:
-# CHECK-LE-EMPTY:
-# CHECK-LE-NEXT: glob:
-# CHECK-LE-NEXT: 10030000:       37 00 00 00
-
-# CHECK-BE: Disassembly of section .got:
-# CHECK-BE-EMPTY:
-# CHECK-BE-NEXT: .got:
-# CHECK-BE-NEXT: 10020000:       00 00 00 00
-# CHECK-BE-NEXT: 10020004:       10 02 80 00
-
-# Verify that .toc comes right after .got
-# CHECK-BE: Disassembly of section .toc:
-# CHECK-BE-EMPTY:
-# CHECK-BE: 10020008:       00 00 00 00
-# CHECK-BE: 1002000c:       10 03 00 00
-
-# CHECK-BE: Disassembly of section .data:
-# CHECK-BE-EMPTY:
-# CHECK-BE-NEXT: glob:
-# CHECK-BE-NEXT: 10030000:       00 00 00 37

Modified: lld/trunk/test/ELF/ppc64-relocs.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/ppc64-relocs.s?rev=360112&r1=360111&r2=360112&view=diff
==============================================================================
--- lld/trunk/test/ELF/ppc64-relocs.s (original)
+++ lld/trunk/test/ELF/ppc64-relocs.s Mon May  6 21:26:05 2019
@@ -1,14 +1,14 @@
 # REQUIRES: ppc
 
-# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t
-# RUN: ld.lld %t -o %t2
-# RUN: llvm-readelf -x .rodata -x .eh_frame %t2 | FileCheck %s --check-prefix=DATALE
-# RUN: llvm-objdump -d --no-show-raw-insn %t2 | FileCheck %s
-
-# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t
-# RUN: ld.lld %t -o %t2
-# RUN: llvm-readelf -x .rodata -x .eh_frame %t2 | FileCheck %s --check-prefix=DATABE
-# RUN: llvm-objdump -d --no-show-raw-insn %t2 | FileCheck %s
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+# RUN: ld.lld --no-toc-optimize %t.o -o %t
+# RUN: llvm-readelf -x .rodata -x .eh_frame %t | FileCheck %s --check-prefix=DATALE
+# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
+# RUN: ld.lld --no-toc-optimize %t.o -o %t
+# RUN: llvm-readelf -x .rodata -x .eh_frame %t | FileCheck %s --check-prefix=DATABE
+# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s
 
 .text
 .global _start
@@ -67,7 +67,7 @@ _start:
 # CHECK: Disassembly of section .R_PPC64_TOC16_HA:
 # CHECK-EMPTY:
 # CHECK: .FR_PPC64_TOC16_HA:
-# CHECK: 10010018:       nop
+# CHECK: 10010018:       addis 1, 2, 0
 
 .section .R_PPC64_REL24,"ax", at progbits
 .globl .FR_PPC64_REL24
@@ -183,8 +183,8 @@ _start:
 # CHECK: Disassembly of section .R_PPC64_REL32:
 # CHECK-EMPTY:
 # CHECK: .FR_PPC64_REL32:
-# CHECK: 10010040:       nop
-# CHECK: 10010044:       ld 5, -32736(2)
+# CHECK: 10010040:       addis 5, 2, 0
+# CHECK: 10010044:       ld 5, -32736(5)
 # CHECK: 10010048:       add 3, 3, 4
 
 .section .R_PPC64_REL64, "ax", at progbits

Added: lld/trunk/test/ELF/ppc64-toc-relax-constants.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/ppc64-toc-relax-constants.s?rev=360112&view=auto
==============================================================================
--- lld/trunk/test/ELF/ppc64-toc-relax-constants.s (added)
+++ lld/trunk/test/ELF/ppc64-toc-relax-constants.s Mon May  6 21:26:05 2019
@@ -0,0 +1,61 @@
+# REQUIRES: ppc
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unkown-linux %p/Inputs/ppc64-toc-relax-shared.s -o %t.o
+# RUN: ld.lld -shared %t.o -o %t.so
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-toc-relax.s -o %t2.o
+# RUN: llvm-readobj -r %t1.o | FileCheck --check-prefix=RELOCS %s
+# RUN: ld.lld %t1.o %t2.o %t.so -o %t
+# RUN: llvm-readelf -S %t | FileCheck --check-prefix=SECTIONS %s
+# RUN: llvm-nm %t | FileCheck --check-prefix=NM %s
+# RUN: llvm-objdump -D %t | FileCheck %s
+
+# In most cases, .toc contains exclusively addresses relocated by R_PPC64_ADDR16.
+# Rarely .toc contain constants or variables.
+# Test we can still perform toc-indirect to toc-relative relaxation.
+
+# RELOCS:      .rela.text {
+# RELOCS-NEXT:   0x0 R_PPC64_TOC16_HA .toc 0x0
+# RELOCS-NEXT:   0x4 R_PPC64_TOC16_LO_DS .toc 0x0
+# RELOCS-NEXT:   0x8 R_PPC64_TOC16_HA .toc 0x8
+# RELOCS-NEXT:   0xC R_PPC64_TOC16_LO_DS .toc 0x8
+# RELOCS-NEXT:   0x10 R_PPC64_TOC16_HA .toc 0x10
+# RELOCS-NEXT:   0x14 R_PPC64_TOC16_LO_DS .toc 0x10
+# RELOCS-NEXT: }
+
+# SECTIONS: .got              PROGBITS        0000000010020090
+# SECTIONS: .toc              PROGBITS        0000000010020090
+
+# NM: 0000000010030000 D default
+
+# .LCONST1 is .toc[0].
+# .LCONST1 - (.got+0x8000) = 0x10020090 - (0x10020090+0x8000) = -32768
+# CHECK: nop
+# CHECK: lwa 3, -32768(2)
+  addis 3, 2, .LCONST1 at toc@ha
+  lwa 3, .LCONST1 at toc@l(3)
+
+# .LCONST2 is .toc[1]
+# .LCONST2 - (.got+0x8000) = 0x10020098 - (0x10020090+0x8000) = -32760
+# CHECK: nop
+# CHECK: ld 4, -32760(2)
+  addis 4, 2, .LCONST2 at toc@ha
+  ld 4, .LCONST2 at toc@l(4)
+
+# .Ldefault is .toc[2]. `default` is not preemptable when producing an executable.
+# After toc-indirection to toc-relative relaxation, it is loaded using an
+# offset relative to r2.
+# CHECK: nop
+# CHECK: addi 5, 2, 32624
+# CHECK: lwa 5, 0(5)
+  addis 5, 2, .Ldefault at toc@ha
+  ld    5, .Ldefault at toc@l(5)
+  lwa   5, 0(5)
+
+.section .toc,"aw", at progbits
+.LCONST1:
+  .quad 11
+.LCONST2:
+  .quad 22
+.Ldefault:
+  .tc default[TC],default

Added: lld/trunk/test/ELF/ppc64-toc-relax-jumptable.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/ppc64-toc-relax-jumptable.s?rev=360112&view=auto
==============================================================================
--- lld/trunk/test/ELF/ppc64-toc-relax-jumptable.s (added)
+++ lld/trunk/test/ELF/ppc64-toc-relax-jumptable.s Mon May  6 21:26:05 2019
@@ -0,0 +1,73 @@
+# REQUIRES: ppc
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t
+# RUN: llvm-readelf -S %t | FileCheck --check-prefixes=SECTIONS %s
+# RUN: llvm-readelf -x .toc %t | FileCheck --check-prefixes=HEX-LE %s
+# RUN: llvm-objdump -d %t | FileCheck --check-prefixes=CHECK %s
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t
+# RUN: llvm-readelf -S %t | FileCheck --check-prefixes=SECTIONS %s
+# RUN: llvm-readelf -x .toc %t | FileCheck --check-prefixes=HEX-BE %s
+# RUN: llvm-objdump -d %t | FileCheck --check-prefixes=CHECK %s
+
+# .LJT is a local symbol (non-preemptable).
+# Test we can perform the toc-indirect to toc-relative relaxation.
+
+# SECTIONS: .rodata PROGBITS 00000000100001c8
+
+# HEX-LE:      section '.toc':
+# HEX-LE-NEXT: 10020008 c8010010 00000000
+
+# HEX-BE:      section '.toc':
+# HEX-BE-NEXT: 10020008 00000000 100001c8
+
+# CHECK-LABEL: _start
+# CHECK:       clrldi  3, 3, 62
+# CHECK-NEXT:  addis 4, 2, -2
+# CHECK-NEXT:  addi  4, 4, -32312
+# CHECK-NEXT:  sldi  3, 3, 2
+
+    .text
+    .global _start
+    .type _start, @function
+_start:
+.Lstart_gep:
+    addis 2, 12, .TOC.-.Lstart_gep at ha
+    addi  2,  2, .TOC.-.Lstart_gep at l
+.Lstart_lep:
+    .localentry _start, .Lstart_lep-.Lstart_gep
+    rldicl 3, 3, 0, 62
+    addis 4, 2, .LJTI_TE at toc@ha
+    ld    4, .LJTI_TE at toc@l(4)
+    sldi  3, 3, 2
+    lwax  3, 3, 4
+    add   3, 3, 4
+    mtctr 3
+    bctr
+
+.LBB1:
+    li 3, 0
+    blr
+.LBB2:
+    li 3, 10
+    blr
+.LBB3:
+    li 3, 55
+    blr
+.LBB4:
+    li 3, 255
+    blr
+
+    .section        .rodata,"a", at progbits
+    .p2align        2
+.LJT:
+    .long   .LBB1-.LJT
+    .long   .LBB2-.LJT
+    .long   .LBB3-.LJT
+    .long   .LBB4-.LJT
+
+.section        .toc,"aw", at progbits
+# TOC entry for the jumptable address.
+.LJTI_TE:
+    .tc .LJT[TC],.LJT

Added: lld/trunk/test/ELF/ppc64-toc-relax.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/ppc64-toc-relax.s?rev=360112&view=auto
==============================================================================
--- lld/trunk/test/ELF/ppc64-toc-relax.s (added)
+++ lld/trunk/test/ELF/ppc64-toc-relax.s Mon May  6 21:26:05 2019
@@ -0,0 +1,105 @@
+# REQUIRES: ppc
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-toc-relax-shared.s -o %t.o
+# RUN: ld.lld -shared %t.o -o %t.so
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-toc-relax.s -o %t2.o
+# RUN: llvm-readobj -r %t1.o | FileCheck --check-prefixes=RELOCS-LE,RELOCS %s
+# RUN: ld.lld %t1.o %t2.o %t.so -o %t
+# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefixes=COMMON,EXE %s
+
+# RUN: ld.lld -shared %t1.o %t2.o %t.so -o %t2.so
+# RUN: llvm-objdump -d --no-show-raw-insn %t2.so | FileCheck --check-prefixes=COMMON,SHARED %s
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/ppc64-toc-relax-shared.s -o %t.o
+# RUN: ld.lld -shared %t.o -o %t.so
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/ppc64-toc-relax.s -o %t2.o
+# RUN: llvm-readobj -r %t1.o | FileCheck --check-prefixes=RELOCS-BE,RELOCS %s
+# RUN: ld.lld %t1.o %t2.o %t.so -o %t
+# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefixes=COMMON,EXE %s
+
+# RUN: ld.lld -shared %t1.o %t2.o %t.so -o %t2.so
+# RUN: llvm-objdump -d --no-show-raw-insn %t2.so | FileCheck --check-prefixes=COMMON,SHARED %s
+
+# RELOCS-LE:      .rela.text {
+# RELOCS-LE-NEXT:   0x0 R_PPC64_TOC16_HA .toc 0x0
+# RELOCS-LE-NEXT:   0x4 R_PPC64_TOC16_LO_DS .toc 0x0
+# RELOCS-LE-NEXT:   0xC R_PPC64_TOC16_HA .toc 0x8
+# RELOCS-LE-NEXT:   0x10 R_PPC64_TOC16_LO_DS .toc 0x8
+# RELOCS-LE-NEXT:   0x18 R_PPC64_TOC16_HA .toc 0x10
+# RELOCS-LE-NEXT:   0x1C R_PPC64_TOC16_LO_DS .toc 0x10
+# RELOCS-LE-NEXT:   0x24 R_PPC64_TOC16_HA .toc 0x18
+# RELOCS-LE-NEXT:   0x28 R_PPC64_TOC16_LO_DS .toc 0x18
+# RELOCS-LE-NEXT: }
+
+# RELOCS-BE:      .rela.text {
+# RELOCS-BE-NEXT:   0x2 R_PPC64_TOC16_HA .toc 0x0
+# RELOCS-BE-NEXT:   0x6 R_PPC64_TOC16_LO_DS .toc 0x0
+# RELOCS-BE-NEXT:   0xE R_PPC64_TOC16_HA .toc 0x8
+# RELOCS-BE-NEXT:   0x12 R_PPC64_TOC16_LO_DS .toc 0x8
+# RELOCS-BE-NEXT:   0x1A R_PPC64_TOC16_HA .toc 0x10
+# RELOCS-BE-NEXT:   0x1E R_PPC64_TOC16_LO_DS .toc 0x10
+# RELOCS-BE-NEXT:   0x26 R_PPC64_TOC16_HA .toc 0x18
+# RELOCS-BE-NEXT:   0x2A R_PPC64_TOC16_LO_DS .toc 0x18
+# RELOCS-BE-NEXT: }
+
+# RELOCS:         .rela.toc {
+# RELOCS-NEXT:      0x0 R_PPC64_ADDR64 hidden 0x0
+# RELOCS-NEXT:      0x8 R_PPC64_ADDR64 hidden2 0x0
+# RELOCS-NEXT:      0x10 R_PPC64_ADDR64 shared 0x0
+# RELOCS-NEXT:      0x18 R_PPC64_ADDR64 default 0x0
+# RELOCS-NEXT:    }
+
+# NM-DAG: 0000000010030000 D default
+# NM-DAG: 0000000010030000 d hidden
+# NM-DAG: 0000000010040000 d hidden2
+
+# 'hidden' is non-preemptable. It is relaxed.
+# address(hidden) - (.got+0x8000) = 0x10030000 - (0x100200c0+0x8000) = 32576
+# COMMON: nop
+# COMMON: addi 3, 2, 32576
+# COMMON: lwa 3, 0(3)
+  addis 3, 2, .Lhidden at toc@ha
+  ld    3, .Lhidden at toc@l(3)
+  lwa   3, 0(3)
+
+# address(hidden2) - (.got+0x8000) = 0x10040000 - (0x100200c0+0x8000) = (1<<16)+32576
+# COMMON: addis 3, 2, 1
+# COMMON: addi 3, 3, 32576
+# COMMON: lwa 3, 0(3)
+  addis 3, 2, .Lhidden2 at toc@ha
+  ld    3, .Lhidden2 at toc@l(3)
+  lwa   3, 0(3)
+
+# 'shared' is not defined in an object file. Its definition is determined at
+# runtime by the dynamic linker, so the extra indirection cannot be relaxed.
+# The first addis can still be relaxed to nop, though.
+# COMMON: nop
+# COMMON: ld 4, -32752(2)
+# COMMON: lwa 4, 0(4)
+  addis 4, 2, .Lshared at toc@ha
+  ld    4, .Lshared at toc@l(4)
+  lwa   4, 0(4)
+
+# 'default' has default visibility. It is non-preemptable when producing an executable.
+# address(default) - (.got+0x8000) = 0x10030000 - (0x100200c0+0x8000) = 32576
+# EXE: nop
+# EXE: addi 5, 2, 32576
+# EXE: lwa 5, 0(5)
+
+# SHARED: nop
+# SHARED: ld 5, -32744(2)
+# SHARED: lwa 5, 0(5)
+  addis 5, 2, .Ldefault at toc@ha
+  ld    5, .Ldefault at toc@l(5)
+  lwa   5, 0(5)
+
+.section .toc,"aw", at progbits
+.Lhidden:
+  .tc hidden[TC], hidden
+.Lhidden2:
+  .tc hidden2[TC], hidden2
+.Lshared:
+  .tc shared[TC], shared
+.Ldefault:
+  .tc default[TC], default




More information about the llvm-commits mailing list