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, @@ -221,7 +225,8 @@ bool isImmElgibleForForwarding(const MachineOperand &ImmMO, const MachineInstr &DefMI, const ImmInstrInfo &III, - int64_t &Imm) const; + int64_t &Imm, + int64_t BaseImm = 0) const; bool isRegElgibleForForwarding(const MachineOperand &RegMO, const MachineInstr &DefMI, const MachineInstr &MI, bool KillDefMI, 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 @@ -2563,7 +2563,8 @@ MachineRegisterInfo *MRI = &MI.getParent()->getParent()->getRegInfo(); const TargetRegisterInfo *TRI = &getRegisterInfo(); // 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. + // within the basic block to see if the register is defined using an + // LI/LI8/ADDI/ADDI8. if (MRI->isSSA()) { for (int i = 1, e = MI.getNumOperands(); i < e; i++) { if (!MI.getOperand(i).isReg()) @@ -2574,9 +2575,16 @@ unsigned TrueReg = TRI->lookThruCopyLike(Reg, MRI); if (Register::isVirtualRegister(TrueReg)) { DefMI = MRI->getVRegDef(TrueReg); - if (DefMI->getOpcode() == PPC::LI || DefMI->getOpcode() == PPC::LI8) { + if (DefMI->getOpcode() == PPC::LI || DefMI->getOpcode() == PPC::LI8 || + DefMI->getOpcode() == PPC::ADDI || + DefMI->getOpcode() == PPC::ADDI8) { OpNoForForwarding = i; - break; + // The ADDI and LI operand maybe exist in one instruction at same + // time. we prefer to fold LI operand as LI only has one Imm operand + // and is more possible to be converted. So if current DefMI is + // ADDI/ADDI8, we continue to find possible LI/LI8. + if (DefMI->getOpcode() == PPC::LI || DefMI->getOpcode() == PPC::LI8) + break; } } } @@ -2647,10 +2655,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()) && @@ -2973,6 +2977,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()) @@ -3513,6 +3524,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. @@ -3561,7 +3576,8 @@ bool PPCInstrInfo::isImmElgibleForForwarding(const MachineOperand &ImmMO, const MachineInstr &DefMI, const ImmInstrInfo &III, - int64_t &Imm) const { + int64_t &Imm, + int64_t BaseImm) const { assert(isAnImmediateOperand(ImmMO) && "ImmMO is NOT an immediate"); if (DefMI.getOpcode() == PPC::ADDItocL) { // The operand for ADDItocL is CPI, which isn't imm at compiling time, @@ -3584,10 +3600,10 @@ 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; + // DefMI may be folded with another imm form instruction, the result Imm is + // the sum of Imm of DefMI and BaseImm which is from imm form instruction. + Imm = SignExtend64<16>(ImmMO.getImm() + BaseImm); if (Imm % III.ImmMustBeMultipleOf) return false; @@ -3840,6 +3856,99 @@ 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 have x-form opcode"); + + // 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. + // Set ImmBase from imm instruction as base and get new Imm inside + // isImmElgibleForForwarding. + int64_t ImmBase = ImmOperandMI.getImm(); + int64_t Imm = 0; + if (!isImmElgibleForForwarding(*ImmMO, DefMI, III, Imm, ImmBase)) + 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 +...