Index: llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp =================================================================== --- llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp +++ llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp @@ -579,6 +579,34 @@ } } #endif + + auto getTOCEntryLoadingExprForXCOFF = + [IsPPC64, 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 int EntryDistanceFromTOCBase = + (TOCEntryIter - TOC.begin()) * EntryByteSize; + const int16_t PositiveTOCRange = INT16_MAX; + // Nothing needs to be done when TOC entries are still within positive + // range. + if (EntryDistanceFromTOCBase < PositiveTOCRange) + return Expr; + + // AIX system assembler could not directly deal with TOC entries that are + // not within the range that could be represented by an int16_t type in + // small code model mode. But it works happily if we keep the offset of + // those TOC entries within that range. + const int TOCRange = 0x10000; + const int Multiply = + (EntryDistanceFromTOCBase - PositiveTOCRange) / TOCRange + 1; + return MCBinaryExpr::createAdd( + Expr, MCConstantExpr::create(-TOCRange * Multiply, OutContext), + OutContext); + }; + // Lower multi-instruction pseudo operations. switch (MI->getOpcode()) { default: break; @@ -725,6 +753,7 @@ 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 +782,20 @@ 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 +1853,6 @@ PPCTargetStreamer *TS = static_cast(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( Index: llvm/test/CodeGen/PowerPC/aix-overflow-toc.test =================================================================== --- /dev/null +++ llvm/test/CodeGen/PowerPC/aix-overflow-toc.test @@ -0,0 +1,39 @@ +# 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 + +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)