diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp --- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp +++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp @@ -649,16 +649,17 @@ } } case PPC::LWZtoc: { - // Transform %r3 = LWZtoc @min1, %r2 + // Transform %rN = LWZtoc @op1, %r2 LowerPPCMachineInstrToMCInst(MI, TmpInst, *this, isDarwin); - // Change the opcode to LWZ, and the global address operand to be a - // reference to the GOT entry we will synthesize later. + // Change the opcode to LWZ. TmpInst.setOpcode(PPC::LWZ); + const MachineOperand &MO = MI->getOperand(1); + assert(MO.isGlobal() || MO.isCPI() || MO.isJTI() || MO.isBlockAddress() && + "Unexpected operand type for LWZtoc pseudo."); - // Map symbol -> label of TOC entry - assert(MO.isGlobal() || MO.isCPI() || MO.isJTI() || MO.isBlockAddress()); + // Map the operand to its corresponding MCSymbol. MCSymbol *MOSymbol = nullptr; if (MO.isGlobal()) MOSymbol = getSymbol(MO.getGlobal()); @@ -669,23 +670,40 @@ else if (MO.isBlockAddress()) MOSymbol = GetBlockAddressSymbol(MO.getBlockAddress()); - if (PL == PICLevel::SmallPIC) { + const bool IsAIX = TM.getTargetTriple().isOSAIX(); + + if (PL == PICLevel::SmallPIC && !IsAIX) { const MCExpr *Exp = MCSymbolRefExpr::create(MOSymbol, MCSymbolRefExpr::VK_GOT, OutContext); TmpInst.getOperand(1) = MCOperand::createExpr(Exp); - } else { - MCSymbol *TOCEntry = lookUpOrCreateTOCEntry(MOSymbol); + EmitToStreamer(*OutStreamer, TmpInst); + return; + } - const MCExpr *Exp = - MCSymbolRefExpr::create(TOCEntry, MCSymbolRefExpr::VK_None, - OutContext); - const MCExpr *PB = - MCSymbolRefExpr::create(OutContext.getOrCreateSymbol(Twine(".LTOC")), - OutContext); - Exp = MCBinaryExpr::createSub(Exp, PB, OutContext); + // Otherwise use the TOC. 'TOCEntry' is a local symbol used to reference + // the storage allocated in the TOC which contains the address of + // 'MOSymbol'. Said TOC entry will be synthesized later. + MCSymbol *TOCEntry = lookUpOrCreateTOCEntry(MOSymbol); + const MCExpr *Exp = + MCSymbolRefExpr::create(TOCEntry, MCSymbolRefExpr::VK_None, OutContext); + + // AIX uses the local symbol directly for the operand; that the symbol is + // accessed toc-relative is implicit. + if (IsAIX) { + assert(TM.getCodeModel() == CodeModel::Small && + "This pseudo should only be selected for small code model."); TmpInst.getOperand(1) = MCOperand::createExpr(Exp); + EmitToStreamer(*OutStreamer, TmpInst); + return; } + + // Create an explicit subtract expression between the local symbol and + // '.LTOC' to manifest the toc-relative offset. + const MCExpr *PB = MCSymbolRefExpr::create( + OutContext.getOrCreateSymbol(Twine(".LTOC")), OutContext); + Exp = MCBinaryExpr::createSub(Exp, PB, OutContext); + TmpInst.getOperand(1) = MCOperand::createExpr(Exp); EmitToStreamer(*OutStreamer, TmpInst); return; } diff --git a/llvm/test/CodeGen/PowerPC/lower-globaladdr32-aix-asm.ll b/llvm/test/CodeGen/PowerPC/lower-globaladdr32-aix-asm.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/lower-globaladdr32-aix-asm.ll @@ -0,0 +1,22 @@ +; RUN: llc -mtriple powerpc-ibm-aix-xcoff \ +; RUN: -code-model=small < %s | FileCheck %s + +@b = common dso_local local_unnamed_addr global i32 0, align 4 +@a = common dso_local local_unnamed_addr global i32 0, align 4 + +; Function Attrs: norecurse nounwind +define dso_local void @test() local_unnamed_addr #0 { + %1 = load i32, i32* @b, align 4 + store i32 %1, i32* @a, align 4 + ret void +} + +; CHECK-LABEL: test +; CHECK-DAG: lwz [[REG1:[0-9]+]], LC0(2) +; CHECK-DAG: lwz [[REG2:[0-9]+]], LC1(2) +; CHECK-DAG: lwz [[REG3:[0-9]+]], 0([[REG1]]) +; CHECK: stw [[REG3]], 0([[REG2]]) +; CHECK: blr + +; TODO Update test when TOC-entry emission lands. +; CHECK-NOT: .tc