From 6b74e505be1016223e090a6c806f7caa3165a146 Mon Sep 17 00:00:00 2001 From: Jakob Stoklund Olesen Date: Fri, 4 Dec 2009 00:16:04 +0000 Subject: [PATCH] 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 --- include/llvm/CodeGen/LiveIntervalAnalysis.h | 6 ++ lib/CodeGen/LiveIntervalAnalysis.cpp | 54 ++++++++++-- lib/CodeGen/RegAllocLinearScan.cpp | 92 +++++++++++---------- test/CodeGen/X86/2009-01-12-CoalescerBug.ll | 2 +- test/CodeGen/X86/twoaddr-coalesce.ll | 2 +- 5 files changed, 103 insertions(+), 53 deletions(-) diff --git a/include/llvm/CodeGen/LiveIntervalAnalysis.h b/include/llvm/CodeGen/LiveIntervalAnalysis.h index 7a02d0fe991..65f36e72566 100644 --- a/include/llvm/CodeGen/LiveIntervalAnalysis.h +++ b/include/llvm/CodeGen/LiveIntervalAnalysis.h @@ -117,6 +117,12 @@ namespace llvm { bool conflictsWithPhysRegDef(const LiveInterval &li, VirtRegMap &vrm, 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 /// it can check use as well. bool conflictsWithPhysRegRef(LiveInterval &li, unsigned Reg, diff --git a/lib/CodeGen/LiveIntervalAnalysis.cpp b/lib/CodeGen/LiveIntervalAnalysis.cpp index 35337efd504..09456342acb 100644 --- a/lib/CodeGen/LiveIntervalAnalysis.cpp +++ b/lib/CodeGen/LiveIntervalAnalysis.cpp @@ -157,19 +157,15 @@ bool LiveIntervals::conflictsWithPhysRegDef(const LiveInterval &li, 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()) { + index != end; + index = index.getNextIndex()) { MachineInstr *MI = getInstructionFromIndex(index); if (!MI) 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) { MachineOperand& mop = MI->getOperand(i); - if (!mop.isReg()) + if (!mop.isReg() || mop.isUse()) continue; unsigned PhysReg = mop.getReg(); if (PhysReg == 0 || PhysReg == li.reg) @@ -188,6 +184,50 @@ bool LiveIntervals::conflictsWithPhysRegDef(const LiveInterval &li, 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 /// it can check use as well. bool LiveIntervals::conflictsWithPhysRegRef(LiveInterval &li, diff --git a/lib/CodeGen/RegAllocLinearScan.cpp b/lib/CodeGen/RegAllocLinearScan.cpp index 4ff512932f8..79bde1611f9 100644 --- a/lib/CodeGen/RegAllocLinearScan.cpp +++ b/lib/CodeGen/RegAllocLinearScan.cpp @@ -390,66 +390,70 @@ void RALinScan::ComputeRelatedRegClasses() { RelatedRegClasses.unionSets(I->second, OneClassForEachPhysReg[*AS]); } -/// attemptTrivialCoalescing - If a simple interval is defined by a copy, -/// try allocate the definition the same register as the source register -/// if the register is not defined during live time of the interval. This -/// eliminate a copy. This is used to coalesce copies which were not -/// coalesced away before allocation either due to dest and src being in -/// different register classes or because the coalescer was overly -/// conservative. +/// attemptTrivialCoalescing - If a simple interval is defined by a copy, try +/// allocate the definition the same register as the source register if the +/// register is not defined during live time of the interval. If the interval is +/// killed by a copy, try to use the destination register. This eliminates a +/// copy. This is used to coalesce copies which were not coalesced away before +/// allocation either due to dest and src being in different register classes or +/// because the coalescer was overly conservative. unsigned RALinScan::attemptTrivialCoalescing(LiveInterval &cur, unsigned Reg) { unsigned Preference = vrm_->getRegAllocPref(cur.reg); if ((Preference && Preference == Reg) || !cur.containsOneValue()) return Reg; VNInfo *vni = cur.begin()->valno; - if ((vni->def == SlotIndex()) || - vni->isUnused() || !vni->isDefAccurate()) + if (vni->isUnused()) return Reg; - MachineInstr *CopyMI = li_->getInstructionFromIndex(vni->def); - unsigned SrcReg, DstReg, SrcSubReg, DstSubReg, PhysReg; - if (!CopyMI || - !tii_->isMoveInstr(*CopyMI, SrcReg, DstReg, SrcSubReg, DstSubReg)) - return Reg; - PhysReg = SrcReg; - if (TargetRegisterInfo::isVirtualRegister(SrcReg)) { - if (!vrm_->isAssignedReg(SrcReg)) + unsigned CandReg; + bool forward; // extending physreg forward + { + MachineInstr *CopyMI; + unsigned SrcReg, DstReg, SrcSubReg, DstSubReg; + if (vni->def != SlotIndex() && vni->isDefAccurate() && + (CopyMI = li_->getInstructionFromIndex(vni->def)) && + 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; - 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; const TargetRegisterClass *RC = mri_->getRegClass(cur.reg); - if (!RC->contains(PhysReg)) + if (!RC->contains(CandReg)) return Reg; - // Try to coalesce. - if (!li_->conflictsWithPhysRegDef(cur, *vrm_, PhysReg)) { - DEBUG(errs() << "Coalescing: " << cur << " -> " << tri_->getName(PhysReg) - << '\n'); - vrm_->clearVirt(cur.reg); - vrm_->assignVirt2Phys(cur.reg, PhysReg); - - // 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; + if (forward) { + if (li_->conflictsWithPhysRegDef(cur, *vrm_, CandReg)) + return Reg; + } else { + if (li_->conflictsWithPhysRegUse(cur, *vrm_, CandReg)) + return Reg; } - 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) { diff --git a/test/CodeGen/X86/2009-01-12-CoalescerBug.ll b/test/CodeGen/X86/2009-01-12-CoalescerBug.ll index 27a7113ffd5..8e41e5a8b77 100644 --- a/test/CodeGen/X86/2009-01-12-CoalescerBug.ll +++ b/test/CodeGen/X86/2009-01-12-CoalescerBug.ll @@ -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 %struct.CUMULATIVE_ARGS = type { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } diff --git a/test/CodeGen/X86/twoaddr-coalesce.ll b/test/CodeGen/X86/twoaddr-coalesce.ll index d0e13f61f2d..4c37225ce02 100644 --- a/test/CodeGen/X86/twoaddr-coalesce.ll +++ b/test/CodeGen/X86/twoaddr-coalesce.ll @@ -1,4 +1,4 @@ -; RUN: llc < %s -march=x86 | grep mov | count 5 +; RUN: llc < %s -march=x86 | grep mov | count 4 ; rdar://6523745 @"\01LC" = internal constant [4 x i8] c"%d\0A\00" ; <[4 x i8]*> [#uses=1]