Simplify RegScavenger::forward a bit more.

Verify that early clobber registers and their aliases are not used.

All changes to RegsAvailable are now done as a transaction so the order of
operands makes no difference.

The included test case is from PR4686. It has behaviour that was dependent on the order of operands.

llvm-svn: 78465
This commit is contained in:
Jakob Stoklund Olesen 2009-08-08 13:18:47 +00:00
parent aadd8cfa2f
commit f73b30b329
3 changed files with 80 additions and 66 deletions

View File

@ -162,8 +162,14 @@ private:
MachineInstr *findFirstUse(MachineBasicBlock *MBB, MachineInstr *findFirstUse(MachineBasicBlock *MBB,
MachineBasicBlock::iterator I, unsigned Reg, MachineBasicBlock::iterator I, unsigned Reg,
unsigned &Dist); unsigned &Dist);
/// Add Reg and all its sub-registers to BV.
void addRegWithSubRegs(BitVector &BV, unsigned Reg);
/// Add Reg and its aliases to BV.
void addRegWithAliases(BitVector &BV, unsigned Reg);
}; };
} // End llvm namespace } // End llvm namespace
#endif #endif

View File

@ -51,13 +51,6 @@ static bool RedefinesSuperRegPart(const MachineInstr *MI, unsigned SubReg,
return SeenSuperDef && SeenSuperUse; return SeenSuperDef && SeenSuperUse;
} }
static bool RedefinesSuperRegPart(const MachineInstr *MI,
const MachineOperand &MO,
const TargetRegisterInfo *TRI) {
assert(MO.isReg() && MO.isDef() && "Not a register def!");
return RedefinesSuperRegPart(MI, MO.getReg(), TRI);
}
bool RegScavenger::isSuperRegUsed(unsigned Reg) const { bool RegScavenger::isSuperRegUsed(unsigned Reg) const {
for (const unsigned *SuperRegs = TRI->getSuperRegisters(Reg); for (const unsigned *SuperRegs = TRI->getSuperRegisters(Reg);
unsigned SuperReg = *SuperRegs; ++SuperRegs) unsigned SuperReg = *SuperRegs; ++SuperRegs)
@ -190,6 +183,18 @@ static bool isLiveInButUnusedBefore(unsigned Reg, MachineInstr *MI,
} }
#endif #endif
void RegScavenger::addRegWithSubRegs(BitVector &BV, unsigned Reg) {
BV.set(Reg);
for (const unsigned *R = TRI->getSubRegisters(Reg); *R; R++)
BV.set(*R);
}
void RegScavenger::addRegWithAliases(BitVector &BV, unsigned Reg) {
BV.set(Reg);
for (const unsigned *R = TRI->getAliasSet(Reg); *R; R++)
BV.set(*R);
}
void RegScavenger::forward() { void RegScavenger::forward() {
// Move ptr forward. // Move ptr forward.
if (!Tracking) { if (!Tracking) {
@ -209,76 +214,59 @@ void RegScavenger::forward() {
ScavengeRestore = NULL; ScavengeRestore = NULL;
} }
// Separate register operands into 3 classes: uses, defs, earlyclobbers. // Find out which registers are early clobbered, killed, defined, and marked
SmallVector<std::pair<const MachineOperand*,unsigned>, 4> UseMOs; // def-dead in this instruction.
SmallVector<std::pair<const MachineOperand*,unsigned>, 4> DefMOs; BitVector EarlyClobberRegs(NumPhysRegs);
SmallVector<std::pair<const MachineOperand*,unsigned>, 4> EarlyClobberMOs; BitVector KillRegs(NumPhysRegs);
BitVector DefRegs(NumPhysRegs);
BitVector DeadRegs(NumPhysRegs);
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
const MachineOperand &MO = MI->getOperand(i); const MachineOperand &MO = MI->getOperand(i);
if (!MO.isReg() || MO.getReg() == 0 || MO.isUndef()) if (!MO.isReg() || MO.isUndef())
continue; continue;
if (MO.isUse()) unsigned Reg = MO.getReg();
UseMOs.push_back(std::make_pair(&MO,i)); if (!Reg || isReserved(Reg))
else if (MO.isEarlyClobber()) continue;
EarlyClobberMOs.push_back(std::make_pair(&MO,i));
else { if (MO.isUse()) {
// Two-address operands implicitly kill.
if (MO.isKill() || MI->isRegTiedToDefOperand(i))
addRegWithSubRegs(KillRegs, Reg);
} else {
assert(MO.isDef()); assert(MO.isDef());
DefMOs.push_back(std::make_pair(&MO,i)); if (MO.isDead())
addRegWithSubRegs(DeadRegs, Reg);
else
addRegWithSubRegs(DefRegs, Reg);
if (MO.isEarlyClobber())
addRegWithAliases(EarlyClobberRegs, Reg);
} }
} }
// Process uses first. // Verify uses and defs.
BitVector KillRegs(NumPhysRegs); for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
for (unsigned i = 0, e = UseMOs.size(); i != e; ++i) { const MachineOperand &MO = MI->getOperand(i);
const MachineOperand MO = *UseMOs[i].first; if (!MO.isReg() || MO.isUndef())
unsigned Idx = UseMOs[i].second; continue;
unsigned Reg = MO.getReg(); unsigned Reg = MO.getReg();
if (!Reg || isReserved(Reg))
assert(isUsed(Reg) && "Using an undefined register!"); continue;
if (MO.isUse()) {
// Two-address operands implicitly kill. assert(isUsed(Reg) && "Using an undefined register!");
if ((MO.isKill() || MI->isRegTiedToDefOperand(Idx)) && !isReserved(Reg)) { assert(!EarlyClobberRegs.test(Reg) &&
KillRegs.set(Reg); "Using an early clobbered register!");
} else {
// Mark sub-registers as used. assert(MO.isDef());
for (const unsigned *SubRegs = TRI->getSubRegisters(Reg); assert((KillRegs.test(Reg) || isUnused(Reg) || isSuperRegUsed(Reg) ||
unsigned SubReg = *SubRegs; ++SubRegs) isLiveInButUnusedBefore(Reg, MI, MBB, TRI, MRI)) &&
KillRegs.set(SubReg); "Re-defining a live register!");
} }
} }
// Change states of all registers after all the uses are processed to guard // Commit the changes.
// against multiple uses.
setUnused(KillRegs); setUnused(KillRegs);
setUnused(DeadRegs);
// Process early clobber defs then process defs. We can have a early clobber setUsed(DefRegs);
// that is dead, it should not conflict with a def that happens one "slot"
// (see InstrSlots in LiveIntervalAnalysis.h) later.
unsigned NumECs = EarlyClobberMOs.size();
unsigned NumDefs = DefMOs.size();
for (unsigned i = 0, e = NumECs + NumDefs; i != e; ++i) {
const MachineOperand &MO = (i < NumECs)
? *EarlyClobberMOs[i].first : *DefMOs[i-NumECs].first;
unsigned Reg = MO.getReg();
if (MO.isUndef())
continue;
// If it's dead upon def, then it is now free.
if (MO.isDead()) {
setUnused(Reg, MI);
continue;
}
// Skip if this is merely redefining part of a super-register.
if (RedefinesSuperRegPart(MI, MO, TRI))
continue;
assert((isReserved(Reg) || isUnused(Reg) || isSuperRegUsed(Reg) ||
isLiveInButUnusedBefore(Reg, MI, MBB, TRI, MRI)) &&
"Re-defining a live register!");
setUsed(Reg);
}
} }
void RegScavenger::getRegsUsed(BitVector &used, bool includeReserved) { void RegScavenger::getRegsUsed(BitVector &used, bool includeReserved) {

View File

@ -0,0 +1,20 @@
; RUN: llvm-as < %s | llc -mtriple=armv7-eabi -mattr=+vfp2
; PR4686
@g_d = external global double ; <double*> [#uses=1]
define arm_aapcscc void @foo(float %yIncr) {
entry:
br i1 undef, label %bb, label %bb4
bb: ; preds = %entry
%0 = call arm_aapcs_vfpcc float @bar() ; <float> [#uses=1]
%1 = fpext float %0 to double ; <double> [#uses=1]
store double %1, double* @g_d, align 8
br label %bb4
bb4: ; preds = %bb, %entry
unreachable
}
declare arm_aapcs_vfpcc float @bar()