Fix a long-standing wart in the code generator: two-address instruction lowering

actually *removes* one of the operands, instead of just assigning both operands
the same register.  This make reasoning about instructions unnecessarily complex,
because you need to know if you are before or after register allocation to match
up operand #'s with the target description file.

Changing this also gets rid of a bunch of hacky code in various places.

This patch also includes changes to fold loads into cmp/test instructions in
the X86 backend, along with a significant simplification to the X86 spill
folding code.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@30108 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Chris Lattner 2006-09-05 02:12:02 +00:00
parent 89c0b4a90e
commit 2926869b4a
9 changed files with 576 additions and 603 deletions

View File

@ -262,23 +262,11 @@ addIntervalsForSpills(const LiveInterval &li, VirtRegMap &vrm, int slot) {
MachineInstr *MI = getInstructionFromIndex(index); MachineInstr *MI = getInstructionFromIndex(index);
// NewRegLiveIn - This instruction might have multiple uses of the spilled RestartInstruction:
// register. In this case, for the first use, keep track of the new vreg
// that we reload it into. If we see a second use, reuse this vreg
// instead of creating live ranges for two reloads.
unsigned NewRegLiveIn = 0;
for_operand:
for (unsigned i = 0; i != MI->getNumOperands(); ++i) { for (unsigned i = 0; i != MI->getNumOperands(); ++i) {
MachineOperand& mop = MI->getOperand(i); MachineOperand& mop = MI->getOperand(i);
if (mop.isRegister() && mop.getReg() == li.reg) { if (mop.isRegister() && mop.getReg() == li.reg) {
if (NewRegLiveIn && mop.isUse()) { if (MachineInstr *fmi = mri_->foldMemoryOperand(MI, i, slot)) {
// We already emitted a reload of this value, reuse it for
// subsequent operands.
MI->getOperand(i).setReg(NewRegLiveIn);
DEBUG(std::cerr << "\t\t\t\treused reload into reg" << NewRegLiveIn
<< " for operand #" << i << '\n');
} else if (MachineInstr* fmi = mri_->foldMemoryOperand(MI, i, slot)) {
// Attempt to fold the memory reference into the instruction. If we // Attempt to fold the memory reference into the instruction. If we
// can do this, we don't need to insert spill code. // can do this, we don't need to insert spill code.
if (lv_) if (lv_)
@ -292,47 +280,63 @@ addIntervalsForSpills(const LiveInterval &li, VirtRegMap &vrm, int slot) {
++numFolded; ++numFolded;
// Folding the load/store can completely change the instruction in // Folding the load/store can completely change the instruction in
// unpredictable ways, rescan it from the beginning. // unpredictable ways, rescan it from the beginning.
goto for_operand; goto RestartInstruction;
} else { } else {
// This is tricky. We need to add information in the interval about // Create a new virtual register for the spill interval.
// the spill code so we have to use our extra load/store slots. unsigned NewVReg = mf_->getSSARegMap()->createVirtualRegister(rc);
// Scan all of the operands of this instruction rewriting operands
// to use NewVReg instead of li.reg as appropriate. We do this for
// two reasons:
// //
// If we have a use we are going to have a load so we start the // 1. If the instr reads the same spilled vreg multiple times, we
// interval from the load slot onwards. Otherwise we start from the // want to reuse the NewVReg.
// def slot. // 2. If the instr is a two-addr instruction, we are required to
unsigned start = (mop.isUse() ? // keep the src/dst regs pinned.
getLoadIndex(index) : //
getDefIndex(index)); // Keep track of whether we replace a use and/or def so that we can
// If we have a def we are going to have a store right after it so // create the spill interval with the appropriate range.
// we end the interval after the use of the next mop.setReg(NewVReg);
// instruction. Otherwise we end after the use of this instruction.
unsigned end = 1 + (mop.isDef() ? bool HasUse = mop.isUse();
getStoreIndex(index) : bool HasDef = mop.isDef();
getUseIndex(index)); for (unsigned j = i+1, e = MI->getNumOperands(); j != e; ++j) {
if (MI->getOperand(j).isReg() &&
MI->getOperand(j).getReg() == li.reg) {
MI->getOperand(j).setReg(NewVReg);
HasUse |= MI->getOperand(j).isUse();
HasDef |= MI->getOperand(j).isDef();
}
}
// create a new register for this spill // create a new register for this spill
NewRegLiveIn = mf_->getSSARegMap()->createVirtualRegister(rc);
MI->getOperand(i).setReg(NewRegLiveIn);
vrm.grow(); vrm.grow();
vrm.assignVirt2StackSlot(NewRegLiveIn, slot); vrm.assignVirt2StackSlot(NewVReg, slot);
LiveInterval& nI = getOrCreateInterval(NewRegLiveIn); LiveInterval &nI = getOrCreateInterval(NewVReg);
assert(nI.empty()); assert(nI.empty());
// the spill weight is now infinity as it // the spill weight is now infinity as it
// cannot be spilled again // cannot be spilled again
nI.weight = float(HUGE_VAL); nI.weight = float(HUGE_VAL);
LiveRange LR(start, end, nI.getNextValue(~0U, 0));
DEBUG(std::cerr << " +" << LR); if (HasUse) {
nI.addRange(LR); LiveRange LR(getLoadIndex(index), getUseIndex(index),
nI.getNextValue(~0U, 0));
DEBUG(std::cerr << " +" << LR);
nI.addRange(LR);
}
if (HasDef) {
LiveRange LR(getDefIndex(index), getStoreIndex(index),
nI.getNextValue(~0U, 0));
DEBUG(std::cerr << " +" << LR);
nI.addRange(LR);
}
added.push_back(&nI); added.push_back(&nI);
// update live variables if it is available // update live variables if it is available
if (lv_) if (lv_)
lv_->addVirtualRegisterKilled(NewRegLiveIn, MI); lv_->addVirtualRegisterKilled(NewVReg, MI);
// If this is a live in, reuse it for subsequent live-ins. If it's
// a def, we can't do this.
if (!mop.isUse()) NewRegLiveIn = 0;
DEBUG(std::cerr << "\t\t\t\tadded new interval: "; DEBUG(std::cerr << "\t\t\t\tadded new interval: ";
nI.print(std::cerr, mri_); std::cerr << '\n'); nI.print(std::cerr, mri_); std::cerr << '\n');
@ -445,7 +449,9 @@ void LiveIntervals::handleVirtualRegisterDef(MachineBasicBlock *mbb,
// operand, and is a def-and-use. // operand, and is a def-and-use.
if (mi->getOperand(0).isRegister() && if (mi->getOperand(0).isRegister() &&
mi->getOperand(0).getReg() == interval.reg && mi->getOperand(0).getReg() == interval.reg &&
mi->getOperand(0).isDef() && mi->getOperand(0).isUse()) { mi->getNumOperands() > 1 && mi->getOperand(1).isRegister() &&
mi->getOperand(1).getReg() == interval.reg &&
mi->getOperand(0).isDef() && mi->getOperand(1).isUse()) {
// If this is a two-address definition, then we have already processed // If this is a two-address definition, then we have already processed
// the live range. The only problem is that we didn't realize there // the live range. The only problem is that we didn't realize there
// are actually two values in the live interval. Because of this we // are actually two values in the live interval. Because of this we

View File

@ -203,17 +203,13 @@ void RegAllocSimple::AllocateBasicBlock(MachineBasicBlock &MBB) {
physReg = getFreeReg(virtualReg); physReg = getFreeReg(virtualReg);
} else { } else {
// must be same register number as the first operand // must be same register number as the first operand
// This maps a = b + c into b += c, and saves b into a's spot // This maps a = b + c into b = b + c, and saves b into a's spot.
assert(MI->getOperand(1).isRegister() && assert(MI->getOperand(1).isRegister() &&
MI->getOperand(1).getReg() && MI->getOperand(1).getReg() &&
MI->getOperand(1).isUse() && MI->getOperand(1).isUse() &&
"Two address instruction invalid!"); "Two address instruction invalid!");
physReg = MI->getOperand(1).getReg(); physReg = MI->getOperand(1).getReg();
spillVirtReg(MBB, next(MI), virtualReg, physReg);
MI->getOperand(1).setDef();
MI->RemoveOperand(0);
break; // This is the last operand to process
} }
spillVirtReg(MBB, next(MI), virtualReg, physReg); spillVirtReg(MBB, next(MI), virtualReg, physReg);
} else { } else {

View File

@ -206,9 +206,8 @@ bool TwoAddressInstructionPass::runOnMachineFunction(MachineFunction &MF) {
} }
} }
assert(mi->getOperand(0).isDef()); assert(mi->getOperand(0).isDef() && mi->getOperand(1).isUse());
mi->getOperand(0).setUse(); mi->getOperand(1).setReg(mi->getOperand(0).getReg());
mi->RemoveOperand(1);
MadeChange = true; MadeChange = true;
DEBUG(std::cerr << "\t\trewrite to:\t"; mi->print(std::cerr, &TM)); DEBUG(std::cerr << "\t\trewrite to:\t"; mi->print(std::cerr, &TM));

View File

@ -57,6 +57,12 @@ namespace {
// VirtRegMap implementation // VirtRegMap implementation
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
VirtRegMap::VirtRegMap(MachineFunction &mf)
: TII(*mf.getTarget().getInstrInfo()), MF(mf),
Virt2PhysMap(NO_PHYS_REG), Virt2StackSlotMap(NO_STACK_SLOT) {
grow();
}
void VirtRegMap::grow() { void VirtRegMap::grow() {
Virt2PhysMap.grow(MF.getSSARegMap()->getLastVirtReg()); Virt2PhysMap.grow(MF.getSSARegMap()->getLastVirtReg());
Virt2StackSlotMap.grow(MF.getSSARegMap()->getLastVirtReg()); Virt2StackSlotMap.grow(MF.getSSARegMap()->getLastVirtReg());
@ -92,11 +98,13 @@ void VirtRegMap::virtFolded(unsigned VirtReg, MachineInstr *OldMI,
} }
ModRef MRInfo; ModRef MRInfo;
if (!OldMI->getOperand(OpNo).isDef()) { if (OpNo < 2 && TII.isTwoAddrInstr(OldMI->getOpcode())) {
assert(OldMI->getOperand(OpNo).isUse() && "Operand is not use or def?"); // Folded a two-address operand.
MRInfo = isRef; MRInfo = isModRef;
} else if (OldMI->getOperand(OpNo).isDef()) {
MRInfo = isMod;
} else { } else {
MRInfo = OldMI->getOperand(OpNo).isUse() ? isModRef : isMod; MRInfo = isRef;
} }
// add new memory reference // add new memory reference
@ -492,11 +500,6 @@ void LocalSpiller::RewriteMBB(MachineBasicBlock &MBB, VirtRegMap &VRM) {
// that we can choose to reuse the physregs instead of emitting reloads. // that we can choose to reuse the physregs instead of emitting reloads.
AvailableSpills Spills(MRI, TII); AvailableSpills Spills(MRI, TII);
// DefAndUseVReg - When we see a def&use operand that is spilled, keep track
// of it. ".first" is the machine operand index (should always be 0 for now),
// and ".second" is the virtual register that is spilled.
std::vector<std::pair<unsigned, unsigned> > DefAndUseVReg;
// MaybeDeadStores - When we need to write a value back into a stack slot, // MaybeDeadStores - When we need to write a value back into a stack slot,
// keep track of the inserted store. If the stack slot value is never read // keep track of the inserted store. If the stack slot value is never read
// (because the value was used from some available register, for example), and // (because the value was used from some available register, for example), and
@ -516,8 +519,6 @@ void LocalSpiller::RewriteMBB(MachineBasicBlock &MBB, VirtRegMap &VRM) {
/// reuse. /// reuse.
ReuseInfo ReusedOperands(MI); ReuseInfo ReusedOperands(MI);
DefAndUseVReg.clear();
// Process all of the spilled uses and all non spilled reg references. // Process all of the spilled uses and all non spilled reg references.
for (unsigned i = 0, e = MI.getNumOperands(); i != e; ++i) { for (unsigned i = 0, e = MI.getNumOperands(); i != e; ++i) {
MachineOperand &MO = MI.getOperand(i); MachineOperand &MO = MI.getOperand(i);
@ -547,24 +548,27 @@ 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)
// If this is both a def and a use, we need to emit a store to the
// stack slot after the instruction. Keep track of D&U operands
// because we are about to change it to a physreg here.
if (MO.isDef()) {
// Remember that this was a def-and-use operand, and that the
// stack slot is live after this instruction executes.
DefAndUseVReg.push_back(std::make_pair(i, VirtReg));
}
int StackSlot = VRM.getStackSlot(VirtReg); int StackSlot = VRM.getStackSlot(VirtReg);
unsigned PhysReg; unsigned PhysReg;
// Check to see if this stack slot is available. // Check to see if this stack slot is available.
if ((PhysReg = Spills.getSpillSlotPhysReg(StackSlot))) { if ((PhysReg = Spills.getSpillSlotPhysReg(StackSlot))) {
// Don't reuse it for a def&use operand if we aren't allowed to change // This spilled operand might be part of a two-address operand. If this
// the physreg! // is the case, then changing it will necessarily require changing the
if (!MO.isDef() || Spills.canClobberPhysReg(StackSlot)) { // def part of the instruction as well. However, in some cases, we
// aren't allowed to modify the reused register. If none of these cases
// apply, reuse it.
bool CanReuse = true;
if (i == 1 && MI.getOperand(0).isReg() &&
MI.getOperand(0).getReg() == VirtReg &&
TII->isTwoAddrInstr(MI.getOpcode())) {
// Okay, we have a two address operand. We can reuse this physreg as
// long as we are allowed to clobber the value.
CanReuse = Spills.canClobberPhysReg(StackSlot);
}
if (CanReuse) {
// If this stack slot value is already available, reuse it! // If this stack slot value is already available, reuse it!
DEBUG(std::cerr << "Reusing SS#" << StackSlot << " from physreg " DEBUG(std::cerr << "Reusing SS#" << StackSlot << " from physreg "
<< MRI->getName(PhysReg) << " for vreg" << MRI->getName(PhysReg) << " for vreg"
@ -777,47 +781,32 @@ void LocalSpiller::RewriteMBB(MachineBasicBlock &MBB, VirtRegMap &VRM) {
unsigned VirtReg = MO.getReg(); unsigned VirtReg = MO.getReg();
if (!MRegisterInfo::isVirtualRegister(VirtReg)) { if (!MRegisterInfo::isVirtualRegister(VirtReg)) {
// Check to see if this is a def-and-use vreg operand that we do need // Check to see if this is a noop copy. If so, eliminate the
// to insert a store for. // instruction before considering the dest reg to be changed.
bool OpTakenCareOf = false; unsigned Src, Dst;
if (MO.isUse() && !DefAndUseVReg.empty()) { if (TII->isMoveInstr(MI, Src, Dst) && Src == Dst) {
for (unsigned dau = 0, e = DefAndUseVReg.size(); dau != e; ++dau) ++NumDCE;
if (DefAndUseVReg[dau].first == i) { DEBUG(std::cerr << "Removing now-noop copy: " << MI);
VirtReg = DefAndUseVReg[dau].second; MBB.erase(&MI);
OpTakenCareOf = true; VRM.RemoveFromFoldedVirtMap(&MI);
break; goto ProcessNextInst;
}
}
if (!OpTakenCareOf) {
// Check to see if this is a noop copy. If so, eliminate the
// instruction before considering the dest reg to be changed.
unsigned Src, Dst;
if (TII->isMoveInstr(MI, Src, Dst) && Src == Dst) {
++NumDCE;
DEBUG(std::cerr << "Removing now-noop copy: " << MI);
MBB.erase(&MI);
VRM.RemoveFromFoldedVirtMap(&MI);
goto ProcessNextInst;
}
Spills.ClobberPhysReg(VirtReg);
continue;
} }
Spills.ClobberPhysReg(VirtReg);
continue;
} }
// The only vregs left are stack slot definitions. // The only vregs left are stack slot definitions.
int StackSlot = VRM.getStackSlot(VirtReg); int StackSlot = VRM.getStackSlot(VirtReg);
const TargetRegisterClass *RC = const TargetRegisterClass *RC =
MBB.getParent()->getSSARegMap()->getRegClass(VirtReg); MBB.getParent()->getSSARegMap()->getRegClass(VirtReg);
unsigned PhysReg;
// If this is a def&use operand, and we used a different physreg for // If this def is part of a two-address operand, make sure to execute
// it than the one assigned, make sure to execute the store from the // the store from the correct physical register.
// correct physical register. unsigned PhysReg;
if (MO.getReg() == VirtReg) if (i == 0 && TII->isTwoAddrInstr(MI.getOpcode()))
PhysReg = VRM.getPhys(VirtReg); PhysReg = MI.getOperand(1).getReg();
else else
PhysReg = MO.getReg(); PhysReg = VRM.getPhys(VirtReg);
PhysRegsUsed[PhysReg] = true; PhysRegsUsed[PhysReg] = true;
MRI->storeRegToStackSlot(MBB, next(MII), PhysReg, StackSlot, RC); MRI->storeRegToStackSlot(MBB, next(MII), PhysReg, StackSlot, RC);

View File

@ -23,6 +23,7 @@
namespace llvm { namespace llvm {
class MachineInstr; class MachineInstr;
class TargetInstrInfo;
class VirtRegMap { class VirtRegMap {
public: public:
@ -31,6 +32,8 @@ namespace llvm {
std::pair<unsigned, ModRef> > MI2VirtMapTy; std::pair<unsigned, ModRef> > MI2VirtMapTy;
private: private:
const TargetInstrInfo &TII;
MachineFunction &MF; MachineFunction &MF;
/// Virt2PhysMap - This is a virtual to physical register /// Virt2PhysMap - This is a virtual to physical register
/// mapping. Each virtual register is required to have an entry in /// mapping. Each virtual register is required to have an entry in
@ -58,10 +61,7 @@ namespace llvm {
}; };
public: public:
VirtRegMap(MachineFunction &mf) VirtRegMap(MachineFunction &mf);
: MF(mf), Virt2PhysMap(NO_PHYS_REG), Virt2StackSlotMap(NO_STACK_SLOT) {
grow();
}
void grow(); void grow();

View File

@ -22,7 +22,7 @@ using namespace llvm;
X86InstrInfo::X86InstrInfo(X86TargetMachine &tm) X86InstrInfo::X86InstrInfo(X86TargetMachine &tm)
: TargetInstrInfo(X86Insts, sizeof(X86Insts)/sizeof(X86Insts[0])), : TargetInstrInfo(X86Insts, sizeof(X86Insts)/sizeof(X86Insts[0])),
TM(tm) { TM(tm), RI(*this) {
} }

File diff suppressed because it is too large Load Diff

View File

@ -15,15 +15,15 @@
#define X86REGISTERINFO_H #define X86REGISTERINFO_H
#include "llvm/Target/MRegisterInfo.h" #include "llvm/Target/MRegisterInfo.h"
class llvm::Type;
#include "X86GenRegisterInfo.h.inc" #include "X86GenRegisterInfo.h.inc"
namespace llvm { namespace llvm {
class Type;
class TargetInstrInfo;
struct X86RegisterInfo : public X86GenRegisterInfo { struct X86RegisterInfo : public X86GenRegisterInfo {
X86RegisterInfo(); const TargetInstrInfo &TII;
X86RegisterInfo(const TargetInstrInfo &tii);
/// Code Generation virtual methods... /// Code Generation virtual methods...
void storeRegToStackSlot(MachineBasicBlock &MBB, void storeRegToStackSlot(MachineBasicBlock &MBB,

View File

@ -211,15 +211,12 @@ AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, unsigned Variant) {
unsigned OpNo = CGI.getOperandNamed(VarName); unsigned OpNo = CGI.getOperandNamed(VarName);
CodeGenInstruction::OperandInfo OpInfo = CGI.OperandList[OpNo]; CodeGenInstruction::OperandInfo OpInfo = CGI.OperandList[OpNo];
// If this is a two-address instruction and we are not accessing the // If this is a two-address instruction, verify the second operand isn't
// 0th operand, remove an operand. // used.
unsigned MIOp = OpInfo.MIOperandNo; unsigned MIOp = OpInfo.MIOperandNo;
if (CGI.isTwoAddress && MIOp != 0) { if (CGI.isTwoAddress && MIOp == 1)
if (MIOp == 1) throw "Should refer to operand #0 instead of #1 for two-address"
throw "Should refer to operand #0 instead of #1 for two-address" " instruction '" + CGI.TheDef->getName() + "'!";
" instruction '" + CGI.TheDef->getName() + "'!";
--MIOp;
}
if (CurVariant == Variant || CurVariant == ~0U) if (CurVariant == Variant || CurVariant == ~0U)
Operands.push_back(AsmWriterOperand(OpInfo.PrinterMethodName, MIOp, Operands.push_back(AsmWriterOperand(OpInfo.PrinterMethodName, MIOp,