From: Evan Cheng Date: Wed, 7 Jan 2009 02:08:57 +0000 (+0000) Subject: The coalescer does not coalesce a virtual register to a physical register if any... X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=8f90b6eb2fd0125f5b779de80954944f9071fb87;p=oota-llvm.git The coalescer does not coalesce a virtual register to a physical register if any of the physical register's sub-register live intervals overlaps with the virtual register. This is overly conservative. It prevents a extract_subreg from being coalesced away: v1024 = EDI // not killed = = EDI One possible solution is for the coalescer to examine the sub-register live intervals in the same manner as the physical register. Another possibility is to examine defs and uses (when needed) of sub-registers. Both solutions are too expensive. For now, look for "short virtual intervals" and scan instructions to look for conflict instead. This is a small win on x86-64. e.g. It shaves 403.gcc by ~80 instructions. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@61847 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/CodeGen/LiveIntervalAnalysis.h b/include/llvm/CodeGen/LiveIntervalAnalysis.h index 9dd55261492..52ee8852c67 100644 --- a/include/llvm/CodeGen/LiveIntervalAnalysis.h +++ b/include/llvm/CodeGen/LiveIntervalAnalysis.h @@ -24,6 +24,7 @@ #include "llvm/CodeGen/LiveInterval.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/Allocator.h" #include @@ -256,6 +257,12 @@ namespace llvm { bool conflictsWithPhysRegDef(const LiveInterval &li, VirtRegMap &vrm, unsigned reg); + /// conflictsWithPhysRegRef - Similar to conflictsWithPhysRegRef except + /// it can check use as well. + bool conflictsWithPhysRegRef(LiveInterval &li, unsigned Reg, + bool CheckUse, + SmallPtrSet &JoinedCopies); + /// findLiveInMBBs - Given a live range, if the value of the range /// is live in any MBB returns true as well as the list of basic blocks /// in which the value is live. diff --git a/lib/CodeGen/LiveIntervalAnalysis.cpp b/lib/CodeGen/LiveIntervalAnalysis.cpp index 1900c1a4d7d..22595895627 100644 --- a/lib/CodeGen/LiveIntervalAnalysis.cpp +++ b/lib/CodeGen/LiveIntervalAnalysis.cpp @@ -323,6 +323,47 @@ bool LiveIntervals::conflictsWithPhysRegDef(const LiveInterval &li, return false; } +/// conflictsWithPhysRegRef - Similar to conflictsWithPhysRegRef except +/// it can check use as well. +bool LiveIntervals::conflictsWithPhysRegRef(LiveInterval &li, + unsigned Reg, bool CheckUse, + SmallPtrSet &JoinedCopies) { + for (LiveInterval::Ranges::const_iterator + I = li.ranges.begin(), E = li.ranges.end(); I != E; ++I) { + for (unsigned index = getBaseIndex(I->start), + end = getBaseIndex(I->end-1) + InstrSlots::NUM; index != end; + index += InstrSlots::NUM) { + // Skip deleted instructions. + MachineInstr *MI = 0; + while (index != end) { + MI = getInstructionFromIndex(index); + if (MI) + break; + index += InstrSlots::NUM; + } + if (index == end) break; + + if (JoinedCopies.count(MI)) + continue; + for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { + MachineOperand& MO = MI->getOperand(i); + if (!MO.isReg()) + continue; + if (MO.isUse() && !CheckUse) + continue; + unsigned PhysReg = MO.getReg(); + if (PhysReg == 0 || TargetRegisterInfo::isVirtualRegister(PhysReg)) + continue; + if (tri_->isSubRegister(Reg, PhysReg)) + return true; + } + } + } + + return false; +} + + void LiveIntervals::printRegName(unsigned reg) const { if (TargetRegisterInfo::isPhysicalRegister(reg)) cerr << tri_->getName(reg); @@ -794,10 +835,15 @@ unsigned LiveIntervals::getVNInfoSourceReg(const VNInfo *VNI) const { if (!VNI->copy) return 0; - if (VNI->copy->getOpcode() == TargetInstrInfo::EXTRACT_SUBREG) - return VNI->copy->getOperand(1).getReg(); - if (VNI->copy->getOpcode() == TargetInstrInfo::INSERT_SUBREG) + if (VNI->copy->getOpcode() == TargetInstrInfo::EXTRACT_SUBREG) { + // If it's extracting out of a physical register, return the sub-register. + unsigned Reg = VNI->copy->getOperand(1).getReg(); + if (TargetRegisterInfo::isPhysicalRegister(Reg)) + Reg = tri_->getSubReg(Reg, VNI->copy->getOperand(2).getImm()); + return Reg; + } else if (VNI->copy->getOpcode() == TargetInstrInfo::INSERT_SUBREG) return VNI->copy->getOperand(2).getReg(); + unsigned SrcReg, DstReg; if (tii_->isMoveInstr(*VNI->copy, SrcReg, DstReg)) return SrcReg; diff --git a/lib/CodeGen/SimpleRegisterCoalescing.cpp b/lib/CodeGen/SimpleRegisterCoalescing.cpp index cfc77eef046..7f36ef5bcef 100644 --- a/lib/CodeGen/SimpleRegisterCoalescing.cpp +++ b/lib/CodeGen/SimpleRegisterCoalescing.cpp @@ -1276,8 +1276,8 @@ bool SimpleRegisterCoalescing::JoinCopy(CopyRec &TheCopy, bool &Again) { // preference. unsigned Length = li_->getApproximateInstructionCount(JoinVInt); if (Length > Threshold && - (((float)std::distance(mri_->use_begin(JoinVReg), - mri_->use_end()) / Length) < (1.0 / Threshold))) { + (((float)std::distance(mri_->use_begin(JoinVReg), mri_->use_end()) + / Length) < (1.0 / Threshold))) { JoinVInt.preference = JoinPReg; ++numAborts; DOUT << "\tMay tie down a physical register, abort!\n"; @@ -1334,7 +1334,7 @@ bool SimpleRegisterCoalescing::JoinCopy(CopyRec &TheCopy, bool &Again) { assert(TargetRegisterInfo::isVirtualRegister(SrcReg) && "LiveInterval::join didn't work right!"); - // If we're about to merge live ranges into a physical register live range, + // If we're about to merge live ranges into a physical register live interval, // we have to update any aliased register's live ranges to indicate that they // have clobbered values for this range. if (TargetRegisterInfo::isPhysicalRegister(DstReg)) { @@ -1712,8 +1712,9 @@ bool SimpleRegisterCoalescing::SimpleJoin(LiveInterval &LHS, LiveInterval &RHS){ /// physreg, this method always canonicalizes LHS to be it. The output /// "RHS" will not have been modified, so we can use this information /// below to update aliases. -bool SimpleRegisterCoalescing::JoinIntervals(LiveInterval &LHS, - LiveInterval &RHS, bool &Swapped) { +bool +SimpleRegisterCoalescing::JoinIntervals(LiveInterval &LHS, LiveInterval &RHS, + bool &Swapped) { // Compute the final value assignment, assuming that the live ranges can be // coalesced. SmallVector LHSValNoAssignments; @@ -1721,26 +1722,43 @@ bool SimpleRegisterCoalescing::JoinIntervals(LiveInterval &LHS, DenseMap LHSValsDefinedFromRHS; DenseMap RHSValsDefinedFromLHS; SmallVector NewVNInfo; - + // If a live interval is a physical register, conservatively check if any // of its sub-registers is overlapping the live interval of the virtual // register. If so, do not coalesce. if (TargetRegisterInfo::isPhysicalRegister(LHS.reg) && *tri_->getSubRegisters(LHS.reg)) { - for (const unsigned* SR = tri_->getSubRegisters(LHS.reg); *SR; ++SR) - if (li_->hasInterval(*SR) && RHS.overlaps(li_->getInterval(*SR))) { - DOUT << "Interfere with sub-register "; - DEBUG(li_->getInterval(*SR).print(DOUT, tri_)); + // If it's coalescing a virtual register to a physical register, estimate + // its live interval length. This is the *cost* of scanning an entire live + // interval. If the cost is low, we'll do an exhaustive check instead. + if (RHS.containsOneValue() && + li_->getApproximateInstructionCount(RHS) <= 10) { + // Perform a more exhaustive check for some common cases. + if (li_->conflictsWithPhysRegRef(RHS, LHS.reg, true, JoinedCopies)) return false; - } + } else { + for (const unsigned* SR = tri_->getSubRegisters(LHS.reg); *SR; ++SR) + if (li_->hasInterval(*SR) && RHS.overlaps(li_->getInterval(*SR))) { + DOUT << "Interfere with sub-register "; + DEBUG(li_->getInterval(*SR).print(DOUT, tri_)); + return false; + } + } } else if (TargetRegisterInfo::isPhysicalRegister(RHS.reg) && *tri_->getSubRegisters(RHS.reg)) { - for (const unsigned* SR = tri_->getSubRegisters(RHS.reg); *SR; ++SR) - if (li_->hasInterval(*SR) && LHS.overlaps(li_->getInterval(*SR))) { - DOUT << "Interfere with sub-register "; - DEBUG(li_->getInterval(*SR).print(DOUT, tri_)); + if (LHS.containsOneValue() && + li_->getApproximateInstructionCount(LHS) <= 10) { + // Perform a more exhaustive check for some common cases. + if (li_->conflictsWithPhysRegRef(LHS, RHS.reg, false, JoinedCopies)) return false; - } + } else { + for (const unsigned* SR = tri_->getSubRegisters(RHS.reg); *SR; ++SR) + if (li_->hasInterval(*SR) && LHS.overlaps(li_->getInterval(*SR))) { + DOUT << "Interfere with sub-register "; + DEBUG(li_->getInterval(*SR).print(DOUT, tri_)); + return false; + } + } } // Compute ultimate value numbers for the LHS and RHS values. @@ -1755,7 +1773,7 @@ bool SimpleRegisterCoalescing::JoinIntervals(LiveInterval &LHS, VNInfo *RHSValNoInfo = NULL; VNInfo *RHSValNoInfo0 = RHS.getValNumInfo(0); unsigned RHSSrcReg = li_->getVNInfoSourceReg(RHSValNoInfo0); - if ((RHSSrcReg == 0 || RHSSrcReg != LHS.reg)) { + if (RHSSrcReg == 0 || RHSSrcReg != LHS.reg) { // If RHS is not defined as a copy from the LHS, we can use simpler and // faster checks to see if the live ranges are coalescable. This joiner // can't swap the LHS/RHS intervals though. diff --git a/test/CodeGen/X86/phys_subreg_coalesce.ll b/test/CodeGen/X86/phys_subreg_coalesce.ll new file mode 100644 index 00000000000..789a4bae32b --- /dev/null +++ b/test/CodeGen/X86/phys_subreg_coalesce.ll @@ -0,0 +1,24 @@ +; RUN: llvm-as < %s | llc -mtriple=x86_64-apple-darwin9 -mattr=+sse2 | not grep movl + + %struct.dpoint = type { double, double } + +define %struct.dpoint @midpoint(i64 %p1.0, i64 %p2.0) nounwind readnone { +entry: + %0 = trunc i64 %p1.0 to i32 ; [#uses=1] + %1 = sitofp i32 %0 to double ; [#uses=1] + %2 = trunc i64 %p2.0 to i32 ; [#uses=1] + %3 = sitofp i32 %2 to double ; [#uses=1] + %4 = add double %1, %3 ; [#uses=1] + %5 = mul double %4, 5.000000e-01 ; [#uses=1] + %6 = lshr i64 %p1.0, 32 ; [#uses=1] + %7 = trunc i64 %6 to i32 ; [#uses=1] + %8 = sitofp i32 %7 to double ; [#uses=1] + %9 = lshr i64 %p2.0, 32 ; [#uses=1] + %10 = trunc i64 %9 to i32 ; [#uses=1] + %11 = sitofp i32 %10 to double ; [#uses=1] + %12 = add double %8, %11 ; [#uses=1] + %13 = mul double %12, 5.000000e-01 ; [#uses=1] + %mrv3 = insertvalue %struct.dpoint undef, double %5, 0 ; <%struct.dpoint> [#uses=1] + %mrv4 = insertvalue %struct.dpoint %mrv3, double %13, 1 ; <%struct.dpoint> [#uses=1] + ret %struct.dpoint %mrv4 +}