aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlkis Evlogimenos <alkis@evlogimenos.com>2003-12-18 13:06:04 +0000
committerAlkis Evlogimenos <alkis@evlogimenos.com>2003-12-18 13:06:04 +0000
commit71499ded4d76233f3b605638b539548bea8bb2f1 (patch)
tree04520306a552034b6b22a36d10a52c55c9d70f46
parent485ec3c21efcb6388911f654a187c49ad04e86e6 (diff)
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
-rw-r--r--include/llvm/CodeGen/LiveVariables.h68
-rw-r--r--include/llvm/CodeGen/TwoAddressInstructionPass.h51
-rw-r--r--lib/CodeGen/TwoAddressInstructionPass.cpp149
3 files changed, 256 insertions, 12 deletions
diff --git a/include/llvm/CodeGen/LiveVariables.h b/include/llvm/CodeGen/LiveVariables.h
index 737dabc1ae..50e4166f45 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<std::pair<MachineBasicBlock*, MachineInstr*> >::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 0000000000..b268154d8e
--- /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 <iostream>
+#include <map>
+
+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 0000000000..0716ca92a3
--- /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 <iostream>
+
+using namespace llvm;
+
+namespace {
+ RegisterAnalysis<TwoAddressInstructionPass> 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<LiveVariables>();
+ AU.addRequired<LiveVariables>();
+ 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<LiveVariables>();
+
+ 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;
+}