mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 12:41:49 +01:00
[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
This commit is contained in:
parent
97547d7ed0
commit
88bb171b45
@ -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(
|
||||
|
@ -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;
|
||||
@ -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>(
|
||||
|
66
test/CodeGen/PowerPC/aix-overflow-toc.py
Normal file
66
test/CodeGen/PowerPC/aix-overflow-toc.py
Normal file
@ -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]
|
@ -1,2 +1,4 @@
|
||||
if not 'PowerPC' in config.root.targets:
|
||||
config.unsupported = True
|
||||
|
||||
config.suffixes.add('.py')
|
||||
|
Loading…
x
Reference in New Issue
Block a user