mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-01-23 02:32:11 +00:00
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
This commit is contained in:
parent
d37eaa3b97
commit
8f90b6eb2f
@ -24,6 +24,7 @@
|
|||||||
#include "llvm/CodeGen/LiveInterval.h"
|
#include "llvm/CodeGen/LiveInterval.h"
|
||||||
#include "llvm/ADT/BitVector.h"
|
#include "llvm/ADT/BitVector.h"
|
||||||
#include "llvm/ADT/DenseMap.h"
|
#include "llvm/ADT/DenseMap.h"
|
||||||
|
#include "llvm/ADT/SmallPtrSet.h"
|
||||||
#include "llvm/ADT/SmallVector.h"
|
#include "llvm/ADT/SmallVector.h"
|
||||||
#include "llvm/Support/Allocator.h"
|
#include "llvm/Support/Allocator.h"
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
@ -256,6 +257,12 @@ namespace llvm {
|
|||||||
bool conflictsWithPhysRegDef(const LiveInterval &li, VirtRegMap &vrm,
|
bool conflictsWithPhysRegDef(const LiveInterval &li, VirtRegMap &vrm,
|
||||||
unsigned reg);
|
unsigned reg);
|
||||||
|
|
||||||
|
/// conflictsWithPhysRegRef - Similar to conflictsWithPhysRegRef except
|
||||||
|
/// it can check use as well.
|
||||||
|
bool conflictsWithPhysRegRef(LiveInterval &li, unsigned Reg,
|
||||||
|
bool CheckUse,
|
||||||
|
SmallPtrSet<MachineInstr*,32> &JoinedCopies);
|
||||||
|
|
||||||
/// findLiveInMBBs - Given a live range, if the value of the range
|
/// 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
|
/// is live in any MBB returns true as well as the list of basic blocks
|
||||||
/// in which the value is live.
|
/// in which the value is live.
|
||||||
|
@ -323,6 +323,47 @@ bool LiveIntervals::conflictsWithPhysRegDef(const LiveInterval &li,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// conflictsWithPhysRegRef - Similar to conflictsWithPhysRegRef except
|
||||||
|
/// it can check use as well.
|
||||||
|
bool LiveIntervals::conflictsWithPhysRegRef(LiveInterval &li,
|
||||||
|
unsigned Reg, bool CheckUse,
|
||||||
|
SmallPtrSet<MachineInstr*,32> &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 {
|
void LiveIntervals::printRegName(unsigned reg) const {
|
||||||
if (TargetRegisterInfo::isPhysicalRegister(reg))
|
if (TargetRegisterInfo::isPhysicalRegister(reg))
|
||||||
cerr << tri_->getName(reg);
|
cerr << tri_->getName(reg);
|
||||||
@ -794,10 +835,15 @@ unsigned LiveIntervals::getVNInfoSourceReg(const VNInfo *VNI) const {
|
|||||||
if (!VNI->copy)
|
if (!VNI->copy)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (VNI->copy->getOpcode() == TargetInstrInfo::EXTRACT_SUBREG)
|
if (VNI->copy->getOpcode() == TargetInstrInfo::EXTRACT_SUBREG) {
|
||||||
return VNI->copy->getOperand(1).getReg();
|
// If it's extracting out of a physical register, return the sub-register.
|
||||||
if (VNI->copy->getOpcode() == TargetInstrInfo::INSERT_SUBREG)
|
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();
|
return VNI->copy->getOperand(2).getReg();
|
||||||
|
|
||||||
unsigned SrcReg, DstReg;
|
unsigned SrcReg, DstReg;
|
||||||
if (tii_->isMoveInstr(*VNI->copy, SrcReg, DstReg))
|
if (tii_->isMoveInstr(*VNI->copy, SrcReg, DstReg))
|
||||||
return SrcReg;
|
return SrcReg;
|
||||||
|
@ -1276,8 +1276,8 @@ bool SimpleRegisterCoalescing::JoinCopy(CopyRec &TheCopy, bool &Again) {
|
|||||||
// preference.
|
// preference.
|
||||||
unsigned Length = li_->getApproximateInstructionCount(JoinVInt);
|
unsigned Length = li_->getApproximateInstructionCount(JoinVInt);
|
||||||
if (Length > Threshold &&
|
if (Length > Threshold &&
|
||||||
(((float)std::distance(mri_->use_begin(JoinVReg),
|
(((float)std::distance(mri_->use_begin(JoinVReg), mri_->use_end())
|
||||||
mri_->use_end()) / Length) < (1.0 / Threshold))) {
|
/ Length) < (1.0 / Threshold))) {
|
||||||
JoinVInt.preference = JoinPReg;
|
JoinVInt.preference = JoinPReg;
|
||||||
++numAborts;
|
++numAborts;
|
||||||
DOUT << "\tMay tie down a physical register, abort!\n";
|
DOUT << "\tMay tie down a physical register, abort!\n";
|
||||||
@ -1334,7 +1334,7 @@ bool SimpleRegisterCoalescing::JoinCopy(CopyRec &TheCopy, bool &Again) {
|
|||||||
assert(TargetRegisterInfo::isVirtualRegister(SrcReg) &&
|
assert(TargetRegisterInfo::isVirtualRegister(SrcReg) &&
|
||||||
"LiveInterval::join didn't work right!");
|
"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
|
// we have to update any aliased register's live ranges to indicate that they
|
||||||
// have clobbered values for this range.
|
// have clobbered values for this range.
|
||||||
if (TargetRegisterInfo::isPhysicalRegister(DstReg)) {
|
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
|
/// physreg, this method always canonicalizes LHS to be it. The output
|
||||||
/// "RHS" will not have been modified, so we can use this information
|
/// "RHS" will not have been modified, so we can use this information
|
||||||
/// below to update aliases.
|
/// below to update aliases.
|
||||||
bool SimpleRegisterCoalescing::JoinIntervals(LiveInterval &LHS,
|
bool
|
||||||
LiveInterval &RHS, bool &Swapped) {
|
SimpleRegisterCoalescing::JoinIntervals(LiveInterval &LHS, LiveInterval &RHS,
|
||||||
|
bool &Swapped) {
|
||||||
// Compute the final value assignment, assuming that the live ranges can be
|
// Compute the final value assignment, assuming that the live ranges can be
|
||||||
// coalesced.
|
// coalesced.
|
||||||
SmallVector<int, 16> LHSValNoAssignments;
|
SmallVector<int, 16> LHSValNoAssignments;
|
||||||
@ -1721,26 +1722,43 @@ bool SimpleRegisterCoalescing::JoinIntervals(LiveInterval &LHS,
|
|||||||
DenseMap<VNInfo*, VNInfo*> LHSValsDefinedFromRHS;
|
DenseMap<VNInfo*, VNInfo*> LHSValsDefinedFromRHS;
|
||||||
DenseMap<VNInfo*, VNInfo*> RHSValsDefinedFromLHS;
|
DenseMap<VNInfo*, VNInfo*> RHSValsDefinedFromLHS;
|
||||||
SmallVector<VNInfo*, 16> NewVNInfo;
|
SmallVector<VNInfo*, 16> NewVNInfo;
|
||||||
|
|
||||||
// If a live interval is a physical register, conservatively check if any
|
// If a live interval is a physical register, conservatively check if any
|
||||||
// of its sub-registers is overlapping the live interval of the virtual
|
// of its sub-registers is overlapping the live interval of the virtual
|
||||||
// register. If so, do not coalesce.
|
// register. If so, do not coalesce.
|
||||||
if (TargetRegisterInfo::isPhysicalRegister(LHS.reg) &&
|
if (TargetRegisterInfo::isPhysicalRegister(LHS.reg) &&
|
||||||
*tri_->getSubRegisters(LHS.reg)) {
|
*tri_->getSubRegisters(LHS.reg)) {
|
||||||
for (const unsigned* SR = tri_->getSubRegisters(LHS.reg); *SR; ++SR)
|
// If it's coalescing a virtual register to a physical register, estimate
|
||||||
if (li_->hasInterval(*SR) && RHS.overlaps(li_->getInterval(*SR))) {
|
// its live interval length. This is the *cost* of scanning an entire live
|
||||||
DOUT << "Interfere with sub-register ";
|
// interval. If the cost is low, we'll do an exhaustive check instead.
|
||||||
DEBUG(li_->getInterval(*SR).print(DOUT, tri_));
|
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;
|
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) &&
|
} else if (TargetRegisterInfo::isPhysicalRegister(RHS.reg) &&
|
||||||
*tri_->getSubRegisters(RHS.reg)) {
|
*tri_->getSubRegisters(RHS.reg)) {
|
||||||
for (const unsigned* SR = tri_->getSubRegisters(RHS.reg); *SR; ++SR)
|
if (LHS.containsOneValue() &&
|
||||||
if (li_->hasInterval(*SR) && LHS.overlaps(li_->getInterval(*SR))) {
|
li_->getApproximateInstructionCount(LHS) <= 10) {
|
||||||
DOUT << "Interfere with sub-register ";
|
// Perform a more exhaustive check for some common cases.
|
||||||
DEBUG(li_->getInterval(*SR).print(DOUT, tri_));
|
if (li_->conflictsWithPhysRegRef(LHS, RHS.reg, false, JoinedCopies))
|
||||||
return false;
|
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.
|
// Compute ultimate value numbers for the LHS and RHS values.
|
||||||
@ -1755,7 +1773,7 @@ bool SimpleRegisterCoalescing::JoinIntervals(LiveInterval &LHS,
|
|||||||
VNInfo *RHSValNoInfo = NULL;
|
VNInfo *RHSValNoInfo = NULL;
|
||||||
VNInfo *RHSValNoInfo0 = RHS.getValNumInfo(0);
|
VNInfo *RHSValNoInfo0 = RHS.getValNumInfo(0);
|
||||||
unsigned RHSSrcReg = li_->getVNInfoSourceReg(RHSValNoInfo0);
|
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
|
// 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
|
// faster checks to see if the live ranges are coalescable. This joiner
|
||||||
// can't swap the LHS/RHS intervals though.
|
// can't swap the LHS/RHS intervals though.
|
||||||
|
24
test/CodeGen/X86/phys_subreg_coalesce.ll
Normal file
24
test/CodeGen/X86/phys_subreg_coalesce.ll
Normal file
@ -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 ; <i32> [#uses=1]
|
||||||
|
%1 = sitofp i32 %0 to double ; <double> [#uses=1]
|
||||||
|
%2 = trunc i64 %p2.0 to i32 ; <i32> [#uses=1]
|
||||||
|
%3 = sitofp i32 %2 to double ; <double> [#uses=1]
|
||||||
|
%4 = add double %1, %3 ; <double> [#uses=1]
|
||||||
|
%5 = mul double %4, 5.000000e-01 ; <double> [#uses=1]
|
||||||
|
%6 = lshr i64 %p1.0, 32 ; <i64> [#uses=1]
|
||||||
|
%7 = trunc i64 %6 to i32 ; <i32> [#uses=1]
|
||||||
|
%8 = sitofp i32 %7 to double ; <double> [#uses=1]
|
||||||
|
%9 = lshr i64 %p2.0, 32 ; <i64> [#uses=1]
|
||||||
|
%10 = trunc i64 %9 to i32 ; <i32> [#uses=1]
|
||||||
|
%11 = sitofp i32 %10 to double ; <double> [#uses=1]
|
||||||
|
%12 = add double %8, %11 ; <double> [#uses=1]
|
||||||
|
%13 = mul double %12, 5.000000e-01 ; <double> [#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
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user