Index: llvm/include/llvm/MC/MCExpr.h =================================================================== --- llvm/include/llvm/MC/MCExpr.h +++ llvm/include/llvm/MC/MCExpr.h @@ -235,6 +235,8 @@ VK_PPC_TOC_LO, // symbol@toc@l VK_PPC_TOC_HI, // symbol@toc@h VK_PPC_TOC_HA, // symbol@toc@ha + VK_PPC_U, // symbol@u + VK_PPC_L, // symbol@l VK_PPC_DTPMOD, // symbol@dtpmod VK_PPC_TPREL_LO, // symbol@tprel@l VK_PPC_TPREL_HI, // symbol@tprel@h Index: llvm/lib/MC/MCExpr.cpp =================================================================== --- llvm/lib/MC/MCExpr.cpp +++ llvm/lib/MC/MCExpr.cpp @@ -259,6 +259,8 @@ case VK_PPC_TOC_LO: return "toc@l"; case VK_PPC_TOC_HI: return "toc@h"; case VK_PPC_TOC_HA: return "toc@ha"; + case VK_PPC_U: return "u"; + case VK_PPC_L: return "l"; case VK_PPC_DTPMOD: return "dtpmod"; case VK_PPC_TPREL_LO: return "tprel@l"; case VK_PPC_TPREL_HI: return "tprel@h"; @@ -373,6 +375,8 @@ .Case("toc@l", VK_PPC_TOC_LO) .Case("toc@h", VK_PPC_TOC_HI) .Case("toc@ha", VK_PPC_TOC_HA) + .Case("u", VK_PPC_U) + .Case("l", VK_PPC_L) .Case("tls", VK_PPC_TLS) .Case("dtpmod", VK_PPC_DTPMOD) .Case("tprel@l", VK_PPC_TPREL_LO) Index: llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp =================================================================== --- llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp +++ llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp @@ -66,6 +66,31 @@ void PPCInstPrinter::printInst(const MCInst *MI, raw_ostream &O, StringRef Annot, const MCSubtargetInfo &STI) { + // Customize printing of the addis instruction on AIX. When an operand is a + // symbol reference, the instruction syntax is changed to look like a load + // operation, i.e: + // Transform: addis $rD, $rA, $src --> addis $rD, $src($rA). + if (TT.isOSAIX() && + (MI->getOpcode() == PPC::ADDIS8 || MI->getOpcode() == PPC::ADDIS) && + MI->getOperand(2).isExpr()) { + assert((MI->getOperand(0).isReg() && MI->getOperand(1).isReg()) && + "The first and the second operand of an addis instruction" + " should be registers."); + + assert(isa(MI->getOperand(2).getExpr()) && + "The third operand of an addis instruction should be a symbol " + "reference expression if it is an expression at all."); + + O << "\taddis "; + printOperand(MI, 0, O); + O << ", "; + printOperand(MI, 2, O); + O << "("; + printOperand(MI, 1, O); + O << ")"; + return; + } + // Check for slwi/srwi mnemonics. if (MI->getOpcode() == PPC::RLWINM) { unsigned char SH = MI->getOperand(2).getImm(); Index: llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp =================================================================== --- llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp +++ llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp @@ -512,12 +512,28 @@ .addExpr(SymVar)); } +// Map the machine operand to its corresponding MCSymbol. +static MCSymbol *getMCSymbolForTOCPseudoMO(const MachineOperand &MO, AsmPrinter &AP) { + if (MO.isGlobal()) + return AP.getSymbol(MO.getGlobal()); + if (MO.isCPI()) + return AP.GetCPISymbol(MO.getIndex()); + if (MO.isJTI()) + return AP.GetJTISymbol(MO.getIndex()); + if (MO.isBlockAddress()) + return AP.GetBlockAddressSymbol(MO.getBlockAddress()); + + llvm_unreachable("Unsupported machine operand type."); +} + /// EmitInstruction -- Print out a single PowerPC MI in Darwin syntax to /// the current output stream. /// void PPCAsmPrinter::EmitInstruction(const MachineInstr *MI) { MCInst TmpInst; const bool IsDarwin = TM.getTargetTriple().isOSDarwin(); + const bool IsPPC64 = Subtarget->isPPC64(); + const bool IsAIX = Subtarget->isAIXABI(); const Module *M = MF->getFunction().getParent(); PICLevel::Level PL = M->getPICLevel(); @@ -668,17 +684,7 @@ "Unexpected operand type for LWZtoc pseudo."); // Map the operand to its corresponding MCSymbol. - MCSymbol *MOSymbol = nullptr; - if (MO.isGlobal()) - MOSymbol = getSymbol(MO.getGlobal()); - else if (MO.isCPI()) - MOSymbol = GetCPISymbol(MO.getIndex()); - else if (MO.isJTI()) - MOSymbol = GetJTISymbol(MO.getIndex()); - else if (MO.isBlockAddress()) - MOSymbol = GetBlockAddressSymbol(MO.getBlockAddress()); - - const bool IsAIX = TM.getTargetTriple().isOSAIX(); + MCSymbol *MOSymbol = getMCSymbolForTOCPseudoMO(MO, *this); // Create a reference to the GOT entry for the symbol. The GOT entry will be // synthesized later. @@ -723,71 +729,122 @@ case PPC::LDtocCPT: case PPC::LDtocBA: case PPC::LDtoc: { + assert (!IsDarwin && "TOC is an ELF/XCOFF construct"); + // Transform %x3 = LDtoc @min1, %x2 LowerPPCMachineInstrToMCInst(MI, TmpInst, *this, IsDarwin); - // Change the opcode to LD, and the global address operand to be a - // reference to the TOC entry we will synthesize later. + // Change the opcode to LD. TmpInst.setOpcode(PPC::LD); + const MachineOperand &MO = MI->getOperand(1); + assert((MO.isGlobal() || MO.isCPI() || MO.isJTI() || MO.isBlockAddress()) && + "Unexpected operand type."); - // Map symbol -> label of TOC entry - assert(MO.isGlobal() || MO.isCPI() || MO.isJTI() || MO.isBlockAddress()); - MCSymbol *MOSymbol = nullptr; - if (MO.isGlobal()) - MOSymbol = getSymbol(MO.getGlobal()); - else if (MO.isCPI()) - MOSymbol = GetCPISymbol(MO.getIndex()); - else if (MO.isJTI()) - MOSymbol = GetJTISymbol(MO.getIndex()); - else if (MO.isBlockAddress()) - MOSymbol = GetBlockAddressSymbol(MO.getBlockAddress()); + // Map the machine operand to its corresponding MCSymbol. + MCSymbol *MOSymbol = getMCSymbolForTOCPseudoMO(MO, *this); + // Map the global address operand to be a reference to the TOC entry we + // will synthesize later. MCSymbol *TOCEntry = lookUpOrCreateTOCEntry(MOSymbol); + const MCSymbolRefExpr::VariantKind VK = + IsAIX ? MCSymbolRefExpr::VK_None : MCSymbolRefExpr::VK_PPC_TOC; const MCExpr *Exp = - MCSymbolRefExpr::create(TOCEntry, MCSymbolRefExpr::VK_PPC_TOC, - OutContext); + MCSymbolRefExpr::create(TOCEntry, VK, OutContext); TmpInst.getOperand(1) = MCOperand::createExpr(Exp); EmitToStreamer(*OutStreamer, TmpInst); return; } + case PPC::ADDIStocHA: { + assert((IsAIX && !IsPPC64 && TM.getCodeModel() == CodeModel::Large) && + "This pseudo should only be selected for 32-bit large code model on" + " AIX."); + + // Transform %rd = ADDIStocHA %rA, @sym(%r2) + LowerPPCMachineInstrToMCInst(MI, TmpInst, *this, IsDarwin); + + // Change the opcode to ADDIS. + TmpInst.setOpcode(PPC::ADDIS); + + const MachineOperand &MO = MI->getOperand(2); + assert((MO.isGlobal() || MO.isCPI() || MO.isJTI() || MO.isBlockAddress()) && + "Unexpected operand type for ADDIStocHA pseudo."); + + // Map the machine operand to its corresponding MCSymbol. + MCSymbol *MOSymbol = getMCSymbolForTOCPseudoMO(MO, *this); + + // Always use TOC on AIX. Map the global address operand to be a reference + // to the TOC entry we will synthesize later. 'TOCEntry' is a label used to + // reference the storage allocated in the TOC which contains the address of + // 'MOSymbol'. + MCSymbol *TOCEntry = lookUpOrCreateTOCEntry(MOSymbol); + const MCExpr *Exp = MCSymbolRefExpr::create(TOCEntry, + MCSymbolRefExpr::VK_PPC_U, + OutContext); + TmpInst.getOperand(2) = MCOperand::createExpr(Exp); + EmitToStreamer(*OutStreamer, TmpInst); + return; + } + case PPC::LWZtocL: { + assert(IsAIX && !IsPPC64 && TM.getCodeModel() == CodeModel::Large && + "This pseudo should only be selected for 32-bit large code model on" + " AIX."); + + // Transform %rd = LWZtocL @sym, %rs. + LowerPPCMachineInstrToMCInst(MI, TmpInst, *this, IsDarwin); + // 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 LWZtocL pseudo."); + + // Map the machine operand to its corresponding MCSymbol. + MCSymbol *MOSymbol = getMCSymbolForTOCPseudoMO(MO, *this); + + // Always use TOC on AIX. Map the global address operand to be a reference + // to the TOC entry we will synthesize later. 'TOCEntry' is a label used to + // reference the storage allocated in the TOC which contains the address of + // 'MOSymbol'. + MCSymbol *TOCEntry = lookUpOrCreateTOCEntry(MOSymbol); + const MCExpr *Exp = MCSymbolRefExpr::create(TOCEntry, + MCSymbolRefExpr::VK_PPC_L, + OutContext); + TmpInst.getOperand(1) = MCOperand::createExpr(Exp); + EmitToStreamer(*OutStreamer, TmpInst); + return; + } case PPC::ADDIStocHA8: { + assert (!IsDarwin && "TOC is an ELF/XCOFF construct"); + // Transform %xd = ADDIStocHA8 %x2, @sym LowerPPCMachineInstrToMCInst(MI, TmpInst, *this, IsDarwin); - // Change the opcode to ADDIS8. If the global address is external, has - // common linkage, is a non-local function address, or is a jump table - // address, then generate a TOC entry and reference that. Otherwise - // reference the symbol directly. + // Change the opcode to ADDIS8. If the global address is the address of + // an external symbol, is a jump table address, or is a block address; or if + // the large code model is enabled then generate a TOC entry and reference + // that. Otherwise, reference the symbol directly. TmpInst.setOpcode(PPC::ADDIS8); + const MachineOperand &MO = MI->getOperand(2); - assert((MO.isGlobal() || MO.isCPI() || MO.isJTI() || - MO.isBlockAddress()) && - "Invalid operand for ADDIStocHA8!"); - MCSymbol *MOSymbol = nullptr; - bool GlobalToc = false; + assert((MO.isGlobal() || MO.isCPI() || MO.isJTI() || MO.isBlockAddress()) && + "Unexpected operand type for ADDIStocHA8 pseudo."); - if (MO.isGlobal()) { - const GlobalValue *GV = MO.getGlobal(); - MOSymbol = getSymbol(GV); - GlobalToc = Subtarget->isGVIndirectSymbol(GV); - } else if (MO.isCPI()) { - MOSymbol = GetCPISymbol(MO.getIndex()); - } else if (MO.isJTI()) { - MOSymbol = GetJTISymbol(MO.getIndex()); - } else if (MO.isBlockAddress()) { - MOSymbol = GetBlockAddressSymbol(MO.getBlockAddress()); - } + MCSymbol *MOSymbol = getMCSymbolForTOCPseudoMO(MO, *this); + + bool GlobalToc = + MO.isGlobal() && Subtarget->isGVIndirectSymbol(MO.getGlobal()); if (GlobalToc || MO.isJTI() || MO.isBlockAddress() || - TM.getCodeModel() == CodeModel::Large) + (MO.isCPI() && TM.getCodeModel() == CodeModel::Large)) MOSymbol = lookUpOrCreateTOCEntry(MOSymbol); + const MCSymbolRefExpr::VariantKind VK = + !IsAIX ? MCSymbolRefExpr::VK_PPC_TOC_HA : MCSymbolRefExpr::VK_PPC_U; const MCExpr *Exp = - MCSymbolRefExpr::create(MOSymbol, MCSymbolRefExpr::VK_PPC_TOC_HA, - OutContext); + MCSymbolRefExpr::create(MOSymbol, VK, OutContext); if (!MO.isJTI() && MO.getOffset()) Exp = MCBinaryExpr::createAdd(Exp, @@ -800,43 +857,35 @@ return; } case PPC::LDtocL: { + assert (!IsDarwin && "TOC is an ELF/XCOFF construct"); + // Transform %xd = LDtocL @sym, %xs LowerPPCMachineInstrToMCInst(MI, TmpInst, *this, IsDarwin); - // Change the opcode to LD. If the global address is external, has - // common linkage, or is a jump table address, then reference the - // associated TOC entry. Otherwise reference the symbol directly. + // Change the opcode to LD. If the global address is the address of + // an external symbol, is a jump table address, is a block address; or if + // large code model is enabled then generate a TOC entry and reference that. + // Otherwise reference the symbol directly. TmpInst.setOpcode(PPC::LD); + const MachineOperand &MO = MI->getOperand(1); - assert((MO.isGlobal() || MO.isCPI() || MO.isJTI() || - MO.isBlockAddress()) && - "Invalid operand for LDtocL!"); - MCSymbol *MOSymbol = nullptr; + assert((MO.isGlobal() || MO.isCPI() || MO.isJTI() || MO.isBlockAddress()) && + "Unexpected operand type for LDtocL pseudo."); - if (MO.isJTI()) - MOSymbol = lookUpOrCreateTOCEntry(GetJTISymbol(MO.getIndex())); - else if (MO.isBlockAddress()) { - MOSymbol = GetBlockAddressSymbol(MO.getBlockAddress()); - MOSymbol = lookUpOrCreateTOCEntry(MOSymbol); - } - else if (MO.isCPI()) { - MOSymbol = GetCPISymbol(MO.getIndex()); - if (TM.getCodeModel() == CodeModel::Large) - MOSymbol = lookUpOrCreateTOCEntry(MOSymbol); - } - else if (MO.isGlobal()) { - const GlobalValue *GV = MO.getGlobal(); - MOSymbol = getSymbol(GV); - LLVM_DEBUG( - assert((Subtarget->isGVIndirectSymbol(GV)) && - "LDtocL used on symbol that could be accessed directly is " - "invalid. Must match ADDIStocHA8.")); + MCSymbol *MOSymbol = getMCSymbolForTOCPseudoMO(MO, *this); + + LLVM_DEBUG( + assert((!MO.isGlobal() || Subtarget->isGVIndirectSymbol(MO.getGlobal())) && + "LDtocL used on symbol that could be accessed directly is " + "invalid. Must match ADDIStocHA8.")); + + if (!MO.isCPI() || TM.getCodeModel() == CodeModel::Large) MOSymbol = lookUpOrCreateTOCEntry(MOSymbol); - } + const MCSymbolRefExpr::VariantKind VK = + !IsAIX ? MCSymbolRefExpr::VK_PPC_TOC_LO : MCSymbolRefExpr::VK_PPC_L; const MCExpr *Exp = - MCSymbolRefExpr::create(MOSymbol, MCSymbolRefExpr::VK_PPC_TOC_LO, - OutContext); + MCSymbolRefExpr::create(MOSymbol, VK, OutContext); TmpInst.getOperand(1) = MCOperand::createExpr(Exp); EmitToStreamer(*OutStreamer, TmpInst); return; Index: llvm/lib/Target/PowerPC/PPCInstrInfo.cpp =================================================================== --- llvm/lib/Target/PowerPC/PPCInstrInfo.cpp +++ llvm/lib/Target/PowerPC/PPCInstrInfo.cpp @@ -329,6 +329,7 @@ case PPC::LIS8: case PPC::QVGPCI: case PPC::ADDIStocHA8: + case PPC::ADDIStocHA: case PPC::ADDItocL: case PPC::LOAD_STACK_GUARD: case PPC::XXLXORz: Index: llvm/lib/Target/PowerPC/PPCInstrInfo.td =================================================================== --- llvm/lib/Target/PowerPC/PPCInstrInfo.td +++ llvm/lib/Target/PowerPC/PPCInstrInfo.td @@ -3168,10 +3168,12 @@ "#LWZtocL", [(set i32:$rD, (PPCtoc_entry tglobaladdr:$disp, i32:$reg))]>; +let hasSideEffects = 0, isReMaterializable = 1 in { def ADDIStocHA : PPCEmitTimePseudo<(outs gprc:$rD), (ins gprc_nor0:$reg, tocentry32:$disp), - "#ADDIStocHA", - [(set i32:$rD, - (PPCtoc_entry i32:$reg, tglobaladdr:$disp))]>; + "#ADDIStocHA", + [(set i32:$rD, + (PPCtoc_entry i32:$reg, tglobaladdr:$disp))]>; +} // Get Global (GOT) Base Register offset, from the word immediately preceding // the function label. Index: llvm/test/CodeGen/PowerPC/lower-globaladdr32-aix-asm.ll =================================================================== --- llvm/test/CodeGen/PowerPC/lower-globaladdr32-aix-asm.ll +++ llvm/test/CodeGen/PowerPC/lower-globaladdr32-aix-asm.ll @@ -1,5 +1,8 @@ -; RUN: llc -mtriple powerpc-ibm-aix-xcoff \ -; RUN: -code-model=small < %s | FileCheck %s +; RUN: llc -verify-machineinstrs -mcpu=pwr7 -mtriple powerpc-ibm-aix-xcoff \ +; RUN: -code-model=small < %s | FileCheck %s --check-prefix=SMALL + +; RUN: llc -verify-machineinstrs -mcpu=pwr7 -mtriple powerpc-ibm-aix-xcoff \ +; RUN: -code-model=large < %s | FileCheck %s --check-prefix=LARGE @b = common global i32 0 @a = common global i32 0 @@ -9,13 +12,18 @@ store i32 %1, i32* @a ret void } +; SMALL: lwz [[REG1:[0-9]+]], LC0(2) +; SMALL: lwz [[REG2:[0-9]+]], LC1(2) +; SMALL: lwz [[REG3:[0-9]+]], 0([[REG1]]) +; SMALL: stw [[REG3]], 0([[REG2]]) +; SMALL: blr + +; LARGE: addis [[REG1:[0-9]+]], LC0@u(2) +; LARGE: lwz [[REG2:[0-9]+]], LC0@l([[REG1]]) +; LARGE: lwz [[REG3:[0-9]+]], 0([[REG2]]) +; LARGE: addis [[REG4:[0-9]+]], LC1@u(2) +; LARGE: lwz [[REG5:[0-9]+]], LC1@l([[REG4]]) -; 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 Index: llvm/test/CodeGen/PowerPC/lower-globaladdr64-aix-asm.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/PowerPC/lower-globaladdr64-aix-asm.ll @@ -0,0 +1,30 @@ +; RUN: llc -verify-machineinstrs -mcpu=pwr7 -mtriple powerpc64-ibm-aix-xcoff \ +; RUN: -code-model=small < %s | FileCheck %s --check-prefix=SMALL + +; RUN: llc -verify-machineinstrs -mcpu=pwr7 -mtriple powerpc64-ibm-aix-xcoff \ +; RUN: -code-model=large < %s | FileCheck %s --check-prefix=LARGE + +@b = common global i32 0 +@a = common global i32 0 + +define void @test() { + %1 = load i32, i32* @b + store i32 %1, i32* @a + ret void +} + +; SMALL: ld [[REG1:[0-9]+]], LC0(2) +; SMALL: ld [[REG2:[0-9]+]], LC1(2) +; SMALL: lwz [[REG3:[0-9]+]], 0([[REG1]]) +; SMALL: stw [[REG3]], 0([[REG2]]) +; SMALL: blr + +; LARGE: addis [[REG1:[0-9]+]], LC0@u(2) +; LARGE: addis [[REG2:[0-9]+]], LC1@u(2) +; LARGE: ld [[REG3:[0-9]+]], LC0@l([[REG1]]) +; LARGE: ld [[REG4:[0-9]+]], LC1@l([[REG2]]) +; LARGE: lwz [[REG4:[0-9]+]], 0([[REG3]]) + + +; TODO Update test when TOC-entry emission lands. +; CHECK-NOT: .tc