From 875357d213ab1830efa1e3e9de0fcde95df7eefc Mon Sep 17 00:00:00 2001 From: Evan Cheng Date: Thu, 13 Mar 2008 06:37:55 +0000 Subject: 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 --- lib/CodeGen/TwoAddressInstructionPass.cpp | 144 ++++++++++++++++++++++++++--- test/CodeGen/X86/2006-05-02-InstrSched2.ll | 2 +- test/CodeGen/X86/twoaddr-pass-sink.ll | 29 ++++++ 3 files changed, 161 insertions(+), 14 deletions(-) create mode 100644 test/CodeGen/X86/twoaddr-pass-sink.ll diff --git a/lib/CodeGen/TwoAddressInstructionPass.cpp b/lib/CodeGen/TwoAddressInstructionPass.cpp index 5d8781b871..977a8ff54a 100644 --- a/lib/CodeGen/TwoAddressInstructionPass.cpp +++ b/lib/CodeGen/TwoAddressInstructionPass.cpp @@ -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 + 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 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(); + MRI = &MF.getRegInfo(); + TII = TM.getInstrInfo(); + TRI = TM.getRegisterInfo(); + LV = &getAnalysis(); 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) { diff --git a/test/CodeGen/X86/2006-05-02-InstrSched2.ll b/test/CodeGen/X86/2006-05-02-InstrSched2.ll index 6782b68bbc..fb9c67cf93 100644 --- a/test/CodeGen/X86/2006-05-02-InstrSched2.ll +++ b/test/CodeGen/X86/2006-05-02-InstrSched2.ll @@ -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: diff --git a/test/CodeGen/X86/twoaddr-pass-sink.ll b/test/CodeGen/X86/twoaddr-pass-sink.ll new file mode 100644 index 0000000000..765588059f --- /dev/null +++ b/test/CodeGen/X86/twoaddr-pass-sink.ll @@ -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 ] ; [#uses=3] + %vYp_addr.0.rec = shl i32 %skiplist_addr.0.rec, 3 ; [#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 ; [#uses=1] + %vDct_addr.0.sum43 = or i32 %vYp_addr.0.rec, 1 ; [#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 ; [#uses=1] + %tmp38 = icmp eq i8 %tmp37, 0 ; [#uses=1] + %indvar.next = add i32 %skiplist_addr.0.rec, 1 ; [#uses=1] + br i1 %tmp38, label %return, label %bb +return: ; preds = %bb + ret void +} -- cgit v1.2.3