mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-13 04:30:23 +00:00
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.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@48333 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
6634e26aa1
commit
875357d213
@ -37,8 +37,9 @@
|
||||
#include "llvm/Target/TargetRegisterInfo.h"
|
||||
#include "llvm/Target/TargetInstrInfo.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
using namespace llvm;
|
||||
@ -46,10 +47,22 @@ using namespace llvm;
|
||||
STATISTIC(NumTwoAddressInstrs, "Number of two-address instructions");
|
||||
STATISTIC(NumCommuted , "Number of instructions commuted to coalesce");
|
||||
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 {
|
||||
struct VISIBILITY_HIDDEN TwoAddressInstructionPass
|
||||
: public MachineFunctionPass {
|
||||
const TargetInstrInfo *TII;
|
||||
const TargetRegisterInfo *TRI;
|
||||
MachineRegisterInfo *MRI;
|
||||
LiveVariables *LV;
|
||||
|
||||
public:
|
||||
static char ID; // Pass identification, replacement for typeid
|
||||
TwoAddressInstructionPass() : MachineFunctionPass((intptr_t)&ID) {}
|
||||
|
||||
@ -57,6 +70,11 @@ namespace {
|
||||
|
||||
/// runOnMachineFunction - pass entry point
|
||||
bool runOnMachineFunction(MachineFunction&);
|
||||
|
||||
private:
|
||||
bool Sink3AddrInstruction(MachineBasicBlock *MBB, MachineInstr *MI,
|
||||
unsigned Reg,
|
||||
MachineBasicBlock::iterator OldPos);
|
||||
};
|
||||
|
||||
char TwoAddressInstructionPass::ID = 0;
|
||||
@ -75,14 +93,113 @@ void TwoAddressInstructionPass::getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
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
|
||||
/// operands.
|
||||
///
|
||||
bool TwoAddressInstructionPass::runOnMachineFunction(MachineFunction &MF) {
|
||||
DOUT << "Machine Function\n";
|
||||
const TargetMachine &TM = MF.getTarget();
|
||||
const TargetInstrInfo &TII = *TM.getInstrInfo();
|
||||
LiveVariables &LV = getAnalysis<LiveVariables>();
|
||||
MRI = &MF.getRegInfo();
|
||||
TII = TM.getInstrInfo();
|
||||
TRI = TM.getRegisterInfo();
|
||||
LV = &getAnalysis<LiveVariables>();
|
||||
|
||||
bool MadeChange = false;
|
||||
|
||||
@ -150,14 +267,14 @@ bool TwoAddressInstructionPass::runOnMachineFunction(MachineFunction &MF) {
|
||||
unsigned regC = mi->getOperand(3-si).getReg();
|
||||
if (mi->killsRegister(regC)) {
|
||||
DOUT << "2addr: COMMUTING : " << *mi;
|
||||
MachineInstr *NewMI = TII.commuteInstruction(mi);
|
||||
MachineInstr *NewMI = TII->commuteInstruction(mi);
|
||||
if (NewMI == 0) {
|
||||
DOUT << "2addr: COMMUTING FAILED!\n";
|
||||
} else {
|
||||
DOUT << "2addr: COMMUTED TO: " << *NewMI;
|
||||
// If the instruction changed to commute it, update livevar.
|
||||
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->erase(mi); // Nuke the old inst.
|
||||
mi = NewMI;
|
||||
@ -180,11 +297,12 @@ bool TwoAddressInstructionPass::runOnMachineFunction(MachineFunction &MF) {
|
||||
assert(TID.getOperandConstraint(i, TOI::TIED_TO) == -1);
|
||||
#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: TO 3-ADDR: " << *New;
|
||||
bool Sunk = Sink3AddrInstruction(mbbi, New, regB, mi);
|
||||
mbbi->erase(mi); // Nuke the old inst.
|
||||
mi = New;
|
||||
if (!Sunk) mi = New;
|
||||
++NumConvertedTo3Addr;
|
||||
// Done with this instruction.
|
||||
break;
|
||||
@ -194,20 +312,20 @@ bool TwoAddressInstructionPass::runOnMachineFunction(MachineFunction &MF) {
|
||||
|
||||
InstructionRearranged:
|
||||
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);
|
||||
DOUT << "\t\tprepend:\t"; DEBUG(prevMi->print(*cerr.stream(), &TM));
|
||||
|
||||
// update live variables for regB
|
||||
LiveVariables::VarInfo& varInfoB = LV.getVarInfo(regB);
|
||||
LiveVariables::VarInfo& varInfoB = LV->getVarInfo(regB);
|
||||
// regB is used in this BB.
|
||||
varInfoB.UsedBlocks[mbbi->getNumber()] = true;
|
||||
if (LV.removeVirtualRegisterKilled(regB, mbbi, mi))
|
||||
LV.addVirtualRegisterKilled(regB, prevMi);
|
||||
if (LV->removeVirtualRegisterKilled(regB, mbbi, mi))
|
||||
LV->addVirtualRegisterKilled(regB, prevMi);
|
||||
|
||||
if (LV.removeVirtualRegisterDead(regB, mbbi, mi))
|
||||
LV.addVirtualRegisterDead(regB, prevMi);
|
||||
if (LV->removeVirtualRegisterDead(regB, mbbi, mi))
|
||||
LV->addVirtualRegisterDead(regB, prevMi);
|
||||
|
||||
// replace all occurences of regB with regA
|
||||
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: 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) {
|
||||
newFuncRoot:
|
||||
|
29
test/CodeGen/X86/twoaddr-pass-sink.ll
Normal file
29
test/CodeGen/X86/twoaddr-pass-sink.ll
Normal 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
|
||||
}
|
Loading…
Reference in New Issue
Block a user