From 90aeecae420954f6ec78cc426375c31fbdfa5ee3 Mon Sep 17 00:00:00 2001 From: Alkis Evlogimenos Date: Thu, 18 Dec 2003 13:06:04 +0000 Subject: [PATCH] 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. llvm-svn: 10512 --- include/llvm/CodeGen/LiveVariables.h | 68 ++++++-- .../llvm/CodeGen/TwoAddressInstructionPass.h | 51 ++++++ lib/CodeGen/TwoAddressInstructionPass.cpp | 149 ++++++++++++++++++ 3 files changed, 256 insertions(+), 12 deletions(-) create mode 100644 include/llvm/CodeGen/TwoAddressInstructionPass.h create mode 100644 lib/CodeGen/TwoAddressInstructionPass.cpp 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; +}