[PowerPC] fix killed/dead flag after convert x-form to d-form tranformation.

Differential Revision: https://reviews.llvm.org/D58428

llvm-svn: 355378
This commit is contained in:
Chen Zheng 2019-03-05 04:56:54 +00:00
parent 7cbb408850
commit 9cfe7e81f1
4 changed files with 343 additions and 22 deletions

View File

@ -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;
}

View File

@ -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;

View File

@ -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

View File

@ -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
...