Index: llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp =================================================================== --- llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp +++ llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp @@ -179,27 +179,81 @@ PPCMCCodeEmitter::getMemRI34PCRelEncoding(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const { - // Encode (imm, reg) as a memri34, which has the low 34-bits as the - // displacement and the next 5 bits as an immediate 0. + // Encode the PCRelative version of memri34: imm34(r0). + // In the PC relative version the register for the address must be zero. + // The 34 bit immediate can fall into one of three cases: + // 1) It is a relocation to be filled in by the linker represented as: + // (MCExpr::SymbolRef) + // 2) It is a relocation + SignedOffset represented as: + // (MCExpr::Binary(MCExpr::SymbolRef + MCExpr::Constant)) + // 3) It is a known value at compile time. + + // Make sure that the register is a zero as expected. assert(MI.getOperand(OpNo + 1).isImm() && "Expecting an immediate."); uint64_t RegBits = getMachineOpValue(MI, MI.getOperand(OpNo + 1), Fixups, STI) << 34; + assert(RegBits == 0 && "Operand must be 0."); - if (RegBits != 0) - report_fatal_error("Operand must be 0"); - + // Check if the operand is an expression. A value of true indicates case + // 1) or 2) above. A false here is case 3) and we drop to the return at + // the end. const MCOperand &MO = MI.getOperand(OpNo); if (MO.isExpr()) { const MCExpr *Expr = MO.getExpr(); - const MCSymbolRefExpr *SRE = cast(Expr); - assert((SRE->getKind() == MCSymbolRefExpr::VK_PCREL || - SRE->getKind() == MCSymbolRefExpr::VK_PPC_GOT_PCREL) && - "VariantKind must be VK_PCREL or VK_PPC_GOT_PCREL"); - Fixups.push_back( - MCFixup::create(IsLittleEndian ? 0 : 1, Expr, - static_cast(PPC::fixup_ppc_pcrel34))); - return 0; + switch (Expr->getKind()) { + default: + llvm_unreachable("Unsupported MCExpr for getMemRI34PCRelEncoding."); + case MCExpr::SymbolRef: { + // Case 1). Relocation alone. + const MCSymbolRefExpr *SRE = cast(Expr); + // Currently these are the only valid PCRelative Relocations. + assert((SRE->getKind() == MCSymbolRefExpr::VK_PCREL || + SRE->getKind() == MCSymbolRefExpr::VK_PPC_GOT_PCREL) && + "VariantKind must be VK_PCREL or VK_PPC_GOT_PCREL"); + // Generate the fixup for the relocation. + Fixups.push_back( + MCFixup::create(IsLittleEndian ? 0 : 1, Expr, + static_cast(PPC::fixup_ppc_pcrel34))); + // There is no offset to return so just return 0. + return 0; + } + case MCExpr::Binary: { + // Case 2). Relocation plus some offset. + const MCBinaryExpr *BE = cast(Expr); + assert(BE->getOpcode() == MCBinaryExpr::Add && + "Binary expression opcode must be an add."); + + // Need to check in both directions. Reloc+Offset and Offset+Reloc. + const MCExpr *LHS = BE->getLHS(); + const MCExpr *RHS = BE->getRHS(); + const MCSymbolRefExpr *SRE = 0; + const MCConstantExpr *CE = 0; + if (LHS->getKind() == MCExpr::SymbolRef && + RHS->getKind() == MCExpr::Constant) { + SRE = cast(LHS); + CE = cast(RHS); + } else if (LHS->getKind() == MCExpr::Constant && + RHS->getKind() == MCExpr::SymbolRef) { + SRE = cast(RHS); + CE = cast(LHS); + } else { + llvm_unreachable("Expecting to have one constant and one relocation."); + } + + // Currently these are the only valid PCRelative Relocations. + assert((SRE->getKind() == MCSymbolRefExpr::VK_PCREL || + SRE->getKind() == MCSymbolRefExpr::VK_PPC_GOT_PCREL) && + "VariantKind must be VK_PCREL or VK_PPC_GOT_PCREL"); + // Generate the fixup for the relocation. + Fixups.push_back( + MCFixup::create(IsLittleEndian ? 0 : 1, SRE, + static_cast(PPC::fixup_ppc_pcrel34))); + // Return the offset that should be added to the relocation by the linker. + return (CE->getValue() & 0x3FFFFFFFFUL) | RegBits; + } + } } + // Case 3). The operand is a constant so we just emit that. return ((getMachineOpValue(MI, MO, Fixups, STI)) & 0x3FFFFFFFFUL) | RegBits; } Index: llvm/lib/Target/PowerPC/PPCISelLowering.cpp =================================================================== --- llvm/lib/Target/PowerPC/PPCISelLowering.cpp +++ llvm/lib/Target/PowerPC/PPCISelLowering.cpp @@ -15641,10 +15641,63 @@ return SDValue(); } +// Transform +// (add C1, (MAT_PCREL_ADDR GlobalAddr+C2)) to +// (MAT_PCREL_ADDR GlobalAddr+(C1+C2)) +// In this case both C1 and C2 must be known constants. +// C1+C2 must fit into a 34 bit signed integer. +static SDValue combineADDToMAT_PCREL_ADDR(SDNode *N, SelectionDAG &DAG, + const PPCSubtarget &Subtarget) { + if (!Subtarget.isPPC64()) + return SDValue(); + if (!Subtarget.hasPCRelativeMemops()) + return SDValue(); + + // Check both Operand 0 and Operand 1 of the ADD node for the PCRel node. + // If we find that node try to cast the Global Address and the Constant. + SDValue OP0 = N->getOperand(0); + SDValue OP1 = N->getOperand(1); + GlobalAddressSDNode *GSDN = 0; + ConstantSDNode* ConstNode = 0; + if (OP0.getNode()->getOpcode() == PPCISD::MAT_PCREL_ADDR) { + GSDN = dyn_cast(OP0.getOperand(0).getNode()); + ConstNode = dyn_cast(OP1.getNode()); + } else if (OP1.getNode()->getOpcode() == PPCISD::MAT_PCREL_ADDR) { + GSDN = dyn_cast(OP1.getOperand(0).getNode()); + ConstNode = dyn_cast(OP0.getNode()); + } else { + return SDValue(); + } + + // Check that both casts succeeded. + if (GSDN && ConstNode) { + int64_t NewOffset = GSDN->getOffset() + ConstNode->getSExtValue(); + SDLoc DL(GSDN); + + // The signed int offset needs to fit in 34 bits. + APInt APOffset(64, NewOffset); + if (!APOffset.isSignedIntN(34)) + return SDValue(); + + // The new global address is a copy of the old global address except + // that it has the updated Offset. + SDValue GA = + DAG.getTargetGlobalAddress(GSDN->getGlobal(), DL, GSDN->getValueType(0), + NewOffset, GSDN->getTargetFlags()); + SDValue MatPCRel = + DAG.getNode(PPCISD::MAT_PCREL_ADDR, DL, GSDN->getValueType(0), GA); + return MatPCRel; + } + return SDValue(); +} + SDValue PPCTargetLowering::combineADD(SDNode *N, DAGCombinerInfo &DCI) const { if (auto Value = combineADDToADDZE(N, DCI.DAG, Subtarget)) return Value; + if (auto Value = combineADDToMAT_PCREL_ADDR(N, DCI.DAG, Subtarget)) + return Value; + return SDValue(); } Index: llvm/test/CodeGen/PowerPC/global-address-non-got-indirect-access.ll =================================================================== --- llvm/test/CodeGen/PowerPC/global-address-non-got-indirect-access.ll +++ llvm/test/CodeGen/PowerPC/global-address-non-got-indirect-access.ll @@ -131,9 +131,8 @@ define ppc_fp128 @_Z23ReadStaticLongDoubleVarv() { ; CHECK-LABEL: _Z23ReadStaticLongDoubleVarv: ; CHECK: # %bb.0: # %entry -; CHECK-NEXT: paddi r3, 0, _ZL19StaticLongDoubleVar@PCREL, 1 -; CHECK-NEXT: lfd f2, 8(r3) ; CHECK-NEXT: plfd f1, _ZL19StaticLongDoubleVar@PCREL(0), 1 +; CHECK-NEXT: plfd f2, _ZL19StaticLongDoubleVar@PCREL+8(0), 1 ; CHECK-NEXT: blr entry: %0 = load ppc_fp128, ppc_fp128* @_ZL19StaticLongDoubleVar, align 16 @@ -144,9 +143,8 @@ define i128 @_Z27ReadStaticSigned__Int128Varv() { ; CHECK-LABEL: _Z27ReadStaticSigned__Int128Varv: ; CHECK: # %bb.0: # %entry -; CHECK-NEXT: paddi r3, 0, _ZL23StaticSigned__Int128Var@PCREL, 1 -; CHECK-NEXT: ld r4, 8(r3) ; CHECK-NEXT: pld r3, _ZL23StaticSigned__Int128Var@PCREL(0), 1 +; CHECK-NEXT: pld r4, _ZL23StaticSigned__Int128Var@PCREL+8(0), 1 ; CHECK-NEXT: blr entry: %0 = load i128, i128* @_ZL23StaticSigned__Int128Var, align 16 @@ -340,8 +338,7 @@ define void @_Z24WriteStaticLongDoubleVarg(ppc_fp128 %val) { ; CHECK-LABEL: _Z24WriteStaticLongDoubleVarg: ; CHECK: # %bb.0: # %entry -; CHECK-NEXT: paddi r3, 0, _ZL19StaticLongDoubleVar@PCREL, 1 -; CHECK-NEXT: stfd f2, 8(r3) +; CHECK-NEXT: pstfd f2, _ZL19StaticLongDoubleVar@PCREL+8(0), 1 ; CHECK-NEXT: pstfd f1, _ZL19StaticLongDoubleVar@PCREL(0), 1 ; CHECK-NEXT: blr entry: @@ -353,8 +350,7 @@ define void @_Z28WriteStaticSigned__Int128Varn(i128 %val) { ; CHECK-LABEL: _Z28WriteStaticSigned__Int128Varn: ; CHECK: # %bb.0: # %entry -; CHECK-NEXT: paddi r5, 0, _ZL23StaticSigned__Int128Var@PCREL, 1 -; CHECK-NEXT: std r4, 8(r5) +; CHECK-NEXT: pstd r4, _ZL23StaticSigned__Int128Var@PCREL+8(0), 1 ; CHECK-NEXT: pstd r3, _ZL23StaticSigned__Int128Var@PCREL(0), 1 ; CHECK-NEXT: blr entry: @@ -490,8 +486,7 @@ define signext i32 @_Z15ReadStaticArrayv() { ; CHECK-LABEL: _Z15ReadStaticArrayv: ; CHECK: # %bb.0: # %entry -; CHECK-NEXT: paddi r3, 0, _ZL5array@PCREL, 1 -; CHECK-NEXT: lwa r3, 12(r3) +; CHECK-NEXT: plwa r3, _ZL5array@PCREL+12(0), 1 ; CHECK-NEXT: blr entry: %0 = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @_ZL5array, i64 0, i64 3), align 4 @@ -502,9 +497,8 @@ define void @_Z16WriteStaticArrayv() { ; CHECK-LABEL: _Z16WriteStaticArrayv: ; CHECK: # %bb.0: # %entry -; CHECK-NEXT: paddi r3, 0, _ZL5array@PCREL, 1 -; CHECK-NEXT: li r4, 5 -; CHECK-NEXT: stw r4, 12(r3) +; CHECK-NEXT: li r3, 5 +; CHECK-NEXT: pstw r3, _ZL5array@PCREL+12(0), 1 ; CHECK-NEXT: blr entry: store i32 5, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @_ZL5array, i64 0, i64 3), align 4 @@ -518,8 +512,7 @@ define signext i32 @_Z16ReadStaticStructv() { ; CHECK-LABEL: _Z16ReadStaticStructv: ; CHECK: # %bb.0: # %entry -; CHECK-NEXT: paddi r3, 0, _ZL9structure@PCREL, 1 -; CHECK-NEXT: lwa r3, 4(r3) +; CHECK-NEXT: plwa r3, _ZL9structure@PCREL+4(0), 1 ; CHECK-NEXT: blr entry: %0 = load i32, i32* getelementptr inbounds (%struct.Struct, %struct.Struct* @_ZL9structure, i64 0, i32 2), align 4 @@ -530,9 +523,8 @@ define void @_Z17WriteStaticStructv() { ; CHECK-LABEL: _Z17WriteStaticStructv: ; CHECK: # %bb.0: # %entry -; CHECK-NEXT: paddi r3, 0, _ZL9structure@PCREL, 1 -; CHECK-NEXT: li r4, 3 -; CHECK-NEXT: stw r4, 4(r3) +; CHECK-NEXT: li r3, 3 +; CHECK-NEXT: pstw r3, _ZL9structure@PCREL+4(0), 1 ; CHECK-NEXT: blr entry: store i32 3, i32* getelementptr inbounds (%struct.Struct, %struct.Struct* @_ZL9structure, i64 0, i32 2), align 4