Skip to content

Commit

Permalink
[XCOFF][AIX] Handle TOC entries that could not be reached by positive…
Browse files Browse the repository at this point in the history
… 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
  • Loading branch information
jasonliudev committed Sep 14, 2020
1 parent 08baa97 commit 9868ea7
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 20 deletions.
16 changes: 9 additions & 7 deletions llvm/lib/MC/XCOFFObjectWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 *);
Expand Down Expand Up @@ -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(
Expand Down
52 changes: 39 additions & 13 deletions llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,38 @@ void PPCAsmPrinter::emitInstruction(const MachineInstr *MI) {
}
}
#endif

auto getTOCRelocAdjustedExprForXCOFF = [this](const MCExpr *Expr,
ptrdiff_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.
ptrdiff_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 ptrdiff_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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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>(
Expand Down
66 changes: 66 additions & 0 deletions llvm/test/CodeGen/PowerPC/aix-overflow-toc.py
Original file line number Diff line number Diff line change
@@ -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]
2 changes: 2 additions & 0 deletions llvm/test/CodeGen/PowerPC/lit.local.cfg
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
if not 'PowerPC' in config.root.targets:
config.unsupported = True

config.suffixes.add('.py')

0 comments on commit 9868ea7

Please sign in to comment.