[llvm] 9868ea7 - [XCOFF][AIX] Handle TOC entries that could not be reached by positive range in small code model

via llvm-commits llvm-commits at lists.llvm.org
Mon Sep 14 06:43:06 PDT 2020


Author: jasonliu
Date: 2020-09-14T13:41:34Z
New Revision: 9868ea764f31b0fd4ec250867807aa0ad7958abf

URL: https://github.com/llvm/llvm-project/commit/9868ea764f31b0fd4ec250867807aa0ad7958abf
DIFF: https://github.com/llvm/llvm-project/commit/9868ea764f31b0fd4ec250867807aa0ad7958abf.diff

LOG: [XCOFF][AIX] Handle TOC entries that could not be reached by positive range in small code model

Summary:
In small code model, AIX assembler could not deal with labels that
could not be reached within the [-0x8000, 0x8000) range from TOC base.
So when generating the assembly, we would need to help the assembler
by subtracting an offset from the label to keep the actual value
within [-0x8000, 0x8000).

Reviewed By: hubert.reinterpretcast, Xiangling_L

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

Added: 
    llvm/test/CodeGen/PowerPC/aix-overflow-toc.py

Modified: 
    llvm/lib/MC/XCOFFObjectWriter.cpp
    llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
    llvm/test/CodeGen/PowerPC/lit.local.cfg

Removed: 
    


