TwoAddressInstructionPass enhancement. After it converts a two address instruction into a 3-address one, sink it past the instruction that kills the read-mod-write register if its definition is used past the kill. This reduces the number of live register by one.

llvm-svn: 48333
This commit is contained in:
Evan Cheng 2008-03-13 06:37:55 +00:00
parent fdc0748940
commit 5c26bde55e
3 changed files with 161 additions and 14 deletions

View File

@ -37,8 +37,9 @@
#include "llvm/Target/TargetRegisterInfo.h" #include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetMachine.h"
#include "llvm/Support/Debug.h" #include "llvm/Support/CommandLine.h"
#include "llvm/Support/Compiler.h" #include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include "llvm/ADT/Statistic.h" #include "llvm/ADT/Statistic.h"
#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/STLExtras.h"
using namespace llvm; using namespace llvm;
@ -46,10 +47,22 @@ using namespace llvm;
STATISTIC(NumTwoAddressInstrs, "Number of two-address instructions"); STATISTIC(NumTwoAddressInstrs, "Number of two-address instructions");
STATISTIC(NumCommuted , "Number of instructions commuted to coalesce"); STATISTIC(NumCommuted , "Number of instructions commuted to coalesce");
STATISTIC(NumConvertedTo3Addr, "Number of instructions promoted to 3-address"); STATISTIC(NumConvertedTo3Addr, "Number of instructions promoted to 3-address");
STATISTIC(Num3AddrSunk, "Number of 3-address instructions sunk");
namespace {
static cl::opt<int>
SinkLimit("two-addr-sink-limit", cl::init(-1), cl::Hidden);
}
namespace { namespace {
struct VISIBILITY_HIDDEN TwoAddressInstructionPass struct VISIBILITY_HIDDEN TwoAddressInstructionPass
: public MachineFunctionPass { : public MachineFunctionPass {
const TargetInstrInfo *TII;
const TargetRegisterInfo *TRI;
MachineRegisterInfo *MRI;
LiveVariables *LV;
public:
static char ID; // Pass identification, replacement for typeid static char ID; // Pass identification, replacement for typeid
TwoAddressInstructionPass() : MachineFunctionPass((intptr_t)&ID) {} TwoAddressInstructionPass() : MachineFunctionPass((intptr_t)&ID) {}
@ -57,6 +70,11 @@ namespace {
/// runOnMachineFunction - pass entry point /// runOnMachineFunction - pass entry point
bool runOnMachineFunction(MachineFunction&); bool runOnMachineFunction(MachineFunction&);
private:
bool Sink3AddrInstruction(MachineBasicBlock *MBB, MachineInstr *MI,
unsigned Reg,
MachineBasicBlock::iterator OldPos);
}; };
char TwoAddressInstructionPass::ID = 0; char TwoAddressInstructionPass::ID = 0;
@ -75,14 +93,113 @@ void TwoAddressInstructionPass::getAnalysisUsage(AnalysisUsage &AU) const {
MachineFunctionPass::getAnalysisUsage(AU); MachineFunctionPass::getAnalysisUsage(AU);
} }
/// Sink3AddrInstruction - A two-address instruction has been converted to a
/// three-address instruction to avoid clobbering a register. Try to sink it
/// past the instruction that would kill the above mentioned register to
/// reduce register pressure.
bool TwoAddressInstructionPass::Sink3AddrInstruction(MachineBasicBlock *MBB,
MachineInstr *MI, unsigned SavedReg,
MachineBasicBlock::iterator OldPos) {
// Check if it's safe to move this instruction.
bool SeenStore = true; // Be conservative.
if (!MI->isSafeToMove(TII, SeenStore))
return false;
unsigned DefReg = 0;
SmallSet<unsigned, 4> UseRegs;
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
const MachineOperand &MO = MI->getOperand(i);
if (!MO.isRegister())
continue;
unsigned MOReg = MO.getReg();
if (!MOReg)
continue;
if (MO.isUse() && MOReg != SavedReg)
UseRegs.insert(MO.getReg());
if (!MO.isDef())
continue;
if (MO.isImplicit())
// Don't try to move it if it implicitly defines a register.
return false;
if (DefReg)
// For now, don't move any instructions that define multiple registers.
return false;
DefReg = MO.getReg();
}
// Find the instruction that kills SavedReg.
MachineInstr *KillMI = NULL;
for (MachineRegisterInfo::use_iterator UI = MRI->use_begin(SavedReg),
UE = MRI->use_end(); UI != UE; ++UI) {
MachineOperand &UseMO = UI.getOperand();
if (!UseMO.isKill())
continue;
KillMI = UseMO.getParent();
break;
}
if (!KillMI || KillMI->getParent() != MBB)
return false;
// If any of the definitions are used by another instruction between
// the position and the kill use, then it's not safe to sink it.
// FIXME: This can be sped up if there is an easy way to query whether
// an instruction if before or after another instruction. Then we can
// use MachineRegisterInfo def / use instead.
MachineOperand *KillMO = NULL;
MachineBasicBlock::iterator KillPos = KillMI;
++KillPos;
for (MachineBasicBlock::iterator I = next(OldPos); I != KillPos; ++I) {
MachineInstr *OtherMI = I;
for (unsigned i = 0, e = OtherMI->getNumOperands(); i != e; ++i) {
MachineOperand &MO = OtherMI->getOperand(i);
if (!MO.isRegister())
continue;
unsigned MOReg = MO.getReg();
if (!MOReg)
continue;
if (DefReg == MOReg)
return false;
if (MO.isKill()) {
if (OtherMI == KillMI && MOReg == SavedReg)
// Save the operand that kills the register. We want unset the kill
// marker is we can sink MI past it.
KillMO = &MO;
else if (UseRegs.count(MOReg))
// One of the uses is killed before the destination.
return false;
}
}
}
if (SinkLimit != -1 && Num3AddrSunk == (unsigned)SinkLimit)
return false;
// Update kill and LV information.
KillMO->setIsKill(false);
KillMO = MI->findRegisterUseOperand(SavedReg, false, TRI);
KillMO->setIsKill(true);
LiveVariables::VarInfo& VarInfo = LV->getVarInfo(SavedReg);
VarInfo.removeKill(KillMI);
VarInfo.Kills.push_back(MI);
// Move instruction to its destination.
MBB->remove(MI);
MBB->insert(KillPos, MI);
++Num3AddrSunk;
return true;
}
/// runOnMachineFunction - Reduce two-address instructions to two /// runOnMachineFunction - Reduce two-address instructions to two
/// operands. /// operands.
/// ///
bool TwoAddressInstructionPass::runOnMachineFunction(MachineFunction &MF) { bool TwoAddressInstructionPass::runOnMachineFunction(MachineFunction &MF) {
DOUT << "Machine Function\n"; DOUT << "Machine Function\n";
const TargetMachine &TM = MF.getTarget(); const TargetMachine &TM = MF.getTarget();
const TargetInstrInfo &TII = *TM.getInstrInfo(); MRI = &MF.getRegInfo();
LiveVariables &LV = getAnalysis<LiveVariables>(); TII = TM.getInstrInfo();
TRI = TM.getRegisterInfo();
LV = &getAnalysis<LiveVariables>();
bool MadeChange = false; bool MadeChange = false;
@ -150,14 +267,14 @@ bool TwoAddressInstructionPass::runOnMachineFunction(MachineFunction &MF) {
unsigned regC = mi->getOperand(3-si).getReg(); unsigned regC = mi->getOperand(3-si).getReg();
if (mi->killsRegister(regC)) { if (mi->killsRegister(regC)) {
DOUT << "2addr: COMMUTING : " << *mi; DOUT << "2addr: COMMUTING : " << *mi;
MachineInstr *NewMI = TII.commuteInstruction(mi); MachineInstr *NewMI = TII->commuteInstruction(mi);
if (NewMI == 0) { if (NewMI == 0) {
DOUT << "2addr: COMMUTING FAILED!\n"; DOUT << "2addr: COMMUTING FAILED!\n";
} else { } else {
DOUT << "2addr: COMMUTED TO: " << *NewMI; DOUT << "2addr: COMMUTED TO: " << *NewMI;
// If the instruction changed to commute it, update livevar. // If the instruction changed to commute it, update livevar.
if (NewMI != mi) { if (NewMI != mi) {
LV.instructionChanged(mi, NewMI); // Update live variables LV->instructionChanged(mi, NewMI); // Update live variables
mbbi->insert(mi, NewMI); // Insert the new inst mbbi->insert(mi, NewMI); // Insert the new inst
mbbi->erase(mi); // Nuke the old inst. mbbi->erase(mi); // Nuke the old inst.
mi = NewMI; mi = NewMI;
@ -180,11 +297,12 @@ bool TwoAddressInstructionPass::runOnMachineFunction(MachineFunction &MF) {
assert(TID.getOperandConstraint(i, TOI::TIED_TO) == -1); assert(TID.getOperandConstraint(i, TOI::TIED_TO) == -1);
#endif #endif
if (MachineInstr *New = TII.convertToThreeAddress(mbbi, mi, LV)) { if (MachineInstr *New=TII->convertToThreeAddress(mbbi, mi, *LV)) {
DOUT << "2addr: CONVERTING 2-ADDR: " << *mi; DOUT << "2addr: CONVERTING 2-ADDR: " << *mi;
DOUT << "2addr: TO 3-ADDR: " << *New; DOUT << "2addr: TO 3-ADDR: " << *New;
bool Sunk = Sink3AddrInstruction(mbbi, New, regB, mi);
mbbi->erase(mi); // Nuke the old inst. mbbi->erase(mi); // Nuke the old inst.
mi = New; if (!Sunk) mi = New;
++NumConvertedTo3Addr; ++NumConvertedTo3Addr;
// Done with this instruction. // Done with this instruction.
break; break;
@ -194,20 +312,20 @@ bool TwoAddressInstructionPass::runOnMachineFunction(MachineFunction &MF) {
InstructionRearranged: InstructionRearranged:
const TargetRegisterClass* rc = MF.getRegInfo().getRegClass(regA); const TargetRegisterClass* rc = MF.getRegInfo().getRegClass(regA);
TII.copyRegToReg(*mbbi, mi, regA, regB, rc, rc); TII->copyRegToReg(*mbbi, mi, regA, regB, rc, rc);
MachineBasicBlock::iterator prevMi = prior(mi); MachineBasicBlock::iterator prevMi = prior(mi);
DOUT << "\t\tprepend:\t"; DEBUG(prevMi->print(*cerr.stream(), &TM)); DOUT << "\t\tprepend:\t"; DEBUG(prevMi->print(*cerr.stream(), &TM));
// update live variables for regB // update live variables for regB
LiveVariables::VarInfo& varInfoB = LV.getVarInfo(regB); LiveVariables::VarInfo& varInfoB = LV->getVarInfo(regB);
// regB is used in this BB. // regB is used in this BB.
varInfoB.UsedBlocks[mbbi->getNumber()] = true; varInfoB.UsedBlocks[mbbi->getNumber()] = true;
if (LV.removeVirtualRegisterKilled(regB, mbbi, mi)) if (LV->removeVirtualRegisterKilled(regB, mbbi, mi))
LV.addVirtualRegisterKilled(regB, prevMi); LV->addVirtualRegisterKilled(regB, prevMi);
if (LV.removeVirtualRegisterDead(regB, mbbi, mi)) if (LV->removeVirtualRegisterDead(regB, mbbi, mi))
LV.addVirtualRegisterDead(regB, prevMi); LV->addVirtualRegisterDead(regB, prevMi);
// replace all occurences of regB with regA // replace all occurences of regB with regA
for (unsigned i = 0, e = mi->getNumOperands(); i != e; ++i) { for (unsigned i = 0, e = mi->getNumOperands(); i != e; ++i) {

View File

@ -1,5 +1,5 @@
; RUN: llvm-upgrade < %s | llvm-as | llc -march=x86 -stats |& \ ; RUN: llvm-upgrade < %s | llvm-as | llc -march=x86 -stats |& \
; RUN: grep asm-printer | grep 14 ; RUN: grep asm-printer | grep 13
void %_ZN9__gnu_cxx9hashtableISt4pairIKPKciES3_NS_4hashIS3_EESt10_Select1stIS5_E5eqstrSaIiEE14find_or_insertERKS5__cond_true456.i(sbyte* %tmp435.i, uint* %tmp449.i.out) { void %_ZN9__gnu_cxx9hashtableISt4pairIKPKciES3_NS_4hashIS3_EESt10_Select1stIS5_E5eqstrSaIiEE14find_or_insertERKS5__cond_true456.i(sbyte* %tmp435.i, uint* %tmp449.i.out) {
newFuncRoot: newFuncRoot:

View File

@ -0,0 +1,29 @@
; RUN: llvm-as < %s | llc -march=x86 -mattr=+sse2 -stats |& grep {Number of 3-address instructions sunk}
define void @t2(<2 x i64>* %vDct, <2 x i64>* %vYp, i8* %skiplist, <2 x i64> %a1) nounwind {
entry:
%tmp25 = bitcast <2 x i64> %a1 to <8 x i16> ; <<8 x i16>> [#uses=1]
br label %bb
bb: ; preds = %bb, %entry
%skiplist_addr.0.rec = phi i32 [ 0, %entry ], [ %indvar.next, %bb ] ; <i32> [#uses=3]
%vYp_addr.0.rec = shl i32 %skiplist_addr.0.rec, 3 ; <i32> [#uses=3]
%vDct_addr.0 = getelementptr <2 x i64>* %vDct, i32 %vYp_addr.0.rec ; <<2 x i64>*> [#uses=1]
%vYp_addr.0 = getelementptr <2 x i64>* %vYp, i32 %vYp_addr.0.rec ; <<2 x i64>*> [#uses=1]
%skiplist_addr.0 = getelementptr i8* %skiplist, i32 %skiplist_addr.0.rec ; <i8*> [#uses=1]
%vDct_addr.0.sum43 = or i32 %vYp_addr.0.rec, 1 ; <i32> [#uses=1]
%tmp7 = getelementptr <2 x i64>* %vDct, i32 %vDct_addr.0.sum43 ; <<2 x i64>*> [#uses=1]
%tmp8 = load <2 x i64>* %tmp7, align 16 ; <<2 x i64>> [#uses=1]
%tmp11 = load <2 x i64>* %vDct_addr.0, align 16 ; <<2 x i64>> [#uses=1]
%tmp13 = bitcast <2 x i64> %tmp8 to <8 x i16> ; <<8 x i16>> [#uses=1]
%tmp15 = bitcast <2 x i64> %tmp11 to <8 x i16> ; <<8 x i16>> [#uses=1]
%tmp16 = shufflevector <8 x i16> %tmp15, <8 x i16> %tmp13, <8 x i32> < i32 0, i32 8, i32 1, i32 9, i32 2, i32 10, i32 3, i32 11 > ; <<8 x i16>> [#uses=1]
%tmp26 = mul <8 x i16> %tmp25, %tmp16 ; <<8 x i16>> [#uses=1]
%tmp27 = bitcast <8 x i16> %tmp26 to <2 x i64> ; <<2 x i64>> [#uses=1]
store <2 x i64> %tmp27, <2 x i64>* %vYp_addr.0, align 16
%tmp37 = load i8* %skiplist_addr.0, align 1 ; <i8> [#uses=1]
%tmp38 = icmp eq i8 %tmp37, 0 ; <i1> [#uses=1]
%indvar.next = add i32 %skiplist_addr.0.rec, 1 ; <i32> [#uses=1]
br i1 %tmp38, label %return, label %bb
return: ; preds = %bb
ret void
}