diff options
| -rw-r--r-- | llvm/lib/Target/PowerPC/PPCInstrInfo.cpp | 158 | ||||
| -rw-r--r-- | llvm/lib/Target/PowerPC/PPCInstrInfo.h | 22 | ||||
| -rw-r--r-- | llvm/test/CodeGen/PowerPC/convert-rr-to-ri-instr-add.mir | 2 | ||||
| -rw-r--r-- | llvm/test/CodeGen/PowerPC/convert-rr-to-ri-instrs-kill-flag.mir | 183 | 
4 files changed, 343 insertions, 22 deletions
diff --git a/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp b/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp index 78206f9959d..936cbcc4c30 100644 --- a/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp +++ b/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp @@ -2424,6 +2424,83 @@ const unsigned *PPCInstrInfo::getLoadOpcodesForSpillArray() const {    return OpcodesForSpill[(Subtarget.hasP9Vector()) ? 1 : 0];  } +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()) && +         "Instructions are not in same basic block"); + +  bool IsKillSet = false; + +  auto clearOperandKillInfo = [=] (MachineInstr &MI, unsigned Index) { +    MachineOperand &MO = MI.getOperand(Index); +    if (MO.isReg() && MO.isUse() && MO.isKill() && +        getRegisterInfo().regsOverlap(MO.getReg(), RegNo)) +      MO.setIsKill(false); +  }; + +  // Set killed flag for EndMI. +  // No need to do anything if EndMI defines RegNo. +  int UseIndex = +      EndMI.findRegisterUseOperandIdx(RegNo, false, &getRegisterInfo()); +  if (UseIndex != -1) { +    EndMI.getOperand(UseIndex).setIsKill(true); +    IsKillSet = true; +    // Clear killed flag for other EndMI operands related to RegNo. In some +    // upexpected cases, killed may be set multiple times for same register +    // operand in same MI. +    for (int i = 0, e = EndMI.getNumOperands(); i != e; ++i) +      if (i != UseIndex) +        clearOperandKillInfo(EndMI, i); +  } + +  // Walking the inst in reverse order (EndMI -> StartMI]. +  MachineBasicBlock::reverse_iterator It = EndMI; +  MachineBasicBlock::reverse_iterator E = EndMI.getParent()->rend(); +  // EndMI has been handled above, skip it here. +  It++; +  MachineOperand *MO = nullptr; +  for (; It != E; ++It) { +    // Skip insturctions which could not be a def/use of RegNo. +    if (It->isDebugInstr() || It->isPosition()) +      continue; + +    // Clear killed flag for all It operands related to RegNo. In some +    // upexpected cases, killed may be set multiple times for same register +    // operand in same MI. +    for (int i = 0, e = It->getNumOperands(); i != e; ++i) +        clearOperandKillInfo(*It, i); + +    // If killed is not set, set killed for its last use or set dead for its def +    // if no use found. +    if (!IsKillSet) { +      if ((MO = It->findRegisterUseOperand(RegNo, false, &getRegisterInfo()))) { +        // Use found, set it killed. +        IsKillSet = true; +        MO->setIsKill(true); +        continue; +      } else if ((MO = It->findRegisterDefOperand(RegNo, false, true, +                                                  &getRegisterInfo()))) { +        // No use found, set dead for its def. +        assert(&*It == &StartMI && "No new def between StartMI and EndMI."); +        MO->setIsDead(true); +        break; +      } +    } + +    if ((&*It) == &StartMI) +      break; +  } +  // Ensure RegMo liveness is killed after EndMI. +  assert((IsKillSet || (MO && MO->isDead())) && +         "RegNo should be killed or dead"); +} +  // If this instruction has an immediate form and one of its operands is a  // result of a load-immediate or an add-immediate, convert it to  // the immediate form if the constant is in range. @@ -2440,8 +2517,9 @@ bool PPCInstrInfo::convertToImmediateForm(MachineInstr &MI,      return false;    assert(ForwardingOperand < MI.getNumOperands() &&           "The forwarding operand needs to be valid at this point"); -  bool KillFwdDefMI = !SeenIntermediateUse && -    MI.getOperand(ForwardingOperand).isKill(); +  bool IsForwardingOperandKilled = MI.getOperand(ForwardingOperand).isKill(); +  bool KillFwdDefMI = !SeenIntermediateUse && IsForwardingOperandKilled; +  unsigned ForwardingOperandReg = MI.getOperand(ForwardingOperand).getReg();    if (KilledDef && KillFwdDefMI)      *KilledDef = DefMI; @@ -2450,8 +2528,9 @@ bool PPCInstrInfo::convertToImmediateForm(MachineInstr &MI,    // If this is a reg+reg instruction that has a reg+imm form,    // and one of the operands is produced by an add-immediate,    // try to convert it. -  if (HasImmForm && transformToImmFormFedByAdd(MI, III, ForwardingOperand, -                                               *DefMI, KillFwdDefMI)) +  if (HasImmForm && +      transformToImmFormFedByAdd(MI, III, ForwardingOperand, *DefMI, +                                 KillFwdDefMI))      return true;    if ((DefMI->getOpcode() != PPC::LI && DefMI->getOpcode() != PPC::LI8) || @@ -2466,7 +2545,7 @@ bool PPCInstrInfo::convertToImmediateForm(MachineInstr &MI,    // If this is a reg+reg instruction that has a reg+imm form,    // and one of the operands is produced by LI, convert it now.    if (HasImmForm) -    return transformToImmFormFedByLI(MI, III, ForwardingOperand, SExtImm); +    return transformToImmFormFedByLI(MI, III, ForwardingOperand, *DefMI, SExtImm);    bool ReplaceWithLI = false;    bool Is64BitLI = false; @@ -2486,6 +2565,8 @@ bool PPCInstrInfo::convertToImmediateForm(MachineInstr &MI,    case PPC::CMPLDI: {      // Doing this post-RA would require dataflow analysis to reliably find uses      // of the CR register set by the compare. +    // No need to fixup killed/dead flag since this transformation is only valid +    // before RA.      if (PostRA)        return false;      // If a compare-immediate is fed by an immediate and is itself an input of @@ -2662,6 +2743,14 @@ bool PPCInstrInfo::convertToImmediateForm(MachineInstr &MI,      if (KilledDef && SetCR)        *KilledDef = nullptr;      replaceInstrWithLI(MI, LII); + +    // Fixup killed/dead flag after transformation. +    // Pattern: +    // ForwardingOperandReg = LI imm1 +    // y = op2 imm2, ForwardingOperandReg(killed) +    if (IsForwardingOperandKilled) +      fixupIsDeadOrKill(*DefMI, MI, ForwardingOperandReg); +      LLVM_DEBUG(dbgs() << "With:\n");      LLVM_DEBUG(MI.dump());      return true; @@ -3169,11 +3258,10 @@ bool PPCInstrInfo::isDefMIElgibleForForwarding(MachineInstr &DefMI,    return isAnImmediateOperand(*ImmMO);  } -bool PPCInstrInfo::isRegElgibleForForwarding(const MachineOperand &RegMO, -                                             const MachineInstr &DefMI, -                                             const MachineInstr &MI, -                                             bool KillDefMI -                                             ) const { +bool PPCInstrInfo::isRegElgibleForForwarding( +    const MachineOperand &RegMO, const MachineInstr &DefMI, +    const MachineInstr &MI, bool KillDefMI, +    bool &IsFwdFeederRegKilled) const {    // x = addi y, imm    // ...    // z = lfdx 0, x   -> z = lfd imm(y) @@ -3193,6 +3281,8 @@ bool PPCInstrInfo::isRegElgibleForForwarding(const MachineOperand &RegMO,    for (; It != E; ++It) {      if (It->modifiesRegister(Reg, &getRegisterInfo()) && (&*It) != &DefMI)        return false; +    else if (It->killsRegister(Reg, &getRegisterInfo()) && (&*It) != &DefMI) +      IsFwdFeederRegKilled = true;      // Made it to DefMI without encountering a clobber.      if ((&*It) == &DefMI)        break; @@ -3264,11 +3354,9 @@ bool PPCInstrInfo::isImmElgibleForForwarding(const MachineOperand &ImmMO,  // is the literal zero, attempt to forward the source of the add-immediate to  // the corresponding D-Form instruction with the displacement coming from  // the immediate being added. -bool PPCInstrInfo::transformToImmFormFedByAdd(MachineInstr &MI, -                                              const ImmInstrInfo &III, -                                              unsigned OpNoForForwarding, -                                              MachineInstr &DefMI, -                                              bool KillDefMI) const { +bool PPCInstrInfo::transformToImmFormFedByAdd( +    MachineInstr &MI, const ImmInstrInfo &III, unsigned OpNoForForwarding, +    MachineInstr &DefMI, bool KillDefMI) const {    //         RegMO ImmMO    //           |    |    // x = addi reg, imm  <----- DefMI @@ -3293,10 +3381,19 @@ bool PPCInstrInfo::transformToImmFormFedByAdd(MachineInstr &MI,    if (!isImmElgibleForForwarding(*ImmMO, DefMI, III, Imm))      return false; +  bool IsFwdFeederRegKilled = false;    // Check if the RegMO can be forwarded to MI. -  if (!isRegElgibleForForwarding(*RegMO, DefMI, MI, KillDefMI)) +  if (!isRegElgibleForForwarding(*RegMO, DefMI, MI, KillDefMI, +                                 IsFwdFeederRegKilled))      return false; +  // Get killed info in case fixup needed after transformation. +  unsigned ForwardKilledOperandReg = ~0U; +  MachineRegisterInfo &MRI = MI.getParent()->getParent()->getRegInfo(); +  bool PostRA = !MRI.isSSA(); +  if (PostRA && MI.getOperand(OpNoForForwarding).isKill()) +    ForwardKilledOperandReg = MI.getOperand(OpNoForForwarding).getReg(); +    // We know that, the MI and DefMI both meet the pattern, and    // the Imm also meet the requirement with the new Imm-form.    // It is safe to do the transformation now. @@ -3347,6 +3444,22 @@ bool PPCInstrInfo::transformToImmFormFedByAdd(MachineInstr &MI,    // Update the opcode.    MI.setDesc(get(III.ImmOpcode)); +  // Fix up killed/dead flag after transformation. +  // Pattern 1: +  // x = ADD KilledFwdFeederReg, imm +  // n = opn KilledFwdFeederReg(killed), regn +  // y = XOP 0, x +  // Pattern 2: +  // x = ADD reg(killed), imm +  // y = XOP 0, x +  if (IsFwdFeederRegKilled || RegMO->isKill()) +    fixupIsDeadOrKill(DefMI, MI, RegMO->getReg()); +  // Pattern 3: +  // ForwardKilledOperandReg = ADD reg, imm +  // y = XOP 0, ForwardKilledOperandReg(killed) +  if (ForwardKilledOperandReg != ~0U) +    fixupIsDeadOrKill(DefMI, MI, ForwardKilledOperandReg); +    LLVM_DEBUG(dbgs() << "With:\n");    LLVM_DEBUG(MI.dump()); @@ -3356,6 +3469,7 @@ bool PPCInstrInfo::transformToImmFormFedByAdd(MachineInstr &MI,  bool PPCInstrInfo::transformToImmFormFedByLI(MachineInstr &MI,                                               const ImmInstrInfo &III,                                               unsigned ConstantOpNo, +                                             MachineInstr &DefMI,                                               int64_t Imm) const {    MachineRegisterInfo &MRI = MI.getParent()->getParent()->getRegInfo();    bool PostRA = !MRI.isSSA(); @@ -3394,6 +3508,11 @@ bool PPCInstrInfo::transformToImmFormFedByLI(MachineInstr &MI,        return false;    } +  // Get killed info in case fixup needed after transformation. +  unsigned ForwardKilledOperandReg = ~0U; +  if (PostRA && MI.getOperand(ConstantOpNo).isKill()) +    ForwardKilledOperandReg = MI.getOperand(ConstantOpNo).getReg(); +    unsigned Opc = MI.getOpcode();    bool SpecialShift32 =      Opc == PPC::SLW || Opc == PPC::SLWo || Opc == PPC::SRW || Opc == PPC::SRWo; @@ -3476,6 +3595,13 @@ bool PPCInstrInfo::transformToImmFormFedByLI(MachineInstr &MI,        }      }    } + +  // Fix up killed/dead flag after transformation. +  // Pattern: +  // ForwardKilledOperandReg = LI imm +  // y = XOP reg, ForwardKilledOperandReg(killed) +  if (ForwardKilledOperandReg != ~0U) +    fixupIsDeadOrKill(DefMI, MI, ForwardKilledOperandReg);    return true;  } diff --git a/llvm/lib/Target/PowerPC/PPCInstrInfo.h b/llvm/lib/Target/PowerPC/PPCInstrInfo.h index ee16d439d9e..264f7bc6f6e 100644 --- a/llvm/lib/Target/PowerPC/PPCInstrInfo.h +++ b/llvm/lib/Target/PowerPC/PPCInstrInfo.h @@ -128,12 +128,12 @@ class PPCInstrInfo : public PPCGenInstrInfo {    // If the inst 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, -                                 unsigned ConstantOpNo, int64_t Imm) const; +                                 unsigned ConstantOpNo, MachineInstr &DefMI, +                                 int64_t Imm) const;    // If the inst has imm-form and one of its operand is produced by an    // add-immediate, try to transform it when possible.    bool transformToImmFormFedByAdd(MachineInstr &MI, const ImmInstrInfo &III, -                                  unsigned ConstantOpNo, -                                  MachineInstr &DefMI, +                                  unsigned ConstantOpNo, MachineInstr &DefMI,                                    bool KillDefMI) const;    // Try to find that, if the instruction 'MI' contains any operand that    // could be forwarded from some inst that feeds it. If yes, return the @@ -158,8 +158,8 @@ class PPCInstrInfo : public PPCGenInstrInfo {                                   int64_t &Imm) const;    bool isRegElgibleForForwarding(const MachineOperand &RegMO,                                   const MachineInstr &DefMI, -                                 const MachineInstr &MI, -                                 bool KillDefMI) const; +                                 const MachineInstr &MI, bool KillDefMI, +                                 bool &IsFwdFeederRegKilled) const;    const unsigned *getStoreOpcodesForSpillArray() const;    const unsigned *getLoadOpcodesForSpillArray() const;    virtual void anchor(); @@ -411,6 +411,18 @@ public:    bool convertToImmediateForm(MachineInstr &MI,                                MachineInstr **KilledDef = nullptr) const; + +  /// Fixup killed/dead flag for register \p RegNo between instructions [\p +  /// StartMI, \p EndMI]. Some PostRA transformations may violate register +  /// killed/dead flags semantics, this function can be called to fix up. Before +  /// calling this function, +  /// 1. Ensure that \p RegNo liveness is killed after instruction \p EndMI. +  /// 2. Ensure that there is no new definition between (\p StartMI, \p EndMI) +  ///    and possible definition for \p RegNo is \p StartMI or \p EndMI. +  /// 3. Ensure that all instructions between [\p StartMI, \p EndMI] are in same +  ///    basic block. +  void fixupIsDeadOrKill(MachineInstr &StartMI, MachineInstr &EndMI, +                         unsigned RegNo) const;    void replaceInstrWithLI(MachineInstr &MI, const LoadImmediateInfo &LII) const;    void replaceInstrOperandWithImm(MachineInstr &MI, unsigned OpNo,                                    int64_t Imm) const; diff --git a/llvm/test/CodeGen/PowerPC/convert-rr-to-ri-instr-add.mir b/llvm/test/CodeGen/PowerPC/convert-rr-to-ri-instr-add.mir index b92884ae9b4..334ab61567c 100644 --- a/llvm/test/CodeGen/PowerPC/convert-rr-to-ri-instr-add.mir +++ b/llvm/test/CodeGen/PowerPC/convert-rr-to-ri-instr-add.mir @@ -27,7 +27,7 @@ body: |      ; Following instruction $r3 also reads $x3, ADDI8 can not be erased      ; CHECK: $x3 = ADDI8 $x5, 100, implicit-def $r3      STW $r3, $x5, 100 -    ; CHECK: STW $r3, $x5, 100 +    ; CHECK: STW killed $r3, $x5, 100      STFSX killed $f1, $zero8, $x3      ; CHECK: STFS killed $f1, 100, $x5      STD $x5, $x5, 100 diff --git a/llvm/test/CodeGen/PowerPC/convert-rr-to-ri-instrs-kill-flag.mir b/llvm/test/CodeGen/PowerPC/convert-rr-to-ri-instrs-kill-flag.mir new file mode 100644 index 00000000000..8594a89997d --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/convert-rr-to-ri-instrs-kill-flag.mir @@ -0,0 +1,183 @@ +# RUN: llc -mtriple=powerpc64le--linux-gnu -stop-after ppc-pre-emit-peephole %s -o - -verify-machineinstrs | FileCheck %s + +--- +# LI + XFORM -> DFORM, no killed/dead flag fixup. +name: testKillPassUpLI1 +#CHECK : name : testKillPassUpLI1 +tracksRegLiveness: true +body: | +  bb.0.entry: +    liveins: $x3, $f1, $x5 +    $x3 = LI8 100 +    STFSX killed $f1, $x3, $x5 +    ; CHECK: STFS killed $f1, 100, $x5 +    STD killed $x3, killed $x5, 100 +    ; CHECK: STD killed $x3, killed $x5, 100 +    BLR8 implicit $lr8, implicit $rm + +... +--- +# LI + XFORM -> DFORM, fixup killed/dead flag for $x3, find no use, set def as +# dead(LI8 is deleted). +name : testKillPassUpLI2 +# CHECK: name: testKillPassUpLI2 +tracksRegLiveness: true +body: | +  bb.0.entry: +    liveins: $x3, $f1, $x5 +    $x3 = LI8 100 +    ; CHECK-NOT: LI8 +    STFSX killed $f1, killed $x3, killed $x5 +    ; CHECK: STFS killed $f1, 100, killed $x5 +    BLR8 implicit $lr8, implicit $rm + +... +--- +# LI + XFORM -> DFORM, fixup killed/dead flag for $x3, find last use, set last +# use as killed. +name: testKillPassUpLI3 +# CHECK: name: testKillPassUpLI3 +tracksRegLiveness: true +body: | +  bb.0.entry: +    liveins: $x3, $f1, $x5 +    $x3 = LI8 100 +    STD $x3, $x5, 100 +    ; CHECK: STD killed $x3, $x5, 100 +    STFSX killed $f1, killed $x3, $x5 +    ; CHECK: STFS killed $f1, 100, $x5 +    STD killed $x5, $x5, 100 +    ; CHECK: STD killed $x5, $x5, 100 +    BLR8 implicit $lr8, implicit $rm + +... +--- +# LI + OP -> LI, fixup killed/dead flag for $x3, find last use, set last use as +# killed. +name: testKillPassUpLI4 +# CHECK: name: testKillPassUpLI4 +tracksRegLiveness: true +body: | +  bb.0.entry: +    liveins: $x3, $x5 +    $x3 = LI8 100 +    STD $x3, $x5, 100 +    ; CHECK: STD killed $x3, killed $x5, 100 +    $x5 = ADDI8 killed $x3, 200 +    ; CHECK: $x5 = LI8 300 +    STD $x5, $x5, 100 +    BLR8 implicit $lr8, implicit $rm + +... +--- +# ADD + XFORM -> DFORM, fixup killed/dead flag for $x3, find no use, set def as dead +# (ADDI8 is deleted). +name: testKillPassUpADD1 +# CHECK: name: testKillPassUpADD1 +tracksRegLiveness: true +body: | +  bb.0.entry: +    liveins: $x3, $f1, $x5 +    $x3 = ADDI8 killed $x5, 100 +    ; CHECK-NOT: ADDI8 +    STFSX killed $f1, $zero8, killed $x3 +    ; CHECK: STFS killed $f1, 100, killed $x5 +    BLR8 implicit $lr8, implicit $rm + +... +--- +# ADD + XFORM -> DFORM, fixup killed/dead flag for $x3, find last use, set last +# use as killed. +name: testKillPassUpADD2 +# CHECK: name: testKillPassUpADD2 +tracksRegLiveness: true +body: | +  bb.0.entry: +    liveins: $x3, $f1, $x5 +    $x3 = ADDI8 $x5, 100 +    STD $x3, $x5, 100 +    ; CHECK: STD killed $x3, $x5, 100 +    STFSX killed $f1, $zero8, killed $x3 +    ; CHECK: STFS killed $f1, 100, $x5 +    STD killed $x5, $x5, 100 +    ; CHECK: STD killed $x5, $x5, 100 +    BLR8 implicit $lr8, implicit $rm + +... +--- +# ADD + XFORM -> DFORM, fixup killed/dead flag for register $x5, DFORM +# instruction uses $x5 and no other kill uses, set it as killed in +# DFORM instruction. +name: testKillPassDownADD1 +# CHECK: name: testKillPassDownADD1 +tracksRegLiveness: true +body: | +  bb.0.entry: +    liveins: $x3, $f1, $x5 +    $x3 = ADDI8 killed $x5, 100 +    ; CHECK: $x3 = ADDI8 $x5, 100 +    STFSX killed $f1, $zero8, $x3 +    ; CHECK: STFS killed $f1, 100, killed $x5 +    STD killed $x3, $x3, 100 +    ; CHECK: STD killed $x3, $x3, 100 +    BLR8 implicit $lr8, implicit $rm + +... +--- +# ADD + XFORM -> DFORM, fixup killed/dead flag for register $x5, DFORM +# instruction uses $x5 and there is one kill use, set $x5 as killed in +# DFORM instruction and clear the other kill use killed flag. +name: testKillPassDownADD2 +# CHECK: name: testKillPassDownADD2 +tracksRegLiveness: true +body: | +  bb.0.entry: +    liveins: $x3, $f1, $x5 +    $x3 = ADDI8 $x5, 100 +    STD killed $x5, $x5, 100 +    ; CHECK: STD $x5, $x5, 100 +    STFSX killed $f1, $zero8, killed $x3 +    ; CHECK: STFS killed $f1, 100, killed $x5 +    BLR8 implicit $lr8, implicit $rm + +... +--- +# ADD + XFORM -> DFORM, fixup killed/dead flag for register $x3, DFORM +# instruction defines $x3, do nothing for killed/dead flag. +name: testKillPassDownADD3 +# CHECK: name: testKillPassDownADD3 +tracksRegLiveness: true +body: | +  bb.0.entry: +    liveins: $x3, $x5 +    $x3 = ADDI8 $x5, 100 +    $x3 = LDX $zero8, killed $x3 +    ; CHECK: $x3 = LD 100, $x5 +    STD killed $x5, $x5, 100 +    ; CHECK: STD killed $x5, $x5, 100 +    STD killed $x3, $x3, 200 +    ; CHECK: STD killed $x3, $x3, 200 +    BLR8 implicit $lr8, implicit $rm + +... +--- +# ADD + XFORM -> DFORM, fixup killed/dead flag for both register $x5 and $x3, +# DFORM instruction uses $x5 and there is one kill use, set $x5 as killed in +# DFORM instruction and clear the other kill use killed flag. Find last use for +# $x3, set last use as killed. +name: testKillPassDownADD4 +# CHECK: name: testKillPassDownADD4 +tracksRegLiveness: true +body: | +  bb.0.entry: +    liveins: $x3, $f1, $x5 +    $x3 = ADDI8 $x5, 100 +    STD killed $x5, $x5, 100 +    ; CHECK: STD $x5, $x5, 100 +    STD $x3, $x3, 200 +    ; CHECK: STD killed $x3, $x3, 200 +    STFSX killed $f1, $zero8, killed $x3 +    ; CHECK: STFS killed $f1, 100, killed $x5 +    BLR8 implicit $lr8, implicit $rm + +...  | 

