diff options
author | Bob Wilson <bob.wilson@apple.com> | 2009-09-01 04:18:40 +0000 |
---|---|---|
committer | Bob Wilson <bob.wilson@apple.com> | 2009-09-01 04:18:40 +0000 |
commit | 71124f698befddb89309758f4aa171e11b9beff3 (patch) | |
tree | bf511efdbeb7cf31489194f414bf344dbb3f9d04 | |
parent | efbb5330b8d383a393c83d2da5d631c98b0bb3fd (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.cpp | 66 | ||||
-rw-r--r-- | test/CodeGen/ARM/2009-08-31-TwoRegShuffle.ll | 9 |
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 +} |