forked from OSchip/llvm-project
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:
parent
fdc0748940
commit
5c26bde55e
|
@ -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) {
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
Loading…
Reference in New Issue