diff --git a/llvm/lib/Target/PowerPC/PPCInstrInfo.h b/llvm/lib/Target/PowerPC/PPCInstrInfo.h --- a/llvm/lib/Target/PowerPC/PPCInstrInfo.h +++ b/llvm/lib/Target/PowerPC/PPCInstrInfo.h @@ -191,6 +191,10 @@ // LI8. bool simplifyToLI(MachineInstr &MI, MachineInstr &DefMI, unsigned OpNoForForwarding, MachineInstr **KilledDef) const; + // If the inst is imm-form and its register operand is produced by a ADDI, put + // the imm into the inst directly and remove the ADDI if possible. + bool transformToNewImmFormFedByAdd(MachineInstr &MI, MachineInstr &DefMI, + unsigned OpNoForForwarding) const; // If the inst is x-form and has imm-form and one of its operand is produced // by a LI, put the imm into the inst directly and remove the LI if possible. bool transformToImmFormFedByLI(MachineInstr &MI, const ImmInstrInfo &III, diff --git a/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp b/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp --- a/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp +++ b/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp @@ -2238,6 +2238,11 @@ // If we're in SSA, get the defs through the MRI. Otherwise, only look // within the basic block to see if the register is defined using an LI/LI8. if (MRI->isSSA()) { + unsigned OpADDI = 0; + unsigned OpLI = 0; + MachineInstr *MIADDI = nullptr; + MachineInstr *MILI = nullptr; + MachineInstr *MITmp = nullptr; for (int i = 1, e = MI.getNumOperands(); i < e; i++) { if (!MI.getOperand(i).isReg()) continue; @@ -2246,13 +2251,28 @@ continue; unsigned TrueReg = TRI->lookThruCopyLike(Reg, MRI); if (Register::isVirtualRegister(TrueReg)) { - DefMI = MRI->getVRegDef(TrueReg); - if (DefMI->getOpcode() == PPC::LI || DefMI->getOpcode() == PPC::LI8) { - OpNoForForwarding = i; - break; + // The ADDI and LI operand maybe exist in one instruction at same time. + MITmp = MRI->getVRegDef(TrueReg); + if (!OpLI && + (MITmp->getOpcode() == PPC::LI || MITmp->getOpcode() == PPC::LI8)) { + OpLI = i; + MILI = MITmp; + } else if (!OpADDI && (MITmp->getOpcode() == PPC::ADDI || + MITmp->getOpcode() == PPC::ADDI8)) { + OpADDI = i; + MIADDI = MITmp; } } } + // Prefer to fold LI operand as LI only has one Imm operand and is more + // possible to be converted. + if (OpLI != 0) { + OpNoForForwarding = OpLI; + DefMI = MILI; + } else if (OpADDI != 0) { + OpNoForForwarding = OpADDI; + DefMI = MIADDI; + } } else { // Looking back through the definition for each operand could be expensive, // so exit early if this isn't an instruction that either has an immediate @@ -2320,10 +2340,6 @@ void PPCInstrInfo::fixupIsDeadOrKill(MachineInstr &StartMI, MachineInstr &EndMI, unsigned RegNo) const { - const MachineRegisterInfo &MRI = - StartMI.getParent()->getParent()->getRegInfo(); - if (MRI.isSSA()) - return; // Instructions between [StartMI, EndMI] should be in same basic block. assert((StartMI.getParent() == EndMI.getParent()) && @@ -2646,6 +2662,13 @@ if (KilledDef && KillFwdDefMI) *KilledDef = DefMI; + // If this is a imm instruction and its register operands is produced by ADDI, + // put the imm into imm inst directly. + if (RI.getMappedIdxOpcForImmOpc(MI.getOpcode()) != + PPC::INSTRUCTION_LIST_END && + transformToNewImmFormFedByAdd(MI, *DefMI, ForwardingOperand)) + return true; + ImmInstrInfo III; bool IsVFReg = MI.getOperand(0).isReg() ? isVFRegister(MI.getOperand(0).getReg()) @@ -3186,6 +3209,10 @@ RegMO = &DefMI.getOperand(1); ImmMO = &DefMI.getOperand(2); + // Before RA, ADDI first operand could be a frame index. + if (!RegMO->isReg()) + return false; + // This DefMI is elgible for forwarding if it is: // 1. add inst // 2. one of the operands is Imm/CPI/Global. @@ -3257,10 +3284,8 @@ if (ImmMO.isImm()) { // It is Imm, we need to check if the Imm fit the range. - int64_t Immediate = ImmMO.getImm(); // Sign-extend to 64-bits. - Imm = ((uint64_t)Immediate & ~0x7FFFuLL) != 0 ? - (Immediate | 0xFFFFFFFFFFFF0000) : Immediate; + Imm += SignExtend64<16>(ImmMO.getImm()); if (Imm % III.ImmMustBeMultipleOf) return false; @@ -3514,6 +3539,95 @@ return false; } +bool PPCInstrInfo::transformToNewImmFormFedByAdd( + MachineInstr &MI, MachineInstr &DefMI, unsigned OpNoForForwarding) const { + MachineRegisterInfo *MRI = &MI.getParent()->getParent()->getRegInfo(); + bool PostRA = !MRI->isSSA(); + // FIXME: extend this to post-ra. Need to do some change in getForwardingDefMI + // for post-ra. + if (PostRA) + return false; + + // Only handle load/store. + if (!MI.mayLoadOrStore()) + return false; + + unsigned XFormOpcode = RI.getMappedIdxOpcForImmOpc(MI.getOpcode()); + + assert((XFormOpcode != PPC::INSTRUCTION_LIST_END) && "MI must be imm form"); + + // get Imm Form info. + ImmInstrInfo III; + bool IsVFReg = MI.getOperand(0).isReg() + ? isVFRegister(MI.getOperand(0).getReg()) + : false; + + if (!instrHasImmForm(XFormOpcode, IsVFReg, III, PostRA)) + return false; + + if (!III.IsSummingOperands) + return false; + + if (OpNoForForwarding != III.OpNoForForwarding) + return false; + + MachineOperand ImmOperandMI = MI.getOperand(III.ImmOpNo); + if (!ImmOperandMI.isImm()) + return false; + + // Check DefMI. + MachineOperand *ImmMO = nullptr; + MachineOperand *RegMO = nullptr; + if (!isDefMIElgibleForForwarding(DefMI, III, ImmMO, RegMO)) + return false; + assert(ImmMO && RegMO && "Imm and Reg operand must have been set"); + + // Check Imm. + int64_t Imm = ImmOperandMI.getImm(); + if (!isImmElgibleForForwarding(*ImmMO, DefMI, III, Imm)) + return false; + + // Get killed info in case fixup needed after transformation. + unsigned ForwardKilledOperandReg = ~0U; + if (MI.getOperand(III.OpNoForForwarding).isKill()) + ForwardKilledOperandReg = MI.getOperand(III.OpNoForForwarding).getReg(); + + // Do the transform + LLVM_DEBUG(dbgs() << "Replacing instruction:\n"); + LLVM_DEBUG(MI.dump()); + LLVM_DEBUG(dbgs() << "Fed by:\n"); + LLVM_DEBUG(DefMI.dump()); + + MI.getOperand(III.OpNoForForwarding).setReg(RegMO->getReg()); + MI.getOperand(III.OpNoForForwarding).setIsKill(RegMO->isKill()); + MI.getOperand(III.ImmOpNo).setImm(Imm); + + // FIXME: fix kill/dead flag if MI and DefMI are not in same basic block. + if (DefMI.getParent() == MI.getParent()) { + // Check if reg is killed between MI and DefMI. + auto IsKilledFor = [&](unsigned Reg) { + MachineBasicBlock::const_reverse_iterator It = MI; + MachineBasicBlock::const_reverse_iterator E = DefMI; + It++; + for (; It != E; ++It) { + if (It->killsRegister(Reg)) + return true; + } + return false; + }; + + // Update kill flag + if (RegMO->isKill() || IsKilledFor(RegMO->getReg())) + fixupIsDeadOrKill(DefMI, MI, RegMO->getReg()); + if (ForwardKilledOperandReg != ~0U) + fixupIsDeadOrKill(DefMI, MI, ForwardKilledOperandReg); + } + + LLVM_DEBUG(dbgs() << "With:\n"); + LLVM_DEBUG(MI.dump()); + return true; +} + // If an X-Form instruction is fed by an add-immediate and one of its operands // is the literal zero, attempt to forward the source of the add-immediate to // the corresponding D-Form instruction with the displacement coming from diff --git a/llvm/test/CodeGen/PowerPC/convert-ri-addi-to-ri.mir b/llvm/test/CodeGen/PowerPC/convert-ri-addi-to-ri.mir new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/convert-ri-addi-to-ri.mir @@ -0,0 +1,67 @@ +# RUN: llc -mtriple=powerpc64le-unknown-linux-gnu -verify-machineinstrs \ +# RUN: -run-pass ppc-mi-peepholes -ppc-convert-rr-to-ri %s -o - | FileCheck %s + +--- +name: foldNewDformStore +# CHECK: name: foldNewDformStore +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x3 + + %0:g8rc_and_g8rc_nox0 = COPY $x3 + %1:g8rc_and_g8rc_nox0 = ADDI8 %0:g8rc_and_g8rc_nox0, 144 + %2:g8rc = LI8 0 + ; CHECK: STD killed %2, 160, %0 + STD killed %2:g8rc, 16, %1:g8rc_and_g8rc_nox0 + BLR8 implicit $lr8, implicit $rm +... +--- +name: foldNewDformStoreAlignNotMatch +# CHECK: name: foldNewDformStoreAlignNotMatch +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x3 + + %0:g8rc_and_g8rc_nox0 = COPY $x3 + %1:g8rc_and_g8rc_nox0 = ADDI8 %0:g8rc_and_g8rc_nox0, 141 + %2:g8rc = LI8 0 + ; CHECK: STD killed %2, 16, %1 + STD killed %2:g8rc, 16, %1:g8rc_and_g8rc_nox0 + BLR8 implicit $lr8, implicit $rm +... +--- +name: foldNewDformStoreKilledFlag +# CHECK: name: foldNewDformStoreKilledFlag +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x3 + + %0:g8rc_and_g8rc_nox0 = COPY $x3 + %1:g8rc_and_g8rc_nox0 = ADDI8 %0:g8rc_and_g8rc_nox0, 144 + %2:g8rc = LI8 0 + ; CHECK: STD %1, 0, %0 + STD %1:g8rc_and_g8rc_nox0, 0, killed %0:g8rc_and_g8rc_nox0 + ; CHECK: STD killed %2, 160, killed %0 + STD killed %2:g8rc, 16, %1:g8rc_and_g8rc_nox0 + BLR8 implicit $lr8, implicit $rm +... +--- +name: foldNewDformPreferLIOperand +# CHECK: name: foldNewDformPreferLIOperand +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x3 + %0:g8rc_and_g8rc_nox0 = COPY $x3 + %1:g8rc = ADDI8 %0:g8rc_and_g8rc_nox0, 1 + %2:g8rc = LI8 1 + ; CHECK: SUBFIC8 killed %1, 1, implicit-def $carry + %3:g8rc = SUBFC8 killed %1:g8rc, %2:g8rc, implicit-def $carry + %4:g8rc = SUBFE8 %2:g8rc, %2:g8rc, implicit-def dead $carry, implicit $carry + %5:g8rc = NEG8 killed %4:g8rc + $x3 = COPY %5:g8rc + BLR8 implicit $lr8, implicit $rm, implicit $x3 +...