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:
Jakob Stoklund Olesen 2009-12-04 00:16:04 +00:00
parent 2e65c29ac6
commit 6b74e505be
5 changed files with 103 additions and 53 deletions

View File

@ -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,

View File

@ -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,

View File

@ -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) {

View File

@ -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 }

View File

@ -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]