################################################################################
diff  --git a/llvm/lib/MC/XCOFFObjectWriter.cpp b/llvm/lib/MC/XCOFFObjectWriter.cpp
index 5047b5041aa7..d6cee3bb59bb 100644
--- a/llvm/lib/MC/XCOFFObjectWriter.cpp
+++ b/llvm/lib/MC/XCOFFObjectWriter.cpp
@@ -49,7 +49,6 @@ namespace {
 
 constexpr unsigned DefaultSectionAlign = 4;
 constexpr int16_t MaxSectionIndex = INT16_MAX;
-constexpr uint16_t MaxTOCSizeInARegion = UINT16_MAX;
 
 // Packs the csect's alignment and type into a byte.
 uint8_t getEncodedType(const MCSectionXCOFF *);
@@ -431,12 +430,15 @@ void XCOFFObjectWriter::recordRelocation(MCAssembler &Asm,
     FixedValue = getVirtualAddress(SymA, SymASec) + Target.getConstant();
   else if (Type == XCOFF::RelocationType::R_TOC ||
            Type == XCOFF::RelocationType::R_TOCL) {
-    // The FixedValue should be the TC entry offset from TOC-base.
-    FixedValue = SectionMap[SymASec]->Address - TOCCsects.front().Address;
-    if (FixedValue >= MaxTOCSizeInARegion)
-      report_fatal_error(
-          "handling of TOC entries could not fit in the initial TOC "
-          "entry region is not yet supported");
+    // The FixedValue should be the TOC entry offset from the TOC-base plus any
+    // constant offset value.
+    const int64_t TOCEntryOffset = SectionMap[SymASec]->Address -
+                                   TOCCsects.front().Address +
+                                   Target.getConstant();
+    if (Type == XCOFF::RelocationType::R_TOC && !isInt<16>(TOCEntryOffset))
+      report_fatal_error("TOCEntryOffset overflows in small code model mode");
+
+    FixedValue = TOCEntryOffset;
   }
 
   assert(

diff  --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
index 8f1477012bfd..f950e748158f 100644
--- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
+++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
@@ -579,6 +579,38 @@ void PPCAsmPrinter::emitInstruction(const MachineInstr *MI) {
     }
   }
 #endif
+
+  auto getTOCRelocAdjustedExprForXCOFF = [this](const MCExpr *Expr,
+                                                ptr
diff _t OriginalOffset) {
+    // Apply an offset to the TOC-based expression such that the adjusted
+    // notional offset from the TOC base (to be encoded into the instruction's D
+    // or DS field) is the signed 16-bit truncation of the original notional
+    // offset from the TOC base.
+    // This is consistent with the treatment used both by XL C/C++ and
+    // by AIX ld -r.
+    ptr
diff _t Adjustment =
+        OriginalOffset - llvm::SignExtend32<16>(OriginalOffset);
+    return MCBinaryExpr::createAdd(
+        Expr, MCConstantExpr::create(-Adjustment, OutContext), OutContext);
+  };
+
+  auto getTOCEntryLoadingExprForXCOFF =
+      [IsPPC64, getTOCRelocAdjustedExprForXCOFF,
+       this](const MCSymbol *MOSymbol, const MCExpr *Expr) -> const MCExpr * {
+    const unsigned EntryByteSize = IsPPC64 ? 8 : 4;
+    const auto TOCEntryIter = TOC.find(MOSymbol);
+    assert(TOCEntryIter != TOC.end() &&
+           "Could not find the TOC entry for this symbol.");
+    const ptr
diff _t EntryDistanceFromTOCBase =
+        (TOCEntryIter - TOC.begin()) * EntryByteSize;
+    constexpr int16_t PositiveTOCRange = INT16_MAX;
+
+    if (EntryDistanceFromTOCBase > PositiveTOCRange)
+      return getTOCRelocAdjustedExprForXCOFF(Expr, EntryDistanceFromTOCBase);
+
+    return Expr;
+  };
+
   // Lower multi-instruction pseudo operations.
   switch (MI->getOpcode()) {
   default: break;
@@ -725,6 +757,7 @@ void PPCAsmPrinter::emitInstruction(const MachineInstr *MI) {
       assert(
           TM.getCodeModel() == CodeModel::Small &&
           "This pseudo should only be selected for 32-bit small code model.");
+      Exp = getTOCEntryLoadingExprForXCOFF(MOSymbol, Exp);
       TmpInst.getOperand(1) = MCOperand::createExpr(Exp);
       EmitToStreamer(*OutStreamer, TmpInst);
       return;
@@ -753,17 +786,20 @@ void PPCAsmPrinter::emitInstruction(const MachineInstr *MI) {
     assert((MO.isGlobal() || MO.isCPI() || MO.isJTI() || MO.isBlockAddress()) &&
            "Invalid operand!");
 
+    // Map the operand to its corresponding MCSymbol.
+    const MCSymbol *const MOSymbol = getMCSymbolForTOCPseudoMO(MO, *this);
+
     // Map the machine operand to its corresponding MCSymbol, then map the
     // global address operand to be a reference to the TOC entry we will
     // synthesize later.
-    MCSymbol *TOCEntry =
-        lookUpOrCreateTOCEntry(getMCSymbolForTOCPseudoMO(MO, *this));
+    MCSymbol *TOCEntry = lookUpOrCreateTOCEntry(MOSymbol);
 
     const MCSymbolRefExpr::VariantKind VK =
         IsAIX ? MCSymbolRefExpr::VK_None : MCSymbolRefExpr::VK_PPC_TOC;
     const MCExpr *Exp =
         MCSymbolRefExpr::create(TOCEntry, VK, OutContext);
-    TmpInst.getOperand(1) = MCOperand::createExpr(Exp);
+    TmpInst.getOperand(1) = MCOperand::createExpr(
+        IsAIX ? getTOCEntryLoadingExprForXCOFF(MOSymbol, Exp) : Exp);
     EmitToStreamer(*OutStreamer, TmpInst);
     return;
   }
@@ -1821,16 +1857,6 @@ void PPCAIXAsmPrinter::emitEndOfAsmFile(Module &M) {
   PPCTargetStreamer *TS =
       static_cast<PPCTargetStreamer *>(OutStreamer->getTargetStreamer());
 
-  const unsigned EntryByteSize = Subtarget->isPPC64() ? 8 : 4;
-  const unsigned TOCEntriesByteSize = TOC.size() * EntryByteSize;
-  // TODO: If TOC entries' size is larger than 32768, then we run out of
-  // positive displacement to reach the TOC entry. We need to decide how to
-  // handle entries' size larger than that later.
-  if (TOCEntriesByteSize > 32767) {
-    report_fatal_error("Handling of TOC entry displacement larger than 32767 "
-                       "is not yet implemented.");
-  }
-
   for (auto &I : TOC) {
     // Setup the csect for the current TC entry.
     MCSectionXCOFF *TCEntry = cast<MCSectionXCOFF>(

diff  --git a/llvm/test/CodeGen/PowerPC/aix-overflow-toc.py b/llvm/test/CodeGen/PowerPC/aix-overflow-toc.py
new file mode 100644
index 000000000000..5e56b6f9fa25
--- /dev/null
+++ b/llvm/test/CodeGen/PowerPC/aix-overflow-toc.py
@@ -0,0 +1,66 @@
+# RUN: python %s > %t.ll
+# RUN: llc -mtriple powerpc-ibm-aix-xcoff -code-model=small -mcpu=pwr4 -mattr=-altivec -O0 < %t.ll | \
+# RUN:   FileCheck --check-prefix=ASM32 %s
+
+# RUN: llc -mtriple powerpc64-ibm-aix-xcoff -code-model=small -mcpu=pwr4 -mattr=-altivec -O0 < %t.ll | \
+# RUN:   FileCheck --check-prefix=ASM64 %s
+
+# RUN: llc -mtriple powerpc-ibm-aix-xcoff -code-model=small -mcpu=pwr4 -mattr=-altivec -O0 \
+# RUN:     -filetype=obj -o %t.o < %t.ll
+# RUN: llvm-objdump -D -r --symbol-description %t.o | FileCheck --check-prefix=DIS32 %s
+
+# RUN: not --crash llc -mtriple powerpc64-ibm-aix-xcoff \
+# RUN:     -mcpu=pwr4 -mattr=-altivec -filetype=obj -o %t.o 2>&1 < %t.ll | \
+# RUN:   FileCheck --check-prefix=XCOFF64 %s
+# XCOFF64: LLVM ERROR: 64-bit XCOFF object files are not supported yet.
+
+numentries = 12290
+for x in range(0, numentries):
+    print("@a%d = global i32 0, align 4" % (x))
+
+print("define void @foo() {")
+print("entry:")
+for x in range(0, numentries):
+    print("store i32 1, i32* @a%d, align 4" % (x))
+print("ret void")
+print("}")
+
+# 32-bit assembly check
+# ASM32:  lwz 3, L..C0(2)
+# ASM32:  lwz 3, L..C1(2)
+
+# ASM32:  lwz 3, L..C8191(2)
+# ASM32:  lwz 3, L..C8192-65536(2)
+# ASM32:  lwz 3, L..C8193-65536(2)
+
+# ASM32:  lwz 3, L..C12288-65536(2)
+# ASM32:  lwz 3, L..C12289-65536(2)
+
+# 64-bit assembly check
+# ASM64:  ld 3, L..C0(2)
+# ASM64:  ld 3, L..C1(2)
+
+# ASM64:  ld 3, L..C4095(2)
+# ASM64:  ld 3, L..C4096-65536(2)
+# ASM64:  ld 3, L..C4097-65536(2)
+
+# ASM64:  ld 3, L..C12287-65536(2)
+# ASM64:  ld 3, L..C12288-131072(2)
+# ASM64:  ld 3, L..C12289-131072(2)
+
+# DIS32:   0: 80 62 00 00   lwz 3, 0(2)
+# DIS32:  00000002:  R_TOC  (idx: 24590) a0[TC]
+# DIS32:   c: 80 62 00 04   lwz 3, 4(2)
+# DIS32:  0000000e:  R_TOC  (idx: 24592) a1[TC]
+
+# DIS32:    fffc: 80 62 7f fc   lwz 3, 32764(2)
+# DIS32:      0000fffe:  R_TOC  (idx: 40972) a8191[TC]
+# DIS32:   10004: 80 62 80 00   lwz 3, -32768(2)
+# DIS32:      00010006:  R_TOC  (idx: 40974) a8192[TC]
+# DIS32:   1000c: 80 62 80 04   lwz 3, -32764(2)
+# DIS32:      0001000e:  R_TOC  (idx: 40976) a8193[TC]
+
+# DIS32:   18004: 80 62 c0 00   lwz 3, -16384(2)
+# DIS32:      00018006:  R_TOC  (idx: 49166) a12288[TC]
+# DIS32:   1800c: 80 62 c0 04   lwz 3, -16380(2)
+# DIS32:      0001800e:  R_TOC  (idx: 49168) a12289[TC]

diff  --git a/llvm/test/CodeGen/PowerPC/lit.local.cfg b/llvm/test/CodeGen/PowerPC/lit.local.cfg
index 091332439b18..1dbbf92fcf5e 100644
--- a/llvm/test/CodeGen/PowerPC/lit.local.cfg
+++ b/llvm/test/CodeGen/PowerPC/lit.local.cfg
@@ -1,2 +1,4 @@
 if not 'PowerPC' in config.root.targets:
     config.unsupported = True
+
+config.suffixes.add('.py')


        


More information about the llvm-commits mailing list