mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-02-12 03:32:10 +00:00
Fix the handling of partial redefines in the fast register allocator.
A partial redefine needs to be treated like a tied operand, and the register must be reloaded while processing use operands. This fixes a bug where partially redefined registers were processed as normal defs with a reload added. The reload could clobber another use operand if it was a kill that allowed register reuse. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@107193 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
5d52165e4e
commit
d1303d2a66
@ -515,7 +515,6 @@ RAFast::defineVirtReg(MachineInstr *MI, unsigned OpNum,
|
||||
bool New;
|
||||
tie(LRI, New) = LiveVirtRegs.insert(std::make_pair(VirtReg, LiveReg()));
|
||||
LiveReg &LR = LRI->second;
|
||||
bool PartialRedef = MI->getOperand(OpNum).getSubReg();
|
||||
if (New) {
|
||||
// If there is no hint, peek at the only use of this register.
|
||||
if ((!Hint || !TargetRegisterInfo::isPhysicalRegister(Hint)) &&
|
||||
@ -527,15 +526,7 @@ RAFast::defineVirtReg(MachineInstr *MI, unsigned OpNum,
|
||||
Hint = DstReg;
|
||||
}
|
||||
allocVirtReg(MI, *LRI, Hint);
|
||||
// If this is only a partial redefinition, we must reload the other parts.
|
||||
if (PartialRedef && MI->readsVirtualRegister(VirtReg)) {
|
||||
const TargetRegisterClass *RC = MRI->getRegClass(VirtReg);
|
||||
int FI = getStackSpaceFor(VirtReg, RC);
|
||||
DEBUG(dbgs() << "Reloading for partial redef: %reg" << VirtReg << "\n");
|
||||
TII->loadRegFromStackSlot(*MBB, MI, LR.PhysReg, FI, RC, TRI);
|
||||
++NumLoads;
|
||||
}
|
||||
} else if (LR.LastUse && !PartialRedef) {
|
||||
} else if (LR.LastUse) {
|
||||
// Redefining a live register - kill at the last use, unless it is this
|
||||
// instruction defining VirtReg multiple times.
|
||||
if (LR.LastUse != MI || LR.LastUse->getOperand(LR.LastOpNum).isUse())
|
||||
@ -571,10 +562,16 @@ RAFast::reloadVirtReg(MachineInstr *MI, unsigned OpNum,
|
||||
} else if (LR.Dirty) {
|
||||
if (isLastUseOfLocalReg(MO)) {
|
||||
DEBUG(dbgs() << "Killing last use: " << MO << "\n");
|
||||
MO.setIsKill();
|
||||
if (MO.isUse())
|
||||
MO.setIsKill();
|
||||
else
|
||||
MO.setIsDead();
|
||||
} else if (MO.isKill()) {
|
||||
DEBUG(dbgs() << "Clearing dubious kill: " << MO << "\n");
|
||||
MO.setIsKill(false);
|
||||
} else if (MO.isDead()) {
|
||||
DEBUG(dbgs() << "Clearing dubious dead: " << MO << "\n");
|
||||
MO.setIsDead(false);
|
||||
}
|
||||
} else if (MO.isKill()) {
|
||||
// We must remove kill flags from uses of reloaded registers because the
|
||||
@ -583,6 +580,9 @@ RAFast::reloadVirtReg(MachineInstr *MI, unsigned OpNum,
|
||||
// This would cause a second reload of %x into a different register.
|
||||
DEBUG(dbgs() << "Clearing clean kill: " << MO << "\n");
|
||||
MO.setIsKill(false);
|
||||
} else if (MO.isDead()) {
|
||||
DEBUG(dbgs() << "Clearing clean dead: " << MO << "\n");
|
||||
MO.setIsDead(false);
|
||||
}
|
||||
assert(LR.PhysReg && "Register not assigned");
|
||||
LR.LastUse = MI;
|
||||
@ -625,7 +625,8 @@ void RAFast::handleThroughOperands(MachineInstr *MI,
|
||||
if (!MO.isReg()) continue;
|
||||
unsigned Reg = MO.getReg();
|
||||
if (!Reg || TargetRegisterInfo::isPhysicalRegister(Reg)) continue;
|
||||
if (MO.isEarlyClobber() || MI->isRegTiedToDefOperand(i)) {
|
||||
if (MO.isEarlyClobber() || MI->isRegTiedToDefOperand(i) ||
|
||||
(MO.getSubReg() && MI->readsVirtualRegister(Reg))) {
|
||||
if (ThroughRegs.insert(Reg))
|
||||
DEBUG(dbgs() << " %reg" << Reg);
|
||||
}
|
||||
@ -649,6 +650,7 @@ void RAFast::handleThroughOperands(MachineInstr *MI,
|
||||
}
|
||||
}
|
||||
|
||||
SmallVector<unsigned, 8> PartialDefs;
|
||||
DEBUG(dbgs() << "Allocating tied uses and early clobbers.\n");
|
||||
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
|
||||
MachineOperand &MO = MI->getOperand(i);
|
||||
@ -663,6 +665,14 @@ void RAFast::handleThroughOperands(MachineInstr *MI,
|
||||
LiveRegMap::iterator LRI = reloadVirtReg(MI, i, Reg, 0);
|
||||
unsigned PhysReg = LRI->second.PhysReg;
|
||||
setPhysReg(MI, i, PhysReg);
|
||||
// Note: we don't update the def operand yet. That would cause the normal
|
||||
// def-scan to attempt spilling.
|
||||
} else if (MO.getSubReg() && MI->readsVirtualRegister(Reg)) {
|
||||
DEBUG(dbgs() << "Partial redefine: " << MO << "\n");
|
||||
// Reload the register, but don't assign to the operand just yet.
|
||||
// That would confuse the later phys-def processing pass.
|
||||
LiveRegMap::iterator LRI = reloadVirtReg(MI, i, Reg, 0);
|
||||
PartialDefs.push_back(LRI->second.PhysReg);
|
||||
} else if (MO.isEarlyClobber()) {
|
||||
// Note: defineVirtReg may invalidate MO.
|
||||
LiveRegMap::iterator LRI = defineVirtReg(MI, i, Reg, 0);
|
||||
@ -683,6 +693,10 @@ void RAFast::handleThroughOperands(MachineInstr *MI,
|
||||
for (const unsigned *AS = TRI->getAliasSet(Reg); *AS; ++AS)
|
||||
UsedInInstr.set(*AS);
|
||||
}
|
||||
|
||||
// Also mark PartialDefs as used to avoid reallocation.
|
||||
for (unsigned i = 0, e = PartialDefs.size(); i != e; ++i)
|
||||
UsedInInstr.set(PartialDefs[i]);
|
||||
}
|
||||
|
||||
void RAFast::AllocateBasicBlock() {
|
||||
@ -767,7 +781,10 @@ void RAFast::AllocateBasicBlock() {
|
||||
// Mark physreg uses and early clobbers as used.
|
||||
// Find the end of the virtreg operands
|
||||
unsigned VirtOpEnd = 0;
|
||||
bool hasTiedOps = false, hasEarlyClobbers = false, hasPhysDefs = false;
|
||||
bool hasTiedOps = false;
|
||||
bool hasEarlyClobbers = false;
|
||||
bool hasPartialRedefs = false;
|
||||
bool hasPhysDefs = false;
|
||||
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
|
||||
MachineOperand &MO = MI->getOperand(i);
|
||||
if (!MO.isReg()) continue;
|
||||
@ -775,11 +792,15 @@ void RAFast::AllocateBasicBlock() {
|
||||
if (!Reg) continue;
|
||||
if (TargetRegisterInfo::isVirtualRegister(Reg)) {
|
||||
VirtOpEnd = i+1;
|
||||
if (MO.isUse())
|
||||
if (MO.isUse()) {
|
||||
hasTiedOps = hasTiedOps ||
|
||||
TID.getOperandConstraint(i, TOI::TIED_TO) != -1;
|
||||
else if (MO.isEarlyClobber())
|
||||
hasEarlyClobbers = true;
|
||||
} else {
|
||||
if (MO.isEarlyClobber())
|
||||
hasEarlyClobbers = true;
|
||||
if (MO.getSubReg() && MI->readsVirtualRegister(Reg))
|
||||
hasPartialRedefs = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (!Allocatable.test(Reg)) continue;
|
||||
@ -800,7 +821,8 @@ void RAFast::AllocateBasicBlock() {
|
||||
// operands.
|
||||
// We didn't detect inline asm tied operands above, so just make this extra
|
||||
// pass for all inline asm.
|
||||
if (MI->isInlineAsm() || hasEarlyClobbers || (hasTiedOps && hasPhysDefs)) {
|
||||
if (MI->isInlineAsm() || hasEarlyClobbers || hasPartialRedefs ||
|
||||
(hasTiedOps && hasPhysDefs)) {
|
||||
handleThroughOperands(MI, VirtDead);
|
||||
// Don't attempt coalescing when we have funny stuff going on.
|
||||
CopyDst = 0;
|
||||
|
22
test/CodeGen/ARM/2010-06-29-PartialRedefFastAlloc.ll
Normal file
22
test/CodeGen/ARM/2010-06-29-PartialRedefFastAlloc.ll
Normal file
@ -0,0 +1,22 @@
|
||||
; RUN: llc < %s -O0 -mcpu=cortex-a8 | FileCheck %s
|
||||
target datalayout = "e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-i64:32:32-f32:32:32-f64:32:32-v64:32:64-v128:32:128-a0:0:32-n32"
|
||||
target triple = "thumbv7-apple-darwin10"
|
||||
|
||||
; This tests the fast register allocator's handling of partial redefines:
|
||||
;
|
||||
; %reg1026<def> = VMOVv16i8 0, pred:14, pred:%reg0
|
||||
; %reg1028:dsub_1<def> = EXTRACT_SUBREG %reg1026<kill>, 1
|
||||
;
|
||||
; %reg1026 gets allocated %Q0, and if %reg1028 is reloaded for the partial redef,
|
||||
; it cannot also get %Q0.
|
||||
|
||||
; CHECK: vmov.i8 q0, #0x0
|
||||
; CHECK-NOT: vld1.64 {d0,d1}
|
||||
; CHECK: vmov.f64 d3, d0
|
||||
|
||||
define i32 @main(i32 %argc, i8** %argv) nounwind {
|
||||
entry:
|
||||
%0 = shufflevector <2 x i64> undef, <2 x i64> zeroinitializer, <2 x i32> <i32 1, i32 2> ; <<2 x i64>> [#uses=1]
|
||||
store <2 x i64> %0, <2 x i64>* undef, align 16
|
||||
ret i32 undef
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user