mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 20:51:52 +01:00
It has finally happened. Spiller is now using live interval info.
This fixes a very subtle bug. vr defined by an implicit_def is allowed overlap with any register since it doesn't actually modify anything. However, if it's used as a two-address use, its live range can be extended and it can be spilled. The spiller must take care not to emit a reload for the vn number that's defined by the implicit_def. This is both a correctness and performance issue. llvm-svn: 69743
This commit is contained in:
parent
19990f2310
commit
a36c6c6819
@ -300,9 +300,9 @@ namespace llvm {
|
|||||||
r2iMap_.erase(I);
|
r2iMap_.erase(I);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// isRemoved - returns true if the specified machine instr has been
|
/// isNotInMIMap - returns true if the specified machine instr has been
|
||||||
/// removed.
|
/// removed or was never entered in the map.
|
||||||
bool isRemoved(MachineInstr* instr) const {
|
bool isNotInMIMap(MachineInstr* instr) const {
|
||||||
return !mi2iMap_.count(instr);
|
return !mi2iMap_.count(instr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1338,7 +1338,7 @@ rewriteInstructionForSpills(const LiveInterval &li, const VNInfo *VNI,
|
|||||||
HasUse = false;
|
HasUse = false;
|
||||||
HasDef = false;
|
HasDef = false;
|
||||||
CanFold = false;
|
CanFold = false;
|
||||||
if (isRemoved(MI)) {
|
if (isNotInMIMap(MI)) {
|
||||||
SSWeight -= Weight;
|
SSWeight -= Weight;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1393,7 +1393,7 @@ rewriteInstructionForSpills(const LiveInterval &li, const VNInfo *VNI,
|
|||||||
if (DefIsReMat && ImpUse)
|
if (DefIsReMat && ImpUse)
|
||||||
MI->addOperand(MachineOperand::CreateReg(ImpUse, false, true));
|
MI->addOperand(MachineOperand::CreateReg(ImpUse, false, true));
|
||||||
|
|
||||||
// create a new register interval for this spill / remat.
|
// Create a new register interval for this spill / remat.
|
||||||
LiveInterval &nI = getOrCreateInterval(NewVReg);
|
LiveInterval &nI = getOrCreateInterval(NewVReg);
|
||||||
if (CreatedNewVReg) {
|
if (CreatedNewVReg) {
|
||||||
NewLIs.push_back(&nI);
|
NewLIs.push_back(&nI);
|
||||||
|
@ -345,7 +345,7 @@ bool RALinScan::runOnMachineFunction(MachineFunction &fn) {
|
|||||||
linearScan();
|
linearScan();
|
||||||
|
|
||||||
// Rewrite spill code and update the PhysRegsUsed set.
|
// Rewrite spill code and update the PhysRegsUsed set.
|
||||||
spiller_->runOnMachineFunction(*mf_, *vrm_);
|
spiller_->runOnMachineFunction(*mf_, *vrm_, li_);
|
||||||
|
|
||||||
assert(unhandled_.empty() && "Unhandled live intervals remain!");
|
assert(unhandled_.empty() && "Unhandled live intervals remain!");
|
||||||
fixed_.clear();
|
fixed_.clear();
|
||||||
|
@ -854,7 +854,7 @@ bool PBQPRegAlloc::runOnMachineFunction(MachineFunction &MF) {
|
|||||||
|
|
||||||
// Run spiller
|
// Run spiller
|
||||||
std::auto_ptr<Spiller> spiller(createSpiller());
|
std::auto_ptr<Spiller> spiller(createSpiller());
|
||||||
spiller->runOnMachineFunction(*mf, *vrm);
|
spiller->runOnMachineFunction(*mf, *vrm, lis);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ STATISTIC(NumDRM , "Number of re-materializable defs elided");
|
|||||||
STATISTIC(NumStores , "Number of stores added");
|
STATISTIC(NumStores , "Number of stores added");
|
||||||
STATISTIC(NumPSpills , "Number of physical register spills");
|
STATISTIC(NumPSpills , "Number of physical register spills");
|
||||||
STATISTIC(NumOmitted , "Number of reloads omited");
|
STATISTIC(NumOmitted , "Number of reloads omited");
|
||||||
|
STATISTIC(NumAvoided , "Number of reloads deemed unnecessary");
|
||||||
STATISTIC(NumCopified, "Number of available reloads turned into copies");
|
STATISTIC(NumCopified, "Number of available reloads turned into copies");
|
||||||
STATISTIC(NumReMats , "Number of re-materialization");
|
STATISTIC(NumReMats , "Number of re-materialization");
|
||||||
STATISTIC(NumLoads , "Number of loads added");
|
STATISTIC(NumLoads , "Number of loads added");
|
||||||
@ -50,7 +51,8 @@ SpillerOpt("spiller",
|
|||||||
|
|
||||||
Spiller::~Spiller() {}
|
Spiller::~Spiller() {}
|
||||||
|
|
||||||
bool SimpleSpiller::runOnMachineFunction(MachineFunction &MF, VirtRegMap &VRM) {
|
bool SimpleSpiller::runOnMachineFunction(MachineFunction &MF, VirtRegMap &VRM,
|
||||||
|
LiveIntervals* LIs) {
|
||||||
DOUT << "********** REWRITE MACHINE CODE **********\n";
|
DOUT << "********** REWRITE MACHINE CODE **********\n";
|
||||||
DOUT << "********** Function: " << MF.getFunction()->getName() << '\n';
|
DOUT << "********** Function: " << MF.getFunction()->getName() << '\n';
|
||||||
const TargetMachine &TM = MF.getTarget();
|
const TargetMachine &TM = MF.getTarget();
|
||||||
@ -521,7 +523,8 @@ unsigned ReuseInfo::GetRegForReload(unsigned PhysReg, MachineInstr *MI,
|
|||||||
// Local Spiller Implementation //
|
// Local Spiller Implementation //
|
||||||
// ***************************** //
|
// ***************************** //
|
||||||
|
|
||||||
bool LocalSpiller::runOnMachineFunction(MachineFunction &MF, VirtRegMap &VRM) {
|
bool LocalSpiller::runOnMachineFunction(MachineFunction &MF, VirtRegMap &VRM,
|
||||||
|
LiveIntervals* LIs) {
|
||||||
RegInfo = &MF.getRegInfo();
|
RegInfo = &MF.getRegInfo();
|
||||||
TRI = MF.getTarget().getRegisterInfo();
|
TRI = MF.getTarget().getRegisterInfo();
|
||||||
TII = MF.getTarget().getInstrInfo();
|
TII = MF.getTarget().getInstrInfo();
|
||||||
@ -555,7 +558,7 @@ bool LocalSpiller::runOnMachineFunction(MachineFunction &MF, VirtRegMap &VRM) {
|
|||||||
DFI != E; ++DFI) {
|
DFI != E; ++DFI) {
|
||||||
MachineBasicBlock *MBB = *DFI;
|
MachineBasicBlock *MBB = *DFI;
|
||||||
if (!EarlyVisited.count(MBB))
|
if (!EarlyVisited.count(MBB))
|
||||||
RewriteMBB(*MBB, VRM, Spills, RegKills, KillOps);
|
RewriteMBB(*MBB, VRM, LIs, Spills, RegKills, KillOps);
|
||||||
|
|
||||||
// If this MBB is the only predecessor of a successor. Keep the
|
// If this MBB is the only predecessor of a successor. Keep the
|
||||||
// availability information and visit it next.
|
// availability information and visit it next.
|
||||||
@ -571,7 +574,7 @@ bool LocalSpiller::runOnMachineFunction(MachineFunction &MF, VirtRegMap &VRM) {
|
|||||||
MBB = SinglePredSuccs[0];
|
MBB = SinglePredSuccs[0];
|
||||||
if (!Visited.count(MBB) && EarlyVisited.insert(MBB)) {
|
if (!Visited.count(MBB) && EarlyVisited.insert(MBB)) {
|
||||||
Spills.AddAvailableRegsToLiveIn(*MBB, RegKills, KillOps);
|
Spills.AddAvailableRegsToLiveIn(*MBB, RegKills, KillOps);
|
||||||
RewriteMBB(*MBB, VRM, Spills, RegKills, KillOps);
|
RewriteMBB(*MBB, VRM, LIs, Spills, RegKills, KillOps);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (MBB);
|
} while (MBB);
|
||||||
@ -1109,6 +1112,7 @@ void LocalSpiller::TransferDeadness(MachineBasicBlock *MBB, unsigned CurDist,
|
|||||||
/// rewriteMBB - Keep track of which spills are available even after the
|
/// rewriteMBB - Keep track of which spills are available even after the
|
||||||
/// register allocator is done with them. If possible, avid reloading vregs.
|
/// register allocator is done with them. If possible, avid reloading vregs.
|
||||||
void LocalSpiller::RewriteMBB(MachineBasicBlock &MBB, VirtRegMap &VRM,
|
void LocalSpiller::RewriteMBB(MachineBasicBlock &MBB, VirtRegMap &VRM,
|
||||||
|
LiveIntervals *LIs,
|
||||||
AvailableSpills &Spills, BitVector &RegKills,
|
AvailableSpills &Spills, BitVector &RegKills,
|
||||||
std::vector<MachineOperand*> &KillOps) {
|
std::vector<MachineOperand*> &KillOps) {
|
||||||
DOUT << "\n**** Local spiller rewriting MBB '"
|
DOUT << "\n**** Local spiller rewriting MBB '"
|
||||||
@ -1339,6 +1343,22 @@ void LocalSpiller::RewriteMBB(MachineBasicBlock &MBB, VirtRegMap &VRM,
|
|||||||
if (!MO.isUse())
|
if (!MO.isUse())
|
||||||
continue; // Handle defs in the loop below (handle use&def here though)
|
continue; // Handle defs in the loop below (handle use&def here though)
|
||||||
|
|
||||||
|
bool AvoidReload = false;
|
||||||
|
if (LIs->hasInterval(VirtReg)) {
|
||||||
|
LiveInterval &LI = LIs->getInterval(VirtReg);
|
||||||
|
if (!LI.liveAt(LIs->getUseIndex(LI.beginNumber())))
|
||||||
|
// Must be defined by an implicit def. It should not be spilled. Note,
|
||||||
|
// this is for correctness reason. e.g.
|
||||||
|
// 8 %reg1024<def> = IMPLICIT_DEF
|
||||||
|
// 12 %reg1024<def> = INSERT_SUBREG %reg1024<kill>, %reg1025, 2
|
||||||
|
// The live range [12, 14) are not part of the r1024 live interval since
|
||||||
|
// it's defined by an implicit def. It will not conflicts with live
|
||||||
|
// interval of r1025. Now suppose both registers are spilled, you can
|
||||||
|
// easily see a situation where both registers are reloaded before
|
||||||
|
// the INSERT_SUBREG and both target registers that would overlap.
|
||||||
|
AvoidReload = true;
|
||||||
|
}
|
||||||
|
|
||||||
bool DoReMat = VRM.isReMaterialized(VirtReg);
|
bool DoReMat = VRM.isReMaterialized(VirtReg);
|
||||||
int SSorRMId = DoReMat
|
int SSorRMId = DoReMat
|
||||||
? VRM.getReMatId(VirtReg) : VRM.getStackSlot(VirtReg);
|
? VRM.getReMatId(VirtReg) : VRM.getStackSlot(VirtReg);
|
||||||
@ -1357,14 +1377,14 @@ void LocalSpiller::RewriteMBB(MachineBasicBlock &MBB, VirtRegMap &VRM,
|
|||||||
// = EXTRACT_SUBREG fi#1
|
// = EXTRACT_SUBREG fi#1
|
||||||
// fi#1 is available in EDI, but it cannot be reused because it's not in
|
// fi#1 is available in EDI, but it cannot be reused because it's not in
|
||||||
// the right register file.
|
// the right register file.
|
||||||
if (PhysReg &&
|
if (PhysReg && !AvoidReload &&
|
||||||
(SubIdx || MI.getOpcode() == TargetInstrInfo::EXTRACT_SUBREG)) {
|
(SubIdx || MI.getOpcode() == TargetInstrInfo::EXTRACT_SUBREG)) {
|
||||||
const TargetRegisterClass* RC = RegInfo->getRegClass(VirtReg);
|
const TargetRegisterClass* RC = RegInfo->getRegClass(VirtReg);
|
||||||
if (!RC->contains(PhysReg))
|
if (!RC->contains(PhysReg))
|
||||||
PhysReg = 0;
|
PhysReg = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PhysReg) {
|
if (PhysReg && !AvoidReload) {
|
||||||
// This spilled operand might be part of a two-address operand. If this
|
// This spilled operand might be part of a two-address operand. If this
|
||||||
// is the case, then changing it will necessarily require changing the
|
// is the case, then changing it will necessarily require changing the
|
||||||
// def part of the instruction as well. However, in some cases, we
|
// def part of the instruction as well. However, in some cases, we
|
||||||
@ -1513,6 +1533,9 @@ void LocalSpiller::RewriteMBB(MachineBasicBlock &MBB, VirtRegMap &VRM,
|
|||||||
|
|
||||||
RegInfo->setPhysRegUsed(PhysReg);
|
RegInfo->setPhysRegUsed(PhysReg);
|
||||||
ReusedOperands.markClobbered(PhysReg);
|
ReusedOperands.markClobbered(PhysReg);
|
||||||
|
if (AvoidReload)
|
||||||
|
++NumAvoided;
|
||||||
|
else {
|
||||||
if (DoReMat) {
|
if (DoReMat) {
|
||||||
ReMaterialize(MBB, MII, PhysReg, VirtReg, TII, TRI, VRM);
|
ReMaterialize(MBB, MII, PhysReg, VirtReg, TII, TRI, VRM);
|
||||||
} else {
|
} else {
|
||||||
@ -1536,11 +1559,13 @@ void LocalSpiller::RewriteMBB(MachineBasicBlock &MBB, VirtRegMap &VRM,
|
|||||||
MI.getOperand(i).setIsKill();
|
MI.getOperand(i).setIsKill();
|
||||||
KilledMIRegs.insert(VirtReg);
|
KilledMIRegs.insert(VirtReg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UpdateKills(*prior(MII), RegKills, KillOps, TRI);
|
||||||
|
DOUT << '\t' << *prior(MII);
|
||||||
|
}
|
||||||
unsigned RReg = SubIdx ? TRI->getSubReg(PhysReg, SubIdx) : PhysReg;
|
unsigned RReg = SubIdx ? TRI->getSubReg(PhysReg, SubIdx) : PhysReg;
|
||||||
MI.getOperand(i).setReg(RReg);
|
MI.getOperand(i).setReg(RReg);
|
||||||
MI.getOperand(i).setSubReg(0);
|
MI.getOperand(i).setSubReg(0);
|
||||||
UpdateKills(*prior(MII), RegKills, KillOps, TRI);
|
|
||||||
DOUT << '\t' << *prior(MII);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ok - now we can remove stores that have been confirmed dead.
|
// Ok - now we can remove stores that have been confirmed dead.
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include "llvm/ADT/SmallVector.h"
|
#include "llvm/ADT/SmallVector.h"
|
||||||
#include "llvm/Support/Streams.h"
|
#include "llvm/Support/Streams.h"
|
||||||
#include "llvm/Function.h"
|
#include "llvm/Function.h"
|
||||||
|
#include "llvm/CodeGen/LiveIntervalAnalysis.h"
|
||||||
#include "llvm/CodeGen/MachineFrameInfo.h"
|
#include "llvm/CodeGen/MachineFrameInfo.h"
|
||||||
#include "llvm/CodeGen/MachineFunction.h"
|
#include "llvm/CodeGen/MachineFunction.h"
|
||||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||||
@ -37,8 +38,8 @@ namespace llvm {
|
|||||||
/// virtual registers to stack slots, rewriting the code.
|
/// virtual registers to stack slots, rewriting the code.
|
||||||
struct Spiller {
|
struct Spiller {
|
||||||
virtual ~Spiller();
|
virtual ~Spiller();
|
||||||
virtual bool runOnMachineFunction(MachineFunction &MF,
|
virtual bool runOnMachineFunction(MachineFunction &MF, VirtRegMap &VRM,
|
||||||
VirtRegMap &VRM) = 0;
|
LiveIntervals* LIs) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// createSpiller - Create an return a spiller object, as specified on the
|
/// createSpiller - Create an return a spiller object, as specified on the
|
||||||
@ -49,7 +50,8 @@ namespace llvm {
|
|||||||
|
|
||||||
// Simple Spiller Implementation
|
// Simple Spiller Implementation
|
||||||
struct VISIBILITY_HIDDEN SimpleSpiller : public Spiller {
|
struct VISIBILITY_HIDDEN SimpleSpiller : public Spiller {
|
||||||
bool runOnMachineFunction(MachineFunction& mf, VirtRegMap &VRM);
|
bool runOnMachineFunction(MachineFunction& mf, VirtRegMap &VRM,
|
||||||
|
LiveIntervals* LIs);
|
||||||
};
|
};
|
||||||
|
|
||||||
// ************************************************************************ //
|
// ************************************************************************ //
|
||||||
@ -287,7 +289,8 @@ namespace llvm {
|
|||||||
BitVector AllocatableRegs;
|
BitVector AllocatableRegs;
|
||||||
DenseMap<MachineInstr*, unsigned> DistanceMap;
|
DenseMap<MachineInstr*, unsigned> DistanceMap;
|
||||||
public:
|
public:
|
||||||
bool runOnMachineFunction(MachineFunction &MF, VirtRegMap &VRM);
|
bool runOnMachineFunction(MachineFunction &MF, VirtRegMap &VRM,
|
||||||
|
LiveIntervals* LI);
|
||||||
private:
|
private:
|
||||||
void TransferDeadness(MachineBasicBlock *MBB, unsigned CurDist,
|
void TransferDeadness(MachineBasicBlock *MBB, unsigned CurDist,
|
||||||
unsigned Reg, BitVector &RegKills,
|
unsigned Reg, BitVector &RegKills,
|
||||||
@ -329,7 +332,7 @@ namespace llvm {
|
|||||||
VirtRegMap &VRM);
|
VirtRegMap &VRM);
|
||||||
|
|
||||||
void RewriteMBB(MachineBasicBlock &MBB, VirtRegMap &VRM,
|
void RewriteMBB(MachineBasicBlock &MBB, VirtRegMap &VRM,
|
||||||
AvailableSpills &Spills,
|
LiveIntervals *LIs, AvailableSpills &Spills,
|
||||||
BitVector &RegKills, std::vector<MachineOperand*> &KillOps);
|
BitVector &RegKills, std::vector<MachineOperand*> &KillOps);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
25
test/CodeGen/X86/2009-04-21-NoReloadImpDef.ll
Normal file
25
test/CodeGen/X86/2009-04-21-NoReloadImpDef.ll
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
; RUN: llvm-as < %s | llc -mtriple=i386-apple-darwin10.0 -relocation-model=pic -disable-fp-elim -mattr=-sse41,-sse3,+sse2 | \
|
||||||
|
; RUN: %prcontext {14} 2 | grep {(%ebp)} | count 1
|
||||||
|
; rdar://6808032
|
||||||
|
|
||||||
|
define void @update(i8** %args_list) nounwind {
|
||||||
|
entry:
|
||||||
|
%cmp.i = icmp eq i32 0, 0 ; <i1> [#uses=1]
|
||||||
|
br i1 %cmp.i, label %if.then.i, label %test_cl.exit
|
||||||
|
|
||||||
|
if.then.i: ; preds = %entry
|
||||||
|
%val = load <16 x i8> addrspace(1)* null ; <<16 x i8>> [#uses=8]
|
||||||
|
%tmp10.i = shufflevector <16 x i8> <i8 0, i8 0, i8 0, i8 undef, i8 0, i8 undef, i8 0, i8 undef, i8 undef, i8 undef, i8 0, i8 0, i8 0, i8 undef, i8 undef, i8 undef>, <16 x i8> %val, <16 x i32> <i32 0, i32 1, i32 2, i32 undef, i32 4, i32 undef, i32 6, i32 undef, i32 29, i32 undef, i32 10, i32 11, i32 12, i32 undef, i32 undef, i32 undef> ; <<16 x i8>> [#uses=1]
|
||||||
|
%tmp17.i = shufflevector <16 x i8> %tmp10.i, <16 x i8> %val, <16 x i32> <i32 0, i32 1, i32 2, i32 18, i32 4, i32 undef, i32 6, i32 undef, i32 8, i32 undef, i32 10, i32 11, i32 12, i32 undef, i32 undef, i32 undef> ; <<16 x i8>> [#uses=1]
|
||||||
|
%tmp24.i = shufflevector <16 x i8> %tmp17.i, <16 x i8> %val, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 24, i32 6, i32 undef, i32 8, i32 undef, i32 10, i32 11, i32 12, i32 undef, i32 undef, i32 undef> ; <<16 x i8>> [#uses=1]
|
||||||
|
%tmp31.i = shufflevector <16 x i8> %tmp24.i, <16 x i8> %val, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 undef, i32 8, i32 undef, i32 10, i32 11, i32 12, i32 21, i32 undef, i32 undef> ; <<16 x i8>> [#uses=1]
|
||||||
|
%tmp38.i = shufflevector <16 x i8> %tmp31.i, <16 x i8> %val, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 27, i32 8, i32 undef, i32 10, i32 11, i32 12, i32 13, i32 undef, i32 undef> ; <<16 x i8>> [#uses=1]
|
||||||
|
%tmp45.i = shufflevector <16 x i8> %tmp38.i, <16 x i8> %val, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 undef, i32 10, i32 11, i32 12, i32 13, i32 29, i32 undef> ; <<16 x i8>> [#uses=1]
|
||||||
|
%tmp52.i = shufflevector <16 x i8> %tmp45.i, <16 x i8> %val, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 21, i32 10, i32 11, i32 12, i32 13, i32 14, i32 undef> ; <<16 x i8>> [#uses=1]
|
||||||
|
%tmp59.i = shufflevector <16 x i8> %tmp52.i, <16 x i8> %val, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 20> ; <<16 x i8>> [#uses=1]
|
||||||
|
store <16 x i8> %tmp59.i, <16 x i8> addrspace(1)* null
|
||||||
|
ret void
|
||||||
|
|
||||||
|
test_cl.exit: ; preds = %entry
|
||||||
|
ret void
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user