aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBob Wilson <bob.wilson@apple.com>2009-09-01 04:18:40 +0000
committerBob Wilson <bob.wilson@apple.com>2009-09-01 04:18:40 +0000
commit71124f698befddb89309758f4aa171e11b9beff3 (patch)
treebf511efdbeb7cf31489194f414bf344dbb3f9d04
parentefbb5330b8d383a393c83d2da5d631c98b0bb3fd (diff)
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. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@80654 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/CodeGen/TwoAddressInstructionPass.cpp66
-rw-r--r--test/CodeGen/ARM/2009-08-31-TwoRegShuffle.ll9
2 files changed, 64 insertions, 11 deletions
diff --git a/lib/CodeGen/TwoAddressInstructionPass.cpp b/lib/CodeGen/TwoAddressInstructionPass.cpp
index 605f4cf58d..d75396906e 100644
--- a/lib/CodeGen/TwoAddressInstructionPass.cpp
+++ b/lib/CodeGen/TwoAddressInstructionPass.cpp
@@ -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;
+ }
- // Update live variables for regB.
- if (LV) {
- if (LV->removeVirtualRegisterKilled(regB, mi))
- LV->addVirtualRegisterKilled(regB, prevMI);
+ if (MO.isKill()) {
+ KillMO = &MO;
+ KillMOKept = isKept;
+ }
+ }
+ }
- if (LV->removeVirtualRegisterDead(regB, mi))
- LV->addVirtualRegisterDead(regB, prevMI);
+ // Update live variables for regB.
+ 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());
diff --git a/test/CodeGen/ARM/2009-08-31-TwoRegShuffle.ll b/test/CodeGen/ARM/2009-08-31-TwoRegShuffle.ll
new file mode 100644
index 0000000000..dca3424e18
--- /dev/null
+++ b/test/CodeGen/ARM/2009-08-31-TwoRegShuffle.ll
@@ -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
+}