From: Alkis Evlogimenos Date: Thu, 18 Dec 2003 13:06:04 +0000 (+0000) Subject: Add TwoAddressInstructionPass to handle instructions that have two or X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=71499ded4d76233f3b605638b539548bea8bb2f1;p=oota-llvm.git Add TwoAddressInstructionPass to handle instructions that have two or more operands and the two first operands are constrained to be the same. The pass takes an instruction of the form: a = b op c and transforms it into: a = b a = a op c and also preserves live variables. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@10512 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/CodeGen/LiveVariables.h b/include/llvm/CodeGen/LiveVariables.h index 737dabc1ae7..50e4166f455 100644 --- a/include/llvm/CodeGen/LiveVariables.h +++ b/include/llvm/CodeGen/LiveVariables.h @@ -57,15 +57,18 @@ public: VarInfo() : DefBlock(0), DefInst(0) {} - /// removeKill - Delete a kill corresponding to the specified machine instr - void removeKill(MachineInstr *MI) { - for (unsigned i = 0; ; ++i) { - assert(i < Kills.size() && "Machine instr is not a kill!"); - if (Kills[i].second == MI) { - Kills.erase(Kills.begin()+i); - return; + /// removeKill - Delete a kill corresponding to the specified + /// machine instruction. Returns true if there was a kill + /// corresponding to this instruction, false otherwise. + bool removeKill(MachineInstr *MI) { + for (std::vector >::iterator + i = Kills.begin(); i != Kills.end(); ++i) { + if (i->second == MI) { + Kills.erase(i); + return true; } } + return false; } }; @@ -156,30 +159,71 @@ public: /// specified register is killed after being used by the specified /// instruction. /// - void addVirtualRegisterKilled(unsigned IncomingReg, MachineBasicBlock *MBB, + void addVirtualRegisterKilled(unsigned IncomingReg, + MachineBasicBlock *MBB, MachineInstr *MI) { RegistersKilled.insert(std::make_pair(MI, IncomingReg)); getVarInfo(IncomingReg).Kills.push_back(std::make_pair(MBB, MI)); } + /// removeVirtualRegisterKilled - Remove the specified virtual + /// register from the live variable information. Returns true if the + /// variable was marked as killed by the specified instruction, + /// false otherwise. + bool removeVirtualRegisterKilled(unsigned reg, + MachineBasicBlock *MBB, + MachineInstr *MI) { + if (!getVarInfo(reg).removeKill(MI)) + return false; + for (killed_iterator i = killed_begin(MI), e = killed_end(MI); i != e; ) { + if (i->second == reg) + RegistersKilled.erase(i++); + else + ++i; + } + return true; + } + /// removeVirtualRegistersKilled - Remove all of the specified killed /// registers from the live variable information. void removeVirtualRegistersKilled(killed_iterator B, killed_iterator E) { - for (killed_iterator I = B; I != E; ++I) // Remove VarInfo entries... - getVarInfo(I->second).removeKill(I->first); + for (killed_iterator I = B; I != E; ++I) { // Remove VarInfo entries... + bool removed = getVarInfo(I->second).removeKill(I->first); + assert(removed && "kill not in register's VarInfo?"); + } RegistersKilled.erase(B, E); } /// addVirtualRegisterDead - Add information about the fact that the specified /// register is dead after being used by the specified instruction. /// - void addVirtualRegisterDead(unsigned IncomingReg, MachineBasicBlock *MBB, + void addVirtualRegisterDead(unsigned IncomingReg, + MachineBasicBlock *MBB, MachineInstr *MI) { RegistersDead.insert(std::make_pair(MI, IncomingReg)); getVarInfo(IncomingReg).Kills.push_back(std::make_pair(MBB, MI)); } - /// removeVirtualRegistersKilled - Remove all of the specified killed + /// removeVirtualRegisterDead - Remove the specified virtual + /// register from the live variable information. Returns true if the + /// variable was marked dead at the specified instruction, false + /// otherwise. + bool removeVirtualRegisterDead(unsigned reg, + MachineBasicBlock *MBB, + MachineInstr *MI) { + if (!getVarInfo(reg).removeKill(MI)) + return false; + + for (killed_iterator i = killed_begin(MI), e = killed_end(MI); i != e; ) { + if (i->second == reg) + RegistersKilled.erase(i++); + else + ++i; + } + return true; + } + + /// removeVirtualRegistersDead - Remove all of the specified dead /// registers from the live variable information. void removeVirtualRegistersDead(killed_iterator B, killed_iterator E) { for (killed_iterator I = B; I != E; ++I) // Remove VarInfo entries... diff --git a/include/llvm/CodeGen/TwoAddressInstructionPass.h b/include/llvm/CodeGen/TwoAddressInstructionPass.h new file mode 100644 index 00000000000..b268154d8e8 --- /dev/null +++ b/include/llvm/CodeGen/TwoAddressInstructionPass.h @@ -0,0 +1,51 @@ +//===-- llvm/CodeGen/TwoAddressInstructionPass.h - Two-Address instruction pass -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by the LLVM research group and is distributed under +// the University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Two-Address instruction rewriter pass. In +// some architectures instructions have a combined source/destination +// operand. In those cases the instruction cannot have three operands +// as the destination is implicit (for example ADD %EAX, %EBX on the +// IA-32). After code generation this restrictions are not handled and +// instructions may have three operands. This pass remedies this and +// reduces all two-address instructions to two operands. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_TWOADDRESSINSTRUCTIONPASS_H +#define LLVM_CODEGEN_TWOADDRESSINSTRUCTIONPASS_H + +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineBasicBlock.h" +#include +#include + +namespace llvm { + + class LiveVariables; + class MRegisterInfo; + + class TwoAddressInstructionPass : public MachineFunctionPass + { + private: + MachineFunction* mf_; + const TargetMachine* tm_; + const MRegisterInfo* mri_; + LiveVariables* lv_; + + public: + virtual void getAnalysisUsage(AnalysisUsage &AU) const; + + private: + /// runOnMachineFunction - pass entry point + bool runOnMachineFunction(MachineFunction&); + }; + +} // End llvm namespace + +#endif diff --git a/lib/CodeGen/TwoAddressInstructionPass.cpp b/lib/CodeGen/TwoAddressInstructionPass.cpp new file mode 100644 index 00000000000..0716ca92a3c --- /dev/null +++ b/lib/CodeGen/TwoAddressInstructionPass.cpp @@ -0,0 +1,149 @@ +//===-- TwoAddressInstructionPass.cpp - Two-Address instruction pass ------===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by the LLVM research group and is distributed under +// the University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the LiveInterval analysis pass which is used +// by the Linear Scan Register allocator. This pass linearizes the +// basic blocks of the function in DFS order and uses the +// LiveVariables pass to conservatively compute live intervals for +// each virtual and physical register. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "twoaddrinstr" +#include "llvm/CodeGen/TwoAddressInstructionPass.h" +#include "llvm/Function.h" +#include "llvm/CodeGen/LiveVariables.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/CodeGen/SSARegMap.h" +#include "llvm/Target/MRegisterInfo.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetRegInfo.h" +#include "Support/Debug.h" +#include "Support/Statistic.h" +#include "Support/STLExtras.h" +#include + +using namespace llvm; + +namespace { + RegisterAnalysis X( + "twoaddressinstruction", "Two-Address instruction pass"); + + Statistic<> numTwoAddressInstrs("twoaddressinstruction", + "Number of two-address instructions"); + Statistic<> numInstrsAdded("twoaddressinstruction", + "Number of instructions added"); +}; + +void TwoAddressInstructionPass::getAnalysisUsage(AnalysisUsage &AU) const +{ + AU.addPreserved(); + AU.addRequired(); + AU.addPreservedID(PHIEliminationID); + AU.addRequiredID(PHIEliminationID); + MachineFunctionPass::getAnalysisUsage(AU); +} + +/// runOnMachineFunction - Reduce two-address instructions to two +/// operands +/// +bool TwoAddressInstructionPass::runOnMachineFunction(MachineFunction &fn) { + DEBUG(std::cerr << "Machine Function\n"); + mf_ = &fn; + tm_ = &fn.getTarget(); + mri_ = tm_->getRegisterInfo(); + lv_ = &getAnalysis(); + + const TargetInstrInfo& tii = tm_->getInstrInfo(); + + for (MachineFunction::iterator mbbi = mf_->begin(), mbbe = mf_->end(); + mbbi != mbbe; ++mbbi) { + for (MachineBasicBlock::iterator mii = mbbi->begin(); + mii != mbbi->end(); ++mii) { + MachineInstr* mi = *mii; + + unsigned opcode = mi->getOpcode(); + // ignore if it is not a two-address instruction + if (!tii.isTwoAddrInstr(opcode)) + continue; + + ++numTwoAddressInstrs; + + DEBUG(std::cerr << "\tinstruction: "; mi->print(std::cerr, *tm_)); + + // we have nothing to do if the two operands are the same + if (mi->getOperand(0).getAllocatedRegNum() == + mi->getOperand(1).getAllocatedRegNum()) + continue; + + assert(mi->getOperand(1).isRegister() && + mi->getOperand(1).getAllocatedRegNum() && + mi->getOperand(1).isUse() && + "two address instruction invalid"); + + // rewrite: + // a = b op c + // to: + // a = b + // a = a op c + unsigned regA = mi->getOperand(0).getAllocatedRegNum(); + unsigned regB = mi->getOperand(1).getAllocatedRegNum(); + bool regAisPhysical = regA < MRegisterInfo::FirstVirtualRegister; + bool regBisPhysical = regB < MRegisterInfo::FirstVirtualRegister; + + const TargetRegisterClass* rc = regAisPhysical ? + mri_->getRegClass(regA) : + mf_->getSSARegMap()->getRegClass(regA); + + numInstrsAdded += mri_->copyRegToReg(*mbbi, mii, regA, regB, rc); + + MachineInstr* prevMi = *(mii - 1); + DEBUG(std::cerr << "\t\tadded instruction: "; + prevMi->print(std::cerr, *tm_)); + + // update live variables for regA + if (regAisPhysical) { + lv_->HandlePhysRegDef(regA, prevMi); + } + else { + LiveVariables::VarInfo& varInfo = lv_->getVarInfo(regA); + varInfo.DefInst = prevMi; + } + + // update live variables for regB + if (regBisPhysical) { + lv_->HandlePhysRegUse(regB, prevMi); + } + else { + if (lv_->removeVirtualRegisterKilled(regB, &*mbbi, mi)) + lv_->addVirtualRegisterKilled(regB, &*mbbi, prevMi); + + if (lv_->removeVirtualRegisterDead(regB, &*mbbi, mi)) + lv_->addVirtualRegisterDead(regB, &*mbbi, prevMi); + } + + // replace all occurences of regB with regA + for (unsigned i = 1; i < mi->getNumOperands(); ++i) { + if (mi->getOperand(i).isRegister() && + mi->getOperand(i).getReg() == regB) + mi->SetMachineOperandReg(i, regA); + } + DEBUG(std::cerr << "\t\tmodified original to: "; + mi->print(std::cerr, *tm_)); + assert(mi->getOperand(0).getAllocatedRegNum() == + mi->getOperand(1).getAllocatedRegNum()); + } + } + + return numInstrsAdded != 0; +}