mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-01-19 04:32:19 +00:00
Also attempt trivial coalescing for live intervals that end in a copy.
The coalescer is supposed to clean these up, but when setting up parameters for a function call, there may be copies to physregs. If the defining instruction has been LICM'ed far away, the coalescer won't touch it. The register allocation hint does not always work - when the register allocator is backtracking, it clears the hints. This patch takes care of a few more cases that r90163 missed. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@90502 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
2e65c29ac6
commit
6b74e505be
@ -117,6 +117,12 @@ namespace llvm {
|
|||||||
bool conflictsWithPhysRegDef(const LiveInterval &li, VirtRegMap &vrm,
|
bool conflictsWithPhysRegDef(const LiveInterval &li, VirtRegMap &vrm,
|
||||||
unsigned reg);
|
unsigned reg);
|
||||||
|
|
||||||
|
/// conflictsWithPhysRegUse - Returns true if the specified register is used
|
||||||
|
/// or defined during the duration of the specified interval. Copies to and
|
||||||
|
/// from li.reg are allowed.
|
||||||
|
bool conflictsWithPhysRegUse(const LiveInterval &li, VirtRegMap &vrm,
|
||||||
|
unsigned reg);
|
||||||
|
|
||||||
/// conflictsWithPhysRegRef - Similar to conflictsWithPhysRegRef except
|
/// conflictsWithPhysRegRef - Similar to conflictsWithPhysRegRef except
|
||||||
/// it can check use as well.
|
/// it can check use as well.
|
||||||
bool conflictsWithPhysRegRef(LiveInterval &li, unsigned Reg,
|
bool conflictsWithPhysRegRef(LiveInterval &li, unsigned Reg,
|
||||||
|
@ -157,19 +157,15 @@ bool LiveIntervals::conflictsWithPhysRegDef(const LiveInterval &li,
|
|||||||
I = li.ranges.begin(), E = li.ranges.end(); I != E; ++I) {
|
I = li.ranges.begin(), E = li.ranges.end(); I != E; ++I) {
|
||||||
for (SlotIndex index = I->start.getBaseIndex(),
|
for (SlotIndex index = I->start.getBaseIndex(),
|
||||||
end = I->end.getPrevSlot().getBaseIndex().getNextIndex();
|
end = I->end.getPrevSlot().getBaseIndex().getNextIndex();
|
||||||
index != end;
|
index != end;
|
||||||
index = index.getNextIndex()) {
|
index = index.getNextIndex()) {
|
||||||
MachineInstr *MI = getInstructionFromIndex(index);
|
MachineInstr *MI = getInstructionFromIndex(index);
|
||||||
if (!MI)
|
if (!MI)
|
||||||
continue; // skip deleted instructions
|
continue; // skip deleted instructions
|
||||||
|
|
||||||
unsigned SrcReg, DstReg, SrcSubReg, DstSubReg;
|
|
||||||
if (tii_->isMoveInstr(*MI, SrcReg, DstReg, SrcSubReg, DstSubReg))
|
|
||||||
if (SrcReg == li.reg || DstReg == li.reg)
|
|
||||||
continue;
|
|
||||||
for (unsigned i = 0; i != MI->getNumOperands(); ++i) {
|
for (unsigned i = 0; i != MI->getNumOperands(); ++i) {
|
||||||
MachineOperand& mop = MI->getOperand(i);
|
MachineOperand& mop = MI->getOperand(i);
|
||||||
if (!mop.isReg())
|
if (!mop.isReg() || mop.isUse())
|
||||||
continue;
|
continue;
|
||||||
unsigned PhysReg = mop.getReg();
|
unsigned PhysReg = mop.getReg();
|
||||||
if (PhysReg == 0 || PhysReg == li.reg)
|
if (PhysReg == 0 || PhysReg == li.reg)
|
||||||
@ -188,6 +184,50 @@ bool LiveIntervals::conflictsWithPhysRegDef(const LiveInterval &li,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// conflictsWithPhysRegUse - Returns true if the specified register is used or
|
||||||
|
/// defined during the duration of the specified interval. Copies to and from
|
||||||
|
/// li.reg are allowed.
|
||||||
|
bool LiveIntervals::conflictsWithPhysRegUse(const LiveInterval &li,
|
||||||
|
VirtRegMap &vrm, unsigned reg) {
|
||||||
|
for (LiveInterval::Ranges::const_iterator
|
||||||
|
I = li.ranges.begin(), E = li.ranges.end(); I != E; ++I) {
|
||||||
|
for (SlotIndex index = I->start.getBaseIndex(),
|
||||||
|
end = I->end.getPrevSlot().getBaseIndex().getNextIndex();
|
||||||
|
index != end;
|
||||||
|
index = index.getNextIndex()) {
|
||||||
|
MachineInstr *MI = getInstructionFromIndex(index);
|
||||||
|
if (!MI)
|
||||||
|
continue; // skip deleted instructions
|
||||||
|
|
||||||
|
// Terminators are considered conflicts since reg may be used at the
|
||||||
|
// destination.
|
||||||
|
if (MI->getDesc().isTerminator())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
|
||||||
|
MachineOperand& mop = MI->getOperand(i);
|
||||||
|
if (!mop.isReg() || mop.isUndef())
|
||||||
|
continue;
|
||||||
|
unsigned PhysReg = mop.getReg();
|
||||||
|
if (PhysReg == 0 || PhysReg == li.reg)
|
||||||
|
continue;
|
||||||
|
if (TargetRegisterInfo::isVirtualRegister(PhysReg)) {
|
||||||
|
if (!vrm.hasPhys(PhysReg))
|
||||||
|
continue;
|
||||||
|
PhysReg = vrm.getPhys(PhysReg);
|
||||||
|
}
|
||||||
|
if (PhysReg && tri_->regsOverlap(PhysReg, reg)) {
|
||||||
|
unsigned SrcReg, DstReg, SrcSubReg, DstSubReg;
|
||||||
|
if (!tii_->isMoveInstr(*MI, SrcReg, DstReg, SrcSubReg, DstSubReg) ||
|
||||||
|
(SrcReg != li.reg && DstReg != li.reg))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// conflictsWithPhysRegRef - Similar to conflictsWithPhysRegRef except
|
/// conflictsWithPhysRegRef - Similar to conflictsWithPhysRegRef except
|
||||||
/// it can check use as well.
|
/// it can check use as well.
|
||||||
bool LiveIntervals::conflictsWithPhysRegRef(LiveInterval &li,
|
bool LiveIntervals::conflictsWithPhysRegRef(LiveInterval &li,
|
||||||
|
@ -390,66 +390,70 @@ void RALinScan::ComputeRelatedRegClasses() {
|
|||||||
RelatedRegClasses.unionSets(I->second, OneClassForEachPhysReg[*AS]);
|
RelatedRegClasses.unionSets(I->second, OneClassForEachPhysReg[*AS]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// attemptTrivialCoalescing - If a simple interval is defined by a copy,
|
/// attemptTrivialCoalescing - If a simple interval is defined by a copy, try
|
||||||
/// try allocate the definition the same register as the source register
|
/// allocate the definition the same register as the source register if the
|
||||||
/// if the register is not defined during live time of the interval. This
|
/// register is not defined during live time of the interval. If the interval is
|
||||||
/// eliminate a copy. This is used to coalesce copies which were not
|
/// killed by a copy, try to use the destination register. This eliminates a
|
||||||
/// coalesced away before allocation either due to dest and src being in
|
/// copy. This is used to coalesce copies which were not coalesced away before
|
||||||
/// different register classes or because the coalescer was overly
|
/// allocation either due to dest and src being in different register classes or
|
||||||
/// conservative.
|
/// because the coalescer was overly conservative.
|
||||||
unsigned RALinScan::attemptTrivialCoalescing(LiveInterval &cur, unsigned Reg) {
|
unsigned RALinScan::attemptTrivialCoalescing(LiveInterval &cur, unsigned Reg) {
|
||||||
unsigned Preference = vrm_->getRegAllocPref(cur.reg);
|
unsigned Preference = vrm_->getRegAllocPref(cur.reg);
|
||||||
if ((Preference && Preference == Reg) || !cur.containsOneValue())
|
if ((Preference && Preference == Reg) || !cur.containsOneValue())
|
||||||
return Reg;
|
return Reg;
|
||||||
|
|
||||||
VNInfo *vni = cur.begin()->valno;
|
VNInfo *vni = cur.begin()->valno;
|
||||||
if ((vni->def == SlotIndex()) ||
|
if (vni->isUnused())
|
||||||
vni->isUnused() || !vni->isDefAccurate())
|
|
||||||
return Reg;
|
return Reg;
|
||||||
MachineInstr *CopyMI = li_->getInstructionFromIndex(vni->def);
|
unsigned CandReg;
|
||||||
unsigned SrcReg, DstReg, SrcSubReg, DstSubReg, PhysReg;
|
bool forward; // extending physreg forward
|
||||||
if (!CopyMI ||
|
{
|
||||||
!tii_->isMoveInstr(*CopyMI, SrcReg, DstReg, SrcSubReg, DstSubReg))
|
MachineInstr *CopyMI;
|
||||||
return Reg;
|
unsigned SrcReg, DstReg, SrcSubReg, DstSubReg;
|
||||||
PhysReg = SrcReg;
|
if (vni->def != SlotIndex() && vni->isDefAccurate() &&
|
||||||
if (TargetRegisterInfo::isVirtualRegister(SrcReg)) {
|
(CopyMI = li_->getInstructionFromIndex(vni->def)) &&
|
||||||
if (!vrm_->isAssignedReg(SrcReg))
|
tii_->isMoveInstr(*CopyMI, SrcReg, DstReg, SrcSubReg, DstSubReg))
|
||||||
|
// Defined by a copy, try to extend SrcReg forward
|
||||||
|
CandReg = SrcReg, forward = true;
|
||||||
|
else if (cur.ranges.size()==1 &&
|
||||||
|
(CopyMI =
|
||||||
|
li_->getInstructionFromIndex(cur.begin()->end.getBaseIndex())) &&
|
||||||
|
tii_->isMoveInstr(*CopyMI, SrcReg, DstReg, SrcSubReg, DstSubReg) &&
|
||||||
|
cur.reg == SrcReg)
|
||||||
|
// Only used by a copy, try to extend DstReg backwards
|
||||||
|
CandReg = DstReg, forward = false;
|
||||||
|
else
|
||||||
return Reg;
|
return Reg;
|
||||||
PhysReg = vrm_->getPhys(SrcReg);
|
|
||||||
}
|
}
|
||||||
if (Reg == PhysReg)
|
|
||||||
|
if (TargetRegisterInfo::isVirtualRegister(CandReg)) {
|
||||||
|
if (!vrm_->isAssignedReg(CandReg))
|
||||||
|
return Reg;
|
||||||
|
CandReg = vrm_->getPhys(CandReg);
|
||||||
|
}
|
||||||
|
if (Reg == CandReg)
|
||||||
return Reg;
|
return Reg;
|
||||||
|
|
||||||
const TargetRegisterClass *RC = mri_->getRegClass(cur.reg);
|
const TargetRegisterClass *RC = mri_->getRegClass(cur.reg);
|
||||||
if (!RC->contains(PhysReg))
|
if (!RC->contains(CandReg))
|
||||||
return Reg;
|
return Reg;
|
||||||
|
|
||||||
// Try to coalesce.
|
if (forward) {
|
||||||
if (!li_->conflictsWithPhysRegDef(cur, *vrm_, PhysReg)) {
|
if (li_->conflictsWithPhysRegDef(cur, *vrm_, CandReg))
|
||||||
DEBUG(errs() << "Coalescing: " << cur << " -> " << tri_->getName(PhysReg)
|
return Reg;
|
||||||
<< '\n');
|
} else {
|
||||||
vrm_->clearVirt(cur.reg);
|
if (li_->conflictsWithPhysRegUse(cur, *vrm_, CandReg))
|
||||||
vrm_->assignVirt2Phys(cur.reg, PhysReg);
|
return Reg;
|
||||||
|
|
||||||
// Remove unnecessary kills since a copy does not clobber the register.
|
|
||||||
if (li_->hasInterval(SrcReg)) {
|
|
||||||
LiveInterval &SrcLI = li_->getInterval(SrcReg);
|
|
||||||
for (MachineRegisterInfo::use_iterator I = mri_->use_begin(cur.reg),
|
|
||||||
E = mri_->use_end(); I != E; ++I) {
|
|
||||||
MachineOperand &O = I.getOperand();
|
|
||||||
if (!O.isKill())
|
|
||||||
continue;
|
|
||||||
MachineInstr *MI = &*I;
|
|
||||||
if (SrcLI.liveAt(li_->getInstructionIndex(MI).getDefIndex()))
|
|
||||||
O.setIsKill(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
++NumCoalesce;
|
|
||||||
return PhysReg;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Reg;
|
// Try to coalesce.
|
||||||
|
DEBUG(errs() << "Coalescing: " << cur << " -> " << tri_->getName(CandReg)
|
||||||
|
<< '\n');
|
||||||
|
vrm_->clearVirt(cur.reg);
|
||||||
|
vrm_->assignVirt2Phys(cur.reg, CandReg);
|
||||||
|
|
||||||
|
++NumCoalesce;
|
||||||
|
return CandReg;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RALinScan::runOnMachineFunction(MachineFunction &fn) {
|
bool RALinScan::runOnMachineFunction(MachineFunction &fn) {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu | grep movq | count 2
|
; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu | grep movq | count 1
|
||||||
; PR3311
|
; PR3311
|
||||||
|
|
||||||
%struct.CUMULATIVE_ARGS = type { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 }
|
%struct.CUMULATIVE_ARGS = type { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 }
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
; RUN: llc < %s -march=x86 | grep mov | count 5
|
; RUN: llc < %s -march=x86 | grep mov | count 4
|
||||||
; rdar://6523745
|
; rdar://6523745
|
||||||
|
|
||||||
@"\01LC" = internal constant [4 x i8] c"%d\0A\00" ; <[4 x i8]*> [#uses=1]
|
@"\01LC" = internal constant [4 x i8] c"%d\0A\00" ; <[4 x i8]*> [#uses=1]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user