Fix pr4843: When an instruction has multiple destination registers that are

tied to different source registers, the TwoAddressInstructionPass needs to
be smarter.  Change it to check before replacing a source register whether
that source register is tied to a different destination register, and if so,
defer handling it until a subsequent iteration.

llvm-svn: 80654
This commit is contained in:
Bob Wilson 2009-09-01 04:18:40 +00:00
parent 4fa0595b94
commit 33b408a10f
2 changed files with 64 additions and 11 deletions

View File

@ -968,23 +968,67 @@ bool TwoAddressInstructionPass::runOnMachineFunction(MachineFunction &MF) {
// Update DistanceMap.
DistanceMap.insert(std::make_pair(prevMI, Dist));
DistanceMap[mi] = ++Dist;
// Scan the operands to find: (1) the use operand that kills regB (if
// any); (2) whether the kill operand is being replaced by regA on
// this iteration; and (3) the first use of regB that is not being
// replaced on this iteration. A use of regB will not replaced if it
// is tied to a different destination register and will be handled on
// a later iteration.
MachineOperand *KillMO = NULL;
MachineOperand *FirstKeptMO = NULL;
bool KillMOKept = false;
for (unsigned i = 0, e = mi->getNumOperands(); i != e; ++i) {
MachineOperand &MO = mi->getOperand(i);
if (MO.isReg() && MO.getReg() == regB && MO.isUse()) {
// Check if this operand is tied to a different destination.
bool isKept = false;
unsigned dsti = 0;
if (mi->isRegTiedToDefOperand(i, &dsti) && dsti != ti) {
isKept = true;
if (!FirstKeptMO)
FirstKeptMO = &MO;
}
if (MO.isKill()) {
KillMO = &MO;
KillMOKept = isKept;
}
}
}
// Update live variables for regB.
if (LV) {
if (LV->removeVirtualRegisterKilled(regB, mi))
LV->addVirtualRegisterKilled(regB, prevMI);
if (LV->removeVirtualRegisterDead(regB, mi))
LV->addVirtualRegisterDead(regB, prevMI);
if (KillMO) {
if (!FirstKeptMO) {
// All uses of regB are being replaced; move the kill to prevMI.
if (LV && LV->removeVirtualRegisterKilled(regB, mi))
LV->addVirtualRegisterKilled(regB, prevMI);
} else {
if (!KillMOKept) {
// The kill marker is on an operand being replaced, but there
// are other uses of regB remaining. Move the kill marker to
// one of them.
KillMO->setIsKill(false);
FirstKeptMO->setIsKill(true);
}
}
}
DEBUG(errs() << "\t\tprepend:\t" << *prevMI);
// Replace all occurences of regB with regA.
// Replace uses of regB with regA.
for (unsigned i = 0, e = mi->getNumOperands(); i != e; ++i) {
if (mi->getOperand(i).isReg() &&
mi->getOperand(i).getReg() == regB)
mi->getOperand(i).setReg(regA);
MachineOperand &MO = mi->getOperand(i);
if (MO.isReg() && MO.getReg() == regB && MO.isUse()) {
// Skip operands that are tied to other register definitions.
unsigned dsti = 0;
if (mi->isRegTiedToDefOperand(i, &dsti) && dsti != ti)
continue;
MO.setReg(regA);
}
}
assert(mi->getOperand(ti).isDef() && mi->getOperand(si).isUse());

View File

@ -0,0 +1,9 @@
; RUN: llvm-as < %s | llc -march=arm -mattr=+neon | FileCheck %s
; pr4843
define <4 x i16> @v2regbug(<4 x i16>* %B) nounwind {
;CHECK: v2regbug:
;CHECK: vzip.16
%tmp1 = load <4 x i16>* %B
%tmp2 = shufflevector <4 x i16> %tmp1, <4 x i16> undef, <4 x i32><i32 0, i32 0, i32 1, i32 1>
ret <4 x i16> %tmp2
}