This target is no longer built. The ,v files now live in the reoptimizer.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@27885 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Chris Lattner 2006-04-20 17:15:44 +00:00
parent 43c40ffa41
commit 2706983c48
90 changed files with 0 additions and 32210 deletions

View File

@ -1,4 +0,0 @@
*.inc
SparcV9.burg.in1
SparcV9.burm
SparcV9.burm.cpp

View File

@ -1,137 +0,0 @@
//===- llvm/Transforms/DecomposeMultiDimRefs.cpp - Lower array refs to 1D -===//
//
// 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.
//
//===----------------------------------------------------------------------===//
//
// DecomposeMultiDimRefs - Convert multi-dimensional references consisting of
// any combination of 2 or more array and structure indices into a sequence of
// instructions (using getelementpr and cast) so that each instruction has at
// most one index (except structure references, which need an extra leading
// index of [0]).
//
//===----------------------------------------------------------------------===//
#include "SparcV9Internals.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Constants.h"
#include "llvm/Constant.h"
#include "llvm/Instructions.h"
#include "llvm/BasicBlock.h"
#include "llvm/Pass.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/Debug.h"
#include <iostream>
using namespace llvm;
namespace {
Statistic<> NumAdded("lowerrefs", "# of getelementptr instructions added");
struct DecomposePass : public BasicBlockPass {
virtual bool runOnBasicBlock(BasicBlock &BB);
};
RegisterOpt<DecomposePass> X("lowerrefs", "Decompose multi-dimensional "
"structure/array references");
}
// runOnBasicBlock - Entry point for array or structure references with multiple
// indices.
//
bool DecomposePass::runOnBasicBlock(BasicBlock &BB) {
bool changed = false;
for (BasicBlock::iterator II = BB.begin(); II != BB.end(); )
if (GetElementPtrInst *gep = dyn_cast<GetElementPtrInst>(II++)) // pre-inc
if (gep->getNumIndices() >= 2)
changed |= DecomposeArrayRef(gep); // always modifies II
return changed;
}
FunctionPass *llvm::createDecomposeMultiDimRefsPass() {
return new DecomposePass();
}
static inline bool isZeroConst (Value *V) {
return isa<Constant> (V) && (cast<Constant>(V)->isNullValue());
}
// Function: DecomposeArrayRef()
//
// For any GetElementPtrInst with 2 or more array and structure indices:
//
// opCode CompositeType* P, [uint|ubyte] idx1, ..., [uint|ubyte] idxN
//
// this function generates the following sequence:
//
// ptr1 = getElementPtr P, idx1
// ptr2 = getElementPtr ptr1, 0, idx2
// ...
// ptrN-1 = getElementPtr ptrN-2, 0, idxN-1
// opCode ptrN-1, 0, idxN // New-MAI
//
// Then it replaces the original instruction with this sequence,
// and replaces all uses of the original instruction with New-MAI.
// If idx1 is 0, we simply omit the first getElementPtr instruction.
//
// On return: BBI points to the instruction after the current one
// (whether or not *BBI was replaced).
//
// Return value: true if the instruction was replaced; false otherwise.
//
bool llvm::DecomposeArrayRef(GetElementPtrInst* GEP) {
if (GEP->getNumIndices() < 2
|| (GEP->getNumIndices() == 2
&& isZeroConst(GEP->getOperand(1)))) {
DEBUG (std::cerr << "DecomposeArrayRef: Skipping " << *GEP);
return false;
} else {
DEBUG (std::cerr << "DecomposeArrayRef: Decomposing " << *GEP);
}
BasicBlock *BB = GEP->getParent();
Value *LastPtr = GEP->getPointerOperand();
Instruction *InsertPoint = GEP->getNext(); // Insert before the next insn
// Process each index except the last one.
User::const_op_iterator OI = GEP->idx_begin(), OE = GEP->idx_end();
for (; OI+1 != OE; ++OI) {
std::vector<Value*> Indices;
// If this is the first index and is 0, skip it and move on!
if (OI == GEP->idx_begin()) {
if (isZeroConst (*OI))
continue;
}
else // Not the first index: include initial [0] to deref the last ptr
Indices.push_back(Constant::getNullValue(Type::LongTy));
Indices.push_back(*OI);
// New Instruction: nextPtr1 = GetElementPtr LastPtr, Indices
LastPtr = new GetElementPtrInst(LastPtr, Indices, "ptr1", InsertPoint);
++NumAdded;
}
// Now create a new instruction to replace the original one
//
const PointerType *PtrTy = cast<PointerType>(LastPtr->getType());
// Get the final index vector, including an initial [0] as before.
std::vector<Value*> Indices;
Indices.push_back(Constant::getNullValue(Type::LongTy));
Indices.push_back(*OI);
Value *NewVal = new GetElementPtrInst(LastPtr, Indices, GEP->getName(),
InsertPoint);
// Replace all uses of the old instruction with the new
GEP->replaceAllUsesWith(NewVal);
// Now remove and delete the old instruction...
BB->getInstList().erase(GEP);
return true;
}

View File

@ -1,115 +0,0 @@
//===-- EmitBytecodeToAssembly.cpp - Emit bytecode to SparcV9 .s File ------==//
//
// 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 pass that writes LLVM bytecode as data to a sparc
// assembly file. The bytecode gets assembled into a special bytecode section
// of the executable for use at runtime later.
//
//===----------------------------------------------------------------------===//
#include "SparcV9Internals.h"
#include "llvm/Pass.h"
#include "llvm/Bytecode/Writer.h"
#include <iostream>
using namespace llvm;
namespace {
// sparcasmbuf - stream buf for encoding output bytes as .byte directives for
// the sparc assembler.
//
class sparcasmbuf : public std::streambuf {
std::ostream &BaseStr;
public:
typedef char char_type;
typedef int int_type;
typedef std::streampos pos_type;
typedef std::streamoff off_type;
sparcasmbuf(std::ostream &On) : BaseStr(On) {}
virtual int_type overflow(int_type C) {
if (C != EOF)
BaseStr << "\t.byte " << C << "\n"; // Output C;
return C;
}
};
// osparcasmstream - Define an ostream implementation that uses a sparcasmbuf
// as the underlying streambuf to write the data to. This streambuf formats
// the output as .byte directives for sparc output.
//
class osparcasmstream : public std::ostream {
sparcasmbuf sb;
public:
typedef char char_type;
typedef int int_type;
typedef std::streampos pos_type;
typedef std::streamoff off_type;
explicit osparcasmstream(std::ostream &On) : std::ostream(&sb), sb(On) { }
sparcasmbuf *rdbuf() const {
return const_cast<sparcasmbuf*>(&sb);
}
};
static void writePrologue (std::ostream &Out, const std::string &comment,
const std::string &symName) {
// Prologue:
// Output a comment describing the object.
Out << "!" << comment << "\n";
// Switch the current section to .rodata in the assembly output:
Out << "\t.section \".rodata\"\n\t.align 8\n";
// Output a global symbol naming the object:
Out << "\t.global " << symName << "\n";
Out << "\t.type " << symName << ",#object\n";
Out << symName << ":\n";
}
static void writeEpilogue (std::ostream &Out, const std::string &symName) {
// Epilogue:
// Output a local symbol marking the end of the object:
Out << ".end_" << symName << ":\n";
// Output size directive giving the size of the object:
Out << "\t.size " << symName << ", .end_" << symName << "-" << symName
<< "\n";
}
// SparcV9BytecodeWriter - Write bytecode out to a stream that is sparc'ified
class SparcV9BytecodeWriter : public ModulePass {
std::ostream &Out;
public:
SparcV9BytecodeWriter(std::ostream &out) : Out(out) {}
const char *getPassName() const { return "Emit Bytecode to SparcV9 Assembly";}
virtual bool runOnModule(Module &M) {
// Write an object containing the bytecode to the SPARC assembly stream
writePrologue (Out, "LLVM BYTECODE OUTPUT", "LLVMBytecode");
osparcasmstream OS(Out);
WriteBytecodeToFile(&M, OS);
writeEpilogue (Out, "LLVMBytecode");
// Write an object containing its length as an integer to the
// SPARC assembly stream
writePrologue (Out, "LLVM BYTECODE LENGTH", "llvm_length");
Out <<"\t.word\t.end_LLVMBytecode-LLVMBytecode\n";
writeEpilogue (Out, "llvm_length");
return false;
}
};
} // end anonymous namespace
ModulePass *llvm::createBytecodeAsmPrinterPass(std::ostream &Out) {
return new SparcV9BytecodeWriter(Out);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,14 +0,0 @@
##===- lib/CodeGen/InstrSched/Makefile ---------------------*- Makefile -*-===##
#
# 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.
#
##===----------------------------------------------------------------------===##
LEVEL = ../../../..
DIRS =
LIBRARYNAME = LLVMSparcV9InstrSched
include $(LEVEL)/Makefile.common

View File

@ -1,737 +0,0 @@
//===- SchedGraph.cpp - Scheduling Graph Implementation -------------------===//
//
// 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.
//
//===----------------------------------------------------------------------===//
//
// Scheduling graph based on SSA graph plus extra dependence edges capturing
// dependences due to machine resources (machine registers, CC registers, and
// any others).
//
//===----------------------------------------------------------------------===//
#include "SchedGraph.h"
#include "llvm/Function.h"
#include "llvm/Instructions.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "../MachineCodeForInstruction.h"
#include "../SparcV9RegInfo.h"
#include "../SparcV9InstrInfo.h"
#include "llvm/ADT/STLExtras.h"
#include <iostream>
namespace llvm {
//*********************** Internal Data Structures *************************/
// The following two types need to be classes, not typedefs, so we can use
// opaque declarations in SchedGraph.h
//
struct RefVec: public std::vector<std::pair<SchedGraphNode*, int> > {
typedef std::vector<std::pair<SchedGraphNode*,int> >::iterator iterator;
typedef
std::vector<std::pair<SchedGraphNode*,int> >::const_iterator const_iterator;
};
struct RegToRefVecMap: public hash_map<int, RefVec> {
typedef hash_map<int, RefVec>:: iterator iterator;
typedef hash_map<int, RefVec>::const_iterator const_iterator;
};
struct ValueToDefVecMap: public hash_map<const Value*, RefVec> {
typedef hash_map<const Value*, RefVec>:: iterator iterator;
typedef hash_map<const Value*, RefVec>::const_iterator const_iterator;
};
//
// class SchedGraphNode
//
SchedGraphNode::SchedGraphNode(unsigned NID, MachineBasicBlock *mbb,
int indexInBB, const TargetMachine& Target)
: SchedGraphNodeCommon(NID,indexInBB), MBB(mbb), MI(0) {
if (mbb) {
MachineBasicBlock::iterator I = MBB->begin();
std::advance(I, indexInBB);
MI = I;
MachineOpCode mopCode = MI->getOpcode();
latency = Target.getInstrInfo()->hasResultInterlock(mopCode)
? Target.getInstrInfo()->minLatency(mopCode)
: Target.getInstrInfo()->maxLatency(mopCode);
}
}
//
// Method: SchedGraphNode Destructor
//
// Description:
// Free memory allocated by the SchedGraphNode object.
//
// Notes:
// Do not delete the edges here. The base class will take care of that.
// Only handle subclass specific stuff here (where currently there is
// none).
//
SchedGraphNode::~SchedGraphNode() {
}
//
// class SchedGraph
//
SchedGraph::SchedGraph(MachineBasicBlock &mbb, const TargetMachine& target)
: MBB(mbb) {
buildGraph(target);
}
//
// Method: SchedGraph Destructor
//
// Description:
// This method deletes memory allocated by the SchedGraph object.
//
// Notes:
// Do not delete the graphRoot or graphLeaf here. The base class handles
// that bit of work.
//
SchedGraph::~SchedGraph() {
for (const_iterator I = begin(); I != end(); ++I)
delete I->second;
}
void SchedGraph::dump() const {
std::cerr << " Sched Graph for Basic Block: "
<< MBB.getBasicBlock()->getName()
<< " (" << *MBB.getBasicBlock() << ")"
<< "\n\n Actual Root nodes: ";
for (SchedGraphNodeCommon::const_iterator I = graphRoot->beginOutEdges(),
E = graphRoot->endOutEdges();
I != E; ++I) {
std::cerr << (*I)->getSink ()->getNodeId ();
if (I + 1 != E) { std::cerr << ", "; }
}
std::cerr << "\n Graph Nodes:\n";
for (const_iterator I = begin(), E = end(); I != E; ++I)
std::cerr << "\n" << *I->second;
std::cerr << "\n";
}
void SchedGraph::addDummyEdges() {
assert(graphRoot->getNumOutEdges() == 0);
for (const_iterator I=begin(); I != end(); ++I) {
SchedGraphNode* node = (*I).second;
assert(node != graphRoot && node != graphLeaf);
if (node->beginInEdges() == node->endInEdges())
(void) new SchedGraphEdge(graphRoot, node, SchedGraphEdge::CtrlDep,
SchedGraphEdge::NonDataDep, 0);
if (node->beginOutEdges() == node->endOutEdges())
(void) new SchedGraphEdge(node, graphLeaf, SchedGraphEdge::CtrlDep,
SchedGraphEdge::NonDataDep, 0);
}
}
void SchedGraph::addCDEdges(const TerminatorInst* term,
const TargetMachine& target) {
const TargetInstrInfo& mii = *target.getInstrInfo();
MachineCodeForInstruction &termMvec = MachineCodeForInstruction::get(term);
// Find the first branch instr in the sequence of machine instrs for term
//
unsigned first = 0;
while (! mii.isBranch(termMvec[first]->getOpcode()) &&
! mii.isReturn(termMvec[first]->getOpcode()))
++first;
assert(first < termMvec.size() &&
"No branch instructions for terminator? Ok, but weird!");
if (first == termMvec.size())
return;
SchedGraphNode* firstBrNode = getGraphNodeForInstr(termMvec[first]);
// Add CD edges from each instruction in the sequence to the
// *last preceding* branch instr. in the sequence
// Use a latency of 0 because we only need to prevent out-of-order issue.
//
for (unsigned i = termMvec.size(); i > first+1; --i) {
SchedGraphNode* toNode = getGraphNodeForInstr(termMvec[i-1]);
assert(toNode && "No node for instr generated for branch/ret?");
for (unsigned j = i-1; j != 0; --j)
if (mii.isBranch(termMvec[j-1]->getOpcode()) ||
mii.isReturn(termMvec[j-1]->getOpcode())) {
SchedGraphNode* brNode = getGraphNodeForInstr(termMvec[j-1]);
assert(brNode && "No node for instr generated for branch/ret?");
(void) new SchedGraphEdge(brNode, toNode, SchedGraphEdge::CtrlDep,
SchedGraphEdge::NonDataDep, 0);
break; // only one incoming edge is enough
}
}
// Add CD edges from each instruction preceding the first branch
// to the first branch. Use a latency of 0 as above.
//
for (unsigned i = first; i != 0; --i) {
SchedGraphNode* fromNode = getGraphNodeForInstr(termMvec[i-1]);
assert(fromNode && "No node for instr generated for branch?");
(void) new SchedGraphEdge(fromNode, firstBrNode, SchedGraphEdge::CtrlDep,
SchedGraphEdge::NonDataDep, 0);
}
// Now add CD edges to the first branch instruction in the sequence from
// all preceding instructions in the basic block. Use 0 latency again.
//
for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); I != E; ++I){
if (&*I == termMvec[first]) // reached the first branch
break;
SchedGraphNode* fromNode = getGraphNodeForInstr(I);
if (fromNode == NULL)
continue; // dummy instruction, e.g., PHI
(void) new SchedGraphEdge(fromNode, firstBrNode,
SchedGraphEdge::CtrlDep,
SchedGraphEdge::NonDataDep, 0);
// If we find any other machine instructions (other than due to
// the terminator) that also have delay slots, add an outgoing edge
// from the instruction to the instructions in the delay slots.
//
unsigned d = mii.getNumDelaySlots(I->getOpcode());
MachineBasicBlock::iterator J = I; ++J;
for (unsigned j=1; j <= d; j++, ++J) {
SchedGraphNode* toNode = this->getGraphNodeForInstr(J);
assert(toNode && "No node for machine instr in delay slot?");
(void) new SchedGraphEdge(fromNode, toNode,
SchedGraphEdge::CtrlDep,
SchedGraphEdge::NonDataDep, 0);
}
}
}
static const int SG_LOAD_REF = 0;
static const int SG_STORE_REF = 1;
static const int SG_CALL_REF = 2;
static const unsigned int SG_DepOrderArray[][3] = {
{ SchedGraphEdge::NonDataDep,
SchedGraphEdge::AntiDep,
SchedGraphEdge::AntiDep },
{ SchedGraphEdge::TrueDep,
SchedGraphEdge::OutputDep,
SchedGraphEdge::TrueDep | SchedGraphEdge::OutputDep },
{ SchedGraphEdge::TrueDep,
SchedGraphEdge::AntiDep | SchedGraphEdge::OutputDep,
SchedGraphEdge::TrueDep | SchedGraphEdge::AntiDep
| SchedGraphEdge::OutputDep }
};
// Add a dependence edge between every pair of machine load/store/call
// instructions, where at least one is a store or a call.
// Use latency 1 just to ensure that memory operations are ordered;
// latency does not otherwise matter (true dependences enforce that).
//
void SchedGraph::addMemEdges(const std::vector<SchedGraphNode*>& memNodeVec,
const TargetMachine& target) {
const TargetInstrInfo& mii = *target.getInstrInfo();
// Instructions in memNodeVec are in execution order within the basic block,
// so simply look at all pairs <memNodeVec[i], memNodeVec[j: j > i]>.
//
for (unsigned im=0, NM=memNodeVec.size(); im < NM; im++) {
MachineOpCode fromOpCode = memNodeVec[im]->getOpcode();
int fromType = (mii.isCall(fromOpCode)? SG_CALL_REF
: (mii.isLoad(fromOpCode)? SG_LOAD_REF
: SG_STORE_REF));
for (unsigned jm=im+1; jm < NM; jm++) {
MachineOpCode toOpCode = memNodeVec[jm]->getOpcode();
int toType = (mii.isCall(toOpCode)? SG_CALL_REF
: (mii.isLoad(toOpCode)? SG_LOAD_REF
: SG_STORE_REF));
if (fromType != SG_LOAD_REF || toType != SG_LOAD_REF)
(void) new SchedGraphEdge(memNodeVec[im], memNodeVec[jm],
SchedGraphEdge::MemoryDep,
SG_DepOrderArray[fromType][toType], 1);
}
}
}
// Add edges from/to CC reg instrs to/from call instrs.
// Essentially this prevents anything that sets or uses a CC reg from being
// reordered w.r.t. a call.
// Use a latency of 0 because we only need to prevent out-of-order issue,
// like with control dependences.
//
void SchedGraph::addCallDepEdges(const std::vector<SchedGraphNode*>& callDepNodeVec,
const TargetMachine& target) {
const TargetInstrInfo& mii = *target.getInstrInfo();
// Instructions in memNodeVec are in execution order within the basic block,
// so simply look at all pairs <memNodeVec[i], memNodeVec[j: j > i]>.
//
for (unsigned ic=0, NC=callDepNodeVec.size(); ic < NC; ic++)
if (mii.isCall(callDepNodeVec[ic]->getOpcode())) {
// Add SG_CALL_REF edges from all preds to this instruction.
for (unsigned jc=0; jc < ic; jc++)
(void) new SchedGraphEdge(callDepNodeVec[jc], callDepNodeVec[ic],
SchedGraphEdge::MachineRegister,
MachineIntRegsRID, 0);
// And do the same from this instruction to all successors.
for (unsigned jc=ic+1; jc < NC; jc++)
(void) new SchedGraphEdge(callDepNodeVec[ic], callDepNodeVec[jc],
SchedGraphEdge::MachineRegister,
MachineIntRegsRID, 0);
}
#ifdef CALL_DEP_NODE_VEC_CANNOT_WORK
// Find the call instruction nodes and put them in a vector.
std::vector<SchedGraphNode*> callNodeVec;
for (unsigned im=0, NM=memNodeVec.size(); im < NM; im++)
if (mii.isCall(memNodeVec[im]->getOpcode()))
callNodeVec.push_back(memNodeVec[im]);
// Now walk the entire basic block, looking for CC instructions *and*
// call instructions, and keep track of the order of the instructions.
// Use the call node vec to quickly find earlier and later call nodes
// relative to the current CC instruction.
//
int lastCallNodeIdx = -1;
for (unsigned i=0, N=bbMvec.size(); i < N; i++)
if (mii.isCall(bbMvec[i]->getOpcode())) {
++lastCallNodeIdx;
for ( ; lastCallNodeIdx < (int)callNodeVec.size(); ++lastCallNodeIdx)
if (callNodeVec[lastCallNodeIdx]->getMachineInstr() == bbMvec[i])
break;
assert(lastCallNodeIdx < (int)callNodeVec.size() && "Missed Call?");
}
else if (mii.isCCInstr(bbMvec[i]->getOpcode())) {
// Add incoming/outgoing edges from/to preceding/later calls
SchedGraphNode* ccNode = this->getGraphNodeForInstr(bbMvec[i]);
int j=0;
for ( ; j <= lastCallNodeIdx; j++)
(void) new SchedGraphEdge(callNodeVec[j], ccNode,
MachineCCRegsRID, 0);
for ( ; j < (int) callNodeVec.size(); j++)
(void) new SchedGraphEdge(ccNode, callNodeVec[j],
MachineCCRegsRID, 0);
}
#endif
}
void SchedGraph::addMachineRegEdges(RegToRefVecMap& regToRefVecMap,
const TargetMachine& target) {
// This code assumes that two registers with different numbers are
// not aliased!
//
for (RegToRefVecMap::iterator I = regToRefVecMap.begin();
I != regToRefVecMap.end(); ++I) {
int regNum = (*I).first;
RefVec& regRefVec = (*I).second;
// regRefVec is ordered by control flow order in the basic block
for (unsigned i=0; i < regRefVec.size(); ++i) {
SchedGraphNode* node = regRefVec[i].first;
unsigned int opNum = regRefVec[i].second;
const MachineOperand& mop =
node->getMachineInstr()->getExplOrImplOperand(opNum);
bool isDef = mop.isDef() && !mop.isUse();
bool isDefAndUse = mop.isDef() && mop.isUse();
for (unsigned p=0; p < i; ++p) {
SchedGraphNode* prevNode = regRefVec[p].first;
if (prevNode != node) {
unsigned int prevOpNum = regRefVec[p].second;
const MachineOperand& prevMop =
prevNode->getMachineInstr()->getExplOrImplOperand(prevOpNum);
bool prevIsDef = prevMop.isDef() && !prevMop.isUse();
bool prevIsDefAndUse = prevMop.isDef() && prevMop.isUse();
if (isDef) {
if (prevIsDef)
new SchedGraphEdge(prevNode, node, regNum,
SchedGraphEdge::OutputDep);
if (!prevIsDef || prevIsDefAndUse)
new SchedGraphEdge(prevNode, node, regNum,
SchedGraphEdge::AntiDep);
}
if (prevIsDef)
if (!isDef || isDefAndUse)
new SchedGraphEdge(prevNode, node, regNum,
SchedGraphEdge::TrueDep);
}
}
}
}
}
// Adds dependences to/from refNode from/to all other defs
// in the basic block. refNode may be a use, a def, or both.
// We do not consider other uses because we are not building use-use deps.
//
void SchedGraph::addEdgesForValue(SchedGraphNode* refNode,
const RefVec& defVec,
const Value* defValue,
bool refNodeIsDef,
bool refNodeIsUse,
const TargetMachine& target) {
// Add true or output dep edges from all def nodes before refNode in BB.
// Add anti or output dep edges to all def nodes after refNode.
for (RefVec::const_iterator I=defVec.begin(), E=defVec.end(); I != E; ++I) {
if ((*I).first == refNode)
continue; // Dont add any self-loops
if ((*I).first->getOrigIndexInBB() < refNode->getOrigIndexInBB()) {
// (*).first is before refNode
if (refNodeIsDef && !refNodeIsUse)
(void) new SchedGraphEdge((*I).first, refNode, defValue,
SchedGraphEdge::OutputDep);
if (refNodeIsUse)
(void) new SchedGraphEdge((*I).first, refNode, defValue,
SchedGraphEdge::TrueDep);
} else {
// (*).first is after refNode
if (refNodeIsDef && !refNodeIsUse)
(void) new SchedGraphEdge(refNode, (*I).first, defValue,
SchedGraphEdge::OutputDep);
if (refNodeIsUse)
(void) new SchedGraphEdge(refNode, (*I).first, defValue,
SchedGraphEdge::AntiDep);
}
}
}
void SchedGraph::addEdgesForInstruction(const MachineInstr& MI,
const ValueToDefVecMap& valueToDefVecMap,
const TargetMachine& target) {
SchedGraphNode* node = getGraphNodeForInstr(&MI);
if (node == NULL)
return;
// Add edges for all operands of the machine instruction.
//
for (unsigned i = 0, numOps = MI.getNumOperands(); i != numOps; ++i) {
switch (MI.getOperand(i).getType()) {
case MachineOperand::MO_VirtualRegister:
case MachineOperand::MO_CCRegister:
if (const Value* srcI = MI.getOperand(i).getVRegValue()) {
ValueToDefVecMap::const_iterator I = valueToDefVecMap.find(srcI);
if (I != valueToDefVecMap.end())
addEdgesForValue(node, I->second, srcI,
MI.getOperand(i).isDef(), MI.getOperand(i).isUse(),
target);
}
break;
case MachineOperand::MO_MachineRegister:
break;
case MachineOperand::MO_SignExtendedImmed:
case MachineOperand::MO_UnextendedImmed:
case MachineOperand::MO_PCRelativeDisp:
case MachineOperand::MO_ConstantPoolIndex:
break; // nothing to do for immediate fields
default:
assert(0 && "Unknown machine operand type in SchedGraph builder");
break;
}
}
// Add edges for values implicitly used by the machine instruction.
// Examples include function arguments to a Call instructions or the return
// value of a Ret instruction.
//
for (unsigned i=0, N=MI.getNumImplicitRefs(); i < N; ++i)
if (MI.getImplicitOp(i).isUse())
if (const Value* srcI = MI.getImplicitRef(i)) {
ValueToDefVecMap::const_iterator I = valueToDefVecMap.find(srcI);
if (I != valueToDefVecMap.end())
addEdgesForValue(node, I->second, srcI,
MI.getImplicitOp(i).isDef(),
MI.getImplicitOp(i).isUse(), target);
}
}
void SchedGraph::findDefUseInfoAtInstr(const TargetMachine& target,
SchedGraphNode* node,
std::vector<SchedGraphNode*>& memNodeVec,
std::vector<SchedGraphNode*>& callDepNodeVec,
RegToRefVecMap& regToRefVecMap,
ValueToDefVecMap& valueToDefVecMap) {
const TargetInstrInfo& mii = *target.getInstrInfo();
MachineOpCode opCode = node->getOpcode();
if (mii.isCall(opCode) || mii.isCCInstr(opCode))
callDepNodeVec.push_back(node);
if (mii.isLoad(opCode) || mii.isStore(opCode) || mii.isCall(opCode))
memNodeVec.push_back(node);
// Collect the register references and value defs. for explicit operands
//
const MachineInstr& MI = *node->getMachineInstr();
for (int i=0, numOps = (int) MI.getNumOperands(); i < numOps; i++) {
const MachineOperand& mop = MI.getOperand(i);
// if this references a register other than the hardwired
// "zero" register, record the reference.
if (mop.hasAllocatedReg()) {
unsigned regNum = mop.getReg();
// If this is not a dummy zero register, record the reference in order
if (regNum != target.getRegInfo()->getZeroRegNum())
regToRefVecMap[mop.getReg()]
.push_back(std::make_pair(node, i));
// If this is a volatile register, add the instruction to callDepVec
// (only if the node is not already on the callDepVec!)
if (callDepNodeVec.size() == 0 || callDepNodeVec.back() != node)
{
unsigned rcid = 0;
int regInClass = target.getRegInfo()->getClassRegNum(regNum, rcid);
if (target.getRegInfo()->getMachineRegClass(rcid)
->isRegVolatile(regInClass))
callDepNodeVec.push_back(node);
}
continue; // nothing more to do
}
// ignore all other non-def operands
if (!MI.getOperand(i).isDef())
continue;
// We must be defining a value.
assert((mop.getType() == MachineOperand::MO_VirtualRegister ||
mop.getType() == MachineOperand::MO_CCRegister)
&& "Do not expect any other kind of operand to be defined!");
assert(mop.getVRegValue() != NULL && "Null value being defined?");
valueToDefVecMap[mop.getVRegValue()].push_back(std::make_pair(node, i));
}
//
// Collect value defs. for implicit operands. They may have allocated
// physical registers also.
//
for (unsigned i=0, N = MI.getNumImplicitRefs(); i != N; ++i) {
const MachineOperand& mop = MI.getImplicitOp(i);
if (mop.hasAllocatedReg()) {
unsigned regNum = mop.getReg();
if (regNum != target.getRegInfo()->getZeroRegNum())
regToRefVecMap[mop.getReg()]
.push_back(std::make_pair(node, i + MI.getNumOperands()));
continue; // nothing more to do
}
if (mop.isDef()) {
assert(MI.getImplicitRef(i) != NULL && "Null value being defined?");
valueToDefVecMap[MI.getImplicitRef(i)].push_back(
std::make_pair(node, -i));
}
}
}
void SchedGraph::buildNodesForBB(const TargetMachine& target,
MachineBasicBlock& MBB,
std::vector<SchedGraphNode*>& memNodeVec,
std::vector<SchedGraphNode*>& callDepNodeVec,
RegToRefVecMap& regToRefVecMap,
ValueToDefVecMap& valueToDefVecMap) {
const TargetInstrInfo& mii = *target.getInstrInfo();
// Build graph nodes for each VM instruction and gather def/use info.
// Do both those together in a single pass over all machine instructions.
unsigned i = 0;
for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); I != E;
++I, ++i)
if (I->getOpcode() != V9::PHI) {
SchedGraphNode* node = new SchedGraphNode(getNumNodes(), &MBB, i, target);
noteGraphNodeForInstr(I, node);
// Remember all register references and value defs
findDefUseInfoAtInstr(target, node, memNodeVec, callDepNodeVec,
regToRefVecMap, valueToDefVecMap);
}
}
void SchedGraph::buildGraph(const TargetMachine& target) {
// Use this data structure to note all machine operands that compute
// ordinary LLVM values. These must be computed defs (i.e., instructions).
// Note that there may be multiple machine instructions that define
// each Value.
ValueToDefVecMap valueToDefVecMap;
// Use this data structure to note all memory instructions.
// We use this to add memory dependence edges without a second full walk.
std::vector<SchedGraphNode*> memNodeVec;
// Use this data structure to note all instructions that access physical
// registers that can be modified by a call (including call instructions)
std::vector<SchedGraphNode*> callDepNodeVec;
// Use this data structure to note any uses or definitions of
// machine registers so we can add edges for those later without
// extra passes over the nodes.
// The vector holds an ordered list of references to the machine reg,
// ordered according to control-flow order. This only works for a
// single basic block, hence the assertion. Each reference is identified
// by the pair: <node, operand-number>.
//
RegToRefVecMap regToRefVecMap;
// Make a dummy root node. We'll add edges to the real roots later.
graphRoot = new SchedGraphNode(0, NULL, -1, target);
graphLeaf = new SchedGraphNode(1, NULL, -1, target);
//----------------------------------------------------------------
// First add nodes for all the machine instructions in the basic block
// because this greatly simplifies identifying which edges to add.
// Do this one VM instruction at a time since the SchedGraphNode needs that.
// Also, remember the load/store instructions to add memory deps later.
//----------------------------------------------------------------
buildNodesForBB(target, MBB, memNodeVec, callDepNodeVec,
regToRefVecMap, valueToDefVecMap);
//----------------------------------------------------------------
// Now add edges for the following (all are incoming edges except (4)):
// (1) operands of the machine instruction, including hidden operands
// (2) machine register dependences
// (3) memory load/store dependences
// (3) other resource dependences for the machine instruction, if any
// (4) output dependences when multiple machine instructions define the
// same value; all must have been generated from a single VM instrn
// (5) control dependences to branch instructions generated for the
// terminator instruction of the BB. Because of delay slots and
// 2-way conditional branches, multiple CD edges are needed
// (see addCDEdges for details).
// Also, note any uses or defs of machine registers.
//
//----------------------------------------------------------------
// First, add edges to the terminator instruction of the basic block.
this->addCDEdges(MBB.getBasicBlock()->getTerminator(), target);
// Then add memory dep edges: store->load, load->store, and store->store.
// Call instructions are treated as both load and store.
this->addMemEdges(memNodeVec, target);
// Then add edges between call instructions and CC set/use instructions
this->addCallDepEdges(callDepNodeVec, target);
// Then add incoming def-use (SSA) edges for each machine instruction.
for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); I != E; ++I)
addEdgesForInstruction(*I, valueToDefVecMap, target);
// Then add edges for dependences on machine registers
this->addMachineRegEdges(regToRefVecMap, target);
// Finally, add edges from the dummy root and to dummy leaf
this->addDummyEdges();
}
//
// class SchedGraphSet
//
SchedGraphSet::SchedGraphSet(const Function* _function,
const TargetMachine& target) :
function(_function) {
buildGraphsForMethod(function, target);
}
SchedGraphSet::~SchedGraphSet() {
// delete all the graphs
for(iterator I = begin(), E = end(); I != E; ++I)
delete *I; // destructor is a friend
}
void SchedGraphSet::dump() const {
std::cerr << "======== Sched graphs for function `" << function->getName()
<< "' ========\n\n";
for (const_iterator I=begin(); I != end(); ++I)
(*I)->dump();
std::cerr << "\n====== End graphs for function `" << function->getName()
<< "' ========\n\n";
}
void SchedGraphSet::buildGraphsForMethod(const Function *F,
const TargetMachine& target) {
MachineFunction &MF = MachineFunction::get(F);
for (MachineFunction::iterator I = MF.begin(), E = MF.end(); I != E; ++I)
addGraph(new SchedGraph(*I, target));
}
void SchedGraphEdge::print(std::ostream &os) const {
os << "edge [" << src->getNodeId() << "] -> ["
<< sink->getNodeId() << "] : ";
switch(depType) {
case SchedGraphEdge::CtrlDep:
os<< "Control Dep";
break;
case SchedGraphEdge::ValueDep:
os<< "Reg Value " << *val;
break;
case SchedGraphEdge::MemoryDep:
os<< "Memory Dep";
break;
case SchedGraphEdge::MachineRegister:
os<< "Reg " << machineRegNum;
break;
case SchedGraphEdge::MachineResource:
os<<"Resource "<< resourceId;
break;
default:
assert(0);
break;
}
os << " : delay = " << minDelay << "\n";
}
void SchedGraphNode::print(std::ostream &os) const {
os << std::string(8, ' ')
<< "Node " << ID << " : "
<< "latency = " << latency << "\n" << std::string(12, ' ');
if (getMachineInstr() == NULL)
os << "(Dummy node)\n";
else {
os << *getMachineInstr() << "\n" << std::string(12, ' ');
os << inEdges.size() << " Incoming Edges:\n";
for (unsigned i=0, N = inEdges.size(); i < N; i++)
os << std::string(16, ' ') << *inEdges[i];
os << std::string(12, ' ') << outEdges.size()
<< " Outgoing Edges:\n";
for (unsigned i=0, N= outEdges.size(); i < N; i++)
os << std::string(16, ' ') << *outEdges[i];
}
}
} // End llvm namespace

View File

@ -1,262 +0,0 @@
//===-- SchedGraph.h - Scheduling Graph -------------------------*- 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 is a scheduling graph based on SSA graph plus extra dependence edges
// capturing dependences due to machine resources (machine registers, CC
// registers, and any others).
//
// This graph tries to leverage the SSA graph as much as possible, but captures
// the extra dependences through a common interface.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CODEGEN_SCHEDGRAPH_H
#define LLVM_CODEGEN_SCHEDGRAPH_H
#include "llvm/CodeGen/SchedGraphCommon.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/ADT/hash_map"
#include "llvm/ADT/GraphTraits.h"
namespace llvm {
class RegToRefVecMap;
class ValueToDefVecMap;
class RefVec;
class SchedGraphNode : public SchedGraphNodeCommon {
MachineBasicBlock *MBB;
const MachineInstr *MI;
SchedGraphNode(unsigned nodeId, MachineBasicBlock *mbb, int indexInBB,
const TargetMachine& Target);
~SchedGraphNode();
friend class SchedGraph; // give access for ctor and dtor
friend class SchedGraphEdge; // give access for adding edges
public:
// Accessor methods
const MachineInstr* getMachineInstr() const { return MI; }
const MachineOpCode getOpcode() const { return MI->getOpcode(); }
bool isDummyNode() const { return (MI == NULL); }
MachineBasicBlock &getMachineBasicBlock() const { return *MBB; }
void print(std::ostream &os) const;
};
class SchedGraph : public SchedGraphCommon {
MachineBasicBlock &MBB;
hash_map<const MachineInstr*, SchedGraphNode*> GraphMap;
public:
typedef hash_map<const MachineInstr*, SchedGraphNode*>::const_iterator iterator;
typedef hash_map<const MachineInstr*, SchedGraphNode*>::const_iterator const_iterator;
MachineBasicBlock& getBasicBlock() const{return MBB;}
const unsigned int getNumNodes() const { return GraphMap.size()+2; }
SchedGraphNode* getGraphNodeForInstr(const MachineInstr* MI) const {
const_iterator onePair = find(MI);
return (onePair != end())? onePair->second : NULL;
}
// Debugging support
void dump() const;
protected:
SchedGraph(MachineBasicBlock& mbb, const TargetMachine& TM);
~SchedGraph();
// Unordered iterators.
// Return values is pair<const MachineIntr*,SchedGraphNode*>.
//
hash_map<const MachineInstr*, SchedGraphNode*>::const_iterator begin() const {
return GraphMap.begin();
}
hash_map<const MachineInstr*, SchedGraphNode*>::const_iterator end() const {
return GraphMap.end();
}
unsigned size() { return GraphMap.size(); }
iterator find(const MachineInstr *MI) const { return GraphMap.find(MI); }
SchedGraphNode *&operator[](const MachineInstr *MI) {
return GraphMap[MI];
}
private:
friend class SchedGraphSet; // give access to ctor
inline void noteGraphNodeForInstr (const MachineInstr* minstr,
SchedGraphNode* node) {
assert((*this)[minstr] == NULL);
(*this)[minstr] = node;
}
//
// Graph builder
//
void buildGraph(const TargetMachine& target);
void buildNodesForBB(const TargetMachine& target,MachineBasicBlock &MBB,
std::vector<SchedGraphNode*>& memNV,
std::vector<SchedGraphNode*>& callNV,
RegToRefVecMap& regToRefVecMap,
ValueToDefVecMap& valueToDefVecMap);
void findDefUseInfoAtInstr(const TargetMachine& target, SchedGraphNode* node,
std::vector<SchedGraphNode*>& memNV,
std::vector<SchedGraphNode*>& callNV,
RegToRefVecMap& regToRefVecMap,
ValueToDefVecMap& valueToDefVecMap);
void addEdgesForInstruction(const MachineInstr& minstr,
const ValueToDefVecMap& valueToDefVecMap,
const TargetMachine& target);
void addCDEdges(const TerminatorInst* term, const TargetMachine& target);
void addMemEdges(const std::vector<SchedGraphNode*>& memNod,
const TargetMachine& target);
void addCallCCEdges(const std::vector<SchedGraphNode*>& memNod,
MachineBasicBlock& bbMvec,
const TargetMachine& target);
void addCallDepEdges(const std::vector<SchedGraphNode*>& callNV,
const TargetMachine& target);
void addMachineRegEdges(RegToRefVecMap& regToRefVecMap,
const TargetMachine& target);
void addEdgesForValue(SchedGraphNode* refNode, const RefVec& defVec,
const Value* defValue, bool refNodeIsDef,
bool refNodeIsDefAndUse,
const TargetMachine& target);
void addDummyEdges();
};
class SchedGraphSet {
const Function* function;
std::vector<SchedGraph*> Graphs;
// Graph builder
void buildGraphsForMethod(const Function *F, const TargetMachine& target);
inline void addGraph(SchedGraph* graph) {
assert(graph != NULL);
Graphs.push_back(graph);
}
public:
SchedGraphSet(const Function *function, const TargetMachine& target);
~SchedGraphSet();
//iterators
typedef std::vector<SchedGraph*>::const_iterator iterator;
typedef std::vector<SchedGraph*>::const_iterator const_iterator;
std::vector<SchedGraph*>::const_iterator begin() const { return Graphs.begin(); }
std::vector<SchedGraph*>::const_iterator end() const { return Graphs.end(); }
// Debugging support
void dump() const;
};
//
// sg_pred_iterator
// sg_pred_const_iterator
//
typedef SGPredIterator<SchedGraphNode, SchedGraphEdge, SchedGraphNode::iterator>
sg_pred_iterator;
typedef SGPredIterator<const SchedGraphNode, const SchedGraphEdge,SchedGraphNode::const_iterator>
sg_pred_const_iterator;
inline sg_pred_iterator pred_begin(SchedGraphNode *N) {
return sg_pred_iterator(N->beginInEdges());
}
inline sg_pred_iterator pred_end(SchedGraphNode *N) {
return sg_pred_iterator(N->endInEdges());
}
inline sg_pred_const_iterator pred_begin(const SchedGraphNode *N) {
return sg_pred_const_iterator(N->beginInEdges());
}
inline sg_pred_const_iterator pred_end(const SchedGraphNode *N) {
return sg_pred_const_iterator(N->endInEdges());
}
//
// sg_succ_iterator
// sg_succ_const_iterator
//
typedef SGSuccIterator<SchedGraphNode, SchedGraphEdge, SchedGraphNode::iterator>
sg_succ_iterator;
typedef SGSuccIterator<const SchedGraphNode, const SchedGraphEdge,SchedGraphNode::const_iterator>
sg_succ_const_iterator;
inline sg_succ_iterator succ_begin(SchedGraphNode *N) {
return sg_succ_iterator(N->beginOutEdges());
}
inline sg_succ_iterator succ_end(SchedGraphNode *N) {
return sg_succ_iterator(N->endOutEdges());
}
inline sg_succ_const_iterator succ_begin(const SchedGraphNode *N) {
return sg_succ_const_iterator(N->beginOutEdges());
}
inline sg_succ_const_iterator succ_end(const SchedGraphNode *N) {
return sg_succ_const_iterator(N->endOutEdges());
}
// Provide specializations of GraphTraits to be able to use graph iterators on
// the scheduling graph!
//
template <> struct GraphTraits<SchedGraph*> {
typedef SchedGraphNode NodeType;
typedef sg_succ_iterator ChildIteratorType;
static inline NodeType *getEntryNode(SchedGraph *SG) { return (NodeType*)SG->getRoot(); }
static inline ChildIteratorType child_begin(NodeType *N) {
return succ_begin(N);
}
static inline ChildIteratorType child_end(NodeType *N) {
return succ_end(N);
}
};
template <> struct GraphTraits<const SchedGraph*> {
typedef const SchedGraphNode NodeType;
typedef sg_succ_const_iterator ChildIteratorType;
static inline NodeType *getEntryNode(const SchedGraph *SG) {
return (NodeType*)SG->getRoot();
}
static inline ChildIteratorType child_begin(NodeType *N) {
return succ_begin(N);
}
static inline ChildIteratorType child_end(NodeType *N) {
return succ_end(N);
}
};
} // End llvm namespace
#endif

View File

@ -1,180 +0,0 @@
//===- SchedGraphCommon.cpp - Scheduling Graphs Base Class- ---------------===//
//
// 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.
//
//===----------------------------------------------------------------------===//
//
// Scheduling graph base class that contains common information for SchedGraph
// and ModuloSchedGraph scheduling graphs.
//
//===----------------------------------------------------------------------===//
#include "llvm/CodeGen/SchedGraphCommon.h"
#include "llvm/ADT/STLExtras.h"
#include <algorithm>
#include <iostream>
namespace llvm {
class SchedGraphCommon;
//
// class SchedGraphEdge
//
SchedGraphEdge::SchedGraphEdge(SchedGraphNodeCommon* _src,
SchedGraphNodeCommon* _sink,
SchedGraphEdgeDepType _depType,
unsigned int _depOrderType,
int _minDelay)
: src(_src), sink(_sink), depType(_depType), depOrderType(_depOrderType),
minDelay((_minDelay >= 0)? _minDelay : _src->getLatency()), val(NULL) {
iteDiff=0;
assert(src != sink && "Self-loop in scheduling graph!");
src->addOutEdge(this);
sink->addInEdge(this);
}
SchedGraphEdge::SchedGraphEdge(SchedGraphNodeCommon* _src,
SchedGraphNodeCommon* _sink,
const Value* _val,
unsigned int _depOrderType,
int _minDelay)
: src(_src), sink(_sink), depType(ValueDep), depOrderType(_depOrderType),
minDelay((_minDelay >= 0)? _minDelay : _src->getLatency()), val(_val) {
iteDiff=0;
assert(src != sink && "Self-loop in scheduling graph!");
src->addOutEdge(this);
sink->addInEdge(this);
}
SchedGraphEdge::SchedGraphEdge(SchedGraphNodeCommon* _src,
SchedGraphNodeCommon* _sink,
unsigned int _regNum,
unsigned int _depOrderType,
int _minDelay)
: src(_src), sink(_sink), depType(MachineRegister),
depOrderType(_depOrderType),
minDelay((_minDelay >= 0)? _minDelay : _src->getLatency()),
machineRegNum(_regNum) {
iteDiff=0;
assert(src != sink && "Self-loop in scheduling graph!");
src->addOutEdge(this);
sink->addInEdge(this);
}
SchedGraphEdge::SchedGraphEdge(SchedGraphNodeCommon* _src,
SchedGraphNodeCommon* _sink,
ResourceId _resourceId,
int _minDelay)
: src(_src), sink(_sink), depType(MachineResource), depOrderType(NonDataDep),
minDelay((_minDelay >= 0)? _minDelay : _src->getLatency()),
resourceId(_resourceId) {
iteDiff=0;
assert(src != sink && "Self-loop in scheduling graph!");
src->addOutEdge(this);
sink->addInEdge(this);
}
void SchedGraphEdge::dump(int indent) const {
std::cerr << std::string(indent*2, ' ') << *this;
}
/*dtor*/
SchedGraphNodeCommon::~SchedGraphNodeCommon()
{
// for each node, delete its out-edges
std::for_each(beginOutEdges(), endOutEdges(),
deleter<SchedGraphEdge>);
}
void SchedGraphNodeCommon::removeInEdge(const SchedGraphEdge* edge) {
assert(edge->getSink() == this);
for (iterator I = beginInEdges(); I != endInEdges(); ++I)
if ((*I) == edge) {
inEdges.erase(I);
break;
}
}
void SchedGraphNodeCommon::removeOutEdge(const SchedGraphEdge* edge) {
assert(edge->getSrc() == this);
for (iterator I = beginOutEdges(); I != endOutEdges(); ++I)
if ((*I) == edge) {
outEdges.erase(I);
break;
}
}
void SchedGraphNodeCommon::dump(int indent) const {
std::cerr << std::string(indent*2, ' ') << *this;
}
//class SchedGraphCommon
SchedGraphCommon::~SchedGraphCommon() {
delete graphRoot;
delete graphLeaf;
}
void SchedGraphCommon::eraseIncomingEdges(SchedGraphNodeCommon* node,
bool addDummyEdges) {
// Delete and disconnect all in-edges for the node
for (SchedGraphNodeCommon::iterator I = node->beginInEdges();
I != node->endInEdges(); ++I) {
SchedGraphNodeCommon* srcNode = (*I)->getSrc();
srcNode->removeOutEdge(*I);
delete *I;
if (addDummyEdges && srcNode != getRoot() &&
srcNode->beginOutEdges() == srcNode->endOutEdges()) {
// srcNode has no more out edges, so add an edge to dummy EXIT node
assert(node != getLeaf() && "Adding edge that was just removed?");
(void) new SchedGraphEdge(srcNode, getLeaf(),
SchedGraphEdge::CtrlDep,
SchedGraphEdge::NonDataDep, 0);
}
}
node->inEdges.clear();
}
void SchedGraphCommon::eraseOutgoingEdges(SchedGraphNodeCommon* node,
bool addDummyEdges) {
// Delete and disconnect all out-edges for the node
for (SchedGraphNodeCommon::iterator I = node->beginOutEdges();
I != node->endOutEdges(); ++I) {
SchedGraphNodeCommon* sinkNode = (*I)->getSink();
sinkNode->removeInEdge(*I);
delete *I;
if (addDummyEdges &&
sinkNode != getLeaf() &&
sinkNode->beginInEdges() == sinkNode->endInEdges()) {
//sinkNode has no more in edges, so add an edge from dummy ENTRY node
assert(node != getRoot() && "Adding edge that was just removed?");
(void) new SchedGraphEdge(getRoot(), sinkNode,
SchedGraphEdge::CtrlDep,
SchedGraphEdge::NonDataDep, 0);
}
}
node->outEdges.clear();
}
void SchedGraphCommon::eraseIncidentEdges(SchedGraphNodeCommon* node,
bool addDummyEdges) {
this->eraseIncomingEdges(node, addDummyEdges);
this->eraseOutgoingEdges(node, addDummyEdges);
}
} // End llvm namespace

View File

@ -1,284 +0,0 @@
//===-- SchedPriorities.h - Encapsulate scheduling heuristics -------------===//
//
// 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.
//
//===----------------------------------------------------------------------===//
//
// Strategy:
// Priority ordering rules:
// (1) Max delay, which is the order of the heap S.candsAsHeap.
// (2) Instruction that frees up a register.
// (3) Instruction that has the maximum number of dependent instructions.
// Note that rules 2 and 3 are only used if issue conflicts prevent
// choosing a higher priority instruction by rule 1.
//
//===----------------------------------------------------------------------===//
#include "SchedPriorities.h"
#include "../LiveVar/FunctionLiveVarInfo.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/Support/CFG.h"
#include "llvm/ADT/PostOrderIterator.h"
#include <iostream>
namespace llvm {
std::ostream &operator<<(std::ostream &os, const NodeDelayPair* nd) {
return os << "Delay for node " << nd->node->getNodeId()
<< " = " << (long)nd->delay << "\n";
}
SchedPriorities::SchedPriorities(const Function *, const SchedGraph *G,
FunctionLiveVarInfo &LVI)
: curTime(0), graph(G), methodLiveVarInfo(LVI),
nodeDelayVec(G->getNumNodes(), INVALID_LATENCY), // make errors obvious
earliestReadyTimeForNode(G->getNumNodes(), 0),
earliestReadyTime(0),
nextToTry(candsAsHeap.begin())
{
computeDelays(graph);
}
void
SchedPriorities::initialize() {
initializeReadyHeap(graph);
}
void
SchedPriorities::computeDelays(const SchedGraph* graph) {
po_iterator<const SchedGraph*> poIter = po_begin(graph), poEnd =po_end(graph);
for ( ; poIter != poEnd; ++poIter) {
const SchedGraphNode* node = *poIter;
CycleCount_t nodeDelay;
if (node->beginOutEdges() == node->endOutEdges())
nodeDelay = node->getLatency();
else {
// Iterate over the out-edges of the node to compute delay
nodeDelay = 0;
for (SchedGraphNode::const_iterator E=node->beginOutEdges();
E != node->endOutEdges(); ++E) {
CycleCount_t sinkDelay = getNodeDelay((SchedGraphNode*)(*E)->getSink());
nodeDelay = std::max(nodeDelay, sinkDelay + (*E)->getMinDelay());
}
}
getNodeDelayRef(node) = nodeDelay;
}
}
void
SchedPriorities::initializeReadyHeap(const SchedGraph* graph) {
const SchedGraphNode* graphRoot = (const SchedGraphNode*)graph->getRoot();
assert(graphRoot->getMachineInstr() == NULL && "Expect dummy root");
// Insert immediate successors of dummy root, which are the actual roots
sg_succ_const_iterator SEnd = succ_end(graphRoot);
for (sg_succ_const_iterator S = succ_begin(graphRoot); S != SEnd; ++S)
this->insertReady(*S);
#undef TEST_HEAP_CONVERSION
#ifdef TEST_HEAP_CONVERSION
std::cerr << "Before heap conversion:\n";
copy(candsAsHeap.begin(), candsAsHeap.end(),
ostream_iterator<NodeDelayPair*>(std::cerr,"\n"));
#endif
candsAsHeap.makeHeap();
nextToTry = candsAsHeap.begin();
#ifdef TEST_HEAP_CONVERSION
std::cerr << "After heap conversion:\n";
copy(candsAsHeap.begin(), candsAsHeap.end(),
ostream_iterator<NodeDelayPair*>(std::cerr,"\n"));
#endif
}
void
SchedPriorities::insertReady(const SchedGraphNode* node) {
candsAsHeap.insert(node, nodeDelayVec[node->getNodeId()]);
candsAsSet.insert(node);
mcands.clear(); // ensure reset choices is called before any more choices
earliestReadyTime = std::min(earliestReadyTime,
getEarliestReadyTimeForNode(node));
if (SchedDebugLevel >= Sched_PrintSchedTrace) {
std::cerr << " Node " << node->getNodeId() << " will be ready in Cycle "
<< getEarliestReadyTimeForNode(node) << "; "
<< " Delay = " <<(long)getNodeDelay(node) << "; Instruction: \n"
<< " " << *node->getMachineInstr() << "\n";
}
}
void
SchedPriorities::issuedReadyNodeAt(CycleCount_t curTime,
const SchedGraphNode* node) {
candsAsHeap.removeNode(node);
candsAsSet.erase(node);
mcands.clear(); // ensure reset choices is called before any more choices
if (earliestReadyTime == getEarliestReadyTimeForNode(node)) {
// earliestReadyTime may have been due to this node, so recompute it
earliestReadyTime = HUGE_LATENCY;
for (NodeHeap::const_iterator I=candsAsHeap.begin();
I != candsAsHeap.end(); ++I)
if (candsAsHeap.getNode(I)) {
earliestReadyTime =
std::min(earliestReadyTime,
getEarliestReadyTimeForNode(candsAsHeap.getNode(I)));
}
}
// Now update ready times for successors
for (SchedGraphNode::const_iterator E=node->beginOutEdges();
E != node->endOutEdges(); ++E) {
CycleCount_t& etime =
getEarliestReadyTimeForNodeRef((SchedGraphNode*)(*E)->getSink());
etime = std::max(etime, curTime + (*E)->getMinDelay());
}
}
//----------------------------------------------------------------------
// Priority ordering rules:
// (1) Max delay, which is the order of the heap S.candsAsHeap.
// (2) Instruction that frees up a register.
// (3) Instruction that has the maximum number of dependent instructions.
// Note that rules 2 and 3 are only used if issue conflicts prevent
// choosing a higher priority instruction by rule 1.
//----------------------------------------------------------------------
inline int
SchedPriorities::chooseByRule1(std::vector<candIndex>& mcands) {
return (mcands.size() == 1)? 0 // only one choice exists so take it
: -1; // -1 indicates multiple choices
}
inline int
SchedPriorities::chooseByRule2(std::vector<candIndex>& mcands) {
assert(mcands.size() >= 1 && "Should have at least one candidate here.");
for (unsigned i=0, N = mcands.size(); i < N; i++)
if (instructionHasLastUse(methodLiveVarInfo,
candsAsHeap.getNode(mcands[i])))
return i;
return -1;
}
inline int
SchedPriorities::chooseByRule3(std::vector<candIndex>& mcands) {
assert(mcands.size() >= 1 && "Should have at least one candidate here.");
int maxUses = candsAsHeap.getNode(mcands[0])->getNumOutEdges();
int indexWithMaxUses = 0;
for (unsigned i=1, N = mcands.size(); i < N; i++) {
int numUses = candsAsHeap.getNode(mcands[i])->getNumOutEdges();
if (numUses > maxUses) {
maxUses = numUses;
indexWithMaxUses = i;
}
}
return indexWithMaxUses;
}
const SchedGraphNode*
SchedPriorities::getNextHighest(const SchedulingManager& S,
CycleCount_t curTime) {
int nextIdx = -1;
const SchedGraphNode* nextChoice = NULL;
if (mcands.size() == 0)
findSetWithMaxDelay(mcands, S);
while (nextIdx < 0 && mcands.size() > 0) {
nextIdx = chooseByRule1(mcands); // rule 1
if (nextIdx == -1)
nextIdx = chooseByRule2(mcands); // rule 2
if (nextIdx == -1)
nextIdx = chooseByRule3(mcands); // rule 3
if (nextIdx == -1)
nextIdx = 0; // default to first choice by delays
// We have found the next best candidate. Check if it ready in
// the current cycle, and if it is feasible.
// If not, remove it from mcands and continue. Refill mcands if
// it becomes empty.
nextChoice = candsAsHeap.getNode(mcands[nextIdx]);
if (getEarliestReadyTimeForNode(nextChoice) > curTime
|| ! instrIsFeasible(S, nextChoice->getMachineInstr()->getOpcode()))
{
mcands.erase(mcands.begin() + nextIdx);
nextIdx = -1;
if (mcands.size() == 0)
findSetWithMaxDelay(mcands, S);
}
}
if (nextIdx >= 0) {
mcands.erase(mcands.begin() + nextIdx);
return nextChoice;
} else
return NULL;
}
void
SchedPriorities::findSetWithMaxDelay(std::vector<candIndex>& mcands,
const SchedulingManager& S)
{
if (mcands.size() == 0 && nextToTry != candsAsHeap.end())
{ // out of choices at current maximum delay;
// put nodes with next highest delay in mcands
candIndex next = nextToTry;
CycleCount_t maxDelay = candsAsHeap.getDelay(next);
for (; next != candsAsHeap.end()
&& candsAsHeap.getDelay(next) == maxDelay; ++next)
mcands.push_back(next);
nextToTry = next;
if (SchedDebugLevel >= Sched_PrintSchedTrace) {
std::cerr << " Cycle " << (long)getTime() << ": "
<< "Next highest delay = " << (long)maxDelay << " : "
<< mcands.size() << " Nodes with this delay: ";
for (unsigned i=0; i < mcands.size(); i++)
std::cerr << candsAsHeap.getNode(mcands[i])->getNodeId() << ", ";
std::cerr << "\n";
}
}
}
bool
SchedPriorities::instructionHasLastUse(FunctionLiveVarInfo &LVI,
const SchedGraphNode* graphNode) {
const MachineInstr *MI = graphNode->getMachineInstr();
hash_map<const MachineInstr*, bool>::const_iterator
ui = lastUseMap.find(MI);
if (ui != lastUseMap.end())
return ui->second;
// else check if instruction is a last use and save it in the hash_map
bool hasLastUse = false;
const BasicBlock* bb = graphNode->getMachineBasicBlock().getBasicBlock();
const ValueSet &LVs = LVI.getLiveVarSetBeforeMInst(MI, bb);
for (MachineInstr::const_val_op_iterator OI = MI->begin(), OE = MI->end();
OI != OE; ++OI)
if (!LVs.count(*OI)) {
hasLastUse = true;
break;
}
return lastUseMap[MI] = hasLastUse;
}
} // End llvm namespace

View File

@ -1,221 +0,0 @@
//===-- SchedPriorities.h - Encapsulate scheduling heuristics --*- 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.
//
//===----------------------------------------------------------------------===//
//
// Strategy:
// Priority ordering rules:
// (1) Max delay, which is the order of the heap S.candsAsHeap.
// (2) Instruction that frees up a register.
// (3) Instruction that has the maximum number of dependent instructions.
// Note that rules 2 and 3 are only used if issue conflicts prevent
// choosing a higher priority instruction by rule 1.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CODEGEN_SCHEDPRIORITIES_H
#define LLVM_CODEGEN_SCHEDPRIORITIES_H
#include "SchedGraph.h"
#include "llvm/CodeGen/InstrScheduling.h"
#include "llvm/Target/TargetSchedInfo.h"
#include "llvm/ADT/hash_set"
#include <list>
namespace llvm {
class Function;
class MachineInstr;
class SchedulingManager;
class FunctionLiveVarInfo;
//---------------------------------------------------------------------------
// Debug option levels for instruction scheduling
enum SchedDebugLevel_t {
Sched_NoDebugInfo,
Sched_Disable,
Sched_PrintMachineCode,
Sched_PrintSchedTrace,
Sched_PrintSchedGraphs,
};
extern SchedDebugLevel_t SchedDebugLevel;
//---------------------------------------------------------------------------
// Function: instrIsFeasible
//
// Purpose:
// Used by the priority analysis to filter out instructions
// that are not feasible to issue in the current cycle.
// Should only be used during schedule construction..
//---------------------------------------------------------------------------
bool instrIsFeasible(const SchedulingManager &S, MachineOpCode opCode);
struct NodeDelayPair {
const SchedGraphNode* node;
CycleCount_t delay;
NodeDelayPair(const SchedGraphNode* n, CycleCount_t d) : node(n), delay(d) {}
inline bool operator<(const NodeDelayPair& np) { return delay < np.delay; }
};
inline bool
NDPLessThan(const NodeDelayPair* np1, const NodeDelayPair* np2)
{
return np1->delay < np2->delay;
}
class NodeHeap : public std::list<NodeDelayPair*> {
NodeHeap(const NodeHeap&); // DO NOT IMPLEMENT
void operator=(const NodeHeap&); // DO NOT IMPLEMENT
public:
typedef std::list<NodeDelayPair*>::iterator iterator;
typedef std::list<NodeDelayPair*>::const_iterator const_iterator;
public:
NodeHeap() : _size(0) {}
inline unsigned size() const { return _size; }
const SchedGraphNode* getNode (const_iterator i) const { return (*i)->node; }
CycleCount_t getDelay(const_iterator i) const { return (*i)->delay;}
inline void makeHeap() {
// make_heap(begin(), end(), NDPLessThan);
}
inline iterator findNode(const SchedGraphNode* node) {
for (iterator I=begin(); I != end(); ++I)
if (getNode(I) == node)
return I;
return end();
}
inline void removeNode (const SchedGraphNode* node) {
iterator ndpPtr = findNode(node);
if (ndpPtr != end())
{
delete *ndpPtr;
erase(ndpPtr);
--_size;
}
};
void insert(const SchedGraphNode* node, CycleCount_t delay) {
NodeDelayPair* ndp = new NodeDelayPair(node, delay);
if (_size == 0 || front()->delay < delay)
push_front(ndp);
else
{
iterator I=begin();
for ( ; I != end() && getDelay(I) >= delay; ++I)
;
std::list<NodeDelayPair*>::insert(I, ndp);
}
_size++;
}
private:
unsigned int _size;
};
class SchedPriorities {
SchedPriorities(const SchedPriorities&); // DO NOT IMPLEMENT
void operator=(const SchedPriorities &); // DO NOT IMPLEMENT
public:
SchedPriorities(const Function *F, const SchedGraph *G,
FunctionLiveVarInfo &LVI);
// This must be called before scheduling begins.
void initialize ();
CycleCount_t getTime () const { return curTime; }
CycleCount_t getEarliestReadyTime () const { return earliestReadyTime; }
unsigned getNumReady () const { return candsAsHeap.size(); }
bool nodeIsReady (const SchedGraphNode* node) const {
return (candsAsSet.find(node) != candsAsSet.end());
}
void issuedReadyNodeAt (CycleCount_t curTime,
const SchedGraphNode* node);
void insertReady (const SchedGraphNode* node);
void updateTime (CycleCount_t /*unused*/);
const SchedGraphNode* getNextHighest (const SchedulingManager& S,
CycleCount_t curTime);
// choose next highest priority instr
private:
typedef NodeHeap::iterator candIndex;
private:
CycleCount_t curTime;
const SchedGraph* graph;
FunctionLiveVarInfo &methodLiveVarInfo;
hash_map<const MachineInstr*, bool> lastUseMap;
std::vector<CycleCount_t> nodeDelayVec;
std::vector<CycleCount_t> nodeEarliestUseVec;
std::vector<CycleCount_t> earliestReadyTimeForNode;
CycleCount_t earliestReadyTime;
NodeHeap candsAsHeap; // candidate nodes, ready to go
hash_set<const SchedGraphNode*> candsAsSet; //same entries as candsAsHeap,
// but as set for fast lookup
std::vector<candIndex> mcands; // holds pointers into cands
candIndex nextToTry; // next cand after the last
// one tried in this cycle
int chooseByRule1 (std::vector<candIndex>& mcands);
int chooseByRule2 (std::vector<candIndex>& mcands);
int chooseByRule3 (std::vector<candIndex>& mcands);
void findSetWithMaxDelay (std::vector<candIndex>& mcands,
const SchedulingManager& S);
void computeDelays (const SchedGraph* graph);
void initializeReadyHeap (const SchedGraph* graph);
bool instructionHasLastUse (FunctionLiveVarInfo& LVI,
const SchedGraphNode* graphNode);
// NOTE: The next two return references to the actual vector entries.
// Use the following two if you don't need to modify the value.
CycleCount_t& getNodeDelayRef (const SchedGraphNode* node) {
assert(node->getNodeId() < nodeDelayVec.size());
return nodeDelayVec[node->getNodeId()];
}
CycleCount_t& getEarliestReadyTimeForNodeRef (const SchedGraphNode* node) {
assert(node->getNodeId() < earliestReadyTimeForNode.size());
return earliestReadyTimeForNode[node->getNodeId()];
}
CycleCount_t getNodeDelay (const SchedGraphNode* node) const {
return ((SchedPriorities*) this)->getNodeDelayRef(node);
}
CycleCount_t getEarliestReadyTimeForNode(const SchedGraphNode* node) const {
return ((SchedPriorities*) this)->getEarliestReadyTimeForNodeRef(node);
}
};
inline void SchedPriorities::updateTime(CycleCount_t c) {
curTime = c;
nextToTry = candsAsHeap.begin();
mcands.clear();
}
std::ostream &operator<<(std::ostream &os, const NodeDelayPair* nd);
} // End llvm namespace
#endif

View File

@ -1,82 +0,0 @@
//===-- InternalGlobalMapper.cpp - Mapping Info for Internal Globals ------===//
//
// 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.
//
//===----------------------------------------------------------------------===//
//
// InternalGlobalMapper is a pass that helps the runtime trace optimizer map
// the names of internal GlobalValues (which may have mangled,
// unreconstructible names in the executable) to pointers. If the name mangler
// is changed at some point in the future to allow its results to be
// reconstructible (for instance, by making the type mangling symbolic instead
// of using a UniqueID) this pass should probably be phased out.
//
//===----------------------------------------------------------------------===//
#include "llvm/Constants.h"
#include "llvm/Module.h"
#include "llvm/Pass.h"
#include "llvm/DerivedTypes.h"
using namespace llvm;
typedef std::vector<Constant *> GVVectorTy;
namespace {
struct InternalGlobalMapper : public ModulePass {
bool runOnModule(Module &M);
};
}
namespace llvm {
ModulePass *createInternalGlobalMapperPass() {
return new InternalGlobalMapper();
}
}
static void maybeAddInternalValueToVector (GVVectorTy &Vector, GlobalValue &GV){
// If it's a GlobalValue with internal linkage and a name (i.e. it's going to
// be mangled), then put the GV, casted to sbyte*, in the vector. Otherwise
// add a null.
if (GV.hasInternalLinkage () && GV.hasName ())
Vector.push_back(ConstantExpr::getCast(&GV,
PointerType::get(Type::SByteTy)));
else
Vector.push_back (ConstantPointerNull::get (PointerType::get
(Type::SByteTy)));
}
bool InternalGlobalMapper::runOnModule(Module &M) {
GVVectorTy gvvector;
// Populate the vector with internal global values and their names.
for (Module::global_iterator i = M.global_begin (), e = M.global_end (); i != e; ++i)
maybeAddInternalValueToVector (gvvector, *i);
// Add an extra global for _llvm_internalGlobals itself (null,
// because it's not internal)
gvvector.push_back (ConstantPointerNull::get
(PointerType::get (Type::SByteTy)));
for (Module::iterator i = M.begin (), e = M.end (); i != e; ++i)
maybeAddInternalValueToVector (gvvector, *i);
// Convert the vector to a constant struct of type {Size, [Size x sbyte*]}.
ArrayType *ATy = ArrayType::get (PointerType::get (Type::SByteTy),
gvvector.size ());
std::vector<const Type *> FieldTypes;
FieldTypes.push_back (Type::UIntTy);
FieldTypes.push_back (ATy);
StructType *STy = StructType::get (FieldTypes);
std::vector<Constant *> FieldValues;
FieldValues.push_back (ConstantUInt::get (Type::UIntTy, gvvector.size ()));
FieldValues.push_back (ConstantArray::get (ATy, gvvector));
// Add the constant struct to M as an external global symbol named
// "_llvm_internalGlobals".
new GlobalVariable (STy, true, GlobalValue::ExternalLinkage,
ConstantStruct::get (STy, FieldValues),
"_llvm_internalGlobals", &M);
return true; // Module was modified.
}

View File

@ -1,233 +0,0 @@
//===-- BBLiveVar.cpp - Live Variable Analysis for a BasicBlock -----------===//
//
// 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 is a wrapper class for BasicBlock which is used by live var analysis.
//
//===----------------------------------------------------------------------===//
#include "BBLiveVar.h"
#include "FunctionLiveVarInfo.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/Support/CFG.h"
#include "llvm/ADT/SetOperations.h"
#include "../SparcV9Internals.h"
#include <iostream>
namespace llvm {
BBLiveVar::BBLiveVar(const BasicBlock &bb,
const MachineBasicBlock &mbb,
unsigned id)
: BB(bb), MBB(mbb), POID(id) {
InSetChanged = OutSetChanged = false;
calcDefUseSets();
}
//-----------------------------------------------------------------------------
// calculates def and use sets for each BB
// There are two passes over operands of a machine instruction. This is
// because, we can have instructions like V = V + 1, since we no longer
// assume single definition.
//-----------------------------------------------------------------------------
void BBLiveVar::calcDefUseSets() {
// iterate over all the machine instructions in BB
for (MachineBasicBlock::const_reverse_iterator MII = MBB.rbegin(),
MIE = MBB.rend(); MII != MIE; ++MII) {
const MachineInstr *MI = &*MII;
if (DEBUG_LV >= LV_DEBUG_Verbose) {
std::cerr << " *Iterating over machine instr ";
MI->dump();
std::cerr << "\n";
}
// iterate over MI operands to find defs
for (MachineInstr::const_val_op_iterator OpI = MI->begin(), OpE = MI->end();
OpI != OpE; ++OpI)
if (OpI.isDef()) // add to Defs if this operand is a def
addDef(*OpI);
// do for implicit operands as well
for (unsigned i = 0; i < MI->getNumImplicitRefs(); ++i)
if (MI->getImplicitOp(i).isDef())
addDef(MI->getImplicitRef(i));
// iterate over MI operands to find uses
for (MachineInstr::const_val_op_iterator OpI = MI->begin(), OpE = MI->end();
OpI != OpE; ++OpI) {
const Value *Op = *OpI;
if (isa<BasicBlock>(Op))
continue; // don't process labels
if (OpI.isUse()) { // add to Uses only if this operand is a use
//
// *** WARNING: The following code for handling dummy PHI machine
// instructions is untested. The previous code was broken and I
// fixed it, but it turned out to be unused as long as Phi
// elimination is performed during instruction selection.
//
// Put Phi operands in UseSet for the incoming edge, not node.
// They must not "hide" later defs, and must be handled specially
// during set propagation over the CFG.
if (MI->getOpcode() == V9::PHI) { // for a phi node
const Value *ArgVal = Op;
const BasicBlock *PredBB = cast<BasicBlock>(*++OpI); // next ptr is BB
PredToEdgeInSetMap[PredBB].insert(ArgVal);
if (DEBUG_LV >= LV_DEBUG_Verbose)
std::cerr << " - phi operand " << RAV(ArgVal) << " came from BB "
<< RAV(PredBB) << "\n";
} // if( IsPhi )
else {
// It is not a Phi use: add to regular use set and remove later defs.
addUse(Op);
}
} // if a use
} // for all operands
// do for implicit operands as well
for (unsigned i = 0; i < MI->getNumImplicitRefs(); ++i) {
assert(MI->getOpcode() != V9::PHI && "Phi cannot have implicit operands");
const Value *Op = MI->getImplicitRef(i);
if (Op->getType() == Type::LabelTy) // don't process labels
continue;
if (MI->getImplicitOp(i).isUse())
addUse(Op);
}
} // for all machine instructions
}
//-----------------------------------------------------------------------------
// To add an operand which is a def
//-----------------------------------------------------------------------------
void BBLiveVar::addDef(const Value *Op) {
DefSet.insert(Op); // operand is a def - so add to def set
InSet.erase(Op); // this definition kills any later uses
InSetChanged = true;
if (DEBUG_LV >= LV_DEBUG_Verbose) std::cerr << " +Def: " << RAV(Op) << "\n";
}
//-----------------------------------------------------------------------------
// To add an operand which is a use
//-----------------------------------------------------------------------------
void BBLiveVar::addUse(const Value *Op) {
InSet.insert(Op); // An operand is a use - so add to use set
DefSet.erase(Op); // remove if there is a def below this use
InSetChanged = true;
if (DEBUG_LV >= LV_DEBUG_Verbose) std::cerr << " Use: " << RAV(Op) << "\n";
}
//-----------------------------------------------------------------------------
// Applies the transfer function to a basic block to produce the InSet using
// the OutSet.
//-----------------------------------------------------------------------------
bool BBLiveVar::applyTransferFunc() {
// IMPORTANT: caller should check whether the OutSet changed
// (else no point in calling)
ValueSet OutMinusDef = set_difference(OutSet, DefSet);
InSetChanged = set_union(InSet, OutMinusDef);
OutSetChanged = false; // no change to OutSet since transf func applied
return InSetChanged;
}
//-----------------------------------------------------------------------------
// calculates Out set using In sets of the successors
//-----------------------------------------------------------------------------
bool BBLiveVar::setPropagate(ValueSet *OutSet, const ValueSet *InSet,
const BasicBlock *PredBB) {
bool Changed = false;
// merge all members of InSet into OutSet of the predecessor
for (ValueSet::const_iterator InIt = InSet->begin(), InE = InSet->end();
InIt != InE; ++InIt)
if ((OutSet->insert(*InIt)).second)
Changed = true;
//
//**** WARNING: The following code for handling dummy PHI machine
// instructions is untested. See explanation above.
//
// then merge all members of the EdgeInSet for the predecessor into the OutSet
const ValueSet& EdgeInSet = PredToEdgeInSetMap[PredBB];
for (ValueSet::const_iterator InIt = EdgeInSet.begin(), InE = EdgeInSet.end();
InIt != InE; ++InIt)
if ((OutSet->insert(*InIt)).second)
Changed = true;
//
//****
return Changed;
}
//-----------------------------------------------------------------------------
// propagates in set to OutSets of PREDECESSORs
//-----------------------------------------------------------------------------
bool BBLiveVar::applyFlowFunc(hash_map<const BasicBlock*,
BBLiveVar*> &BBLiveVarInfo) {
// IMPORTANT: caller should check whether inset changed
// (else no point in calling)
// If this BB changed any OutSets of preds whose POID is lower, than we need
// another iteration...
//
bool needAnotherIt = false;
for (pred_const_iterator PI = pred_begin(&BB), PE = pred_end(&BB);
PI != PE ; ++PI) {
BBLiveVar *PredLVBB = BBLiveVarInfo[*PI];
// do set union
if (setPropagate(&PredLVBB->OutSet, &InSet, *PI)) {
PredLVBB->OutSetChanged = true;
// if the predec POID is lower than mine
if (PredLVBB->getPOId() <= POID)
needAnotherIt = true;
}
} // for
return needAnotherIt;
}
// ----------------- Methods For Debugging (Printing) -----------------
void BBLiveVar::printAllSets() const {
std::cerr << " Defs: "; printSet(DefSet); std::cerr << "\n";
std::cerr << " In: "; printSet(InSet); std::cerr << "\n";
std::cerr << " Out: "; printSet(OutSet); std::cerr << "\n";
}
void BBLiveVar::printInOutSets() const {
std::cerr << " In: "; printSet(InSet); std::cerr << "\n";
std::cerr << " Out: "; printSet(OutSet); std::cerr << "\n";
}
} // End llvm namespace

View File

@ -1,90 +0,0 @@
//===-- BBLiveVar.h - Live Variable Analysis for a BasicBlock ---*- 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 is a BasicBlock annotation class that is used by live var analysis to
// hold data flow information for a basic block.
//
//===----------------------------------------------------------------------===//
#ifndef LIVE_VAR_BB_H
#define LIVE_VAR_BB_H
#include "llvm/CodeGen/ValueSet.h"
#include "llvm/ADT/hash_map"
namespace llvm {
class BasicBlock;
class Value;
class MachineBasicBlock;
enum LiveVarDebugLevel_t {
LV_DEBUG_None,
LV_DEBUG_Normal,
LV_DEBUG_Instr,
LV_DEBUG_Verbose
};
extern LiveVarDebugLevel_t DEBUG_LV;
class BBLiveVar {
const BasicBlock &BB; // pointer to BasicBlock
const MachineBasicBlock &MBB; // Pointer to MachineBasicBlock
unsigned POID; // Post-Order ID
ValueSet DefSet; // Def set (with no preceding uses) for LV analysis
ValueSet InSet, OutSet; // In & Out for LV analysis
bool InSetChanged, OutSetChanged; // set if the InSet/OutSet is modified
// map that contains PredBB -> Phi arguments
// coming in on that edge. such uses have to be
// treated differently from ordinary uses.
hash_map<const BasicBlock *, ValueSet> PredToEdgeInSetMap;
// method to propagate an InSet to OutSet of a predecessor
bool setPropagate(ValueSet *OutSetOfPred,
const ValueSet *InSetOfThisBB,
const BasicBlock *PredBB);
// To add an operand which is a def
void addDef(const Value *Op);
// To add an operand which is a use
void addUse(const Value *Op);
void calcDefUseSets(); // calculates the Def & Use sets for this BB
public:
BBLiveVar(const BasicBlock &BB, const MachineBasicBlock &MBB, unsigned POID);
inline bool isInSetChanged() const { return InSetChanged; }
inline bool isOutSetChanged() const { return OutSetChanged; }
const MachineBasicBlock &getMachineBasicBlock() const { return MBB; }
inline unsigned getPOId() const { return POID; }
bool applyTransferFunc(); // calcultes the In in terms of Out
// calculates Out set using In sets of the predecessors
bool applyFlowFunc(hash_map<const BasicBlock*, BBLiveVar*> &BBLiveVarInfo);
inline const ValueSet &getOutSet() const { return OutSet; }
inline ValueSet &getOutSet() { return OutSet; }
inline const ValueSet &getInSet() const { return InSet; }
inline ValueSet &getInSet() { return InSet; }
void printAllSets() const; // for printing Def/In/Out sets
void printInOutSets() const; // for printing In/Out sets
};
} // End llvm namespace
#endif

View File

@ -1,323 +0,0 @@
//===-- FunctionLiveVarInfo.cpp - Live Variable Analysis for a Function ---===//
//
// 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 is the interface to function level live variable information that is
// provided by live variable analysis.
//
//===----------------------------------------------------------------------===//
#include "FunctionLiveVarInfo.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Support/CFG.h"
#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/ADT/SetOperations.h"
#include "llvm/Support/CommandLine.h"
#include "BBLiveVar.h"
#include <iostream>
namespace llvm {
static RegisterAnalysis<FunctionLiveVarInfo>
X("livevar", "Live Variable Analysis");
LiveVarDebugLevel_t DEBUG_LV;
static cl::opt<LiveVarDebugLevel_t, true>
DEBUG_LV_opt("dlivevar", cl::Hidden, cl::location(DEBUG_LV),
cl::desc("enable live-variable debugging information"),
cl::values(
clEnumValN(LV_DEBUG_None , "n", "disable debug output"),
clEnumValN(LV_DEBUG_Normal , "y", "enable debug output"),
clEnumValN(LV_DEBUG_Instr, "i", "print live-var sets before/after "
"every machine instrn"),
clEnumValN(LV_DEBUG_Verbose, "v", "print def, use sets for every instrn also"),
clEnumValEnd));
//-----------------------------------------------------------------------------
// Accessor Functions
//-----------------------------------------------------------------------------
// gets OutSet of a BB
const ValueSet &FunctionLiveVarInfo::getOutSetOfBB(const BasicBlock *BB) const {
return BBLiveVarInfo.find(BB)->second->getOutSet();
}
ValueSet &FunctionLiveVarInfo::getOutSetOfBB(const BasicBlock *BB) {
return BBLiveVarInfo[BB]->getOutSet();
}
// gets InSet of a BB
const ValueSet &FunctionLiveVarInfo::getInSetOfBB(const BasicBlock *BB) const {
return BBLiveVarInfo.find(BB)->second->getInSet();
}
ValueSet &FunctionLiveVarInfo::getInSetOfBB(const BasicBlock *BB) {
return BBLiveVarInfo[BB]->getInSet();
}
//-----------------------------------------------------------------------------
// Performs live var analysis for a function
//-----------------------------------------------------------------------------
bool FunctionLiveVarInfo::runOnFunction(Function &F) {
M = &F;
if (DEBUG_LV) std::cerr << "Analysing live variables ...\n";
// create and initialize all the BBLiveVars of the CFG
constructBBs(M);
unsigned int iter=0;
while (doSingleBackwardPass(M, iter++))
; // Iterate until we are done.
if (DEBUG_LV) std::cerr << "Live Variable Analysis complete!\n";
return false;
}
//-----------------------------------------------------------------------------
// constructs BBLiveVars and init Def and In sets
//-----------------------------------------------------------------------------
void FunctionLiveVarInfo::constructBBs(const Function *F) {
unsigned POId = 0; // Reverse Depth-first Order ID
std::map<const BasicBlock*, unsigned> PONumbering;
for (po_iterator<const Function*> BBI = po_begin(M), BBE = po_end(M);
BBI != BBE; ++BBI)
PONumbering[*BBI] = POId++;
MachineFunction &MF = MachineFunction::get(F);
for (MachineFunction::iterator I = MF.begin(), E = MF.end(); I != E; ++I) {
const BasicBlock &BB = *I->getBasicBlock(); // get the current BB
if (DEBUG_LV) std::cerr << " For BB " << RAV(BB) << ":\n";
BBLiveVar *LVBB;
std::map<const BasicBlock*, unsigned>::iterator POI = PONumbering.find(&BB);
if (POI != PONumbering.end()) {
// create a new BBLiveVar
LVBB = new BBLiveVar(BB, *I, POId);
} else {
// The PO iterator does not discover unreachable blocks, but the random
// iterator later may access these blocks. We must make sure to
// initialize unreachable blocks as well. However, LV info is not correct
// for those blocks (they are not analyzed)
//
LVBB = new BBLiveVar(BB, *I, ++POId);
}
BBLiveVarInfo[&BB] = LVBB;
if (DEBUG_LV)
LVBB->printAllSets();
}
}
//-----------------------------------------------------------------------------
// do one backward pass over the CFG (for iterative analysis)
//-----------------------------------------------------------------------------
bool FunctionLiveVarInfo::doSingleBackwardPass(const Function *M,
unsigned iter) {
if (DEBUG_LV) std::cerr << "\n After Backward Pass " << iter << "...\n";
bool NeedAnotherIteration = false;
for (po_iterator<const Function*> BBI = po_begin(M), BBE = po_end(M);
BBI != BBE; ++BBI) {
BBLiveVar *LVBB = BBLiveVarInfo[*BBI];
assert(LVBB && "BasicBlock information not set for block!");
if (DEBUG_LV) std::cerr << " For BB " << (*BBI)->getName() << ":\n";
// InSets are initialized to "GenSet". Recompute only if OutSet changed.
if(LVBB->isOutSetChanged())
LVBB->applyTransferFunc(); // apply the Tran Func to calc InSet
// OutSets are initialized to EMPTY. Recompute on first iter or if InSet
// changed.
if (iter == 0 || LVBB->isInSetChanged()) // to calc Outsets of preds
NeedAnotherIteration |= LVBB->applyFlowFunc(BBLiveVarInfo);
if (DEBUG_LV) LVBB->printInOutSets();
}
// true if we need to reiterate over the CFG
return NeedAnotherIteration;
}
void FunctionLiveVarInfo::releaseMemory() {
// First remove all BBLiveVars created in constructBBs().
if (M) {
for (Function::const_iterator I = M->begin(), E = M->end(); I != E; ++I)
delete BBLiveVarInfo[I];
BBLiveVarInfo.clear();
}
M = 0;
// Then delete all objects of type ValueSet created in calcLiveVarSetsForBB
// and entered into MInst2LVSetBI and MInst2LVSetAI (these are caches
// to return ValueSet's before/after a machine instruction quickly).
// We do not need to free up ValueSets in MInst2LVSetAI because it holds
// pointers to the same sets as in MInst2LVSetBI (for all instructions
// except the last one in a BB) or in BBLiveVar (for the last instruction).
//
for (hash_map<const MachineInstr*, ValueSet*>::iterator
MI = MInst2LVSetBI.begin(),
ME = MInst2LVSetBI.end(); MI != ME; ++MI)
delete MI->second; // delete all ValueSets in MInst2LVSetBI
MInst2LVSetBI.clear();
MInst2LVSetAI.clear();
}
//-----------------------------------------------------------------------------
// Following functions will give the LiveVar info for any machine instr in
// a function. It should be called after a call to analyze().
//
// These functions calculate live var info for all the machine instrs in a
// BB when LVInfo for one inst is requested. Hence, this function is useful
// when live var info is required for many (or all) instructions in a basic
// block. Also, the arguments to this function does not require specific
// iterators.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Gives live variable information before a machine instruction
//-----------------------------------------------------------------------------
const ValueSet &
FunctionLiveVarInfo::getLiveVarSetBeforeMInst(const MachineInstr *MI,
const BasicBlock *BB) {
ValueSet* &LVSet = MInst2LVSetBI[MI]; // ref. to map entry
if (LVSet == NULL && BB != NULL) { // if not found and BB provided
calcLiveVarSetsForBB(BB); // calc LVSet for all instrs in BB
assert(LVSet != NULL);
}
return *LVSet;
}
//-----------------------------------------------------------------------------
// Gives live variable information after a machine instruction
//-----------------------------------------------------------------------------
const ValueSet &
FunctionLiveVarInfo::getLiveVarSetAfterMInst(const MachineInstr *MI,
const BasicBlock *BB) {
ValueSet* &LVSet = MInst2LVSetAI[MI]; // ref. to map entry
if (LVSet == NULL && BB != NULL) { // if not found and BB provided
calcLiveVarSetsForBB(BB); // calc LVSet for all instrs in BB
assert(LVSet != NULL);
}
return *LVSet;
}
// This function applies a machine instr to a live var set (accepts OutSet) and
// makes necessary changes to it (produces InSet). Note that two for loops are
// used to first kill all defs and then to add all uses. This is because there
// can be instructions like Val = Val + 1 since we allow multiple defs to a
// machine instruction operand.
//
static void applyTranferFuncForMInst(ValueSet &LVS, const MachineInstr *MInst) {
for (MachineInstr::const_val_op_iterator OpI = MInst->begin(),
OpE = MInst->end(); OpI != OpE; ++OpI) {
if (OpI.isDef()) // kill if this operand is a def
LVS.erase(*OpI); // this definition kills any uses
}
// do for implicit operands as well
for (unsigned i=0; i < MInst->getNumImplicitRefs(); ++i) {
if (MInst->getImplicitOp(i).isDef())
LVS.erase(MInst->getImplicitRef(i));
}
for (MachineInstr::const_val_op_iterator OpI = MInst->begin(),
OpE = MInst->end(); OpI != OpE; ++OpI) {
if (!isa<BasicBlock>(*OpI)) // don't process labels
// add only if this operand is a use
if (OpI.isUse())
LVS.insert(*OpI); // An operand is a use - so add to use set
}
// do for implicit operands as well
for (unsigned i = 0, e = MInst->getNumImplicitRefs(); i != e; ++i)
if (MInst->getImplicitOp(i).isUse())
LVS.insert(MInst->getImplicitRef(i));
}
//-----------------------------------------------------------------------------
// This method calculates the live variable information for all the
// instructions in a basic block and enter the newly constructed live
// variable sets into a the caches (MInst2LVSetAI, MInst2LVSetBI)
//-----------------------------------------------------------------------------
void FunctionLiveVarInfo::calcLiveVarSetsForBB(const BasicBlock *BB) {
BBLiveVar *BBLV = BBLiveVarInfo[BB];
assert(BBLV && "BBLiveVar annotation doesn't exist?");
const MachineBasicBlock &MIVec = BBLV->getMachineBasicBlock();
const MachineFunction &MF = MachineFunction::get(M);
const TargetMachine &TM = MF.getTarget();
if (DEBUG_LV >= LV_DEBUG_Instr)
std::cerr << "\n======For BB " << BB->getName()
<< ": Live var sets for instructions======\n";
ValueSet *SetAI = &getOutSetOfBB(BB); // init SetAI with OutSet
ValueSet CurSet(*SetAI); // CurSet now contains OutSet
// iterate over all the machine instructions in BB
for (MachineBasicBlock::const_reverse_iterator MII = MIVec.rbegin(),
MIE = MIVec.rend(); MII != MIE; ++MII) {
// MI is cur machine inst
const MachineInstr *MI = &*MII;
MInst2LVSetAI[MI] = SetAI; // record in After Inst map
applyTranferFuncForMInst(CurSet, MI); // apply the transfer Func
ValueSet *NewSet = new ValueSet(CurSet); // create a new set with a copy
// of the set after T/F
MInst2LVSetBI[MI] = NewSet; // record in Before Inst map
// If the current machine instruction has delay slots, mark values
// used by this instruction as live before and after each delay slot
// instruction (After(MI) is the same as Before(MI+1) except for last MI).
if (unsigned DS = TM.getInstrInfo()->getNumDelaySlots(MI->getOpcode())) {
MachineBasicBlock::const_iterator fwdMII = MII.base(); // ptr to *next* MI
for (unsigned i = 0; i < DS; ++i, ++fwdMII) {
assert(fwdMII != MIVec.end() && "Missing instruction in delay slot?");
const MachineInstr* DelaySlotMI = fwdMII;
if (! TM.getInstrInfo()->isNop(DelaySlotMI->getOpcode())) {
set_union(*MInst2LVSetBI[DelaySlotMI], *NewSet);
if (i+1 == DS)
set_union(*MInst2LVSetAI[DelaySlotMI], *NewSet);
}
}
}
if (DEBUG_LV >= LV_DEBUG_Instr) {
std::cerr << "\nLive var sets before/after instruction " << *MI;
std::cerr << " Before: "; printSet(*NewSet); std::cerr << "\n";
std::cerr << " After : "; printSet(*SetAI); std::cerr << "\n";
}
// SetAI will be used in the next iteration
SetAI = NewSet;
}
}
} // End llvm namespace

View File

@ -1,111 +0,0 @@
//===-- CodeGen/FunctionLiveVarInfo.h - LiveVar Analysis --------*- 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 is the interface for live variable info of a function that is required
// by any other part of the compiler
//
// After the analysis, getInSetOfBB or getOutSetofBB can be called to get
// live var info of a BB.
//
// The live var set before an instruction can be obtained in 2 ways:
//
// 1. Use the method getLiveVarSetAfterInst(Instruction *) to get the LV Info
// just after an instruction. (also exists getLiveVarSetBeforeInst(..))
//
// This function caluclates the LV info for a BB only once and caches that
// info. If the cache does not contain the LV info of the instruction, it
// calculates the LV info for the whole BB and caches them.
//
// Getting liveVar info this way uses more memory since, LV info should be
// cached. However, if you need LV info of nearly all the instructions of a
// BB, this is the best and simplest interfrace.
//
// 2. Use the OutSet and applyTranferFuncForInst(const Instruction *const Inst)
// declared in LiveVarSet and traverse the instructions of a basic block in
// reverse (using const_reverse_iterator in the BB class).
//
//===----------------------------------------------------------------------===//
#ifndef FUNCTION_LIVE_VAR_INFO_H
#define FUNCTION_LIVE_VAR_INFO_H
#include "llvm/ADT/hash_map"
#include "llvm/Pass.h"
#include "llvm/CodeGen/ValueSet.h"
namespace llvm {
class BBLiveVar;
class MachineInstr;
class FunctionLiveVarInfo : public FunctionPass {
// Machine Instr to LiveVarSet Map for providing LVset BEFORE each inst
// These sets are owned by this map and will be freed in releaseMemory().
hash_map<const MachineInstr *, ValueSet *> MInst2LVSetBI;
// Machine Instr to LiveVarSet Map for providing LVset AFTER each inst.
// These sets are just pointers to sets in MInst2LVSetBI or BBLiveVar.
hash_map<const MachineInstr *, ValueSet *> MInst2LVSetAI;
hash_map<const BasicBlock*, BBLiveVar*> BBLiveVarInfo;
// Stored Function that the data is computed with respect to
const Function *M;
// --------- private methods -----------------------------------------
// constructs BBLiveVars and init Def and In sets
void constructBBs(const Function *F);
// do one backward pass over the CFG
bool doSingleBackwardPass(const Function *F, unsigned int iter);
// calculates live var sets for instructions in a BB
void calcLiveVarSetsForBB(const BasicBlock *BB);
public:
// --------- Implement the FunctionPass interface ----------------------
// runOnFunction - Perform analysis, update internal data structures.
virtual bool runOnFunction(Function &F);
// releaseMemory - After LiveVariable analysis has been used, forget!
virtual void releaseMemory();
// getAnalysisUsage - Provide self!
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
AU.setPreservesAll();
}
// --------- Functions to access analysis results -------------------
// get OutSet of a BB
const ValueSet &getOutSetOfBB(const BasicBlock *BB) const;
ValueSet &getOutSetOfBB(const BasicBlock *BB) ;
// get InSet of a BB
const ValueSet &getInSetOfBB(const BasicBlock *BB) const;
ValueSet &getInSetOfBB(const BasicBlock *BB) ;
// gets the Live var set BEFORE an instruction.
// if BB is specified and the live var set has not yet been computed,
// it will be computed on demand.
const ValueSet &getLiveVarSetBeforeMInst(const MachineInstr *MI,
const BasicBlock *BB = 0);
// gets the Live var set AFTER an instruction
// if BB is specified and the live var set has not yet been computed,
// it will be computed on demand.
const ValueSet &getLiveVarSetAfterMInst(const MachineInstr *MI,
const BasicBlock *BB = 0);
};
} // End llvm namespace
#endif

View File

@ -1,14 +0,0 @@
##===- lib/Target/Sparc/LiveVar/Makefile -------------------*- Makefile -*-===##
#
# 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.
#
##===----------------------------------------------------------------------===##
LEVEL = ../../../..
LIBRARYNAME = LLVMSparcV9LiveVar
include $(LEVEL)/Makefile.common

View File

@ -1,31 +0,0 @@
//
// 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.
//
//===----------------------------------------------------------------------===//
// FIXME: Eliminate this file.
#include "llvm/CodeGen/ValueSet.h"
#include "llvm/Value.h"
#include <iostream>
namespace llvm {
std::ostream &operator<<(std::ostream &O, RAV V) { // func to print a Value
const Value &v = V.V;
if (v.hasName())
return O << (void*)&v << "(" << v.getName() << ") ";
else if (isa<Constant>(v) && !isa<GlobalValue>(v))
return O << (void*)&v << "(" << v << ") ";
else
return O << (void*)&v << " ";
}
void printSet(const ValueSet &S) {
for (ValueSet::const_iterator I = S.begin(), E = S.end(); I != E; ++I)
std::cerr << RAV(*I);
}
} // End llvm namespace

View File

@ -1,116 +0,0 @@
//===-- MachineCodeForInstruction.cpp -------------------------------------===//
//
// 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.
//
//===----------------------------------------------------------------------===//
//
// Container for the sequence of MachineInstrs created for a single
// LLVM Instruction. MachineCodeForInstruction also tracks temporary values
// (TmpInstruction objects) created during SparcV9 code generation, so that
// they can be deleted when they are no longer needed, and finally, it also
// holds some extra information for 'call' Instructions (using the
// CallArgsDescriptor object, which is also implemented in this file).
//
//===----------------------------------------------------------------------===//
#include "MachineCodeForInstruction.h"
#include "llvm/Function.h"
#include "llvm/Instructions.h"
#include "llvm/Type.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "MachineFunctionInfo.h"
#include "MachineInstrAnnot.h"
#include "SparcV9TmpInstr.h"
#include "SparcV9RegisterInfo.h"
using namespace llvm;
MachineCodeForInstruction &MachineCodeForInstruction::get(const Instruction *I){
MachineFunction &MF = MachineFunction::get(I->getParent()->getParent());
return MF.getInfo<SparcV9FunctionInfo>()->MCFIEntries[I];
}
void MachineCodeForInstruction::destroy(const Instruction *I) {
MachineFunction &MF = MachineFunction::get(I->getParent()->getParent());
MF.getInfo<SparcV9FunctionInfo>()->MCFIEntries.erase(I);
}
void MachineCodeForInstruction::dropAllReferences() {
for (unsigned i=0, N=tempVec.size(); i < N; i++)
cast<Instruction>(tempVec[i])->dropAllReferences();
}
MachineCodeForInstruction::~MachineCodeForInstruction() {
// Let go of all uses in temp. instructions
dropAllReferences();
// Free the Value objects created to hold intermediate values
for (unsigned i=0, N=tempVec.size(); i < N; i++)
delete tempVec[i];
// do not free the MachineInstr objects allocated. they are managed
// by the ilist in MachineBasicBlock
// Free the CallArgsDescriptor if it exists.
delete callArgsDesc;
}
CallArgsDescriptor::CallArgsDescriptor(CallInst* _callInstr,
TmpInstruction* _retAddrReg,
bool _isVarArgs, bool _noPrototype)
: callInstr(_callInstr),
funcPtr(isa<Function>(_callInstr->getCalledValue())
? NULL : _callInstr->getCalledValue()),
retAddrReg(_retAddrReg),
isVarArgs(_isVarArgs),
noPrototype(_noPrototype) {
unsigned int numArgs = callInstr->getNumOperands();
argInfoVec.reserve(numArgs);
assert(callInstr->getOperand(0) == callInstr->getCalledValue()
&& "Operand 0 is ignored in the loop below!");
for (unsigned int i=1; i < numArgs; ++i)
argInfoVec.push_back(CallArgInfo(callInstr->getOperand(i)));
// Enter this object in the MachineCodeForInstr object of the CallInst.
// This transfers ownership of this object.
MachineCodeForInstruction::get(callInstr).setCallArgsDescriptor(this);
}
CallInst *CallArgsDescriptor::getReturnValue() const {
return (callInstr->getType() == Type::VoidTy? NULL : callInstr);
}
/// CallArgsDescriptor::get - Mechanism to get the descriptor for a CALL
/// MachineInstr. We get the LLVM CallInst from the return-address register
/// argument of the CALL MachineInstr (which is explicit operand #2 for
/// indirect calls or the last implicit operand for direct calls). We then get
/// the CallArgsDescriptor from the MachineCodeForInstruction object for the
/// CallInstr. This is roundabout but avoids adding a new map or annotation
/// just to keep track of CallArgsDescriptors.
///
CallArgsDescriptor *CallArgsDescriptor::get(const MachineInstr *MI) {
const Value *retAddrVal = 0;
if ((MI->getOperand (0).getType () == MachineOperand::MO_MachineRegister
&& MI->getOperand (0).getReg () == SparcV9::g0)
|| (MI->getOperand (0).getType () == MachineOperand::MO_VirtualRegister
&& !isa<Function> (MI->getOperand (0).getVRegValue ()))) {
retAddrVal = MI->getOperand (2).getVRegValue ();
} else {
retAddrVal = MI->getImplicitRef (MI->getNumImplicitRefs () - 1);
}
const TmpInstruction* retAddrReg = cast<TmpInstruction> (retAddrVal);
assert(retAddrReg->getNumOperands() == 1 &&
isa<CallInst>(retAddrReg->getOperand(0)) &&
"Location of callInstr arg for CALL instr. changed? FIX THIS CODE!");
const CallInst* callInstr = cast<CallInst>(retAddrReg->getOperand(0));
CallArgsDescriptor* desc =
MachineCodeForInstruction::get(callInstr).getCallArgsDescriptor();
assert(desc->getCallInst()==callInstr && "Incorrect call args descriptor?");
return desc;
}

View File

@ -1,97 +0,0 @@
//===-- MachineCodeForInstruction.h -----------------------------*- 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.
//
//===----------------------------------------------------------------------===//
//
// FIXME: This file is SparcV9 specific. Do not rely on this class for new
// targets, it will go away in the future.
//
// Representation of the sequence of machine instructions created for a single
// VM instruction. Additionally records information about hidden and implicit
// values used by the machine instructions: about hidden values used by the
// machine instructions:
//
// "Temporary values" are intermediate values used in the machine instruction
// sequence, but not in the VM instruction Note that such values should be
// treated as pure SSA values with no interpretation of their operands (i.e., as
// a TmpInstruction object which actually represents such a value).
//
// (2) "Implicit uses" are values used in the VM instruction but not in
// the machine instruction sequence
//
//===----------------------------------------------------------------------===//
#ifndef MACHINECODE_FOR_INSTRUCTION_H
#define MACHINECODE_FOR_INSTRUCTION_H
#include <vector>
namespace llvm {
class MachineInstr;
class Instruction;
class Value;
class CallArgsDescriptor;
class MachineCodeForInstruction {
std::vector<Value*> tempVec; // used by m/c instr but not VM instr
std::vector<MachineInstr*> Contents; // the machine instr for this VM instr
CallArgsDescriptor* callArgsDesc; // only used for CALL instructions
public:
MachineCodeForInstruction() : callArgsDesc(NULL) {}
~MachineCodeForInstruction();
static MachineCodeForInstruction &get(const Instruction *I);
static void destroy(const Instruction *I);
// Access to underlying machine instructions...
typedef std::vector<MachineInstr*>::iterator iterator;
typedef std::vector<MachineInstr*>::const_iterator const_iterator;
unsigned size() const { return Contents.size(); }
bool empty() const { return Contents.empty(); }
MachineInstr *front() const { return Contents.front(); }
MachineInstr *back() const { return Contents.back(); }
MachineInstr *&operator[](unsigned i) { return Contents[i]; }
MachineInstr *operator[](unsigned i) const { return Contents[i]; }
void pop_back() { Contents.pop_back(); }
iterator begin() { return Contents.begin(); }
iterator end() { return Contents.end(); }
const_iterator begin() const { return Contents.begin(); }
const_iterator end() const { return Contents.end(); }
template<class InIt>
void insert(iterator where, InIt first, InIt last) {
Contents.insert(where, first, last);
}
iterator erase(iterator where) { return Contents.erase(where); }
iterator erase(iterator s, iterator e) { return Contents.erase(s, e); }
// dropAllReferences() - This function drops all references within
// temporary (hidden) instructions created in implementing the original
// VM intruction. This ensures there are no remaining "uses" within
// these hidden instructions, before the values of a method are freed.
//
void dropAllReferences();
const std::vector<Value*> &getTempValues() const { return tempVec; }
std::vector<Value*> &getTempValues() { return tempVec; }
MachineCodeForInstruction &addTemp(Value *tmp) {
tempVec.push_back(tmp);
return *this;
}
void setCallArgsDescriptor(CallArgsDescriptor* desc) { callArgsDesc = desc; }
CallArgsDescriptor* getCallArgsDescriptor() const { return callArgsDesc; }
};
} // End llvm namespace
#endif

View File

@ -1,171 +0,0 @@
//===-- SparcV9FunctionInfo.cpp -------------------------------------------===//
//
// 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 implements the SparcV9 specific MachineFunctionInfo class.
//
//===----------------------------------------------------------------------===//
#include "MachineFunctionInfo.h"
#include "llvm/Instructions.h"
#include "llvm/Function.h"
#include "llvm/Type.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetFrameInfo.h"
using namespace llvm;
static unsigned
ComputeMaxOptionalArgsSize(const TargetMachine& target, const Function *F,
unsigned &maxOptionalNumArgs)
{
unsigned maxSize = 0;
for (Function::const_iterator BB = F->begin(), BBE = F->end(); BB !=BBE; ++BB)
for (BasicBlock::const_iterator I = BB->begin(), E = BB->end(); I != E; ++I)
if (const CallInst *callInst = dyn_cast<CallInst>(I))
{
unsigned numOperands = callInst->getNumOperands() - 1;
int numExtra = numOperands-6;
if (numExtra <= 0)
continue;
unsigned sizeForThisCall = numExtra * 8;
if (maxSize < sizeForThisCall)
maxSize = sizeForThisCall;
if ((int)maxOptionalNumArgs < numExtra)
maxOptionalNumArgs = (unsigned) numExtra;
}
return maxSize;
}
// Align data larger than one L1 cache line on L1 cache line boundaries.
// Align all smaller data on the next higher 2^x boundary (4, 8, ...),
// but not higher than the alignment of the largest type we support
// (currently a double word). -- see class TargetData).
//
// This function is similar to the corresponding function in EmitAssembly.cpp
// but they are unrelated. This one does not align at more than a
// double-word boundary whereas that one might.
//
inline unsigned
SizeToAlignment(unsigned size, const TargetMachine& target)
{
const unsigned short cacheLineSize = 16;
if (size > (unsigned) cacheLineSize / 2)
return cacheLineSize;
else
for (unsigned sz=1; /*no condition*/; sz *= 2)
if (sz >= size || sz >= target.getTargetData().getDoubleAlignment())
return sz;
}
void SparcV9FunctionInfo::CalculateArgSize() {
maxOptionalArgsSize = ComputeMaxOptionalArgsSize(MF.getTarget(),
MF.getFunction(),
maxOptionalNumArgs);
staticStackSize = maxOptionalArgsSize + 176;
}
int
SparcV9FunctionInfo::computeOffsetforLocalVar(const Value* val,
unsigned &getPaddedSize,
unsigned sizeToUse)
{
if (sizeToUse == 0) {
// All integer types smaller than ints promote to 4 byte integers.
if (val->getType()->isIntegral() && val->getType()->getPrimitiveSize() < 4)
sizeToUse = 4;
else
sizeToUse = MF.getTarget().getTargetData().getTypeSize(val->getType());
}
unsigned align = SizeToAlignment(sizeToUse, MF.getTarget());
bool growUp;
int firstOffset = MF.getTarget().getFrameInfo()->getFirstAutomaticVarOffset(MF,
growUp);
int offset = growUp? firstOffset + getAutomaticVarsSize()
: firstOffset - (getAutomaticVarsSize() + sizeToUse);
int aligned = MF.getTarget().getFrameInfo()->adjustAlignment(offset, growUp, align);
getPaddedSize = sizeToUse + abs(aligned - offset);
return aligned;
}
int SparcV9FunctionInfo::allocateLocalVar(const Value* val,
unsigned sizeToUse) {
assert(! automaticVarsAreaFrozen &&
"Size of auto vars area has been used to compute an offset so "
"no more automatic vars should be allocated!");
// Check if we've allocated a stack slot for this value already
//
hash_map<const Value*, int>::const_iterator pair = offsets.find(val);
if (pair != offsets.end())
return pair->second;
unsigned getPaddedSize;
unsigned offset = computeOffsetforLocalVar(val, getPaddedSize, sizeToUse);
offsets[val] = offset;
incrementAutomaticVarsSize(getPaddedSize);
return offset;
}
int
SparcV9FunctionInfo::allocateSpilledValue(const Type* type)
{
assert(! spillsAreaFrozen &&
"Size of reg spills area has been used to compute an offset so "
"no more register spill slots should be allocated!");
unsigned size = MF.getTarget().getTargetData().getTypeSize(type);
unsigned char align = MF.getTarget().getTargetData().getTypeAlignment(type);
bool growUp;
int firstOffset = MF.getTarget().getFrameInfo()->getRegSpillAreaOffset(MF, growUp);
int offset = growUp? firstOffset + getRegSpillsSize()
: firstOffset - (getRegSpillsSize() + size);
int aligned = MF.getTarget().getFrameInfo()->adjustAlignment(offset, growUp, align);
size += abs(aligned - offset); // include alignment padding in size
incrementRegSpillsSize(size); // update size of reg. spills area
return aligned;
}
int
SparcV9FunctionInfo::pushTempValue(unsigned size)
{
unsigned align = SizeToAlignment(size, MF.getTarget());
bool growUp;
int firstOffset = MF.getTarget().getFrameInfo()->getTmpAreaOffset(MF, growUp);
int offset = growUp? firstOffset + currentTmpValuesSize
: firstOffset - (currentTmpValuesSize + size);
int aligned = MF.getTarget().getFrameInfo()->adjustAlignment(offset, growUp,
align);
size += abs(aligned - offset); // include alignment padding in size
incrementTmpAreaSize(size); // update "current" size of tmp area
return aligned;
}
void SparcV9FunctionInfo::popAllTempValues() {
resetTmpAreaSize(); // clear tmp area to reuse
}

View File

@ -1,125 +0,0 @@
//===-- SparcV9FunctionInfo.h -----------------------------------*- 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 class keeps track of information about the stack frame and about the
// per-function constant pool.
//
// FIXME: This class is completely SparcV9 specific. Do not use it for future
// targets. This file will be eliminated in future versions of LLVM.
//
//===----------------------------------------------------------------------===//
#ifndef MACHINEFUNCTIONINFO_H
#define MACHINEFUNCTIONINFO_H
#include "MachineCodeForInstruction.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/ADT/HashExtras.h"
#include "llvm/ADT/hash_set"
namespace llvm {
class MachineFunction;
class Constant;
class Type;
class SparcV9FunctionInfo : public MachineFunctionInfo {
hash_set<const Constant*> constantsForConstPool;
hash_map<const Value*, int> offsets;
unsigned staticStackSize;
unsigned automaticVarsSize;
unsigned regSpillsSize;
unsigned maxOptionalArgsSize;
unsigned maxOptionalNumArgs;
unsigned currentTmpValuesSize;
unsigned maxTmpValuesSize;
bool compiledAsLeaf;
bool spillsAreaFrozen;
bool automaticVarsAreaFrozen;
MachineFunction &MF;
public:
hash_map<const Instruction*, MachineCodeForInstruction> MCFIEntries;
SparcV9FunctionInfo(MachineFunction &mf) : MF(mf) {
staticStackSize = automaticVarsSize = regSpillsSize = 0;
maxOptionalArgsSize = maxOptionalNumArgs = currentTmpValuesSize = 0;
maxTmpValuesSize = 0;
compiledAsLeaf = spillsAreaFrozen = automaticVarsAreaFrozen = false;
}
/// CalculateArgSize - Call this method to fill in the maxOptionalArgsSize &
/// staticStackSize fields...
///
void CalculateArgSize();
//
// Accessors for global information about generated code for a method.
//
bool isCompiledAsLeafMethod() const { return compiledAsLeaf; }
unsigned getStaticStackSize() const { return staticStackSize; }
unsigned getAutomaticVarsSize() const { return automaticVarsSize; }
unsigned getRegSpillsSize() const { return regSpillsSize; }
unsigned getMaxOptionalArgsSize() const { return maxOptionalArgsSize;}
unsigned getMaxOptionalNumArgs() const { return maxOptionalNumArgs;}
const hash_set<const Constant*> &getConstantPoolValues() const {
return constantsForConstPool;
}
//
// Modifiers used during code generation
//
void initializeFrameLayout ();
void addToConstantPool (const Constant* constVal) {
constantsForConstPool.insert(constVal);
}
void markAsLeafMethod() { compiledAsLeaf = true; }
int computeOffsetforLocalVar (const Value* local,
unsigned& getPaddedSize,
unsigned sizeToUse = 0);
int allocateLocalVar (const Value* local,
unsigned sizeToUse = 0);
int allocateSpilledValue (const Type* type);
int pushTempValue (unsigned size);
void popAllTempValues ();
void freezeSpillsArea () { spillsAreaFrozen = true; }
void freezeAutomaticVarsArea () { automaticVarsAreaFrozen=true; }
private:
void incrementAutomaticVarsSize(int incr) {
automaticVarsSize+= incr;
staticStackSize += incr;
}
void incrementRegSpillsSize(int incr) {
regSpillsSize+= incr;
staticStackSize += incr;
}
void incrementTmpAreaSize(int incr) {
currentTmpValuesSize += incr;
if (maxTmpValuesSize < currentTmpValuesSize)
{
staticStackSize += currentTmpValuesSize - maxTmpValuesSize;
maxTmpValuesSize = currentTmpValuesSize;
}
}
void resetTmpAreaSize() {
currentTmpValuesSize = 0;
}
int allocateOptionalArg(const Type* type);
};
} // End llvm namespace
#endif

View File

@ -1,95 +0,0 @@
//===-- MachineInstrAnnot.h -------------------------------------*- 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.
//
//===----------------------------------------------------------------------===//
//
// Annotations used to pass information between SparcV9 code generation phases.
//
//===----------------------------------------------------------------------===//
#ifndef MACHINEINSTRANNOT_H
#define MACHINEINSTRANNOT_H
#include "llvm/CodeGen/MachineInstr.h"
#include "SparcV9RegInfo.h"
namespace llvm {
class Value;
class TmpInstruction;
class CallInst;
class CallArgInfo {
// Flag values for different argument passing methods
static const unsigned char IntArgReg = 0x1;
static const unsigned char FPArgReg = 0x2;
static const unsigned char StackSlot = 0x4;
Value* argVal; // this argument
int argCopyReg; // register used for second copy of arg. when
// multiple copies must be passed in registers
unsigned char passingMethod; // flags recording passing methods
public:
// Constructors
CallArgInfo(Value* _argVal)
: argVal(_argVal), argCopyReg(SparcV9RegInfo::getInvalidRegNum()),
passingMethod(0x0) {}
CallArgInfo(const CallArgInfo& obj)
: argVal(obj.argVal), argCopyReg(obj.argCopyReg),
passingMethod(obj.passingMethod) {}
// Accessor methods
Value* getArgVal() { return argVal; }
int getArgCopy() { return argCopyReg; }
bool usesIntArgReg() { return (bool) (passingMethod & IntArgReg);}
bool usesFPArgReg() { return (bool) (passingMethod & FPArgReg); }
bool usesStackSlot() { return (bool) (passingMethod & StackSlot);}
// Modifier methods
void replaceArgVal(Value* newVal) { argVal = newVal; }
void setUseIntArgReg() { passingMethod |= IntArgReg; }
void setUseFPArgReg() { passingMethod |= FPArgReg; }
void setUseStackSlot() { passingMethod |= StackSlot; }
void setArgCopy(int copyReg) { argCopyReg = copyReg; }
};
class CallArgsDescriptor {
std::vector<CallArgInfo> argInfoVec; // Descriptor for each argument
CallInst* callInstr; // The call instruction == result value
Value* funcPtr; // Pointer for indirect calls
TmpInstruction* retAddrReg; // Tmp value for return address reg.
bool isVarArgs; // Is this a varargs call?
bool noPrototype; // Is this a call with no prototype?
public:
CallArgsDescriptor(CallInst* _callInstr, TmpInstruction* _retAddrReg,
bool _isVarArgs, bool _noPrototype);
// Accessor methods to retrieve information about the call
// Note that operands are numbered 1..#CallArgs
unsigned int getNumArgs() const { return argInfoVec.size(); }
CallArgInfo& getArgInfo(unsigned int op) { assert(op < argInfoVec.size());
return argInfoVec[op]; }
CallInst* getCallInst() const { return callInstr; }
CallInst* getReturnValue() const;
Value* getIndirectFuncPtr() const { return funcPtr; }
TmpInstruction* getReturnAddrReg() const { return retAddrReg; }
bool isVarArgsFunc() const { return isVarArgs; }
bool hasNoPrototype() const { return noPrototype; }
// Mechanism to get the descriptor for a CALL MachineInstr.
//
static CallArgsDescriptor *get(const MachineInstr* MI);
};
} // End llvm namespace
#endif

View File

@ -1,35 +0,0 @@
##===- lib/Target/SparcV9/Makefile -------------------------*- Makefile -*-===##
#
# 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.
#
##===----------------------------------------------------------------------===##
LEVEL = ../../..
LIBRARYNAME = LLVMSparcV9
PARALLEL_DIRS = InstrSched LiveVar ModuloScheduling RegAlloc
TARGET = SparcV9
BUILT_SOURCES = \
SparcV9GenCodeEmitter.inc \
SparcV9.burm.cpp
include $(LEVEL)/Makefile.common
SparcV9.burg.in1 : $(PROJ_SRC_DIR)/SparcV9.burg.in
$(Echo) Pre-processing SparcV9.burg.in
$(Verb) $(CXX) -E $(CPP.Flags) -x c++ $< | $(SED) '/^#/d' | $(SED) 's/Ydefine/#define/' > $@
SparcV9.burm : SparcV9.burg.in1
$(Echo) Pre-processing SparcV9.burg.in
$(Verb) $(CXX) -E $(CPP.Flags) -x c++ $< | $(SED) '/^#/d' | $(SED) 's/^Xinclude/#include/' | $(SED) 's/^Xdefine/#define/' > $@
SparcV9.burm.cpp: SparcV9.burm
$(Echo) "Burging `basename $<`"
$(Verb) $(BURG) -I $< -o $@
clean::
$(Verb) $(RM) -f SparcV9.burg.in1 SparcV9.burm SparcV9.burm.cpp

View File

@ -1,216 +0,0 @@
//===- MappingInfo.cpp - create LLVM info and output to .s file -----------===//
//
// 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 contains a FunctionPass called MappingInfoAsmPrinter,
// which creates a map between MachineBasicBlocks and
// MachineInstrs (the "BB TO MI MAP").
//
// As a side effect, it outputs this information as .byte directives to
// the assembly file. The output is designed to survive the SPARC assembler,
// in order that the Reoptimizer may read it in from memory later when the
// binary is loaded. Therefore, it may contain some hidden SPARC-architecture
// dependencies. Currently this question is purely theoretical as the
// Reoptimizer works only on the SPARC.
//
// The BB TO MI MAP consists of a three-element tuple for each
// MachineBasicBlock in a function, ordered from begin() to end() of
// its MachineFunction: first, the index of the MachineBasicBlock in the
// function; second, the number of the MachineBasicBlock in the function
// as computed by create_BB_to_MInumber_Key; and third, the number of
// MachineInstrs in the MachineBasicBlock.
//
//===--------------------------------------------------------------------===//
#include "MappingInfo.h"
#include "llvm/Pass.h"
#include "llvm/Module.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/ADT/StringExtras.h"
namespace llvm {
namespace {
class MappingInfoAsmPrinter : public FunctionPass {
std::ostream &Out;
public:
MappingInfoAsmPrinter(std::ostream &out) : Out(out){}
const char *getPassName () const { return "Instr. Mapping Info Collector"; }
bool runOnFunction(Function &FI);
typedef std::map<const MachineInstr*, unsigned> InstructionKey;
private:
MappingInfo *currentOutputMap;
std::map<Function *, unsigned> Fkey; // Function # for all functions.
bool doInitialization(Module &M);
void create_BB_to_MInumber_Key(Function &FI, InstructionKey &key);
void buildBBMIMap (Function &FI, MappingInfo &Map);
void writeNumber(unsigned X);
void selectOutputMap (MappingInfo &m) { currentOutputMap = &m; }
void outByte (unsigned char b) { currentOutputMap->outByte (b); }
bool doFinalization (Module &M);
};
}
/// getMappingInfoAsmPrinterPass - Static factory method: returns a new
/// MappingInfoAsmPrinter Pass object, which uses OUT as its output
/// stream for assembly output.
///
ModulePass *getMappingInfoAsmPrinterPass(std::ostream &out){
return new MappingInfoAsmPrinter(out);
}
/// runOnFunction - Builds up the maps for the given function FI and then
/// writes them out as assembly code to the current output stream OUT.
/// This is an entry point to the pass, called by the PassManager.
///
bool MappingInfoAsmPrinter::runOnFunction(Function &FI) {
unsigned num = Fkey[&FI]; // Function number for the current function.
// Create an object to hold the map, then build the map.
MappingInfo BBMIMap ("BB TO MI MAP", "BBMIMap", num);
buildBBMIMap (FI, BBMIMap);
// Now, write out the maps.
BBMIMap.dumpAssembly (Out);
return false;
}
/// writeNumber - Write out the number X as a sequence of .byte
/// directives to the current output stream Out. This method performs a
/// run-length encoding of the unsigned integers X that are output.
///
void MappingInfoAsmPrinter::writeNumber(unsigned X) {
unsigned i=0;
do {
unsigned tmp = X & 127;
X >>= 7;
if (X) tmp |= 128;
outByte (tmp);
++i;
} while(X);
}
/// doInitialization - Assign a number to each Function, as follows:
/// Functions are numbered starting at 0 at the begin() of each Module.
/// Functions which are External (and thus have 0 basic blocks) are not
/// inserted into the maps, and are not assigned a number. The side-effect
/// of this method is to fill in Fkey to contain the mapping from Functions
/// to numbers. (This method is called automatically by the PassManager.)
///
bool MappingInfoAsmPrinter::doInitialization(Module &M) {
unsigned i = 0;
for (Module::iterator FI = M.begin(), FE = M.end(); FI != FE; ++FI) {
if (FI->isExternal()) continue;
Fkey[FI] = i;
++i;
}
return false; // Success.
}
/// create_BB_to_MInumber_Key -- Assign a number to each MachineBasicBlock
/// in the given Function, as follows: Numbering starts at zero in each
/// Function. MachineBasicBlocks are numbered from begin() to end()
/// in the Function's corresponding MachineFunction. Each successive
/// MachineBasicBlock increments the numbering by the number of instructions
/// it contains. The side-effect of this method is to fill in the parameter
/// KEY with the mapping of MachineBasicBlocks to numbers. KEY
/// is keyed on MachineInstrs, so each MachineBasicBlock is represented
/// therein by its first MachineInstr.
///
void MappingInfoAsmPrinter::create_BB_to_MInumber_Key(Function &FI,
InstructionKey &key) {
unsigned i = 0;
MachineFunction &MF = MachineFunction::get(&FI);
for (MachineFunction::iterator BI = MF.begin(), BE = MF.end();
BI != BE; ++BI) {
MachineBasicBlock &miBB = *BI;
key[&miBB.front()] = i;
i = i+(miBB.size());
}
}
/// buildBBMIMap - Build the BB TO MI MAP for the function FI,
/// and save it into the parameter MAP.
///
void MappingInfoAsmPrinter::buildBBMIMap(Function &FI, MappingInfo &Map) {
unsigned bb = 0;
// First build temporary table used to write out the map.
InstructionKey BBkey;
create_BB_to_MInumber_Key(FI, BBkey);
selectOutputMap (Map);
MachineFunction &MF = MachineFunction::get(&FI);
for (MachineFunction::iterator BI = MF.begin(), BE = MF.end();
BI != BE; ++BI, ++bb) {
MachineBasicBlock &miBB = *BI;
writeNumber(bb);
writeNumber(BBkey[&miBB.front()]);
writeNumber(miBB.size());
}
}
void MappingInfo::byteVector::dumpAssembly (std::ostream &Out) {
for (iterator i = begin (), e = end (); i != e; ++i)
Out << ".byte " << (int)*i << "\n";
}
static void writePrologue (std::ostream &Out, const std::string &comment,
const std::string &symName) {
// Prologue:
// Output a comment describing the object.
Out << "!" << comment << "\n";
// Switch the current section to .rodata in the assembly output:
Out << "\t.section \".rodata\"\n\t.align 8\n";
// Output a global symbol naming the object:
Out << "\t.global " << symName << "\n";
Out << "\t.type " << symName << ",#object\n";
Out << symName << ":\n";
}
static void writeEpilogue (std::ostream &Out, const std::string &symName) {
// Epilogue:
// Output a local symbol marking the end of the object:
Out << ".end_" << symName << ":\n";
// Output size directive giving the size of the object:
Out << "\t.size " << symName << ", .end_" << symName << "-" << symName
<< "\n";
}
void MappingInfo::dumpAssembly (std::ostream &Out) {
const std::string &name (symbolPrefix + utostr (functionNumber));
writePrologue (Out, comment, name);
// The LMIMap and BBMIMap are supposed to start with a length word:
Out << "\t.word .end_" << name << "-" << name << "\n";
bytes.dumpAssembly (Out);
writeEpilogue (Out, name);
}
/// doFinalization - This method writes out two tables, named
/// FunctionBB and FunctionLI, which map Function numbers (as in
/// doInitialization) to the BBMIMap and LMIMap tables. (This used to
/// be the "FunctionInfo" pass.)
///
bool MappingInfoAsmPrinter::doFinalization (Module &M) {
unsigned f;
writePrologue(Out, "FUNCTION TO BB MAP", "FunctionBB");
f=0;
for(Module::iterator FI = M.begin (), FE = M.end (); FE != FI; ++FI) {
if (FI->isExternal ())
continue;
Out << "\t.xword BBMIMap" << f << "\n";
++f;
}
writeEpilogue(Out, "FunctionBB");
return false;
}
} // End llvm namespace

View File

@ -1,50 +0,0 @@
//===- lib/Target/SparcV9/MappingInfo.h -------------------------*- 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.
//
//===----------------------------------------------------------------------===//
//
// Data structures to support the Reoptimizer's Instruction-to-MachineInstr
// mapping information gatherer.
//
//===----------------------------------------------------------------------===//
#ifndef MAPPINGINFO_H
#define MAPPINGINFO_H
#include <iosfwd>
#include <vector>
#include <string>
namespace llvm {
class ModulePass;
ModulePass *getMappingInfoAsmPrinterPass(std::ostream &out);
ModulePass *createInternalGlobalMapperPass();
class MappingInfo {
struct byteVector : public std::vector <unsigned char> {
void dumpAssembly (std::ostream &Out);
};
std::string comment;
std::string symbolPrefix;
unsigned functionNumber;
byteVector bytes;
public:
void outByte (unsigned char b) { bytes.push_back (b); }
MappingInfo (std::string Comment, std::string SymbolPrefix,
unsigned FunctionNumber) : comment(Comment),
symbolPrefix(SymbolPrefix), functionNumber(FunctionNumber) {}
void dumpAssembly (std::ostream &Out);
unsigned char *getBytes (unsigned &length) {
length = bytes.size(); return &bytes[0];
}
};
} // End llvm namespace
#endif

View File

@ -1,305 +0,0 @@
//===-- DependenceAnalyzer.cpp - DependenceAnalyzer ------------*- 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.
//
//===----------------------------------------------------------------------===//
//
//
//
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "ModuloSched"
#include "DependenceAnalyzer.h"
#include "llvm/Type.h"
#include "llvm/Support/Debug.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Constants.h"
#include <iostream>
using namespace llvm;
namespace llvm {
/// Create ModuloSchedulingPass
FunctionPass *createDependenceAnalyzer() {
return new DependenceAnalyzer();
}
}
Statistic<> NoDeps("depanalyzer-nodeps", "Number of dependences eliminated");
Statistic<> NumDeps("depanalyzer-deps",
"Number of dependences could not eliminate");
Statistic<> AdvDeps("depanalyzer-advdeps",
"Number of dependences using advanced techniques");
bool DependenceAnalyzer::runOnFunction(Function &F) {
AA = &getAnalysis<AliasAnalysis>();
TD = &getAnalysis<TargetData>();
SE = &getAnalysis<ScalarEvolution>();
return false;
}
static RegisterAnalysis<DependenceAnalyzer>X("depanalyzer",
"Dependence Analyzer");
// - Get inter and intra dependences between loads and stores
//
// Overview of Method:
// Step 1: Use alias analysis to determine dependencies if values are loop
// invariant
// Step 2: If pointers are not GEP, then there is a dependence.
// Step 3: Compare GEP base pointers with AA. If no alias, no dependence.
// If may alias, then add a dependence. If must alias, then analyze
// further (Step 4)
// Step 4: do advanced analysis
void DependenceAnalyzer::AnalyzeDeps(Value *val, Value *val2, bool valLoad,
bool val2Load,
std::vector<Dependence> &deps,
BasicBlock *BB,
bool srcBeforeDest) {
bool loopInvariant = true;
//Check if both are instructions and prove not loop invariant if possible
if(Instruction *valInst = dyn_cast<Instruction>(val))
if(valInst->getParent() == BB)
loopInvariant = false;
if(Instruction *val2Inst = dyn_cast<Instruction>(val2))
if(val2Inst->getParent() == BB)
loopInvariant = false;
//If Loop invariant, let AA decide
if(loopInvariant) {
if(AA->alias(val, (unsigned)TD->getTypeSize(val->getType()),
val2,(unsigned)TD->getTypeSize(val2->getType()))
!= AliasAnalysis::NoAlias) {
createDep(deps, valLoad, val2Load, srcBeforeDest);
}
else
++NoDeps;
return;
}
//Otherwise, continue with step 2
GetElementPtrInst *GP = dyn_cast<GetElementPtrInst>(val);
GetElementPtrInst *GP2 = dyn_cast<GetElementPtrInst>(val2);
//If both are not GP instructions, we can not do further analysis
if(!GP || !GP2) {
createDep(deps, valLoad, val2Load, srcBeforeDest);
return;
}
//Otherwise, compare GEP bases (op #0) with Alias Analysis
Value *GPop = GP->getOperand(0);
Value *GP2op = GP2->getOperand(0);
int alias = AA->alias(GPop, (unsigned)TD->getTypeSize(GPop->getType()),
GP2op,(unsigned)TD->getTypeSize(GP2op->getType()));
if(alias == AliasAnalysis::MustAlias) {
//Further dep analysis to do
advancedDepAnalysis(GP, GP2, valLoad, val2Load, deps, srcBeforeDest);
++AdvDeps;
}
else if(alias == AliasAnalysis::MayAlias) {
createDep(deps, valLoad, val2Load, srcBeforeDest);
}
//Otherwise no dependence since there is no alias
else
++NoDeps;
}
// advancedDepAnalysis - Do advanced data dependence tests
void DependenceAnalyzer::advancedDepAnalysis(GetElementPtrInst *gp1,
GetElementPtrInst *gp2,
bool valLoad,
bool val2Load,
std::vector<Dependence> &deps,
bool srcBeforeDest) {
//Check if both GEPs are in a simple form: 3 ops, constant 0 as second arg
if(gp1->getNumOperands() != 3 || gp2->getNumOperands() != 3) {
createDep(deps, valLoad, val2Load, srcBeforeDest);
return;
}
//Check second arg is constant 0
bool GPok = false;
if(Constant *c1 = dyn_cast<Constant>(gp1->getOperand(1)))
if(Constant *c2 = dyn_cast<Constant>(gp2->getOperand(1)))
if(c1->isNullValue() && c2->isNullValue())
GPok = true;
if(!GPok) {
createDep(deps, valLoad, val2Load, srcBeforeDest);
return;
}
Value *Gep1Idx = gp1->getOperand(2);
Value *Gep2Idx = gp2->getOperand(2);
if(CastInst *c1 = dyn_cast<CastInst>(Gep1Idx))
Gep1Idx = c1->getOperand(0);
if(CastInst *c2 = dyn_cast<CastInst>(Gep2Idx))
Gep2Idx = c2->getOperand(0);
//Get SCEV for each index into the area
SCEVHandle SV1 = SE->getSCEV(Gep1Idx);
SCEVHandle SV2 = SE->getSCEV(Gep2Idx);
//Now handle special cases of dependence analysis
//SV1->print(std::cerr);
//std::cerr << "\n";
//SV2->print(std::cerr);
//std::cerr << "\n";
//Check if we have an SCEVAddExpr, cause we can only handle those
SCEVAddRecExpr *SVAdd1 = dyn_cast<SCEVAddRecExpr>(SV1);
SCEVAddRecExpr *SVAdd2 = dyn_cast<SCEVAddRecExpr>(SV2);
//Default to having a dependence since we can't analyze further
if(!SVAdd1 || !SVAdd2) {
createDep(deps, valLoad, val2Load, srcBeforeDest);
return;
}
//Check if not Affine, we can't handle those
if(!SVAdd1->isAffine( ) || !SVAdd2->isAffine()) {
createDep(deps, valLoad, val2Load, srcBeforeDest);
return;
}
//We know the SCEV is in the form A + B*x, check that B is the same for both
SCEVConstant *B1 = dyn_cast<SCEVConstant>(SVAdd1->getOperand(1));
SCEVConstant *B2 = dyn_cast<SCEVConstant>(SVAdd2->getOperand(1));
if(B1->getValue() != B2->getValue()) {
createDep(deps, valLoad, val2Load, srcBeforeDest);
return;
}
if(B1->getValue()->getRawValue() != 1 || B2->getValue()->getRawValue() != 1) {
createDep(deps, valLoad, val2Load, srcBeforeDest);
return;
}
SCEVConstant *A1 = dyn_cast<SCEVConstant>(SVAdd1->getOperand(0));
SCEVConstant *A2 = dyn_cast<SCEVConstant>(SVAdd2->getOperand(0));
//Come back and deal with nested SCEV!
if(!A1 || !A2) {
createDep(deps, valLoad, val2Load, srcBeforeDest);
return;
}
//If equal, create dep as normal
if(A1->getValue() == A2->getValue()) {
createDep(deps, valLoad, val2Load, srcBeforeDest);
return;
}
//Eliminate a dep if this is a intra dep
else if(srcBeforeDest) {
++NoDeps;
return;
}
//Find constant index difference
int diff = A1->getValue()->getRawValue() - A2->getValue()->getRawValue();
//std::cerr << diff << "\n";
if(diff > 5)
diff = 2;
if(diff > 0)
createDep(deps, valLoad, val2Load, srcBeforeDest, diff);
//assert(diff > 0 && "Expected diff to be greater then 0");
}
// Create dependences once its determined these two instructions
// references the same memory
void DependenceAnalyzer::createDep(std::vector<Dependence> &deps,
bool valLoad, bool val2Load,
bool srcBeforeDest, int diff) {
//If the source instruction occurs after the destination instruction
//(execution order), then this dependence is across iterations
if(!srcBeforeDest && (diff==0))
diff = 1;
//If load/store pair
if(valLoad && !val2Load) {
if(srcBeforeDest)
//Anti Dep
deps.push_back(Dependence(diff, Dependence::AntiDep));
else
deps.push_back(Dependence(diff, Dependence::TrueDep));
++NumDeps;
}
//If store/load pair
else if(!valLoad && val2Load) {
if(srcBeforeDest)
//True Dep
deps.push_back(Dependence(diff, Dependence::TrueDep));
else
deps.push_back(Dependence(diff, Dependence::AntiDep));
++NumDeps;
}
//If store/store pair
else if(!valLoad && !val2Load) {
//True Dep
deps.push_back(Dependence(diff, Dependence::OutputDep));
++NumDeps;
}
}
//Get Dependence Info for a pair of Instructions
DependenceResult DependenceAnalyzer::getDependenceInfo(Instruction *inst1,
Instruction *inst2,
bool srcBeforeDest) {
std::vector<Dependence> deps;
DEBUG(std::cerr << "Inst1: " << *inst1 << "\n");
DEBUG(std::cerr << "Inst2: " << *inst2 << "\n");
//No self deps
if(inst1 == inst2)
return DependenceResult(deps);
if(LoadInst *ldInst = dyn_cast<LoadInst>(inst1)) {
if(StoreInst *stInst = dyn_cast<StoreInst>(inst2))
AnalyzeDeps(ldInst->getOperand(0), stInst->getOperand(1),
true, false, deps, ldInst->getParent(), srcBeforeDest);
}
else if(StoreInst *stInst = dyn_cast<StoreInst>(inst1)) {
if(LoadInst *ldInst = dyn_cast<LoadInst>(inst2))
AnalyzeDeps(stInst->getOperand(1), ldInst->getOperand(0), false, true,
deps, ldInst->getParent(), srcBeforeDest);
else if(StoreInst *stInst2 = dyn_cast<StoreInst>(inst2))
AnalyzeDeps(stInst->getOperand(1), stInst2->getOperand(1), false, false,
deps, stInst->getParent(), srcBeforeDest);
}
else
assert(0 && "Expected a load or a store\n");
DependenceResult dr = DependenceResult(deps);
return dr;
}

View File

@ -1,92 +0,0 @@
//===-- DependenceAnalyzer.h - Dependence Analyzer--------------*- 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.
//
//===----------------------------------------------------------------------===//
//
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_DEPENDENCEANALYZER_H
#define LLVM_DEPENDENCEANALYZER_H
#include "llvm/Instructions.h"
#include "llvm/Function.h"
#include "llvm/Pass.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/ScalarEvolutionExpressions.h"
#include "llvm/Target/TargetData.h"
#include <vector>
namespace llvm {
//class to represent a dependence
struct Dependence {
enum DataDepType {
TrueDep, AntiDep, OutputDep, NonDateDep,
};
Dependence(int diff, DataDepType dep) : iteDiff(diff), depType(dep) {}
unsigned getIteDiff() { return iteDiff; }
unsigned getDepType() { return depType; }
private:
unsigned iteDiff;
unsigned depType;
};
struct DependenceResult {
std::vector<Dependence> dependences;
DependenceResult(const std::vector<Dependence> &d) : dependences(d) {}
};
class DependenceAnalyzer : public FunctionPass {
AliasAnalysis *AA;
TargetData *TD;
ScalarEvolution *SE;
void advancedDepAnalysis(GetElementPtrInst *gp1, GetElementPtrInst *gp2,
bool valLoad, bool val2Load,
std::vector<Dependence> &deps, bool srcBeforeDest);
void AnalyzeDeps(Value *val, Value *val2, bool val1Load, bool val2Load,
std::vector<Dependence> &deps, BasicBlock *BB,
bool srcBeforeDest);
void createDep(std::vector<Dependence> &deps, bool valLoad, bool val2Load,
bool srcBeforeDest, int diff = 0);
public:
DependenceAnalyzer() { AA = 0; TD = 0; SE = 0; }
virtual bool runOnFunction(Function &F);
virtual const char* getPassName() const { return "DependenceAnalyzer"; }
// getAnalysisUsage
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
AU.addRequired<AliasAnalysis>();
AU.addRequired<TargetData>();
AU.addRequired<ScalarEvolution>();
AU.setPreservesAll();
}
//get dependence info
DependenceResult getDependenceInfo(Instruction *inst1, Instruction *inst2,
bool srcBeforeDest);
};
}
#endif

View File

@ -1,309 +0,0 @@
//===-- MSSchedule.cpp Schedule ---------------------------------*- 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.
//
//===----------------------------------------------------------------------===//
//
//
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "ModuloSched"
#include "MSSchedule.h"
#include "llvm/Support/Debug.h"
#include "llvm/Target/TargetSchedInfo.h"
#include "../SparcV9Internals.h"
#include "llvm/CodeGen/MachineInstr.h"
#include <iostream>
using namespace llvm;
//Check if all resources are free
bool resourcesFree(MSchedGraphNode*, int,
std::map<int, std::map<int, int> > &resourceNumPerCycle);
//Returns a boolean indicating if the start cycle needs to be increased/decreased
bool MSSchedule::insert(MSchedGraphNode *node, int cycle, int II) {
//First, check if the cycle has a spot free to start
if(schedule.find(cycle) != schedule.end()) {
//Check if we have a free issue slot at this cycle
if (schedule[cycle].size() < numIssue) {
//Now check if all the resources in their respective cycles are available
if(resourcesFree(node, cycle, II)) {
//Insert to preserve dependencies
addToSchedule(cycle,node);
DEBUG(std::cerr << "Found spot in map, and there is an issue slot\n");
return false;
}
}
}
//Not in the map yet so put it in
else {
if(resourcesFree(node,cycle,II)) {
std::vector<MSchedGraphNode*> nodes;
nodes.push_back(node);
schedule[cycle] = nodes;
DEBUG(std::cerr << "Nothing in map yet so taking an issue slot\n");
return false;
}
}
DEBUG(std::cerr << "All issue slots taken\n");
return true;
}
void MSSchedule::addToSchedule(int cycle, MSchedGraphNode *node) {
std::vector<MSchedGraphNode*> nodesAtCycle = schedule[cycle];
std::map<unsigned, MSchedGraphNode*> indexMap;
for(unsigned i=0; i < nodesAtCycle.size(); ++i) {
indexMap[nodesAtCycle[i]->getIndex()] = nodesAtCycle[i];
}
indexMap[node->getIndex()] = node;
std::vector<MSchedGraphNode*> nodes;
for(std::map<unsigned, MSchedGraphNode*>::iterator I = indexMap.begin(), E = indexMap.end(); I != E; ++I)
nodes.push_back(I->second);
schedule[cycle] = nodes;
}
bool MSSchedule::resourceAvailable(int resourceNum, int cycle) {
bool isFree = true;
//Get Map for this cycle
if(resourceNumPerCycle.count(cycle)) {
if(resourceNumPerCycle[cycle].count(resourceNum)) {
int maxRes = CPUResource::getCPUResource(resourceNum)->maxNumUsers;
if(resourceNumPerCycle[cycle][resourceNum] >= maxRes)
isFree = false;
}
}
return isFree;
}
void MSSchedule::useResource(int resourceNum, int cycle) {
//Get Map for this cycle
if(resourceNumPerCycle.count(cycle)) {
if(resourceNumPerCycle[cycle].count(resourceNum)) {
resourceNumPerCycle[cycle][resourceNum]++;
}
else {
resourceNumPerCycle[cycle][resourceNum] = 1;
}
}
//If no map, create one!
else {
std::map<int, int> resourceUse;
resourceUse[resourceNum] = 1;
resourceNumPerCycle[cycle] = resourceUse;
}
}
bool MSSchedule::resourcesFree(MSchedGraphNode *node, int cycle, int II) {
//Get Resource usage for this instruction
const TargetSchedInfo *msi = node->getParent()->getTarget()->getSchedInfo();
int currentCycle = cycle;
bool success = true;
//Create vector of starting cycles
std::vector<int> cyclesMayConflict;
cyclesMayConflict.push_back(cycle);
if(resourceNumPerCycle.size() > 0) {
for(int i = cycle-II; i >= (resourceNumPerCycle.begin()->first); i-=II)
cyclesMayConflict.push_back(i);
for(int i = cycle+II; i <= resourceNumPerCycle.end()->first; i+=II)
cyclesMayConflict.push_back(i);
}
//Now check all cycles for conflicts
for(int index = 0; index < (int) cyclesMayConflict.size(); ++index) {
currentCycle = cyclesMayConflict[index];
//Get resource usage for this instruction
InstrRUsage rUsage = msi->getInstrRUsage(node->getInst()->getOpcode());
std::vector<std::vector<resourceId_t> > resources = rUsage.resourcesByCycle;
//Loop over resources in each cycle and increments their usage count
for(unsigned i=0; i < resources.size(); ++i) {
for(unsigned j=0; j < resources[i].size(); ++j) {
//Get Resource to check its availability
int resourceNum = resources[i][j];
DEBUG(std::cerr << "Attempting to schedule Resource Num: " << resourceNum << " in cycle: " << currentCycle << "\n");
success = resourceAvailable(resourceNum, currentCycle);
if(!success)
break;
}
if(!success)
break;
//Increase cycle
currentCycle++;
}
if(!success)
return false;
}
//Actually put resources into the map
if(success) {
int currentCycle = cycle;
//Get resource usage for this instruction
InstrRUsage rUsage = msi->getInstrRUsage(node->getInst()->getOpcode());
std::vector<std::vector<resourceId_t> > resources = rUsage.resourcesByCycle;
//Loop over resources in each cycle and increments their usage count
for(unsigned i=0; i < resources.size(); ++i) {
for(unsigned j=0; j < resources[i].size(); ++j) {
int resourceNum = resources[i][j];
useResource(resourceNum, currentCycle);
}
currentCycle++;
}
}
return true;
}
bool MSSchedule::constructKernel(int II, std::vector<MSchedGraphNode*> &branches, std::map<const MachineInstr*, unsigned> &indVar) {
//Our schedule is allowed to have negative numbers, so lets calculate this offset
int offset = schedule.begin()->first;
if(offset > 0)
offset = 0;
DEBUG(std::cerr << "Offset: " << offset << "\n");
//Using the schedule, fold up into kernel and check resource conflicts as we go
std::vector<std::pair<MSchedGraphNode*, int> > tempKernel;
int stageNum = ((schedule.rbegin()->first-offset)+1)/ II;
int maxSN = 0;
DEBUG(std::cerr << "Number of Stages: " << stageNum << "\n");
for(int index = offset; index < (II+offset); ++index) {
int count = 0;
for(int i = index; i <= (schedule.rbegin()->first); i+=II) {
if(schedule.count(i)) {
for(std::vector<MSchedGraphNode*>::iterator I = schedule[i].begin(),
E = schedule[i].end(); I != E; ++I) {
//Check if its a branch
assert(!(*I)->isBranch() && "Branch should not be schedule!");
tempKernel.push_back(std::make_pair(*I, count));
maxSN = std::max(maxSN, count);
}
}
++count;
}
}
//Add in induction var code
for(std::vector<std::pair<MSchedGraphNode*, int> >::iterator I = tempKernel.begin(), IE = tempKernel.end();
I != IE; ++I) {
//Add indVar instructions before this one for the current iteration
if(I->second == 0) {
std::map<unsigned, MachineInstr*> tmpMap;
//Loop over induction variable instructions in the map that come before this instr
for(std::map<const MachineInstr*, unsigned>::iterator N = indVar.begin(), NE = indVar.end(); N != NE; ++N) {
if(N->second < I->first->getIndex())
tmpMap[N->second] = (MachineInstr*) N->first;
}
//Add to kernel, and delete from indVar
for(std::map<unsigned, MachineInstr*>::iterator N = tmpMap.begin(), NE = tmpMap.end(); N != NE; ++N) {
kernel.push_back(std::make_pair(N->second, 0));
indVar.erase(N->second);
}
}
kernel.push_back(std::make_pair((MachineInstr*) I->first->getInst(), I->second));
}
std::map<unsigned, MachineInstr*> tmpMap;
//Add remaining invar instructions
for(std::map<const MachineInstr*, unsigned>::iterator N = indVar.begin(), NE = indVar.end(); N != NE; ++N) {
tmpMap[N->second] = (MachineInstr*) N->first;
}
//Add to kernel, and delete from indVar
for(std::map<unsigned, MachineInstr*>::iterator N = tmpMap.begin(), NE = tmpMap.end(); N != NE; ++N) {
kernel.push_back(std::make_pair(N->second, 0));
indVar.erase(N->second);
}
maxStage = maxSN;
return true;
}
bool MSSchedule::defPreviousStage(Value *def, int stage) {
//Loop over kernel and determine if value is being defined in previous stage
for(std::vector<std::pair<MachineInstr*, int> >::iterator P = kernel.begin(), PE = kernel.end(); P != PE; ++P) {
MachineInstr* inst = P->first;
//Loop over Machine Operands
for(unsigned i=0; i < inst->getNumOperands(); ++i) {
//get machine operand
const MachineOperand &mOp = inst->getOperand(i);
if(mOp.getType() == MachineOperand::MO_VirtualRegister && mOp.isDef()) {
if(def == mOp.getVRegValue()) {
if(P->second >= stage)
return false;
else
return true;
}
}
}
}
assert(0 && "We should always have found the def in our kernel\n");
abort();
}
void MSSchedule::print(std::ostream &os) const {
os << "Schedule:\n";
for(schedule_const_iterator I = schedule.begin(), E = schedule.end(); I != E; ++I) {
os << "Cycle: " << I->first << "\n";
for(std::vector<MSchedGraphNode*>::const_iterator node = I->second.begin(), nodeEnd = I->second.end(); node != nodeEnd; ++node)
os << **node << "\n";
}
os << "Kernel:\n";
for(std::vector<std::pair<MachineInstr*, int> >::const_iterator I = kernel.begin(),
E = kernel.end(); I != E; ++I)
os << "Node: " << *(I->first) << " Stage: " << I->second << "\n";
}

View File

@ -1,72 +0,0 @@
//===-- MSSchedule.h - Schedule ------- -------------------------*- 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.
//
//===----------------------------------------------------------------------===//
//
// The schedule generated by a scheduling algorithm
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_MSSCHEDULE_H
#define LLVM_MSSCHEDULE_H
#include "MSchedGraph.h"
#include <vector>
#include <set>
namespace llvm {
class MSSchedule {
std::map<int, std::vector<MSchedGraphNode*> > schedule;
unsigned numIssue;
//Internal map to keep track of explicit resources
std::map<int, std::map<int, int> > resourceNumPerCycle;
//Check if all resources are free
bool resourcesFree(MSchedGraphNode*, int, int II);
bool resourceAvailable(int resourceNum, int cycle);
void useResource(int resourceNum, int cycle);
//Resulting kernel
std::vector<std::pair<MachineInstr*, int> > kernel;
//Max stage count
int maxStage;
//add at the right spot in the schedule
void addToSchedule(int, MSchedGraphNode*);
public:
MSSchedule(int num) : numIssue(num) {}
MSSchedule() : numIssue(4) {}
bool insert(MSchedGraphNode *node, int cycle, int II);
int getStartCycle(MSchedGraphNode *node);
void clear() { schedule.clear(); resourceNumPerCycle.clear(); kernel.clear(); }
std::vector<std::pair<MachineInstr*, int> >* getKernel() { return &kernel; }
bool constructKernel(int II, std::vector<MSchedGraphNode*> &branches, std::map<const MachineInstr*, unsigned> &indVar);
int getMaxStage() { return maxStage; }
bool defPreviousStage(Value *def, int stage);
//iterators
typedef std::map<int, std::vector<MSchedGraphNode*> >::iterator schedule_iterator;
typedef std::map<int, std::vector<MSchedGraphNode*> >::const_iterator schedule_const_iterator;
schedule_iterator begin() { return schedule.begin(); };
schedule_iterator end() { return schedule.end(); };
void print(std::ostream &os) const;
typedef std::vector<std::pair<MachineInstr*, int> >::iterator kernel_iterator;
typedef std::vector<std::pair<MachineInstr*, int> >::const_iterator kernel_const_iterator;
kernel_iterator kernel_begin() { return kernel.begin(); }
kernel_iterator kernel_end() { return kernel.end(); }
};
}
#endif

View File

@ -1,325 +0,0 @@
//===-- MSScheduleSB.cpp Schedule ---------------------------------*- 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.
//
//===----------------------------------------------------------------------===//
//
//
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "ModuloSchedSB"
#include "MSScheduleSB.h"
#include "llvm/Support/Debug.h"
#include "llvm/Target/TargetSchedInfo.h"
#include "../SparcV9Internals.h"
#include "llvm/CodeGen/MachineInstr.h"
#include <iostream>
using namespace llvm;
//Check if all resources are free
bool resourcesFree(MSchedGraphSBNode*, int,
std::map<int, std::map<int, int> > &resourceNumPerCycle);
//Returns a boolean indicating if the start cycle needs to be increased/decreased
bool MSScheduleSB::insert(MSchedGraphSBNode *node, int cycle, int II) {
//First, check if the cycle has a spot free to start
if(schedule.find(cycle) != schedule.end()) {
//Check if we have a free issue slot at this cycle
if (schedule[cycle].size() < numIssue) {
//Now check if all the resources in their respective cycles are available
if(resourcesFree(node, cycle, II)) {
//Insert to preserve dependencies
addToSchedule(cycle,node);
DEBUG(std::cerr << "Found spot in map, and there is an issue slot\n");
return false;
}
}
}
//Not in the map yet so put it in
else {
if(resourcesFree(node,cycle,II)) {
std::vector<MSchedGraphSBNode*> nodes;
nodes.push_back(node);
schedule[cycle] = nodes;
DEBUG(std::cerr << "Nothing in map yet so taking an issue slot\n");
return false;
}
}
DEBUG(std::cerr << "All issue slots taken\n");
return true;
}
void MSScheduleSB::addToSchedule(int cycle, MSchedGraphSBNode *node) {
std::vector<MSchedGraphSBNode*> nodesAtCycle = schedule[cycle];
std::map<unsigned, MSchedGraphSBNode*> indexMap;
for(unsigned i=0; i < nodesAtCycle.size(); ++i) {
indexMap[nodesAtCycle[i]->getIndex()] = nodesAtCycle[i];
}
indexMap[node->getIndex()] = node;
std::vector<MSchedGraphSBNode*> nodes;
for(std::map<unsigned, MSchedGraphSBNode*>::iterator I = indexMap.begin(), E = indexMap.end(); I != E; ++I)
nodes.push_back(I->second);
schedule[cycle] = nodes;
}
bool MSScheduleSB::resourceAvailable(int resourceNum, int cycle) {
bool isFree = true;
//Get Map for this cycle
if(resourceNumPerCycle.count(cycle)) {
if(resourceNumPerCycle[cycle].count(resourceNum)) {
int maxRes = CPUResource::getCPUResource(resourceNum)->maxNumUsers;
if(resourceNumPerCycle[cycle][resourceNum] >= maxRes)
isFree = false;
}
}
return isFree;
}
void MSScheduleSB::useResource(int resourceNum, int cycle) {
//Get Map for this cycle
if(resourceNumPerCycle.count(cycle)) {
if(resourceNumPerCycle[cycle].count(resourceNum)) {
resourceNumPerCycle[cycle][resourceNum]++;
}
else {
resourceNumPerCycle[cycle][resourceNum] = 1;
}
}
//If no map, create one!
else {
std::map<int, int> resourceUse;
resourceUse[resourceNum] = 1;
resourceNumPerCycle[cycle] = resourceUse;
}
}
bool MSScheduleSB::resourcesFree(MSchedGraphSBNode *node, int cycle, int II) {
//Get Resource usage for this instruction
const TargetSchedInfo *msi = node->getParent()->getTarget()->getSchedInfo();
int currentCycle = cycle;
bool success = true;
//Create vector of starting cycles
std::vector<int> cyclesMayConflict;
cyclesMayConflict.push_back(cycle);
if(resourceNumPerCycle.size() > 0) {
for(int i = cycle-II; i >= (resourceNumPerCycle.begin()->first); i-=II)
cyclesMayConflict.push_back(i);
for(int i = cycle+II; i <= resourceNumPerCycle.end()->first; i+=II)
cyclesMayConflict.push_back(i);
}
//Now check all cycles for conflicts
for(int index = 0; index < (int) cyclesMayConflict.size(); ++index) {
currentCycle = cyclesMayConflict[index];
//Get resource usage for this instruction
InstrRUsage rUsage = msi->getInstrRUsage(node->getInst()->getOpcode());
std::vector<std::vector<resourceId_t> > resources = rUsage.resourcesByCycle;
//Loop over resources in each cycle and increments their usage count
for(unsigned i=0; i < resources.size(); ++i) {
for(unsigned j=0; j < resources[i].size(); ++j) {
//Get Resource to check its availability
int resourceNum = resources[i][j];
DEBUG(std::cerr << "Attempting to schedule Resource Num: " << resourceNum << " in cycle: " << currentCycle << "\n");
success = resourceAvailable(resourceNum, currentCycle);
if(!success)
break;
}
if(!success)
break;
//Increase cycle
currentCycle++;
}
if(!success)
return false;
}
//Actually put resources into the map
if(success) {
int currentCycle = cycle;
//Get resource usage for this instruction
InstrRUsage rUsage = msi->getInstrRUsage(node->getInst()->getOpcode());
std::vector<std::vector<resourceId_t> > resources = rUsage.resourcesByCycle;
//Loop over resources in each cycle and increments their usage count
for(unsigned i=0; i < resources.size(); ++i) {
for(unsigned j=0; j < resources[i].size(); ++j) {
int resourceNum = resources[i][j];
useResource(resourceNum, currentCycle);
}
currentCycle++;
}
}
return true;
}
bool MSScheduleSB::constructKernel(int II, std::vector<MSchedGraphSBNode*> &branches, std::map<const MachineInstr*, unsigned> &indVar) {
//Our schedule is allowed to have negative numbers, so lets calculate this offset
int offset = schedule.begin()->first;
if(offset > 0)
offset = 0;
DEBUG(std::cerr << "Offset: " << offset << "\n");
//Using the schedule, fold up into kernel and check resource conflicts as we go
std::vector<std::pair<MSchedGraphSBNode*, int> > tempKernel;
int stageNum = ((schedule.rbegin()->first-offset)+1)/ II;
int maxSN = 0;
DEBUG(std::cerr << "Number of Stages: " << stageNum << "\n");
for(int index = offset; index < (II+offset); ++index) {
int count = 0;
for(int i = index; i <= (schedule.rbegin()->first); i+=II) {
if(schedule.count(i)) {
for(std::vector<MSchedGraphSBNode*>::iterator I = schedule[i].begin(),
E = schedule[i].end(); I != E; ++I) {
//Check if its a branch
assert(!(*I)->isBranch() && "Branch should not be schedule!");
tempKernel.push_back(std::make_pair(*I, count));
maxSN = std::max(maxSN, count);
}
}
++count;
}
}
//Add in induction var code
for(std::vector<std::pair<MSchedGraphSBNode*, int> >::iterator I = tempKernel.begin(), IE = tempKernel.end();
I != IE; ++I) {
//Add indVar instructions before this one for the current iteration
if(I->second == 0) {
std::map<unsigned, MachineInstr*> tmpMap;
//Loop over induction variable instructions in the map that come before this instr
for(std::map<const MachineInstr*, unsigned>::iterator N = indVar.begin(), NE = indVar.end(); N != NE; ++N) {
if(N->second < I->first->getIndex())
tmpMap[N->second] = (MachineInstr*) N->first;
}
//Add to kernel, and delete from indVar
for(std::map<unsigned, MachineInstr*>::iterator N = tmpMap.begin(), NE = tmpMap.end(); N != NE; ++N) {
kernel.push_back(std::make_pair(N->second, 0));
indVar.erase(N->second);
}
}
kernel.push_back(std::make_pair((MachineInstr*) I->first->getInst(), I->second));
if(I->first->isPredicate()) {
//assert(I->second == 0 && "Predicate node must be from current iteration\n");
std::vector<const MachineInstr*> otherInstrs = I->first->getOtherInstrs();
for(std::vector<const MachineInstr*>::iterator O = otherInstrs.begin(), OE = otherInstrs.end(); O != OE; ++O) {
kernel.push_back(std::make_pair((MachineInstr*) *O, I->second));
}
}
}
std::map<unsigned, MachineInstr*> tmpMap;
//Add remaining invar instructions
for(std::map<const MachineInstr*, unsigned>::iterator N = indVar.begin(), NE = indVar.end(); N != NE; ++N) {
tmpMap[N->second] = (MachineInstr*) N->first;
}
//Add to kernel, and delete from indVar
for(std::map<unsigned, MachineInstr*>::iterator N = tmpMap.begin(), NE = tmpMap.end(); N != NE; ++N) {
kernel.push_back(std::make_pair(N->second, 0));
indVar.erase(N->second);
}
maxStage = maxSN;
return true;
}
bool MSScheduleSB::defPreviousStage(Value *def, int stage) {
//Loop over kernel and determine if value is being defined in previous stage
for(std::vector<std::pair<MachineInstr*, int> >::iterator P = kernel.begin(), PE = kernel.end(); P != PE; ++P) {
MachineInstr* inst = P->first;
//Loop over Machine Operands
for(unsigned i=0; i < inst->getNumOperands(); ++i) {
//get machine operand
const MachineOperand &mOp = inst->getOperand(i);
if(mOp.getType() == MachineOperand::MO_VirtualRegister && mOp.isDef()) {
if(def == mOp.getVRegValue()) {
if(P->second >= stage)
return false;
else
return true;
}
}
}
}
assert(0 && "We should always have found the def in our kernel\n");
abort();
}
void MSScheduleSB::print(std::ostream &os) const {
os << "Schedule:\n";
for(schedule_const_iterator I = schedule.begin(), E = schedule.end(); I != E; ++I) {
os << "Cycle: " << I->first << "\n";
for(std::vector<MSchedGraphSBNode*>::const_iterator node = I->second.begin(), nodeEnd = I->second.end(); node != nodeEnd; ++node)
os << **node << "\n";
}
os << "Kernel:\n";
for(std::vector<std::pair<MachineInstr*, int> >::const_iterator I = kernel.begin(),
E = kernel.end(); I != E; ++I)
os << "Node: " << *(I->first) << " Stage: " << I->second << "\n";
}
void MSScheduleSB::printSchedule(std::ostream &os) const {
os << "Schedule:\n";
for(schedule_const_iterator I = schedule.begin(), E = schedule.end(); I != E; ++I) {
os << "Cycle: " << I->first << "\n";
for(std::vector<MSchedGraphSBNode*>::const_iterator node = I->second.begin(), nodeEnd = I->second.end(); node != nodeEnd; ++node)
os << **node << "\n";
}
}

View File

@ -1,73 +0,0 @@
//===-- MSScheduleSB.h - Schedule ------- -------------------------*- 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.
//
//===----------------------------------------------------------------------===//
//
// The schedule generated by a scheduling algorithm
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_MSSCHEDULESB_H
#define LLVM_MSSCHEDULESB_H
#include "MSchedGraphSB.h"
#include <vector>
#include <set>
namespace llvm {
class MSScheduleSB {
std::map<int, std::vector<MSchedGraphSBNode*> > schedule;
unsigned numIssue;
//Internal map to keep track of explicit resources
std::map<int, std::map<int, int> > resourceNumPerCycle;
//Check if all resources are free
bool resourcesFree(MSchedGraphSBNode*, int, int II);
bool resourceAvailable(int resourceNum, int cycle);
void useResource(int resourceNum, int cycle);
//Resulting kernel
std::vector<std::pair<MachineInstr*, int> > kernel;
//Max stage count
int maxStage;
//add at the right spot in the schedule
void addToSchedule(int, MSchedGraphSBNode*);
public:
MSScheduleSB(int num) : numIssue(num) {}
MSScheduleSB() : numIssue(4) {}
bool insert(MSchedGraphSBNode *node, int cycle, int II);
int getStartCycle(MSchedGraphSBNode *node);
void clear() { schedule.clear(); resourceNumPerCycle.clear(); kernel.clear(); }
std::vector<std::pair<MachineInstr*, int> >* getKernel() { return &kernel; }
bool constructKernel(int II, std::vector<MSchedGraphSBNode*> &branches, std::map<const MachineInstr*, unsigned> &indVar);
int getMaxStage() { return maxStage; }
bool defPreviousStage(Value *def, int stage);
//iterators
typedef std::map<int, std::vector<MSchedGraphSBNode*> >::iterator schedule_iterator;
typedef std::map<int, std::vector<MSchedGraphSBNode*> >::const_iterator schedule_const_iterator;
schedule_iterator begin() { return schedule.begin(); };
schedule_iterator end() { return schedule.end(); };
void print(std::ostream &os) const;
void printSchedule(std::ostream &os) const;
typedef std::vector<std::pair<MachineInstr*, int> >::iterator kernel_iterator;
typedef std::vector<std::pair<MachineInstr*, int> >::const_iterator kernel_const_iterator;
kernel_iterator kernel_begin() { return kernel.begin(); }
kernel_iterator kernel_end() { return kernel.end(); }
};
}
#endif

View File

@ -1,804 +0,0 @@
//===-- MSchedGraph.cpp - Scheduling Graph ----------------------*- 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.
//
//===----------------------------------------------------------------------===//
//
// A graph class for dependencies. This graph only contains true, anti, and
// output data dependencies for a given MachineBasicBlock. Dependencies
// across iterations are also computed. Unless data dependence analysis
// is provided, a conservative approach of adding dependencies between all
// loads and stores is taken.
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "ModuloSched"
#include "MSchedGraph.h"
#include "../SparcV9RegisterInfo.h"
#include "../MachineCodeForInstruction.h"
#include "llvm/BasicBlock.h"
#include "llvm/Constants.h"
#include "llvm/Instructions.h"
#include "llvm/Type.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Support/Debug.h"
#include <cstdlib>
#include <algorithm>
#include <set>
#include <iostream>
using namespace llvm;
//MSchedGraphNode constructor
MSchedGraphNode::MSchedGraphNode(const MachineInstr* inst,
MSchedGraph *graph, unsigned idx,
unsigned late, bool isBranch)
: Inst(inst), Parent(graph), index(idx), latency(late),
isBranchInstr(isBranch) {
//Add to the graph
graph->addNode(inst, this);
}
//MSchedGraphNode copy constructor
MSchedGraphNode::MSchedGraphNode(const MSchedGraphNode &N)
: Predecessors(N.Predecessors), Successors(N.Successors) {
Inst = N.Inst;
Parent = N.Parent;
index = N.index;
latency = N.latency;
isBranchInstr = N.isBranchInstr;
}
//Print the node (instruction and latency)
void MSchedGraphNode::print(std::ostream &os) const {
os << "MSchedGraphNode: Inst=" << *Inst << ", latency= " << latency << "\n";
}
//Get the edge from a predecessor to this node
MSchedGraphEdge MSchedGraphNode::getInEdge(MSchedGraphNode *pred) {
//Loop over all the successors of our predecessor
//return the edge the corresponds to this in edge
for (MSchedGraphNode::succ_iterator I = pred->succ_begin(),
E = pred->succ_end(); I != E; ++I) {
if (*I == this)
return I.getEdge();
}
assert(0 && "Should have found edge between this node and its predecessor!");
abort();
}
//Get the iteration difference for the edge from this node to its successor
unsigned MSchedGraphNode::getIteDiff(MSchedGraphNode *succ) {
for(std::vector<MSchedGraphEdge>::iterator I = Successors.begin(),
E = Successors.end();
I != E; ++I) {
if(I->getDest() == succ)
return I->getIteDiff();
}
return 0;
}
//Get the index into the vector of edges for the edge from pred to this node
unsigned MSchedGraphNode::getInEdgeNum(MSchedGraphNode *pred) {
//Loop over all the successors of our predecessor
//return the edge the corresponds to this in edge
int count = 0;
for(MSchedGraphNode::succ_iterator I = pred->succ_begin(),
E = pred->succ_end();
I != E; ++I) {
if(*I == this)
return count;
count++;
}
assert(0 && "Should have found edge between this node and its predecessor!");
abort();
}
//Determine if succ is a successor of this node
bool MSchedGraphNode::isSuccessor(MSchedGraphNode *succ) {
for(succ_iterator I = succ_begin(), E = succ_end(); I != E; ++I)
if(*I == succ)
return true;
return false;
}
//Dtermine if pred is a predecessor of this node
bool MSchedGraphNode::isPredecessor(MSchedGraphNode *pred) {
if(std::find( Predecessors.begin(), Predecessors.end(),
pred) != Predecessors.end())
return true;
else
return false;
}
//Add a node to the graph
void MSchedGraph::addNode(const MachineInstr *MI,
MSchedGraphNode *node) {
//Make sure node does not already exist
assert(GraphMap.find(MI) == GraphMap.end()
&& "New MSchedGraphNode already exists for this instruction");
GraphMap[MI] = node;
}
//Delete a node to the graph
void MSchedGraph::deleteNode(MSchedGraphNode *node) {
//Delete the edge to this node from all predecessors
while(node->pred_size() > 0) {
//DEBUG(std::cerr << "Delete edge from: " << **P << " to " << *node << "\n");
MSchedGraphNode *pred = *(node->pred_begin());
pred->deleteSuccessor(node);
}
//Remove this node from the graph
GraphMap.erase(node->getInst());
}
//Create a graph for a machine block. The ignoreInstrs map is so that
//we ignore instructions associated to the index variable since this
//is a special case in Modulo Scheduling. We only want to deal with
//the body of the loop.
MSchedGraph::MSchedGraph(const MachineBasicBlock *bb,
const TargetMachine &targ,
std::map<const MachineInstr*, unsigned> &ignoreInstrs,
DependenceAnalyzer &DA,
std::map<MachineInstr*, Instruction*> &machineTollvm)
: Target(targ) {
//Make sure BB is not null,
assert(bb != NULL && "Basic Block is null");
BBs.push_back(bb);
//Create nodes and edges for this BB
buildNodesAndEdges(ignoreInstrs, DA, machineTollvm);
//Experimental!
//addBranchEdges();
}
//Create a graph for a machine block. The ignoreInstrs map is so that
//we ignore instructions associated to the index variable since this
//is a special case in Modulo Scheduling. We only want to deal with
//the body of the loop.
MSchedGraph::MSchedGraph(std::vector<const MachineBasicBlock*> &bbs,
const TargetMachine &targ,
std::map<const MachineInstr*, unsigned> &ignoreInstrs,
DependenceAnalyzer &DA,
std::map<MachineInstr*, Instruction*> &machineTollvm)
: BBs(bbs), Target(targ) {
//Make sure there is at least one BB and it is not null,
assert(((bbs.size() >= 1) && bbs[1] != NULL) && "Basic Block is null");
//Create nodes and edges for this BB
buildNodesAndEdges(ignoreInstrs, DA, machineTollvm);
//Experimental!
//addBranchEdges();
}
//Copies the graph and keeps a map from old to new nodes
MSchedGraph::MSchedGraph(const MSchedGraph &G,
std::map<MSchedGraphNode*, MSchedGraphNode*> &newNodes)
: Target(G.Target) {
BBs = G.BBs;
std::map<MSchedGraphNode*, MSchedGraphNode*> oldToNew;
//Copy all nodes
for(MSchedGraph::const_iterator N = G.GraphMap.begin(),
NE = G.GraphMap.end(); N != NE; ++N) {
MSchedGraphNode *newNode = new MSchedGraphNode(*(N->second));
oldToNew[&*(N->second)] = newNode;
newNodes[newNode] = &*(N->second);
GraphMap[&*(N->first)] = newNode;
}
//Loop over nodes and update edges to point to new nodes
for(MSchedGraph::iterator N = GraphMap.begin(), NE = GraphMap.end();
N != NE; ++N) {
//Get the node we are dealing with
MSchedGraphNode *node = &*(N->second);
node->setParent(this);
//Loop over nodes successors and predecessors and update to the new nodes
for(unsigned i = 0; i < node->pred_size(); ++i) {
node->setPredecessor(i, oldToNew[node->getPredecessor(i)]);
}
for(unsigned i = 0; i < node->succ_size(); ++i) {
MSchedGraphEdge *edge = node->getSuccessor(i);
MSchedGraphNode *oldDest = edge->getDest();
edge->setDest(oldToNew[oldDest]);
}
}
}
//Deconstructor, deletes all nodes in the graph
MSchedGraph::~MSchedGraph () {
for(MSchedGraph::iterator I = GraphMap.begin(), E = GraphMap.end();
I != E; ++I)
delete I->second;
}
//Print out graph
void MSchedGraph::print(std::ostream &os) const {
for(MSchedGraph::const_iterator N = GraphMap.begin(), NE = GraphMap.end();
N != NE; ++N) {
//Get the node we are dealing with
MSchedGraphNode *node = &*(N->second);
os << "Node Start\n";
node->print(os);
os << "Successors:\n";
//print successors
for(unsigned i = 0; i < node->succ_size(); ++i) {
MSchedGraphEdge *edge = node->getSuccessor(i);
MSchedGraphNode *oldDest = edge->getDest();
oldDest->print(os);
}
os << "Node End\n";
}
}
//Calculate total delay
int MSchedGraph::totalDelay() {
int sum = 0;
for(MSchedGraph::const_iterator N = GraphMap.begin(), NE = GraphMap.end();
N != NE; ++N) {
//Get the node we are dealing with
MSchedGraphNode *node = &*(N->second);
sum += node->getLatency();
}
return sum;
}
//Experimental code to add edges from the branch to all nodes dependent upon it.
void hasPath(MSchedGraphNode *node, std::set<MSchedGraphNode*> &visited,
std::set<MSchedGraphNode*> &branches, MSchedGraphNode *startNode,
std::set<std::pair<MSchedGraphNode*,MSchedGraphNode*> > &newEdges ) {
visited.insert(node);
DEBUG(std::cerr << "Visiting: " << *node << "\n");
//Loop over successors
for(unsigned i = 0; i < node->succ_size(); ++i) {
MSchedGraphEdge *edge = node->getSuccessor(i);
MSchedGraphNode *dest = edge->getDest();
if(branches.count(dest))
newEdges.insert(std::make_pair(dest, startNode));
//only visit if we have not already
else if(!visited.count(dest)) {
if(edge->getIteDiff() == 0)
hasPath(dest, visited, branches, startNode, newEdges);}
}
}
//Experimental code to add edges from the branch to all nodes dependent upon it.
void MSchedGraph::addBranchEdges() {
std::set<MSchedGraphNode*> branches;
std::set<MSchedGraphNode*> nodes;
for(MSchedGraph::iterator I = GraphMap.begin(), E = GraphMap.end();
I != E; ++I) {
if(I->second->isBranch())
if(I->second->hasPredecessors())
branches.insert(I->second);
}
//See if there is a path first instruction to the branches, if so, add an
//iteration dependence between that node and the branch
std::set<std::pair<MSchedGraphNode*, MSchedGraphNode*> > newEdges;
for(MSchedGraph::iterator I = GraphMap.begin(), E = GraphMap.end();
I != E; ++I) {
std::set<MSchedGraphNode*> visited;
hasPath((I->second), visited, branches, (I->second), newEdges);
}
//Spit out all edges we are going to add
unsigned min = GraphMap.size();
if(newEdges.size() == 1) {
((newEdges.begin())->first)->addOutEdge(((newEdges.begin())->second),
MSchedGraphEdge::BranchDep,
MSchedGraphEdge::NonDataDep, 1);
}
else {
unsigned count = 0;
MSchedGraphNode *start;
MSchedGraphNode *end;
for(std::set<std::pair<MSchedGraphNode*, MSchedGraphNode*> >::iterator I = newEdges.begin(), E = newEdges.end(); I != E; ++I) {
DEBUG(std::cerr << "Branch Edge from: " << *(I->first) << " to " << *(I->second) << "\n");
// if(I->second->getIndex() <= min) {
start = I->first;
end = I->second;
//min = I->second->getIndex();
//}
start->addOutEdge(end,
MSchedGraphEdge::BranchDep,
MSchedGraphEdge::NonDataDep, 1);
}
}
}
//Add edges between the nodes
void MSchedGraph::buildNodesAndEdges(std::map<const MachineInstr*, unsigned> &ignoreInstrs,
DependenceAnalyzer &DA,
std::map<MachineInstr*, Instruction*> &machineTollvm) {
//Get Machine target information for calculating latency
const TargetInstrInfo *MTI = Target.getInstrInfo();
std::vector<MSchedGraphNode*> memInstructions;
std::map<int, std::vector<OpIndexNodePair> > regNumtoNodeMap;
std::map<const Value*, std::vector<OpIndexNodePair> > valuetoNodeMap;
//Save PHI instructions to deal with later
std::vector<const MachineInstr*> phiInstrs;
unsigned index = 0;
for(std::vector<const MachineBasicBlock*>::iterator B = BBs.begin(),
BE = BBs.end(); B != BE; ++B) {
const MachineBasicBlock *BB = *B;
//Loop over instructions in MBB and add nodes and edges
for (MachineBasicBlock::const_iterator MI = BB->begin(), e = BB->end();
MI != e; ++MI) {
//Ignore indvar instructions
if(ignoreInstrs.count(MI)) {
++index;
continue;
}
//Get each instruction of machine basic block, get the delay
//using the op code, create a new node for it, and add to the
//graph.
MachineOpCode opCode = MI->getOpcode();
int delay;
#if 0 // FIXME: LOOK INTO THIS
//Check if subsequent instructions can be issued before
//the result is ready, if so use min delay.
if(MTI->hasResultInterlock(MIopCode))
delay = MTI->minLatency(MIopCode);
else
#endif
//Get delay
delay = MTI->maxLatency(opCode);
//Create new node for this machine instruction and add to the graph.
//Create only if not a nop
if(MTI->isNop(opCode))
continue;
//Sparc BE does not use PHI opcode, so assert on this case
assert(opCode != TargetInstrInfo::PHI && "Did not expect PHI opcode");
bool isBranch = false;
//We want to flag the branch node to treat it special
if(MTI->isBranch(opCode))
isBranch = true;
//Node is created and added to the graph automatically
MSchedGraphNode *node = new MSchedGraphNode(MI, this, index, delay,
isBranch);
DEBUG(std::cerr << "Created Node: " << *node << "\n");
//Check OpCode to keep track of memory operations to add memory
//dependencies later.
if(MTI->isLoad(opCode) || MTI->isStore(opCode))
memInstructions.push_back(node);
//Loop over all operands, and put them into the register number to
//graph node map for determining dependencies
//If an operands is a use/def, we have an anti dependence to itself
for(unsigned i=0; i < MI->getNumOperands(); ++i) {
//Get Operand
const MachineOperand &mOp = MI->getOperand(i);
//Check if it has an allocated register
if(mOp.hasAllocatedReg()) {
int regNum = mOp.getReg();
if(regNum != SparcV9::g0) {
//Put into our map
regNumtoNodeMap[regNum].push_back(std::make_pair(i, node));
}
continue;
}
//Add virtual registers dependencies
//Check if any exist in the value map already and create dependencies
//between them.
if(mOp.getType() == MachineOperand::MO_VirtualRegister
|| mOp.getType() == MachineOperand::MO_CCRegister) {
//Make sure virtual register value is not null
assert((mOp.getVRegValue() != NULL) && "Null value is defined");
//Check if this is a read operation in a phi node, if so DO NOT PROCESS
if(mOp.isUse() && (opCode == TargetInstrInfo::PHI)) {
DEBUG(std::cerr << "Read Operation in a PHI node\n");
continue;
}
if (const Value* srcI = mOp.getVRegValue()) {
//Find value in the map
std::map<const Value*, std::vector<OpIndexNodePair> >::iterator V
= valuetoNodeMap.find(srcI);
//If there is something in the map already, add edges from
//those instructions
//to this one we are processing
if(V != valuetoNodeMap.end()) {
addValueEdges(V->second, node, mOp.isUse(), mOp.isDef(), phiInstrs);
//Add to value map
V->second.push_back(std::make_pair(i,node));
}
//Otherwise put it in the map
else
//Put into value map
valuetoNodeMap[mOp.getVRegValue()].push_back(std::make_pair(i, node));
}
}
}
++index;
}
//Loop over LLVM BB, examine phi instructions, and add them to our
//phiInstr list to process
const BasicBlock *llvm_bb = BB->getBasicBlock();
for(BasicBlock::const_iterator I = llvm_bb->begin(), E = llvm_bb->end();
I != E; ++I) {
if(const PHINode *PN = dyn_cast<PHINode>(I)) {
MachineCodeForInstruction & tempMvec = MachineCodeForInstruction::get(PN);
for (unsigned j = 0; j < tempMvec.size(); j++) {
if(!ignoreInstrs.count(tempMvec[j])) {
DEBUG(std::cerr << "Inserting phi instr into map: " << *tempMvec[j] << "\n");
phiInstrs.push_back((MachineInstr*) tempMvec[j]);
}
}
}
}
addMemEdges(memInstructions, DA, machineTollvm);
addMachRegEdges(regNumtoNodeMap);
//Finally deal with PHI Nodes and Value*
for(std::vector<const MachineInstr*>::iterator I = phiInstrs.begin(),
E = phiInstrs.end(); I != E; ++I) {
//Get Node for this instruction
std::map<const MachineInstr*, MSchedGraphNode*>::iterator X;
X = find(*I);
if(X == GraphMap.end())
continue;
MSchedGraphNode *node = X->second;
DEBUG(std::cerr << "Adding ite diff edges for node: " << *node << "\n");
//Loop over operands for this instruction and add value edges
for(unsigned i=0; i < (*I)->getNumOperands(); ++i) {
//Get Operand
const MachineOperand &mOp = (*I)->getOperand(i);
if((mOp.getType() == MachineOperand::MO_VirtualRegister
|| mOp.getType() == MachineOperand::MO_CCRegister) && mOp.isUse()) {
//find the value in the map
if (const Value* srcI = mOp.getVRegValue()) {
//Find value in the map
std::map<const Value*, std::vector<OpIndexNodePair> >::iterator V
= valuetoNodeMap.find(srcI);
//If there is something in the map already, add edges from
//those instructions
//to this one we are processing
if(V != valuetoNodeMap.end()) {
addValueEdges(V->second, node, mOp.isUse(), mOp.isDef(),
phiInstrs, 1);
}
}
}
}
}
}
}
//Add dependencies for Value*s
void MSchedGraph::addValueEdges(std::vector<OpIndexNodePair> &NodesInMap,
MSchedGraphNode *destNode, bool nodeIsUse,
bool nodeIsDef, std::vector<const MachineInstr*> &phiInstrs, int diff) {
for(std::vector<OpIndexNodePair>::iterator I = NodesInMap.begin(),
E = NodesInMap.end(); I != E; ++I) {
//Get node in vectors machine operand that is the same value as node
MSchedGraphNode *srcNode = I->second;
MachineOperand mOp = srcNode->getInst()->getOperand(I->first);
if(diff > 0)
if(std::find(phiInstrs.begin(), phiInstrs.end(), srcNode->getInst()) == phiInstrs.end())
continue;
//Node is a Def, so add output dep.
if(nodeIsDef) {
if(mOp.isUse()) {
DEBUG(std::cerr << "Edge from " << *srcNode << " to " << *destNode << " (itediff=" << diff << ", type=anti)\n");
srcNode->addOutEdge(destNode, MSchedGraphEdge::ValueDep,
MSchedGraphEdge::AntiDep, diff);
}
if(mOp.isDef()) {
DEBUG(std::cerr << "Edge from " << *srcNode << " to " << *destNode << " (itediff=" << diff << ", type=output)\n");
srcNode->addOutEdge(destNode, MSchedGraphEdge::ValueDep,
MSchedGraphEdge::OutputDep, diff);
}
}
if(nodeIsUse) {
if(mOp.isDef()) {
DEBUG(std::cerr << "Edge from " << *srcNode << " to " << *destNode << " (itediff=" << diff << ", type=true)\n");
srcNode->addOutEdge(destNode, MSchedGraphEdge::ValueDep,
MSchedGraphEdge::TrueDep, diff);
}
}
}
}
//Add dependencies for machine registers across iterations
void MSchedGraph::addMachRegEdges(std::map<int, std::vector<OpIndexNodePair> >& regNumtoNodeMap) {
//Loop over all machine registers in the map, and add dependencies
//between the instructions that use it
typedef std::map<int, std::vector<OpIndexNodePair> > regNodeMap;
for(regNodeMap::iterator I = regNumtoNodeMap.begin();
I != regNumtoNodeMap.end(); ++I) {
//Get the register number
int regNum = (*I).first;
//Get Vector of nodes that use this register
std::vector<OpIndexNodePair> Nodes = (*I).second;
//Loop over nodes and determine the dependence between the other
//nodes in the vector
for(unsigned i =0; i < Nodes.size(); ++i) {
//Get src node operator index that uses this machine register
int srcOpIndex = Nodes[i].first;
//Get the actual src Node
MSchedGraphNode *srcNode = Nodes[i].second;
//Get Operand
const MachineOperand &srcMOp = srcNode->getInst()->getOperand(srcOpIndex);
bool srcIsUseandDef = srcMOp.isDef() && srcMOp.isUse();
bool srcIsUse = srcMOp.isUse() && !srcMOp.isDef();
//Look at all instructions after this in execution order
for(unsigned j=i+1; j < Nodes.size(); ++j) {
//Sink node is a write
if(Nodes[j].second->getInst()->getOperand(Nodes[j].first).isDef()) {
//Src only uses the register (read)
if(srcIsUse)
srcNode->addOutEdge(Nodes[j].second,
MSchedGraphEdge::MachineRegister,
MSchedGraphEdge::AntiDep);
else if(srcIsUseandDef) {
srcNode->addOutEdge(Nodes[j].second,
MSchedGraphEdge::MachineRegister,
MSchedGraphEdge::AntiDep);
srcNode->addOutEdge(Nodes[j].second,
MSchedGraphEdge::MachineRegister,
MSchedGraphEdge::OutputDep);
}
else
srcNode->addOutEdge(Nodes[j].second,
MSchedGraphEdge::MachineRegister,
MSchedGraphEdge::OutputDep);
}
//Dest node is a read
else {
if(!srcIsUse || srcIsUseandDef)
srcNode->addOutEdge(Nodes[j].second,
MSchedGraphEdge::MachineRegister,
MSchedGraphEdge::TrueDep);
}
}
//Look at all the instructions before this one since machine registers
//could live across iterations.
for(unsigned j = 0; j < i; ++j) {
//Sink node is a write
if(Nodes[j].second->getInst()->getOperand(Nodes[j].first).isDef()) {
//Src only uses the register (read)
if(srcIsUse)
srcNode->addOutEdge(Nodes[j].second,
MSchedGraphEdge::MachineRegister,
MSchedGraphEdge::AntiDep, 1);
else if(srcIsUseandDef) {
srcNode->addOutEdge(Nodes[j].second,
MSchedGraphEdge::MachineRegister,
MSchedGraphEdge::AntiDep, 1);
srcNode->addOutEdge(Nodes[j].second,
MSchedGraphEdge::MachineRegister,
MSchedGraphEdge::OutputDep, 1);
}
else
srcNode->addOutEdge(Nodes[j].second,
MSchedGraphEdge::MachineRegister,
MSchedGraphEdge::OutputDep, 1);
}
//Dest node is a read
else {
if(!srcIsUse || srcIsUseandDef)
srcNode->addOutEdge(Nodes[j].second,
MSchedGraphEdge::MachineRegister,
MSchedGraphEdge::TrueDep,1 );
}
}
}
}
}
//Add edges between all loads and stores
//Can be less strict with alias analysis and data dependence analysis.
void MSchedGraph::addMemEdges(const std::vector<MSchedGraphNode*>& memInst,
DependenceAnalyzer &DA,
std::map<MachineInstr*, Instruction*> &machineTollvm) {
//Get Target machine instruction info
const TargetInstrInfo *TMI = Target.getInstrInfo();
//Loop over all memory instructions in the vector
//Knowing that they are in execution, add true, anti, and output dependencies
for (unsigned srcIndex = 0; srcIndex < memInst.size(); ++srcIndex) {
MachineInstr *srcInst = (MachineInstr*) memInst[srcIndex]->getInst();
//Get the machine opCode to determine type of memory instruction
MachineOpCode srcNodeOpCode = srcInst->getOpcode();
//All instructions after this one in execution order have an
//iteration delay of 0
for(unsigned destIndex = 0; destIndex < memInst.size(); ++destIndex) {
//No self loops
if(destIndex == srcIndex)
continue;
MachineInstr *destInst = (MachineInstr*) memInst[destIndex]->getInst();
DEBUG(std::cerr << "MInst1: " << *srcInst << "\n");
DEBUG(std::cerr << "MInst2: " << *destInst << "\n");
//Assuming instructions without corresponding llvm instructions
//are from constant pools.
if (!machineTollvm.count(srcInst) || !machineTollvm.count(destInst))
continue;
bool useDepAnalyzer = true;
//Some machine loads and stores are generated by casts, so be
//conservative and always add deps
Instruction *srcLLVM = machineTollvm[srcInst];
Instruction *destLLVM = machineTollvm[destInst];
if(!isa<LoadInst>(srcLLVM)
&& !isa<StoreInst>(srcLLVM)) {
if(isa<BinaryOperator>(srcLLVM)) {
if(isa<ConstantFP>(srcLLVM->getOperand(0)) || isa<ConstantFP>(srcLLVM->getOperand(1)))
continue;
}
useDepAnalyzer = false;
}
if(!isa<LoadInst>(destLLVM)
&& !isa<StoreInst>(destLLVM)) {
if(isa<BinaryOperator>(destLLVM)) {
if(isa<ConstantFP>(destLLVM->getOperand(0)) || isa<ConstantFP>(destLLVM->getOperand(1)))
continue;
}
useDepAnalyzer = false;
}
//Use dep analysis when we have corresponding llvm loads/stores
if(useDepAnalyzer) {
bool srcBeforeDest = true;
if(destIndex < srcIndex)
srcBeforeDest = false;
DependenceResult dr = DA.getDependenceInfo(machineTollvm[srcInst],
machineTollvm[destInst],
srcBeforeDest);
for(std::vector<Dependence>::iterator d = dr.dependences.begin(),
de = dr.dependences.end(); d != de; ++d) {
//Add edge from load to store
memInst[srcIndex]->addOutEdge(memInst[destIndex],
MSchedGraphEdge::MemoryDep,
d->getDepType(), d->getIteDiff());
}
}
//Otherwise, we can not do any further analysis and must make a dependence
else {
//Get the machine opCode to determine type of memory instruction
MachineOpCode destNodeOpCode = destInst->getOpcode();
//Get the Value* that we are reading from the load, always the first op
const MachineOperand &mOp = srcInst->getOperand(0);
const MachineOperand &mOp2 = destInst->getOperand(0);
if(mOp.hasAllocatedReg())
if(mOp.getReg() == SparcV9::g0)
continue;
if(mOp2.hasAllocatedReg())
if(mOp2.getReg() == SparcV9::g0)
continue;
DEBUG(std::cerr << "Adding dependence for machine instructions\n");
//Load-Store deps
if(TMI->isLoad(srcNodeOpCode)) {
if(TMI->isStore(destNodeOpCode))
memInst[srcIndex]->addOutEdge(memInst[destIndex],
MSchedGraphEdge::MemoryDep,
MSchedGraphEdge::AntiDep, 0);
}
else if(TMI->isStore(srcNodeOpCode)) {
if(TMI->isStore(destNodeOpCode))
memInst[srcIndex]->addOutEdge(memInst[destIndex],
MSchedGraphEdge::MemoryDep,
MSchedGraphEdge::OutputDep, 0);
else
memInst[srcIndex]->addOutEdge(memInst[destIndex],
MSchedGraphEdge::MemoryDep,
MSchedGraphEdge::TrueDep, 0);
}
}
}
}
}

View File

@ -1,398 +0,0 @@
//===-- MSchedGraph.h - Scheduling Graph ------------------------*- 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.
//
//===----------------------------------------------------------------------===//
//
// A graph class for dependencies. This graph only contains true, anti, and
// output data dependencies for a given MachineBasicBlock. Dependencies
// across iterations are also computed. Unless data dependence analysis
// is provided, a conservative approach of adding dependencies between all
// loads and stores is taken.
//===----------------------------------------------------------------------===//
#ifndef LLVM_MSCHEDGRAPH_H
#define LLVM_MSCHEDGRAPH_H
#include "DependenceAnalyzer.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetData.h"
#include "llvm/ADT/GraphTraits.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/iterator"
#include <vector>
namespace llvm {
class MSchedGraph;
class MSchedGraphNode;
template<class IteratorType, class NodeType>
class MSchedGraphNodeIterator;
//MSchedGraphEdge encapsulates the data dependence between nodes. It
//identifies the dependence type, on what, and the iteration
//difference
struct MSchedGraphEdge {
enum DataDepOrderType {
TrueDep, AntiDep, OutputDep, NonDataDep
};
enum MSchedGraphEdgeType {
MemoryDep, ValueDep, MachineRegister, BranchDep
};
//Get or set edge data
MSchedGraphNode *getDest() const { return dest; }
unsigned getIteDiff() { return iteDiff; }
unsigned getDepOrderType() { return depOrderType; }
void setDest(MSchedGraphNode *newDest) { dest = newDest; }
private:
friend class MSchedGraphNode;
MSchedGraphEdge(MSchedGraphNode *destination, MSchedGraphEdgeType type,
unsigned deptype, unsigned diff)
: dest(destination), depType(type), depOrderType(deptype), iteDiff(diff) {}
MSchedGraphNode *dest;
MSchedGraphEdgeType depType;
unsigned depOrderType;
unsigned iteDiff;
};
//MSchedGraphNode represents a machine instruction and its
//corresponding latency. Each node also contains a list of its
//predecessors and sucessors.
class MSchedGraphNode {
const MachineInstr* Inst; //Machine Instruction
MSchedGraph* Parent; //Graph this node belongs to
unsigned index; //Index in BB
unsigned latency; //Latency of Instruction
bool isBranchInstr; //Is this node the branch instr or not
std::vector<MSchedGraphNode*> Predecessors; //Predecessor Nodes
std::vector<MSchedGraphEdge> Successors; //Successor edges
public:
MSchedGraphNode(const MachineInstr *inst, MSchedGraph *graph,
unsigned index, unsigned late=0, bool isBranch=false);
MSchedGraphNode(const MSchedGraphNode &N);
//Iterators - Predecessor and Succussor
typedef std::vector<MSchedGraphNode*>::iterator pred_iterator;
pred_iterator pred_begin() { return Predecessors.begin(); }
pred_iterator pred_end() { return Predecessors.end(); }
unsigned pred_size() { return Predecessors.size(); }
typedef std::vector<MSchedGraphNode*>::const_iterator pred_const_iterator;
pred_const_iterator pred_begin() const { return Predecessors.begin(); }
pred_const_iterator pred_end() const { return Predecessors.end(); }
typedef MSchedGraphNodeIterator<std::vector<MSchedGraphEdge>::const_iterator,
const MSchedGraphNode> succ_const_iterator;
succ_const_iterator succ_begin() const;
succ_const_iterator succ_end() const;
typedef MSchedGraphNodeIterator<std::vector<MSchedGraphEdge>::iterator,
MSchedGraphNode> succ_iterator;
succ_iterator succ_begin();
succ_iterator succ_end();
unsigned succ_size() { return Successors.size(); }
//Get or set predecessor nodes, or successor edges
void setPredecessor(unsigned index, MSchedGraphNode *dest) {
Predecessors[index] = dest;
}
MSchedGraphNode* getPredecessor(unsigned index) {
return Predecessors[index];
}
MSchedGraphEdge* getSuccessor(unsigned index) {
return &Successors[index];
}
void deleteSuccessor(MSchedGraphNode *node) {
for (unsigned i = 0; i != Successors.size(); ++i)
if (Successors[i].getDest() == node) {
Successors.erase(Successors.begin()+i);
node->Predecessors.erase(std::find(node->Predecessors.begin(),
node->Predecessors.end(), this));
--i; //Decrease index var since we deleted a node
}
}
void addOutEdge(MSchedGraphNode *destination,
MSchedGraphEdge::MSchedGraphEdgeType type,
unsigned deptype, unsigned diff=0) {
Successors.push_back(MSchedGraphEdge(destination, type, deptype,diff));
destination->Predecessors.push_back(this);
}
//General methods to get and set data for the node
const MachineInstr* getInst() { return Inst; }
MSchedGraph* getParent() { return Parent; }
bool hasPredecessors() { return (Predecessors.size() > 0); }
bool hasSuccessors() { return (Successors.size() > 0); }
unsigned getLatency() { return latency; }
unsigned getLatency() const { return latency; }
unsigned getIndex() { return index; }
unsigned getIteDiff(MSchedGraphNode *succ);
MSchedGraphEdge getInEdge(MSchedGraphNode *pred);
unsigned getInEdgeNum(MSchedGraphNode *pred);
bool isSuccessor(MSchedGraphNode *);
bool isPredecessor(MSchedGraphNode *);
bool isBranch() { return isBranchInstr; }
//Debug support
void print(std::ostream &os) const;
void setParent(MSchedGraph *p) { Parent = p; }
};
//Node iterator for graph generation
template<class IteratorType, class NodeType>
class MSchedGraphNodeIterator : public forward_iterator<NodeType*, ptrdiff_t> {
IteratorType I; // std::vector<MSchedGraphEdge>::iterator or const_iterator
public:
MSchedGraphNodeIterator(IteratorType i) : I(i) {}
bool operator==(const MSchedGraphNodeIterator RHS) const { return I == RHS.I; }
bool operator!=(const MSchedGraphNodeIterator RHS) const { return I != RHS.I; }
const MSchedGraphNodeIterator &operator=(const MSchedGraphNodeIterator &RHS) {
I = RHS.I;
return *this;
}
NodeType* operator*() const {
return I->getDest();
}
NodeType* operator->() const { return operator*(); }
MSchedGraphNodeIterator& operator++() { // Preincrement
++I;
return *this;
}
MSchedGraphNodeIterator operator++(int) { // Postincrement
MSchedGraphNodeIterator tmp = *this; ++*this; return tmp;
}
MSchedGraphEdge &getEdge() {
return *I;
}
const MSchedGraphEdge &getEdge() const {
return *I;
}
};
inline MSchedGraphNode::succ_const_iterator MSchedGraphNode::succ_begin() const {
return succ_const_iterator(Successors.begin());
}
inline MSchedGraphNode::succ_const_iterator MSchedGraphNode::succ_end() const {
return succ_const_iterator(Successors.end());
}
inline MSchedGraphNode::succ_iterator MSchedGraphNode::succ_begin() {
return succ_iterator(Successors.begin());
}
inline MSchedGraphNode::succ_iterator MSchedGraphNode::succ_end() {
return succ_iterator(Successors.end());
}
// ostream << operator for MSGraphNode class
inline std::ostream &operator<<(std::ostream &os,
const MSchedGraphNode &node) {
node.print(os);
return os;
}
// Provide specializations of GraphTraits to be able to use graph
// iterators on the scheduling graph!
//
template <> struct GraphTraits<MSchedGraphNode*> {
typedef MSchedGraphNode NodeType;
typedef MSchedGraphNode::succ_iterator ChildIteratorType;
static inline ChildIteratorType child_begin(NodeType *N) {
return N->succ_begin();
}
static inline ChildIteratorType child_end(NodeType *N) {
return N->succ_end();
}
static NodeType *getEntryNode(NodeType* N) { return N; }
};
//Graph class to represent dependence graph
class MSchedGraph {
std::vector<const MachineBasicBlock *> BBs; //Machine basic block
const TargetMachine &Target; //Target Machine
//Nodes
std::map<const MachineInstr*, MSchedGraphNode*> GraphMap;
//Add Nodes and Edges to this graph for our BB
typedef std::pair<int, MSchedGraphNode*> OpIndexNodePair;
void buildNodesAndEdges(std::map<const MachineInstr*, unsigned> &ignoreInstrs, DependenceAnalyzer &DA, std::map<MachineInstr*, Instruction*> &machineTollvm);
void addValueEdges(std::vector<OpIndexNodePair> &NodesInMap,
MSchedGraphNode *node,
bool nodeIsUse, bool nodeIsDef, std::vector<const MachineInstr*> &phiInstrs, int diff=0);
void addMachRegEdges(std::map<int,
std::vector<OpIndexNodePair> >& regNumtoNodeMap);
void addMemEdges(const std::vector<MSchedGraphNode*>& memInst,
DependenceAnalyzer &DA, std::map<MachineInstr*, Instruction*> &machineTollvm);
void addBranchEdges();
public:
MSchedGraph(const MachineBasicBlock *bb, const TargetMachine &targ,
std::map<const MachineInstr*, unsigned> &ignoreInstrs,
DependenceAnalyzer &DA, std::map<MachineInstr*, Instruction*> &machineTollvm);
//Copy constructor with maps to link old nodes to new nodes
MSchedGraph(const MSchedGraph &G, std::map<MSchedGraphNode*, MSchedGraphNode*> &newNodes);
MSchedGraph(std::vector<const MachineBasicBlock*> &bbs,
const TargetMachine &targ,
std::map<const MachineInstr*, unsigned> &ignoreInstrs,
DependenceAnalyzer &DA,
std::map<MachineInstr*, Instruction*> &machineTollvm);
//Print graph
void print(std::ostream &os) const;
//Deconstructor!
~MSchedGraph();
//Add or delete nodes from the Graph
void addNode(const MachineInstr* MI, MSchedGraphNode *node);
void deleteNode(MSchedGraphNode *node);
int totalDelay();
//iterators
typedef std::map<const MachineInstr*, MSchedGraphNode*>::iterator iterator;
typedef std::map<const MachineInstr*, MSchedGraphNode*>::const_iterator const_iterator;
typedef std::map<const MachineInstr*, MSchedGraphNode*>::reverse_iterator reverse_iterator;
iterator find(const MachineInstr* I) { return GraphMap.find(I); }
iterator end() { return GraphMap.end(); }
iterator begin() { return GraphMap.begin(); }
unsigned size() { return GraphMap.size(); }
reverse_iterator rbegin() { return GraphMap.rbegin(); }
reverse_iterator rend() { return GraphMap.rend(); }
//Get Target or original machine basic block
const TargetMachine* getTarget() { return &Target; }
std::vector<const MachineBasicBlock*> getBBs() { return BBs; }
};
// Provide specializations of GraphTraits to be able to use graph
// iterators on the scheduling graph
static MSchedGraphNode& getSecond(std::pair<const MachineInstr* const,
MSchedGraphNode*> &Pair) {
return *Pair.second;
}
template <> struct GraphTraits<MSchedGraph*> {
typedef MSchedGraphNode NodeType;
typedef MSchedGraphNode::succ_iterator ChildIteratorType;
static inline ChildIteratorType child_begin(NodeType *N) {
return N->succ_begin();
}
static inline ChildIteratorType child_end(NodeType *N) {
return N->succ_end();
}
typedef std::pointer_to_unary_function<std::pair<const MachineInstr* const,
MSchedGraphNode*>&, MSchedGraphNode&> DerefFun;
typedef mapped_iterator<MSchedGraph::iterator, DerefFun> nodes_iterator;
static nodes_iterator nodes_begin(MSchedGraph *G) {
return map_iterator(((MSchedGraph*)G)->begin(), DerefFun(getSecond));
}
static nodes_iterator nodes_end(MSchedGraph *G) {
return map_iterator(((MSchedGraph*)G)->end(), DerefFun(getSecond));
}
};
template <> struct GraphTraits<const MSchedGraph*> {
typedef const MSchedGraphNode NodeType;
typedef MSchedGraphNode::succ_const_iterator ChildIteratorType;
static inline ChildIteratorType child_begin(NodeType *N) {
return N->succ_begin();
}
static inline ChildIteratorType child_end(NodeType *N) {
return N->succ_end();
}
typedef std::pointer_to_unary_function<std::pair<const MachineInstr* const,
MSchedGraphNode*>&, MSchedGraphNode&> DerefFun;
typedef mapped_iterator<MSchedGraph::iterator, DerefFun> nodes_iterator;
static nodes_iterator nodes_begin(MSchedGraph *G) {
return map_iterator(((MSchedGraph*)G)->begin(), DerefFun(getSecond));
}
static nodes_iterator nodes_end(MSchedGraph *G) {
return map_iterator(((MSchedGraph*)G)->end(), DerefFun(getSecond));
}
};
template <> struct GraphTraits<Inverse<MSchedGraph*> > {
typedef MSchedGraphNode NodeType;
typedef MSchedGraphNode::pred_iterator ChildIteratorType;
static inline ChildIteratorType child_begin(NodeType *N) {
return N->pred_begin();
}
static inline ChildIteratorType child_end(NodeType *N) {
return N->pred_end();
}
typedef std::pointer_to_unary_function<std::pair<const MachineInstr* const,
MSchedGraphNode*>&, MSchedGraphNode&> DerefFun;
typedef mapped_iterator<MSchedGraph::iterator, DerefFun> nodes_iterator;
static nodes_iterator nodes_begin(MSchedGraph *G) {
return map_iterator(((MSchedGraph*)G)->begin(), DerefFun(getSecond));
}
static nodes_iterator nodes_end(MSchedGraph *G) {
return map_iterator(((MSchedGraph*)G)->end(), DerefFun(getSecond));
}
};
template <> struct GraphTraits<Inverse<const MSchedGraph*> > {
typedef const MSchedGraphNode NodeType;
typedef MSchedGraphNode::pred_const_iterator ChildIteratorType;
static inline ChildIteratorType child_begin(NodeType *N) {
return N->pred_begin();
}
static inline ChildIteratorType child_end(NodeType *N) {
return N->pred_end();
}
typedef std::pointer_to_unary_function<std::pair<const MachineInstr* const,
MSchedGraphNode*>&, MSchedGraphNode&> DerefFun;
typedef mapped_iterator<MSchedGraph::iterator, DerefFun> nodes_iterator;
static nodes_iterator nodes_begin(MSchedGraph *G) {
return map_iterator(((MSchedGraph*)G)->begin(), DerefFun(getSecond));
}
static nodes_iterator nodes_end(MSchedGraph *G) {
return map_iterator(((MSchedGraph*)G)->end(), DerefFun(getSecond));
}
};
}
#endif

View File

@ -1,870 +0,0 @@
//===-- MSchedGraphSB.cpp - Scheduling Graph ----------------------*- 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.
//
//===----------------------------------------------------------------------===//
//
// A graph class for dependencies. This graph only contains true, anti, and
// output data dependencies for a given MachineBasicBlock. Dependencies
// across iterations are also computed. Unless data dependence analysis
// is provided, a conservative approach of adding dependencies between all
// loads and stores is taken.
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "ModuloSchedSB"
#include "MSchedGraphSB.h"
#include "../SparcV9RegisterInfo.h"
#include "../MachineCodeForInstruction.h"
#include "llvm/BasicBlock.h"
#include "llvm/Constants.h"
#include "llvm/Instructions.h"
#include "llvm/Type.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Support/Debug.h"
#include <cstdlib>
#include <algorithm>
#include <set>
#include "llvm/Target/TargetSchedInfo.h"
#include "../SparcV9Internals.h"
#include <iostream>
using namespace llvm;
//MSchedGraphSBNode constructor
MSchedGraphSBNode::MSchedGraphSBNode(const MachineInstr* inst,
MSchedGraphSB *graph, unsigned idx,
unsigned late, bool isBranch)
: Inst(inst), Parent(graph), index(idx), latency(late),
isBranchInstr(isBranch) {
//Add to the graph
graph->addNode(inst, this);
}
//MSchedGraphSBNode constructor
MSchedGraphSBNode::MSchedGraphSBNode(const MachineInstr* inst,
std::vector<const MachineInstr*> &other,
MSchedGraphSB *graph, unsigned idx,
unsigned late, bool isPNode)
: Inst(inst), otherInstrs(other), Parent(graph), index(idx), latency(late), isPredicateNode(isPNode) {
isBranchInstr = false;
//Add to the graph
graph->addNode(inst, this);
}
//MSchedGraphSBNode copy constructor
MSchedGraphSBNode::MSchedGraphSBNode(const MSchedGraphSBNode &N)
: Predecessors(N.Predecessors), Successors(N.Successors) {
Inst = N.Inst;
Parent = N.Parent;
index = N.index;
latency = N.latency;
isBranchInstr = N.isBranchInstr;
otherInstrs = N.otherInstrs;
}
//Print the node (instruction and latency)
void MSchedGraphSBNode::print(std::ostream &os) const {
if(!isPredicate())
os << "MSchedGraphSBNode: Inst=" << *Inst << ", latency= " << latency << "\n";
else
os << "Pred Node\n";
}
//Get the edge from a predecessor to this node
MSchedGraphSBEdge MSchedGraphSBNode::getInEdge(MSchedGraphSBNode *pred) {
//Loop over all the successors of our predecessor
//return the edge the corresponds to this in edge
for (MSchedGraphSBNode::succ_iterator I = pred->succ_begin(),
E = pred->succ_end(); I != E; ++I) {
if (*I == this)
return I.getEdge();
}
assert(0 && "Should have found edge between this node and its predecessor!");
abort();
}
//Get the iteration difference for the edge from this node to its successor
unsigned MSchedGraphSBNode::getIteDiff(MSchedGraphSBNode *succ) {
for(std::vector<MSchedGraphSBEdge>::iterator I = Successors.begin(),
E = Successors.end();
I != E; ++I) {
if(I->getDest() == succ)
return I->getIteDiff();
}
return 0;
}
//Get the index into the vector of edges for the edge from pred to this node
unsigned MSchedGraphSBNode::getInEdgeNum(MSchedGraphSBNode *pred) {
//Loop over all the successors of our predecessor
//return the edge the corresponds to this in edge
int count = 0;
for(MSchedGraphSBNode::succ_iterator I = pred->succ_begin(),
E = pred->succ_end();
I != E; ++I) {
if(*I == this)
return count;
count++;
}
assert(0 && "Should have found edge between this node and its predecessor!");
abort();
}
//Determine if succ is a successor of this node
bool MSchedGraphSBNode::isSuccessor(MSchedGraphSBNode *succ) {
for(succ_iterator I = succ_begin(), E = succ_end(); I != E; ++I)
if(*I == succ)
return true;
return false;
}
//Dtermine if pred is a predecessor of this node
bool MSchedGraphSBNode::isPredecessor(MSchedGraphSBNode *pred) {
if(std::find( Predecessors.begin(), Predecessors.end(),
pred) != Predecessors.end())
return true;
else
return false;
}
//Add a node to the graph
void MSchedGraphSB::addNode(const MachineInstr* MI,
MSchedGraphSBNode *node) {
//Make sure node does not already exist
assert(GraphMap.find(MI) == GraphMap.end()
&& "New MSchedGraphSBNode already exists for this instruction");
GraphMap[MI] = node;
}
//Delete a node to the graph
void MSchedGraphSB::deleteNode(MSchedGraphSBNode *node) {
//Delete the edge to this node from all predecessors
while(node->pred_size() > 0) {
//DEBUG(std::cerr << "Delete edge from: " << **P << " to " << *node << "\n");
MSchedGraphSBNode *pred = *(node->pred_begin());
pred->deleteSuccessor(node);
}
//Remove this node from the graph
GraphMap.erase(node->getInst());
}
//Create a graph for a machine block. The ignoreInstrs map is so that
//we ignore instructions associated to the index variable since this
//is a special case in Modulo Scheduling. We only want to deal with
//the body of the loop.
MSchedGraphSB::MSchedGraphSB(std::vector<const MachineBasicBlock*> &bbs,
const TargetMachine &targ,
std::map<const MachineInstr*, unsigned> &ignoreInstrs,
DependenceAnalyzer &DA,
std::map<MachineInstr*, Instruction*> &machineTollvm)
: BBs(bbs), Target(targ) {
//Make sure there is at least one BB and it is not null,
assert(((bbs.size() >= 1) && bbs[1] != NULL) && "Basic Block is null");
std::map<MSchedGraphSBNode*, std::set<MachineInstr*> > liveOutsideTrace;
std::set<const BasicBlock*> llvmBBs;
for(std::vector<const MachineBasicBlock*>::iterator MBB = bbs.begin(), ME = bbs.end()-1;
MBB != ME; ++MBB)
llvmBBs.insert((*MBB)->getBasicBlock());
//create predicate nodes
DEBUG(std::cerr << "Create predicate nodes\n");
for(std::vector<const MachineBasicBlock*>::iterator MBB = bbs.begin(), ME = bbs.end()-1;
MBB != ME; ++MBB) {
//Get LLVM basic block
BasicBlock *BB = (BasicBlock*) (*MBB)->getBasicBlock();
//Get Terminator
BranchInst *b = dyn_cast<BranchInst>(BB->getTerminator());
std::vector<const MachineInstr*> otherInstrs;
MachineInstr *instr = 0;
//Get the condition for the branch (we already checked if it was conditional)
if(b->isConditional()) {
Value *cond = b->getCondition();
DEBUG(std::cerr << "Condition: " << *cond << "\n");
assert(cond && "Condition must not be null!");
if(Instruction *I = dyn_cast<Instruction>(cond)) {
MachineCodeForInstruction & tempMvec = MachineCodeForInstruction::get(I);
if(tempMvec.size() > 0) {
DEBUG(std::cerr << *(tempMvec[tempMvec.size()-1]) << "\n");;
instr = (MachineInstr*) tempMvec[tempMvec.size()-1];
}
}
}
//Get Machine target information for calculating latency
const TargetInstrInfo *MTI = Target.getInstrInfo();
MachineCodeForInstruction & tempMvec = MachineCodeForInstruction::get(b);
int offset = tempMvec.size();
for (unsigned j = 0; j < tempMvec.size(); j++) {
MachineInstr *mi = tempMvec[j];
if(MTI->isNop(mi->getOpcode()))
continue;
if(!instr) {
instr = mi;
DEBUG(std::cerr << "No Cond MI: " << *mi << "\n");
}
else {
DEBUG(std::cerr << *mi << "\n");;
otherInstrs.push_back(mi);
}
}
//Node is created and added to the graph automatically
MSchedGraphSBNode *node = new MSchedGraphSBNode(instr, otherInstrs, this, (*MBB)->size()-offset-1, 3, true);
DEBUG(std::cerr << "Created Node: " << *node << "\n");
//Now loop over all instructions and see if their def is live outside the trace
MachineBasicBlock *mb = (MachineBasicBlock*) *MBB;
for(MachineBasicBlock::iterator I = mb->begin(), E = mb->end(); I != E; ++I) {
MachineInstr *instr = I;
if(MTI->isNop(instr->getOpcode()) || MTI->isBranch(instr->getOpcode()))
continue;
if(node->getInst() == instr)
continue;
for(unsigned i=0; i < instr->getNumOperands(); ++i) {
MachineOperand &mOp = instr->getOperand(i);
if(mOp.isDef() && mOp.getType() == MachineOperand::MO_VirtualRegister) {
Value *val = mOp.getVRegValue();
//Check if there is a use not in the trace
for(Value::use_iterator V = val->use_begin(), VE = val->use_end(); V != VE; ++V) {
if (Instruction *Inst = dyn_cast<Instruction>(*V)) {
if(llvmBBs.count(Inst->getParent()))
liveOutsideTrace[node].insert(instr);
}
}
}
}
}
}
//Create nodes and edges for this BB
buildNodesAndEdges(ignoreInstrs, DA, machineTollvm, liveOutsideTrace);
}
//Copies the graph and keeps a map from old to new nodes
MSchedGraphSB::MSchedGraphSB(const MSchedGraphSB &G,
std::map<MSchedGraphSBNode*, MSchedGraphSBNode*> &newNodes)
: Target(G.Target) {
BBs = G.BBs;
std::map<MSchedGraphSBNode*, MSchedGraphSBNode*> oldToNew;
//Copy all nodes
for(MSchedGraphSB::const_iterator N = G.GraphMap.begin(),
NE = G.GraphMap.end(); N != NE; ++N) {
MSchedGraphSBNode *newNode = new MSchedGraphSBNode(*(N->second));
oldToNew[&*(N->second)] = newNode;
newNodes[newNode] = &*(N->second);
GraphMap[&*(N->first)] = newNode;
}
//Loop over nodes and update edges to point to new nodes
for(MSchedGraphSB::iterator N = GraphMap.begin(), NE = GraphMap.end();
N != NE; ++N) {
//Get the node we are dealing with
MSchedGraphSBNode *node = &*(N->second);
node->setParent(this);
//Loop over nodes successors and predecessors and update to the new nodes
for(unsigned i = 0; i < node->pred_size(); ++i) {
node->setPredecessor(i, oldToNew[node->getPredecessor(i)]);
}
for(unsigned i = 0; i < node->succ_size(); ++i) {
MSchedGraphSBEdge *edge = node->getSuccessor(i);
MSchedGraphSBNode *oldDest = edge->getDest();
edge->setDest(oldToNew[oldDest]);
}
}
}
//Deconstructor, deletes all nodes in the graph
MSchedGraphSB::~MSchedGraphSB () {
for(MSchedGraphSB::iterator I = GraphMap.begin(), E = GraphMap.end();
I != E; ++I)
delete I->second;
}
//Print out graph
void MSchedGraphSB::print(std::ostream &os) const {
for(MSchedGraphSB::const_iterator N = GraphMap.begin(), NE = GraphMap.end();
N != NE; ++N) {
//Get the node we are dealing with
MSchedGraphSBNode *node = &*(N->second);
os << "Node Start\n";
node->print(os);
os << "Successors:\n";
//print successors
for(unsigned i = 0; i < node->succ_size(); ++i) {
MSchedGraphSBEdge *edge = node->getSuccessor(i);
MSchedGraphSBNode *oldDest = edge->getDest();
oldDest->print(os);
}
os << "Node End\n";
}
}
//Calculate total delay
int MSchedGraphSB::totalDelay() {
int sum = 0;
for(MSchedGraphSB::const_iterator N = GraphMap.begin(), NE = GraphMap.end();
N != NE; ++N) {
//Get the node we are dealing with
MSchedGraphSBNode *node = &*(N->second);
sum += node->getLatency();
}
return sum;
}
bool MSchedGraphSB::instrCauseException(MachineOpCode opCode) {
//Check for integer divide
if(opCode == V9::SDIVXr || opCode == V9::SDIVXi
|| opCode == V9::UDIVXr || opCode == V9::UDIVXi)
return true;
//Check for loads or stores
const TargetInstrInfo *MTI = Target.getInstrInfo();
//if( MTI->isLoad(opCode) ||
if(MTI->isStore(opCode))
return true;
//Check for any floating point operation
const TargetSchedInfo *msi = Target.getSchedInfo();
InstrSchedClass sc = msi->getSchedClass(opCode);
//FIXME: Should check for floating point instructions!
//if(sc == SPARC_FGA || sc == SPARC_FGM)
//return true;
return false;
}
//Add edges between the nodes
void MSchedGraphSB::buildNodesAndEdges(std::map<const MachineInstr*, unsigned> &ignoreInstrs,
DependenceAnalyzer &DA,
std::map<MachineInstr*, Instruction*> &machineTollvm,
std::map<MSchedGraphSBNode*, std::set<MachineInstr*> > &liveOutsideTrace) {
//Get Machine target information for calculating latency
const TargetInstrInfo *MTI = Target.getInstrInfo();
std::vector<MSchedGraphSBNode*> memInstructions;
std::map<int, std::vector<OpIndexNodePair> > regNumtoNodeMap;
std::map<const Value*, std::vector<OpIndexNodePair> > valuetoNodeMap;
//Save PHI instructions to deal with later
std::vector<const MachineInstr*> phiInstrs;
unsigned index = 0;
MSchedGraphSBNode *lastPred = 0;
for(std::vector<const MachineBasicBlock*>::iterator B = BBs.begin(),
BE = BBs.end(); B != BE; ++B) {
const MachineBasicBlock *BB = *B;
//Loop over instructions in MBB and add nodes and edges
for (MachineBasicBlock::const_iterator MI = BB->begin(), e = BB->end();
MI != e; ++MI) {
//Ignore indvar instructions
if(ignoreInstrs.count(MI)) {
++index;
continue;
}
//Get each instruction of machine basic block, get the delay
//using the op code, create a new node for it, and add to the
//graph.
MachineOpCode opCode = MI->getOpcode();
int delay;
//Get delay
delay = MTI->maxLatency(opCode);
//Create new node for this machine instruction and add to the graph.
//Create only if not a nop
if(MTI->isNop(opCode))
continue;
//Sparc BE does not use PHI opcode, so assert on this case
assert(opCode != TargetInstrInfo::PHI && "Did not expect PHI opcode");
bool isBranch = false;
//Skip branches
if(MTI->isBranch(opCode))
continue;
//Node is created and added to the graph automatically
MSchedGraphSBNode *node = 0;
if(!GraphMap.count(MI)){
node = new MSchedGraphSBNode(MI, this, index, delay);
DEBUG(std::cerr << "Created Node: " << *node << "\n");
}
else {
node = GraphMap[MI];
if(node->isPredicate()) {
//Create edge between this node and last pred, then switch to new pred
if(lastPred) {
lastPred->addOutEdge(node, MSchedGraphSBEdge::PredDep,
MSchedGraphSBEdge::NonDataDep, 0);
if(liveOutsideTrace.count(lastPred)) {
for(std::set<MachineInstr*>::iterator L = liveOutsideTrace[lastPred].begin(), LE = liveOutsideTrace[lastPred].end(); L != LE; ++L)
lastPred->addOutEdge(GraphMap[*L], MSchedGraphSBEdge::PredDep,
MSchedGraphSBEdge::NonDataDep, 1);
}
}
lastPred = node;
}
}
//Add dependencies to instructions that cause exceptions
if(lastPred)
lastPred->print(std::cerr);
if(!node->isPredicate() && instrCauseException(opCode)) {
if(lastPred) {
lastPred->addOutEdge(node, MSchedGraphSBEdge::PredDep,
MSchedGraphSBEdge::NonDataDep, 0);
}
}
//Check OpCode to keep track of memory operations to add memory
//dependencies later.
if(MTI->isLoad(opCode) || MTI->isStore(opCode))
memInstructions.push_back(node);
//Loop over all operands, and put them into the register number to
//graph node map for determining dependencies
//If an operands is a use/def, we have an anti dependence to itself
for(unsigned i=0; i < MI->getNumOperands(); ++i) {
//Get Operand
const MachineOperand &mOp = MI->getOperand(i);
//Check if it has an allocated register
if(mOp.hasAllocatedReg()) {
int regNum = mOp.getReg();
if(regNum != SparcV9::g0) {
//Put into our map
regNumtoNodeMap[regNum].push_back(std::make_pair(i, node));
}
continue;
}
//Add virtual registers dependencies
//Check if any exist in the value map already and create dependencies
//between them.
if(mOp.getType() == MachineOperand::MO_VirtualRegister
|| mOp.getType() == MachineOperand::MO_CCRegister) {
//Make sure virtual register value is not null
assert((mOp.getVRegValue() != NULL) && "Null value is defined");
//Check if this is a read operation in a phi node, if so DO NOT PROCESS
if(mOp.isUse() && (opCode == TargetInstrInfo::PHI)) {
DEBUG(std::cerr << "Read Operation in a PHI node\n");
continue;
}
if (const Value* srcI = mOp.getVRegValue()) {
//Find value in the map
std::map<const Value*, std::vector<OpIndexNodePair> >::iterator V
= valuetoNodeMap.find(srcI);
//If there is something in the map already, add edges from
//those instructions
//to this one we are processing
if(V != valuetoNodeMap.end()) {
addValueEdges(V->second, node, mOp.isUse(), mOp.isDef(), phiInstrs);
//Add to value map
V->second.push_back(std::make_pair(i,node));
}
//Otherwise put it in the map
else
//Put into value map
valuetoNodeMap[mOp.getVRegValue()].push_back(std::make_pair(i, node));
}
}
}
++index;
}
//Loop over LLVM BB, examine phi instructions, and add them to our
//phiInstr list to process
const BasicBlock *llvm_bb = BB->getBasicBlock();
for(BasicBlock::const_iterator I = llvm_bb->begin(), E = llvm_bb->end();
I != E; ++I) {
if(const PHINode *PN = dyn_cast<PHINode>(I)) {
MachineCodeForInstruction & tempMvec = MachineCodeForInstruction::get(PN);
for (unsigned j = 0; j < tempMvec.size(); j++) {
if(!ignoreInstrs.count(tempMvec[j])) {
DEBUG(std::cerr << "Inserting phi instr into map: " << *tempMvec[j] << "\n");
phiInstrs.push_back((MachineInstr*) tempMvec[j]);
}
}
}
}
addMemEdges(memInstructions, DA, machineTollvm);
addMachRegEdges(regNumtoNodeMap);
//Finally deal with PHI Nodes and Value*
for(std::vector<const MachineInstr*>::iterator I = phiInstrs.begin(),
E = phiInstrs.end(); I != E; ++I) {
//Get Node for this instruction
std::map<const MachineInstr*, MSchedGraphSBNode*>::iterator X;
X = find(*I);
if(X == GraphMap.end())
continue;
MSchedGraphSBNode *node = X->second;
DEBUG(std::cerr << "Adding ite diff edges for node: " << *node << "\n");
//Loop over operands for this instruction and add value edges
for(unsigned i=0; i < (*I)->getNumOperands(); ++i) {
//Get Operand
const MachineOperand &mOp = (*I)->getOperand(i);
if((mOp.getType() == MachineOperand::MO_VirtualRegister
|| mOp.getType() == MachineOperand::MO_CCRegister) && mOp.isUse()) {
//find the value in the map
if (const Value* srcI = mOp.getVRegValue()) {
//Find value in the map
std::map<const Value*, std::vector<OpIndexNodePair> >::iterator V
= valuetoNodeMap.find(srcI);
//If there is something in the map already, add edges from
//those instructions
//to this one we are processing
if(V != valuetoNodeMap.end()) {
addValueEdges(V->second, node, mOp.isUse(), mOp.isDef(),
phiInstrs, 1);
}
}
}
}
}
}
}
//Add dependencies for Value*s
void MSchedGraphSB::addValueEdges(std::vector<OpIndexNodePair> &NodesInMap,
MSchedGraphSBNode *destNode, bool nodeIsUse,
bool nodeIsDef, std::vector<const MachineInstr*> &phiInstrs, int diff) {
for(std::vector<OpIndexNodePair>::iterator I = NodesInMap.begin(),
E = NodesInMap.end(); I != E; ++I) {
//Get node in vectors machine operand that is the same value as node
MSchedGraphSBNode *srcNode = I->second;
MachineOperand mOp = srcNode->getInst()->getOperand(I->first);
if(diff > 0)
if(std::find(phiInstrs.begin(), phiInstrs.end(), srcNode->getInst()) == phiInstrs.end())
continue;
//Node is a Def, so add output dep.
if(nodeIsDef) {
if(mOp.isUse()) {
DEBUG(std::cerr << "Edge from " << *srcNode << " to " << *destNode << " (itediff=" << diff << ", type=anti)\n");
srcNode->addOutEdge(destNode, MSchedGraphSBEdge::ValueDep,
MSchedGraphSBEdge::AntiDep, diff);
}
if(mOp.isDef()) {
DEBUG(std::cerr << "Edge from " << *srcNode << " to " << *destNode << " (itediff=" << diff << ", type=output)\n");
srcNode->addOutEdge(destNode, MSchedGraphSBEdge::ValueDep,
MSchedGraphSBEdge::OutputDep, diff);
}
}
if(nodeIsUse) {
if(mOp.isDef()) {
DEBUG(std::cerr << "Edge from " << *srcNode << " to " << *destNode << " (itediff=" << diff << ", type=true)\n");
srcNode->addOutEdge(destNode, MSchedGraphSBEdge::ValueDep,
MSchedGraphSBEdge::TrueDep, diff);
}
}
}
}
//Add dependencies for machine registers across iterations
void MSchedGraphSB::addMachRegEdges(std::map<int, std::vector<OpIndexNodePair> >& regNumtoNodeMap) {
//Loop over all machine registers in the map, and add dependencies
//between the instructions that use it
typedef std::map<int, std::vector<OpIndexNodePair> > regNodeMap;
for(regNodeMap::iterator I = regNumtoNodeMap.begin();
I != regNumtoNodeMap.end(); ++I) {
//Get the register number
int regNum = (*I).first;
//Get Vector of nodes that use this register
std::vector<OpIndexNodePair> Nodes = (*I).second;
//Loop over nodes and determine the dependence between the other
//nodes in the vector
for(unsigned i =0; i < Nodes.size(); ++i) {
//Get src node operator index that uses this machine register
int srcOpIndex = Nodes[i].first;
//Get the actual src Node
MSchedGraphSBNode *srcNode = Nodes[i].second;
//Get Operand
const MachineOperand &srcMOp = srcNode->getInst()->getOperand(srcOpIndex);
bool srcIsUseandDef = srcMOp.isDef() && srcMOp.isUse();
bool srcIsUse = srcMOp.isUse() && !srcMOp.isDef();
//Look at all instructions after this in execution order
for(unsigned j=i+1; j < Nodes.size(); ++j) {
//Sink node is a write
if(Nodes[j].second->getInst()->getOperand(Nodes[j].first).isDef()) {
//Src only uses the register (read)
if(srcIsUse)
srcNode->addOutEdge(Nodes[j].second,
MSchedGraphSBEdge::MachineRegister,
MSchedGraphSBEdge::AntiDep);
else if(srcIsUseandDef) {
srcNode->addOutEdge(Nodes[j].second,
MSchedGraphSBEdge::MachineRegister,
MSchedGraphSBEdge::AntiDep);
srcNode->addOutEdge(Nodes[j].second,
MSchedGraphSBEdge::MachineRegister,
MSchedGraphSBEdge::OutputDep);
}
else
srcNode->addOutEdge(Nodes[j].second,
MSchedGraphSBEdge::MachineRegister,
MSchedGraphSBEdge::OutputDep);
}
//Dest node is a read
else {
if(!srcIsUse || srcIsUseandDef)
srcNode->addOutEdge(Nodes[j].second,
MSchedGraphSBEdge::MachineRegister,
MSchedGraphSBEdge::TrueDep);
}
}
//Look at all the instructions before this one since machine registers
//could live across iterations.
for(unsigned j = 0; j < i; ++j) {
//Sink node is a write
if(Nodes[j].second->getInst()->getOperand(Nodes[j].first).isDef()) {
//Src only uses the register (read)
if(srcIsUse)
srcNode->addOutEdge(Nodes[j].second,
MSchedGraphSBEdge::MachineRegister,
MSchedGraphSBEdge::AntiDep, 1);
else if(srcIsUseandDef) {
srcNode->addOutEdge(Nodes[j].second,
MSchedGraphSBEdge::MachineRegister,
MSchedGraphSBEdge::AntiDep, 1);
srcNode->addOutEdge(Nodes[j].second,
MSchedGraphSBEdge::MachineRegister,
MSchedGraphSBEdge::OutputDep, 1);
}
else
srcNode->addOutEdge(Nodes[j].second,
MSchedGraphSBEdge::MachineRegister,
MSchedGraphSBEdge::OutputDep, 1);
}
//Dest node is a read
else {
if(!srcIsUse || srcIsUseandDef)
srcNode->addOutEdge(Nodes[j].second,
MSchedGraphSBEdge::MachineRegister,
MSchedGraphSBEdge::TrueDep,1 );
}
}
}
}
}
//Add edges between all loads and stores
//Can be less strict with alias analysis and data dependence analysis.
void MSchedGraphSB::addMemEdges(const std::vector<MSchedGraphSBNode*>& memInst,
DependenceAnalyzer &DA,
std::map<MachineInstr*, Instruction*> &machineTollvm) {
//Get Target machine instruction info
const TargetInstrInfo *TMI = Target.getInstrInfo();
//Loop over all memory instructions in the vector
//Knowing that they are in execution, add true, anti, and output dependencies
for (unsigned srcIndex = 0; srcIndex < memInst.size(); ++srcIndex) {
MachineInstr *srcInst = (MachineInstr*) memInst[srcIndex]->getInst();
//Get the machine opCode to determine type of memory instruction
MachineOpCode srcNodeOpCode = srcInst->getOpcode();
//All instructions after this one in execution order have an
//iteration delay of 0
for(unsigned destIndex = 0; destIndex < memInst.size(); ++destIndex) {
//No self loops
if(destIndex == srcIndex)
continue;
MachineInstr *destInst = (MachineInstr*) memInst[destIndex]->getInst();
DEBUG(std::cerr << "MInst1: " << *srcInst << "\n");
DEBUG(std::cerr << "MInst2: " << *destInst << "\n");
//Assuming instructions without corresponding llvm instructions
//are from constant pools.
if (!machineTollvm.count(srcInst) || !machineTollvm.count(destInst))
continue;
bool useDepAnalyzer = true;
//Some machine loads and stores are generated by casts, so be
//conservative and always add deps
Instruction *srcLLVM = machineTollvm[srcInst];
Instruction *destLLVM = machineTollvm[destInst];
if(!isa<LoadInst>(srcLLVM)
&& !isa<StoreInst>(srcLLVM)) {
if(isa<BinaryOperator>(srcLLVM)) {
if(isa<ConstantFP>(srcLLVM->getOperand(0)) || isa<ConstantFP>(srcLLVM->getOperand(1)))
continue;
}
useDepAnalyzer = false;
}
if(!isa<LoadInst>(destLLVM)
&& !isa<StoreInst>(destLLVM)) {
if(isa<BinaryOperator>(destLLVM)) {
if(isa<ConstantFP>(destLLVM->getOperand(0)) || isa<ConstantFP>(destLLVM->getOperand(1)))
continue;
}
useDepAnalyzer = false;
}
//Use dep analysis when we have corresponding llvm loads/stores
if(useDepAnalyzer) {
bool srcBeforeDest = true;
if(destIndex < srcIndex)
srcBeforeDest = false;
DependenceResult dr = DA.getDependenceInfo(machineTollvm[srcInst],
machineTollvm[destInst],
srcBeforeDest);
for(std::vector<Dependence>::iterator d = dr.dependences.begin(),
de = dr.dependences.end(); d != de; ++d) {
//Add edge from load to store
memInst[srcIndex]->addOutEdge(memInst[destIndex],
MSchedGraphSBEdge::MemoryDep,
d->getDepType(), d->getIteDiff());
}
}
//Otherwise, we can not do any further analysis and must make a dependence
else {
//Get the machine opCode to determine type of memory instruction
MachineOpCode destNodeOpCode = destInst->getOpcode();
//Get the Value* that we are reading from the load, always the first op
const MachineOperand &mOp = srcInst->getOperand(0);
const MachineOperand &mOp2 = destInst->getOperand(0);
if(mOp.hasAllocatedReg())
if(mOp.getReg() == SparcV9::g0)
continue;
if(mOp2.hasAllocatedReg())
if(mOp2.getReg() == SparcV9::g0)
continue;
DEBUG(std::cerr << "Adding dependence for machine instructions\n");
//Load-Store deps
if(TMI->isLoad(srcNodeOpCode)) {
if(TMI->isStore(destNodeOpCode))
memInst[srcIndex]->addOutEdge(memInst[destIndex],
MSchedGraphSBEdge::MemoryDep,
MSchedGraphSBEdge::AntiDep, 0);
}
else if(TMI->isStore(srcNodeOpCode)) {
if(TMI->isStore(destNodeOpCode))
memInst[srcIndex]->addOutEdge(memInst[destIndex],
MSchedGraphSBEdge::MemoryDep,
MSchedGraphSBEdge::OutputDep, 0);
else
memInst[srcIndex]->addOutEdge(memInst[destIndex],
MSchedGraphSBEdge::MemoryDep,
MSchedGraphSBEdge::TrueDep, 0);
}
}
}
}
}

View File

@ -1,410 +0,0 @@
//===-- MSchedGraphSB.h - Scheduling Graph ------------------------*- 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.
//
//===----------------------------------------------------------------------===//
//
// A graph class for dependencies. This graph only contains true, anti, and
// output data dependencies for a vector of MachineBasicBlock. Dependencies
// across iterations are also computed. Unless data dependence analysis
// is provided, a conservative approach of adding dependencies between all
// loads and stores is taken. It also includes pseudo predicate nodes for
// modulo scheduling superblocks.
//===----------------------------------------------------------------------===//
#ifndef LLVM_MSCHEDGRAPHSB_H
#define LLVM_MSCHEDGRAPHSB_H
#include "DependenceAnalyzer.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetData.h"
#include "llvm/ADT/GraphTraits.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/iterator"
#include <vector>
namespace llvm {
class MSchedGraphSB;
class MSchedGraphSBNode;
template<class IteratorType, class NodeType>
class MSchedGraphSBNodeIterator;
//MSchedGraphSBEdge encapsulates the data dependence between nodes. It
//identifies the dependence type, on what, and the iteration
//difference
struct MSchedGraphSBEdge {
enum DataDepOrderType {
TrueDep, AntiDep, OutputDep, NonDataDep
};
enum MSchedGraphSBEdgeType {
MemoryDep, ValueDep, MachineRegister, PredDep
};
//Get or set edge data
MSchedGraphSBNode *getDest() const { return dest; }
unsigned getIteDiff() { return iteDiff; }
unsigned getDepOrderType() { return depOrderType; }
void setDest(MSchedGraphSBNode *newDest) { dest = newDest; }
private:
friend class MSchedGraphSBNode;
MSchedGraphSBEdge(MSchedGraphSBNode *destination, MSchedGraphSBEdgeType type,
unsigned deptype, unsigned diff)
: dest(destination), depType(type), depOrderType(deptype), iteDiff(diff) {}
MSchedGraphSBNode *dest;
MSchedGraphSBEdgeType depType;
unsigned depOrderType;
unsigned iteDiff;
};
//MSchedGraphSBNode represents a machine instruction and its
//corresponding latency. Each node also contains a list of its
//predecessors and sucessors.
class MSchedGraphSBNode {
const MachineInstr* Inst; //Machine Instruction
std::vector<const MachineInstr*> otherInstrs;
MSchedGraphSB* Parent; //Graph this node belongs to
unsigned index; //Index in BB
unsigned latency; //Latency of Instruction
bool isBranchInstr; //Is this node the branch instr or not
bool isPredicateNode; //Indicate if this node should be treated like a predicate
std::vector<MSchedGraphSBNode*> Predecessors; //Predecessor Nodes
std::vector<MSchedGraphSBEdge> Successors; //Successor edges
public:
MSchedGraphSBNode(const MachineInstr* inst, MSchedGraphSB *graph,
unsigned index, unsigned late=0, bool isBranch=false);
MSchedGraphSBNode(const MachineInstr* inst, std::vector<const MachineInstr*> &other,
MSchedGraphSB *graph,
unsigned index, unsigned late=0, bool isPNode=true);
MSchedGraphSBNode(const MSchedGraphSBNode &N);
//Iterators - Predecessor and Succussor
typedef std::vector<MSchedGraphSBNode*>::iterator pred_iterator;
pred_iterator pred_begin() { return Predecessors.begin(); }
pred_iterator pred_end() { return Predecessors.end(); }
unsigned pred_size() { return Predecessors.size(); }
typedef std::vector<MSchedGraphSBNode*>::const_iterator pred_const_iterator;
pred_const_iterator pred_begin() const { return Predecessors.begin(); }
pred_const_iterator pred_end() const { return Predecessors.end(); }
typedef MSchedGraphSBNodeIterator<std::vector<MSchedGraphSBEdge>::const_iterator,
const MSchedGraphSBNode> succ_const_iterator;
succ_const_iterator succ_begin() const;
succ_const_iterator succ_end() const;
typedef MSchedGraphSBNodeIterator<std::vector<MSchedGraphSBEdge>::iterator,
MSchedGraphSBNode> succ_iterator;
succ_iterator succ_begin();
succ_iterator succ_end();
unsigned succ_size() { return Successors.size(); }
//Get or set predecessor nodes, or successor edges
void setPredecessor(unsigned index, MSchedGraphSBNode *dest) {
Predecessors[index] = dest;
}
MSchedGraphSBNode* getPredecessor(unsigned index) {
return Predecessors[index];
}
MSchedGraphSBEdge* getSuccessor(unsigned index) {
return &Successors[index];
}
void deleteSuccessor(MSchedGraphSBNode *node) {
for (unsigned i = 0; i != Successors.size(); ++i)
if (Successors[i].getDest() == node) {
Successors.erase(Successors.begin()+i);
node->Predecessors.erase(std::find(node->Predecessors.begin(),
node->Predecessors.end(), this));
--i; //Decrease index var since we deleted a node
}
}
void addOutEdge(MSchedGraphSBNode *destination,
MSchedGraphSBEdge::MSchedGraphSBEdgeType type,
unsigned deptype, unsigned diff=0) {
Successors.push_back(MSchedGraphSBEdge(destination, type, deptype,diff));
destination->Predecessors.push_back(this);
}
//General methods to get and set data for the node
const MachineInstr* getInst() { return Inst; }
MSchedGraphSB* getParent() { return Parent; }
bool hasPredecessors() { return (Predecessors.size() > 0); }
bool hasSuccessors() { return (Successors.size() > 0); }
unsigned getLatency() { return latency; }
unsigned getLatency() const { return latency; }
unsigned getIndex() { return index; }
unsigned getIteDiff(MSchedGraphSBNode *succ);
MSchedGraphSBEdge getInEdge(MSchedGraphSBNode *pred);
unsigned getInEdgeNum(MSchedGraphSBNode *pred);
bool isSuccessor(MSchedGraphSBNode *);
bool isPredecessor(MSchedGraphSBNode *);
bool isBranch() { return isBranchInstr; }
bool isPredicate() { return isPredicateNode; }
bool isPredicate() const { return isPredicateNode; }
std::vector<const MachineInstr*> getOtherInstrs() { return otherInstrs; }
//Debug support
void print(std::ostream &os) const;
void setParent(MSchedGraphSB *p) { Parent = p; }
};
//Node iterator for graph generation
template<class IteratorType, class NodeType>
class MSchedGraphSBNodeIterator : public forward_iterator<NodeType*, ptrdiff_t> {
IteratorType I; // std::vector<MSchedGraphSBEdge>::iterator or const_iterator
public:
MSchedGraphSBNodeIterator(IteratorType i) : I(i) {}
bool operator==(const MSchedGraphSBNodeIterator RHS) const { return I == RHS.I; }
bool operator!=(const MSchedGraphSBNodeIterator RHS) const { return I != RHS.I; }
const MSchedGraphSBNodeIterator &operator=(const MSchedGraphSBNodeIterator &RHS) {
I = RHS.I;
return *this;
}
NodeType* operator*() const {
return I->getDest();
}
NodeType* operator->() const { return operator*(); }
MSchedGraphSBNodeIterator& operator++() { // Preincrement
++I;
return *this;
}
MSchedGraphSBNodeIterator operator++(int) { // Postincrement
MSchedGraphSBNodeIterator tmp = *this; ++*this; return tmp;
}
MSchedGraphSBEdge &getEdge() {
return *I;
}
const MSchedGraphSBEdge &getEdge() const {
return *I;
}
};
inline MSchedGraphSBNode::succ_const_iterator MSchedGraphSBNode::succ_begin() const {
return succ_const_iterator(Successors.begin());
}
inline MSchedGraphSBNode::succ_const_iterator MSchedGraphSBNode::succ_end() const {
return succ_const_iterator(Successors.end());
}
inline MSchedGraphSBNode::succ_iterator MSchedGraphSBNode::succ_begin() {
return succ_iterator(Successors.begin());
}
inline MSchedGraphSBNode::succ_iterator MSchedGraphSBNode::succ_end() {
return succ_iterator(Successors.end());
}
// ostream << operator for MSGraphNode class
inline std::ostream &operator<<(std::ostream &os,
const MSchedGraphSBNode &node) {
node.print(os);
return os;
}
// Provide specializations of GraphTraits to be able to use graph
// iterators on the scheduling graph!
//
template <> struct GraphTraits<MSchedGraphSBNode*> {
typedef MSchedGraphSBNode NodeType;
typedef MSchedGraphSBNode::succ_iterator ChildIteratorType;
static inline ChildIteratorType child_begin(NodeType *N) {
return N->succ_begin();
}
static inline ChildIteratorType child_end(NodeType *N) {
return N->succ_end();
}
static NodeType *getEntryNode(NodeType* N) { return N; }
};
//Graph class to represent dependence graph
class MSchedGraphSB {
std::vector<const MachineBasicBlock *> BBs; //Machine basic block
const TargetMachine &Target; //Target Machine
//Nodes
std::map<const MachineInstr*, MSchedGraphSBNode*> GraphMap;
//Add Nodes and Edges to this graph for our BB
typedef std::pair<int, MSchedGraphSBNode*> OpIndexNodePair;
void buildNodesAndEdges(std::map<const MachineInstr*, unsigned> &ignoreInstrs, DependenceAnalyzer &DA, std::map<MachineInstr*, Instruction*> &machineTollvm, std::map<MSchedGraphSBNode*, std::set<MachineInstr*> > &liveOutsideTrace);
void addValueEdges(std::vector<OpIndexNodePair> &NodesInMap,
MSchedGraphSBNode *node,
bool nodeIsUse, bool nodeIsDef, std::vector<const MachineInstr*> &phiInstrs, int diff=0);
void addMachRegEdges(std::map<int,
std::vector<OpIndexNodePair> >& regNumtoNodeMap);
void addMemEdges(const std::vector<MSchedGraphSBNode*>& memInst,
DependenceAnalyzer &DA, std::map<MachineInstr*, Instruction*> &machineTollvm);
bool instrCauseException(MachineOpCode opCode);
public:
MSchedGraphSB(const MachineBasicBlock *bb, const TargetMachine &targ,
std::map<const MachineInstr*, unsigned> &ignoreInstrs,
DependenceAnalyzer &DA, std::map<MachineInstr*, Instruction*> &machineTollvm);
//Copy constructor with maps to link old nodes to new nodes
MSchedGraphSB(const MSchedGraphSB &G, std::map<MSchedGraphSBNode*, MSchedGraphSBNode*> &newNodes);
MSchedGraphSB(std::vector<const MachineBasicBlock*> &bbs,
const TargetMachine &targ,
std::map<const MachineInstr*, unsigned> &ignoreInstrs,
DependenceAnalyzer &DA,
std::map<MachineInstr*, Instruction*> &machineTollvm);
//Print graph
void print(std::ostream &os) const;
//Deconstructor!
~MSchedGraphSB();
//Add or delete nodes from the Graph
void addNode(const MachineInstr* MI, MSchedGraphSBNode *node);
void deleteNode(MSchedGraphSBNode *node);
int totalDelay();
//iterators
typedef std::map<const MachineInstr*, MSchedGraphSBNode*>::iterator iterator;
typedef std::map<const MachineInstr*, MSchedGraphSBNode*>::const_iterator const_iterator;
typedef std::map<const MachineInstr*, MSchedGraphSBNode*>::reverse_iterator reverse_iterator;
iterator find(const MachineInstr* I) { return GraphMap.find(I); }
iterator end() { return GraphMap.end(); }
iterator begin() { return GraphMap.begin(); }
unsigned size() { return GraphMap.size(); }
reverse_iterator rbegin() { return GraphMap.rbegin(); }
reverse_iterator rend() { return GraphMap.rend(); }
//Get Target or original machine basic block
const TargetMachine* getTarget() { return &Target; }
std::vector<const MachineBasicBlock*> getBBs() { return BBs; }
};
// Provide specializations of GraphTraits to be able to use graph
// iterators on the scheduling graph
static MSchedGraphSBNode& getSecond(std::pair<const MachineInstr* const,
MSchedGraphSBNode*> &Pair) {
return *Pair.second;
}
template <> struct GraphTraits<MSchedGraphSB*> {
typedef MSchedGraphSBNode NodeType;
typedef MSchedGraphSBNode::succ_iterator ChildIteratorType;
static inline ChildIteratorType child_begin(NodeType *N) {
return N->succ_begin();
}
static inline ChildIteratorType child_end(NodeType *N) {
return N->succ_end();
}
typedef std::pointer_to_unary_function<std::pair<const MachineInstr* const,
MSchedGraphSBNode*>&, MSchedGraphSBNode&> DerefFun;
typedef mapped_iterator<MSchedGraphSB::iterator, DerefFun> nodes_iterator;
static nodes_iterator nodes_begin(MSchedGraphSB *G) {
return map_iterator(((MSchedGraphSB*)G)->begin(), DerefFun(getSecond));
}
static nodes_iterator nodes_end(MSchedGraphSB *G) {
return map_iterator(((MSchedGraphSB*)G)->end(), DerefFun(getSecond));
}
};
template <> struct GraphTraits<const MSchedGraphSB*> {
typedef const MSchedGraphSBNode NodeType;
typedef MSchedGraphSBNode::succ_const_iterator ChildIteratorType;
static inline ChildIteratorType child_begin(NodeType *N) {
return N->succ_begin();
}
static inline ChildIteratorType child_end(NodeType *N) {
return N->succ_end();
}
typedef std::pointer_to_unary_function<std::pair<const MachineInstr* const,
MSchedGraphSBNode*>&, MSchedGraphSBNode&> DerefFun;
typedef mapped_iterator<MSchedGraphSB::iterator, DerefFun> nodes_iterator;
static nodes_iterator nodes_begin(MSchedGraphSB *G) {
return map_iterator(((MSchedGraphSB*)G)->begin(), DerefFun(getSecond));
}
static nodes_iterator nodes_end(MSchedGraphSB *G) {
return map_iterator(((MSchedGraphSB*)G)->end(), DerefFun(getSecond));
}
};
template <> struct GraphTraits<Inverse<MSchedGraphSB*> > {
typedef MSchedGraphSBNode NodeType;
typedef MSchedGraphSBNode::pred_iterator ChildIteratorType;
static inline ChildIteratorType child_begin(NodeType *N) {
return N->pred_begin();
}
static inline ChildIteratorType child_end(NodeType *N) {
return N->pred_end();
}
typedef std::pointer_to_unary_function<std::pair<const MachineInstr* const,
MSchedGraphSBNode*>&, MSchedGraphSBNode&> DerefFun;
typedef mapped_iterator<MSchedGraphSB::iterator, DerefFun> nodes_iterator;
static nodes_iterator nodes_begin(MSchedGraphSB *G) {
return map_iterator(((MSchedGraphSB*)G)->begin(), DerefFun(getSecond));
}
static nodes_iterator nodes_end(MSchedGraphSB *G) {
return map_iterator(((MSchedGraphSB*)G)->end(), DerefFun(getSecond));
}
};
template <> struct GraphTraits<Inverse<const MSchedGraphSB*> > {
typedef const MSchedGraphSBNode NodeType;
typedef MSchedGraphSBNode::pred_const_iterator ChildIteratorType;
static inline ChildIteratorType child_begin(NodeType *N) {
return N->pred_begin();
}
static inline ChildIteratorType child_end(NodeType *N) {
return N->pred_end();
}
typedef std::pointer_to_unary_function<std::pair<const MachineInstr* const,
MSchedGraphSBNode*>&, MSchedGraphSBNode&> DerefFun;
typedef mapped_iterator<MSchedGraphSB::iterator, DerefFun> nodes_iterator;
static nodes_iterator nodes_begin(MSchedGraphSB *G) {
return map_iterator(((MSchedGraphSB*)G)->begin(), DerefFun(getSecond));
}
static nodes_iterator nodes_end(MSchedGraphSB *G) {
return map_iterator(((MSchedGraphSB*)G)->end(), DerefFun(getSecond));
}
};
}
#endif

View File

@ -1,14 +0,0 @@
##===- lib/Target/SparcV9/ModuloScheduling/Makefile --------*- Makefile -*-===##
#
# 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.
#
##===----------------------------------------------------------------------===##
LEVEL = ../../../..
DIRS =
LIBRARYNAME = LLVMSparcV9ModuloSched
include $(LEVEL)/Makefile.common

File diff suppressed because it is too large Load Diff

View File

@ -1,171 +0,0 @@
//===-- ModuloScheduling.h - Swing Modulo Scheduling------------*- 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.
//
//===----------------------------------------------------------------------===//
//
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_MODULOSCHEDULING_H
#define LLVM_MODULOSCHEDULING_H
#include "MSchedGraph.h"
#include "MSSchedule.h"
#include "llvm/Function.h"
#include "llvm/Pass.h"
#include "DependenceAnalyzer.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/ScalarEvolution.h"
#include <set>
namespace llvm {
//Struct to contain ModuloScheduling Specific Information for each node
struct MSNodeAttributes {
int ASAP; //Earliest time at which the opreation can be scheduled
int ALAP; //Latest time at which the operation can be scheduled.
int MOB;
int depth;
int height;
MSNodeAttributes(int asap=-1, int alap=-1, int mob=-1,
int d=-1, int h=-1) : ASAP(asap), ALAP(alap),
MOB(mob), depth(d),
height(h) {}
};
class ModuloSchedulingPass : public FunctionPass {
const TargetMachine &target;
//Map to hold Value* defs
std::map<const Value*, MachineInstr*> defMap;
//Map to hold list of instructions associate to the induction var for each BB
std::map<const MachineBasicBlock*, std::map<const MachineInstr*, unsigned> > indVarInstrs;
//Map to hold machine to llvm instrs for each valid BB
std::map<const MachineBasicBlock*, std::map<MachineInstr*, Instruction*> > machineTollvm;
//LLVM Instruction we know we can add TmpInstructions to its MCFI
Instruction *defaultInst;
//Map that holds node to node attribute information
std::map<MSchedGraphNode*, MSNodeAttributes> nodeToAttributesMap;
//Map to hold all reccurrences
std::set<std::pair<int, std::vector<MSchedGraphNode*> > > recurrenceList;
//Set of edges to ignore, stored as src node and index into vector of successors
std::set<std::pair<MSchedGraphNode*, unsigned> > edgesToIgnore;
//Vector containing the partial order
std::vector<std::set<MSchedGraphNode*> > partialOrder;
//Vector containing the final node order
std::vector<MSchedGraphNode*> FinalNodeOrder;
//Schedule table, key is the cycle number and the vector is resource, node pairs
MSSchedule schedule;
//Current initiation interval
int II;
//Internal functions
bool CreateDefMap(MachineBasicBlock *BI);
bool MachineBBisValid(const MachineBasicBlock *BI);
bool assocIndVar(Instruction *I, std::set<Instruction*> &indVar,
std::vector<Instruction*> &stack, BasicBlock *BB);
int calculateResMII(const MachineBasicBlock *BI);
int calculateRecMII(MSchedGraph *graph, int MII);
void calculateNodeAttributes(MSchedGraph *graph, int MII);
bool ignoreEdge(MSchedGraphNode *srcNode, MSchedGraphNode *destNode);
int calculateASAP(MSchedGraphNode *node, int MII,MSchedGraphNode *destNode);
int calculateALAP(MSchedGraphNode *node, int MII, int maxASAP, MSchedGraphNode *srcNode);
int calculateHeight(MSchedGraphNode *node,MSchedGraphNode *srcNode);
int calculateDepth(MSchedGraphNode *node, MSchedGraphNode *destNode);
int findMaxASAP();
void orderNodes();
void findAllReccurrences(MSchedGraphNode *node,
std::vector<MSchedGraphNode*> &visitedNodes, int II);
void addReccurrence(std::vector<MSchedGraphNode*> &recurrence, int II, MSchedGraphNode*, MSchedGraphNode*);
void addSCC(std::vector<MSchedGraphNode*> &SCC, std::map<MSchedGraphNode*, MSchedGraphNode*> &newNodes);
void findAllCircuits(MSchedGraph *MSG, int II);
bool circuit(MSchedGraphNode *v, std::vector<MSchedGraphNode*> &stack,
std::set<MSchedGraphNode*> &blocked,
std::vector<MSchedGraphNode*> &SCC, MSchedGraphNode *s,
std::map<MSchedGraphNode*, std::set<MSchedGraphNode*> > &B, int II,
std::map<MSchedGraphNode*, MSchedGraphNode*> &newNodes);
void unblock(MSchedGraphNode *u, std::set<MSchedGraphNode*> &blocked,
std::map<MSchedGraphNode*, std::set<MSchedGraphNode*> > &B);
void addRecc(std::vector<MSchedGraphNode*> &stack, std::map<MSchedGraphNode*, MSchedGraphNode*> &newNodes);
void searchPath(MSchedGraphNode *node,
std::vector<MSchedGraphNode*> &path,
std::set<MSchedGraphNode*> &nodesToAdd,
std::set<MSchedGraphNode*> &new_reccurence);
void pathToRecc(MSchedGraphNode *node,
std::vector<MSchedGraphNode*> &path,
std::set<MSchedGraphNode*> &poSet, std::set<MSchedGraphNode*> &lastNodes);
void computePartialOrder();
bool computeSchedule(const MachineBasicBlock *BB, MSchedGraph *MSG);
bool scheduleNode(MSchedGraphNode *node,
int start, int end);
void predIntersect(std::set<MSchedGraphNode*> &CurrentSet, std::set<MSchedGraphNode*> &IntersectResult);
void succIntersect(std::set<MSchedGraphNode*> &CurrentSet, std::set<MSchedGraphNode*> &IntersectResult);
void reconstructLoop(MachineBasicBlock*);
//void saveValue(const MachineInstr*, const std::set<Value*>&, std::vector<Value*>*);
void fixBranches(std::vector<MachineBasicBlock *> &prologues, std::vector<BasicBlock*> &llvm_prologues, MachineBasicBlock *machineBB, BasicBlock *llvmBB, std::vector<MachineBasicBlock *> &epilogues, std::vector<BasicBlock*> &llvm_epilogues, MachineBasicBlock*);
void writePrologues(std::vector<MachineBasicBlock *> &prologues, MachineBasicBlock *origBB, std::vector<BasicBlock*> &llvm_prologues, std::map<const Value*, std::pair<const MachineInstr*, int> > &valuesToSave, std::map<Value*, std::map<int, Value*> > &newValues, std::map<Value*, MachineBasicBlock*> &newValLocation);
void writeEpilogues(std::vector<MachineBasicBlock *> &epilogues, const MachineBasicBlock *origBB, std::vector<BasicBlock*> &llvm_epilogues, std::map<const Value*, std::pair<const MachineInstr*, int> > &valuesToSave,std::map<Value*, std::map<int, Value*> > &newValues, std::map<Value*, MachineBasicBlock*> &newValLocation, std::map<Value*, std::map<int, Value*> > &kernelPHIs);
void writeKernel(BasicBlock *llvmBB, MachineBasicBlock *machineBB, std::map<const Value*, std::pair<const MachineInstr*, int> > &valuesToSave, std::map<Value*, std::map<int, Value*> > &newValues, std::map<Value*, MachineBasicBlock*> &newValLocation, std::map<Value*, std::map<int, Value*> > &kernelPHIs);
void removePHIs(const MachineBasicBlock* SB, std::vector<MachineBasicBlock*> &prologues, std::vector<MachineBasicBlock *> &epilogues, MachineBasicBlock *kernelBB, std::map<Value*, MachineBasicBlock*> &newValLocation);
void connectedComponentSet(MSchedGraphNode *node, std::set<MSchedGraphNode*> &ccSet, std::set<MSchedGraphNode*> &lastNodes);
public:
ModuloSchedulingPass(TargetMachine &targ) : target(targ) {}
virtual bool runOnFunction(Function &F);
virtual const char* getPassName() const { return "ModuloScheduling"; }
// getAnalysisUsage
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
/// HACK: We don't actually need loopinfo or scev, but we have
/// to say we do so that the pass manager does not delete it
/// before we run.
AU.addRequired<LoopInfo>();
AU.addRequired<ScalarEvolution>();
AU.addRequired<DependenceAnalyzer>();
}
};
}
#endif

View File

@ -1,192 +0,0 @@
//===-- ModuloSchedulingSuperBlock.h -Swing Modulo Scheduling-----*- 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.
//
//===----------------------------------------------------------------------===//
//Swing Modulo Scheduling done on Superblocks ( entry, multiple exit,
//multiple basic block loops).
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_MODULOSCHEDULINGSB_H
#define LLVM_MODULOSCHEDULINGSB_H
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/ScalarEvolution.h"
#include "llvm/Function.h"
#include "llvm/Pass.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "MSScheduleSB.h"
#include "MSchedGraphSB.h"
namespace llvm {
//Struct to contain ModuloScheduling Specific Information for each node
struct MSNodeSBAttributes {
int ASAP; //Earliest time at which the opreation can be scheduled
int ALAP; //Latest time at which the operation can be scheduled.
int MOB;
int depth;
int height;
MSNodeSBAttributes(int asap=-1, int alap=-1, int mob=-1,
int d=-1, int h=-1) : ASAP(asap), ALAP(alap),
MOB(mob), depth(d),
height(h) {}
};
typedef std::vector<const MachineBasicBlock*> SuperBlock;
class ModuloSchedulingSBPass : public FunctionPass {
const TargetMachine &target;
//Map to hold Value* defs
std::map<const Value*, MachineInstr*> defMap;
//Map to hold list of instructions associate to the induction var for each BB
std::map<SuperBlock, std::map<const MachineInstr*, unsigned> > indVarInstrs;
//Map to hold machine to llvm instrs for each valid BB
std::map<SuperBlock, std::map<MachineInstr*, Instruction*> > machineTollvm;
//LLVM Instruction we know we can add TmpInstructions to its MCFI
Instruction *defaultInst;
//Map that holds node to node attribute information
std::map<MSchedGraphSBNode*, MSNodeSBAttributes> nodeToAttributesMap;
//Map to hold all reccurrences
std::set<std::pair<int, std::vector<MSchedGraphSBNode*> > > recurrenceList;
//Set of edges to ignore, stored as src node and index into vector of successors
std::set<std::pair<MSchedGraphSBNode*, unsigned> > edgesToIgnore;
//Vector containing the partial order
std::vector<std::set<MSchedGraphSBNode*> > partialOrder;
//Vector containing the final node order
std::vector<MSchedGraphSBNode*> FinalNodeOrder;
//Schedule table, key is the cycle number and the vector is resource, node pairs
MSScheduleSB schedule;
//Current initiation interval
int II;
//Internal Functions
void FindSuperBlocks(Function &F, LoopInfo &LI,
std::vector<std::vector<const MachineBasicBlock*> > &Worklist);
bool MachineBBisValid(const MachineBasicBlock *B,
std::map<const MachineInstr*, unsigned> &indexMap,
unsigned &offset);
bool CreateDefMap(std::vector<const MachineBasicBlock*> &SB);
bool getIndVar(std::vector<const MachineBasicBlock*> &superBlock,
std::map<BasicBlock*, MachineBasicBlock*> &bbMap,
std::map<const MachineInstr*, unsigned> &indexMap);
bool assocIndVar(Instruction *I, std::set<Instruction*> &indVar,
std::vector<Instruction*> &stack,
std::map<BasicBlock*, MachineBasicBlock*> &bbMap,
const BasicBlock *first,
std::set<const BasicBlock*> &llvmSuperBlock);
int calculateResMII(std::vector<const MachineBasicBlock*> &superBlock);
int calculateRecMII(MSchedGraphSB *graph, int MII);
void findAllCircuits(MSchedGraphSB *g, int II);
void addRecc(std::vector<MSchedGraphSBNode*> &stack,
std::map<MSchedGraphSBNode*, MSchedGraphSBNode*> &newNodes);
bool circuit(MSchedGraphSBNode *v, std::vector<MSchedGraphSBNode*> &stack,
std::set<MSchedGraphSBNode*> &blocked, std::vector<MSchedGraphSBNode*> &SCC,
MSchedGraphSBNode *s, std::map<MSchedGraphSBNode*,
std::set<MSchedGraphSBNode*> > &B,
int II, std::map<MSchedGraphSBNode*, MSchedGraphSBNode*> &newNodes);
void unblock(MSchedGraphSBNode *u, std::set<MSchedGraphSBNode*> &blocked,
std::map<MSchedGraphSBNode*, std::set<MSchedGraphSBNode*> > &B);
void addSCC(std::vector<MSchedGraphSBNode*> &SCC, std::map<MSchedGraphSBNode*, MSchedGraphSBNode*> &newNodes);
void calculateNodeAttributes(MSchedGraphSB *graph, int MII);
bool ignoreEdge(MSchedGraphSBNode *srcNode, MSchedGraphSBNode *destNode);
int calculateASAP(MSchedGraphSBNode *node, int MII, MSchedGraphSBNode *destNode);
int calculateALAP(MSchedGraphSBNode *node, int MII,
int maxASAP, MSchedGraphSBNode *srcNode);
int findMaxASAP();
int calculateHeight(MSchedGraphSBNode *node,MSchedGraphSBNode *srcNode);
int calculateDepth(MSchedGraphSBNode *node, MSchedGraphSBNode *destNode);
void computePartialOrder();
void connectedComponentSet(MSchedGraphSBNode *node, std::set<MSchedGraphSBNode*> &ccSet,
std::set<MSchedGraphSBNode*> &lastNodes);
void searchPath(MSchedGraphSBNode *node,
std::vector<MSchedGraphSBNode*> &path,
std::set<MSchedGraphSBNode*> &nodesToAdd,
std::set<MSchedGraphSBNode*> &new_reccurrence);
void orderNodes();
bool computeSchedule(std::vector<const MachineBasicBlock*> &BB, MSchedGraphSB *MSG);
bool scheduleNode(MSchedGraphSBNode *node, int start, int end);
void predIntersect(std::set<MSchedGraphSBNode*> &CurrentSet, std::set<MSchedGraphSBNode*> &IntersectResult);
void succIntersect(std::set<MSchedGraphSBNode*> &CurrentSet, std::set<MSchedGraphSBNode*> &IntersectResult);
void reconstructLoop(std::vector<const MachineBasicBlock*> &SB);
void fixBranches(std::vector<std::vector<MachineBasicBlock*> > &prologues,
std::vector<std::vector<BasicBlock*> > &llvm_prologues,
std::vector<MachineBasicBlock*> &machineKernelBB,
std::vector<BasicBlock*> &llvmKernelBB,
std::vector<std::vector<MachineBasicBlock*> > &epilogues,
std::vector<std::vector<BasicBlock*> > &llvm_epilogues,
std::vector<const MachineBasicBlock*> &SB,
std::map<const MachineBasicBlock*, Value*> &sideExits);
void writePrologues(std::vector<std::vector<MachineBasicBlock *> > &prologues,
std::vector<const MachineBasicBlock*> &origBB,
std::vector<std::vector<BasicBlock*> > &llvm_prologues,
std::map<const Value*, std::pair<const MachineInstr*, int> > &valuesToSave,
std::map<Value*, std::map<int, Value*> > &newValues,
std::map<Value*, MachineBasicBlock*> &newValLocation);
void writeKernel(std::vector<BasicBlock*> &llvmBB, std::vector<MachineBasicBlock*> &machineBB,
std::map<const Value*, std::pair<const MachineInstr*, int> > &valuesToSave,
std::map<Value*, std::map<int, Value*> > &newValues,
std::map<Value*, MachineBasicBlock*> &newValLocation,
std::map<Value*, std::map<int, Value*> > &kernelPHIs);
void removePHIs(std::vector<const MachineBasicBlock*> &SB,
std::vector<std::vector<MachineBasicBlock*> > &prologues,
std::vector<std::vector<MachineBasicBlock*> > &epilogues,
std::vector<MachineBasicBlock*> &kernelBB,
std::map<Value*, MachineBasicBlock*> &newValLocation);
void writeEpilogues(std::vector<std::vector<MachineBasicBlock*> > &epilogues,
std::vector<const MachineBasicBlock*> &origSB,
std::vector<std::vector<BasicBlock*> > &llvm_epilogues,
std::map<const Value*, std::pair<const MachineInstr*, int> > &valuesToSave,
std::map<Value*, std::map<int, Value*> > &newValues,
std::map<Value*, MachineBasicBlock*> &newValLocation,
std::map<Value*, std::map<int, Value*> > &kernelPHIs);
void writeSideExits(std::vector<std::vector<MachineBasicBlock *> > &prologues,
std::vector<std::vector<BasicBlock*> > &llvm_prologues,
std::vector<std::vector<MachineBasicBlock *> > &epilogues,
std::vector<std::vector<BasicBlock*> > &llvm_epilogues,
std::map<const MachineBasicBlock*, Value*> &sideExits,
std::map<MachineBasicBlock*, std::vector<std::pair<MachineInstr*, int> > > &instrsMovedDown,
std::vector<const MachineBasicBlock*> &SB,
std::vector<MachineBasicBlock*> &kernelMBBs,
std::map<MachineBasicBlock*, int> branchStage);
public:
ModuloSchedulingSBPass(TargetMachine &targ) : target(targ) {}
virtual bool runOnFunction(Function &F);
virtual const char* getPassName() const { return "ModuloScheduling-SuperBlock"; }
// getAnalysisUsage
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
/// HACK: We don't actually need scev, but we have
/// to say we do so that the pass manager does not delete it
/// before we run.
AU.addRequired<LoopInfo>();
AU.addRequired<ScalarEvolution>();
AU.addRequired<DependenceAnalyzer>();
}
};
}
#endif

View File

@ -1,95 +0,0 @@
//===-- AllocInfo.h - Store info about regalloc decisions -------*- 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 header file contains the data structure used to save the state
// of the global, graph-coloring register allocator.
//
//===----------------------------------------------------------------------===//
#ifndef ALLOCINFO_H
#define ALLOCINFO_H
#include "llvm/Type.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Constants.h"
namespace llvm {
/// AllocInfo - Structure representing one instruction's operand's-worth of
/// register allocation state. We create tables made out of these data
/// structures to generate mapping information for this register allocator.
///
struct AllocInfo {
int Instruction; // (-1 if Argument, or 0 .. n - 1 for an instruction).
int Operand; // (-1 if Instruction, or 0 .. n-1 for an operand).
enum AllocStateTy { NotAllocated = 0, Allocated, Spilled };
AllocStateTy AllocState;
int Placement;
AllocInfo (int Inst_, int Op_, AllocStateTy State_, int Place_) :
Instruction(Inst_), Operand(Op_), AllocState(State_), Placement(Place_) { }
/// AllocInfo constructor -- Default constructor creates an invalid AllocInfo
/// (presumably to be replaced with something meaningful later).
///
AllocInfo () :
Instruction(-1), Operand(-1), AllocState(NotAllocated), Placement(-1) { }
/// getConstantType - Return a StructType representing an AllocInfo object.
///
static StructType *getConstantType () {
std::vector<const Type *> TV;
TV.push_back (Type::IntTy);
TV.push_back (Type::IntTy);
TV.push_back (Type::UIntTy);
TV.push_back (Type::IntTy);
return StructType::get (TV);
}
/// toConstant - Convert this AllocInfo into an LLVM Constant of type
/// getConstantType(), and return the Constant.
///
Constant *toConstant () const {
StructType *ST = getConstantType ();
std::vector<Constant *> CV;
CV.push_back (ConstantSInt::get (Type::IntTy, Instruction));
CV.push_back (ConstantSInt::get (Type::IntTy, Operand));
CV.push_back (ConstantUInt::get (Type::UIntTy, AllocState));
CV.push_back (ConstantSInt::get (Type::IntTy, Placement));
return ConstantStruct::get (ST, CV);
}
/// AllocInfos compare equal if the allocation placements are equal
/// (i.e., they can be equal even if they refer to operands from two
/// different instructions.)
///
bool operator== (const AllocInfo &X) const {
return (X.AllocState == AllocState) && (X.Placement == Placement);
}
bool operator!= (const AllocInfo &X) const { return !(*this == X); }
/// Returns a human-readable string representation of the AllocState member.
///
const std::string allocStateToString () const {
static const char *AllocStateNames[] =
{ "NotAllocated", "Allocated", "Spilled" };
return std::string (AllocStateNames[AllocState]);
}
};
static inline std::ostream &operator << (std::ostream &OS, AllocInfo &S) {
OS << "(Instruction " << S.Instruction << " Operand " << S.Operand
<< " AllocState " << S.allocStateToString () << " Placement "
<< S.Placement << ")";
return OS;
}
} // End llvm namespace
#endif // ALLOCINFO_H

View File

@ -1,62 +0,0 @@
//===-- IGNode.cpp --------------------------------------------------------===//
//
// 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 an Interference graph node for coloring-based register
// allocation.
//
//===----------------------------------------------------------------------===//
#include "IGNode.h"
#include <algorithm>
#include <iostream>
namespace llvm {
//-----------------------------------------------------------------------------
// Sets this IGNode on stack and reduce the degree of neighbors
//-----------------------------------------------------------------------------
void IGNode::pushOnStack() {
OnStack = true;
int neighs = AdjList.size();
if (neighs < 0) {
std::cerr << "\nAdj List size = " << neighs;
assert(0 && "Invalid adj list size");
}
for (int i=0; i < neighs; i++)
AdjList[i]->decCurDegree();
}
//-----------------------------------------------------------------------------
// Deletes an adjacency node. IGNodes are deleted when coalescing merges
// two IGNodes together.
//-----------------------------------------------------------------------------
void IGNode::delAdjIGNode(const IGNode *Node) {
std::vector<IGNode *>::iterator It=find(AdjList.begin(), AdjList.end(), Node);
assert(It != AdjList.end() && "The node must be there!");
AdjList.erase(It);
}
//-----------------------------------------------------------------------------
// Get the number of unique neighbors if these two nodes are merged
//-----------------------------------------------------------------------------
unsigned
IGNode::getCombinedDegree(const IGNode* otherNode) const {
std::vector<IGNode*> nbrs(AdjList);
nbrs.insert(nbrs.end(), otherNode->AdjList.begin(), otherNode->AdjList.end());
sort(nbrs.begin(), nbrs.end());
std::vector<IGNode*>::iterator new_end = unique(nbrs.begin(), nbrs.end());
return new_end - nbrs.begin();
}
} // End llvm namespace

View File

@ -1,123 +0,0 @@
//===-- IGNode.h - Represent a node in an interference graph ----*- 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 represents a node in an interference graph.
//
// For efficiency, the AdjList is updated only once - ie. we can add but not
// remove nodes from AdjList.
//
// The removal of nodes from IG is simulated by decrementing the CurDegree.
// If this node is put on stack (that is removed from IG), the CurDegree of all
// the neighbors are decremented and this node is marked OnStack. Hence
// the effective neighbors in the AdjList are the ones that do not have the
// OnStack flag set (therefore, they are in the IG).
//
// The methods that modify/use the CurDegree must be called only
// after all modifications to the IG are over (i.e., all neighbors are fixed).
//
// The vector representation is the most efficient one for adj list.
// Though nodes are removed when coalescing is done, we access it in sequence
// for far many times when coloring (colorNode()).
//
//===----------------------------------------------------------------------===//
#ifndef IGNODE_H
#define IGNODE_H
#include "LiveRange.h"
#include <vector>
namespace llvm {
class RegClass;
//----------------------------------------------------------------------------
// Class IGNode
//
// Represents a node in an interference graph.
//----------------------------------------------------------------------------
class IGNode {
const unsigned Index; // index within IGNodeList
bool OnStack; // this has been pushed on to stack for coloring
std::vector<IGNode *> AdjList;// adjacency list for this live range
int CurDegree;
//
// set by InterferenceGraph::setCurDegreeOfIGNodes() after calculating
// all adjacency lists.
// Decremented when a neighbor is pushed on to the stack.
// After that, never incremented/set again nor used.
V9LiveRange *const ParentLR;
public:
IGNode(V9LiveRange *LR, unsigned index) : Index(index), ParentLR(LR) {
OnStack = false;
CurDegree = -1;
ParentLR->setUserIGNode(this);
}
inline unsigned int getIndex() const { return Index; }
// adjLists must be updated only once. However, the CurDegree can be changed
//
inline void addAdjIGNode(IGNode *AdjNode) { AdjList.push_back(AdjNode); }
inline IGNode *getAdjIGNode(unsigned ind) const
{ assert ( ind < AdjList.size()); return AdjList[ind]; }
// delete a node in AdjList - node must be in the list
// should not be called often
//
void delAdjIGNode(const IGNode *Node);
inline unsigned getNumOfNeighbors() const { return AdjList.size(); }
// Get the number of unique neighbors if these two nodes are merged
unsigned getCombinedDegree(const IGNode* otherNode) const;
inline bool isOnStack() const { return OnStack; }
// remove form IG and pushes on to stack (reduce the degree of neighbors)
//
void pushOnStack();
// CurDegree is the effective number of neighbors when neighbors are
// pushed on to the stack during the coloring phase. Must be called
// after all modifications to the IG are over (i.e., all neighbors are
// fixed).
//
inline void setCurDegree() {
assert(CurDegree == -1);
CurDegree = AdjList.size();
}
inline int getCurDegree() const { return CurDegree; }
// called when a neigh is pushed on to stack
//
inline void decCurDegree() { assert(CurDegree > 0); --CurDegree; }
// The following methods call the methods in ParentLR
// They are added to this class for convenience
// If many of these are called within a single scope,
// consider calling the methods directly on LR
inline bool hasColor() const { return ParentLR->hasColor(); }
inline unsigned int getColor() const { return ParentLR->getColor(); }
inline void setColor(unsigned Col) { ParentLR->setColor(Col); }
inline V9LiveRange *getParentLR() const { return ParentLR; }
};
} // End llvm namespace
#endif

View File

@ -1,248 +0,0 @@
//===-- InterferenceGraph.cpp ---------------------------------------------===//
//
// 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.
//
//===----------------------------------------------------------------------===//
//
// Interference graph for coloring-based register allocation for LLVM.
//
//===----------------------------------------------------------------------===//
#include "IGNode.h"
#include "InterferenceGraph.h"
#include "RegAllocCommon.h"
#include "llvm/ADT/STLExtras.h"
#include <algorithm>
#include <iostream>
namespace llvm {
// for asserting this IG node is infact in the IGNodeList of this class
inline static void assertIGNode(const InterferenceGraph *IG,
const IGNode *Node) {
assert(IG->getIGNodeList()[Node->getIndex()] == Node);
}
//-----------------------------------------------------------------------------
// Constructor: Records the RegClass and initalizes IGNodeList.
// The matrix is NOT yet created by the constructor. Call createGraph()
// to create it after adding all IGNodes to the IGNodeList.
//-----------------------------------------------------------------------------
InterferenceGraph::InterferenceGraph(RegClass *const RC) : RegCl(RC) {
IG = NULL;
Size = 0;
if( DEBUG_RA >= RA_DEBUG_Interference)
std::cerr << "Interference graph created!\n";
}
//-----------------------------------------------------------------------------
// destructor. Deletes the bit matrix and all IGNodes
//-----------------------------------------------------------------------------
InterferenceGraph:: ~InterferenceGraph() {
// delete the matrix
for(unsigned int r=0; r < IGNodeList.size(); ++r)
delete[] IG[r];
delete[] IG;
// delete all IGNodes in the IGNodeList
for_each(IGNodeList.begin(), IGNodeList.end(), deleter<IGNode>);
}
//-----------------------------------------------------------------------------
// Creates (dynamically allocates) the bit matrix necessary to hold the
// interference graph.
//-----------------------------------------------------------------------------
void InterferenceGraph::createGraph()
{
Size = IGNodeList.size();
IG = new char*[Size];
for( unsigned int r=0; r < Size; ++r)
IG[r] = new char[Size];
// init IG matrix
for(unsigned int i=0; i < Size; i++)
for(unsigned int j=0; j < Size; j++)
IG[i][j] = 0;
}
//-----------------------------------------------------------------------------
// creates a new IGNode for the given live range and add to IG
//-----------------------------------------------------------------------------
void InterferenceGraph::addLRToIG(V9LiveRange *const LR)
{
IGNodeList.push_back(new IGNode(LR, IGNodeList.size()));
}
//-----------------------------------------------------------------------------
// set interference for two live ranges
// update both the matrix and AdjLists of nodes.
// If there is already an interference between LR1 and LR2, adj lists
// are not updated. LR1 and LR2 must be distinct since if not, it suggests
// that there is some wrong logic in some other method.
//-----------------------------------------------------------------------------
void InterferenceGraph::setInterference(const V9LiveRange *const LR1,
const V9LiveRange *const LR2 ) {
assert(LR1 != LR2);
IGNode *IGNode1 = LR1->getUserIGNode();
IGNode *IGNode2 = LR2->getUserIGNode();
assertIGNode(this, IGNode1);
assertIGNode(this, IGNode2);
unsigned row = IGNode1->getIndex();
unsigned col = IGNode2->getIndex();
char *val;
if( DEBUG_RA >= RA_DEBUG_Interference)
std::cerr << "setting intf for: [" << row << "][" << col << "]\n";
( row > col) ? val = &IG[row][col]: val = &IG[col][row];
if( ! (*val) ) { // if this interf is not previously set
*val = 1; // add edges between nodes
IGNode1->addAdjIGNode( IGNode2 );
IGNode2->addAdjIGNode( IGNode1 );
}
}
//----------------------------------------------------------------------------
// return whether two live ranges interfere
//----------------------------------------------------------------------------
unsigned InterferenceGraph::getInterference(const V9LiveRange *const LR1,
const V9LiveRange *const LR2)
const {
assert(LR1 != LR2);
assertIGNode(this, LR1->getUserIGNode());
assertIGNode(this, LR2->getUserIGNode());
const unsigned int row = LR1->getUserIGNode()->getIndex();
const unsigned int col = LR2->getUserIGNode()->getIndex();
char ret;
if (row > col)
ret = IG[row][col];
else
ret = IG[col][row];
return ret;
}
//----------------------------------------------------------------------------
// Merge 2 IGNodes. The neighbors of the SrcNode will be added to the DestNode.
// Then the IGNode2L will be deleted. Necessary for coalescing.
// IMPORTANT: The live ranges are NOT merged by this method. Use
// LiveRangeInfo::unionAndUpdateLRs for that purpose.
//----------------------------------------------------------------------------
void InterferenceGraph::mergeIGNodesOfLRs(const V9LiveRange *LR1,
V9LiveRange *LR2) {
assert( LR1 != LR2); // cannot merge the same live range
IGNode *const DestNode = LR1->getUserIGNode();
IGNode *SrcNode = LR2->getUserIGNode();
assertIGNode(this, DestNode);
assertIGNode(this, SrcNode);
if( DEBUG_RA >= RA_DEBUG_Interference) {
std::cerr << "Merging LRs: \"" << *LR1 << "\" and \"" << *LR2 << "\"\n";
}
unsigned SrcDegree = SrcNode->getNumOfNeighbors();
const unsigned SrcInd = SrcNode->getIndex();
// for all neighs of SrcNode
for(unsigned i=0; i < SrcDegree; i++) {
IGNode *NeighNode = SrcNode->getAdjIGNode(i);
V9LiveRange *const LROfNeigh = NeighNode->getParentLR();
// delete edge between src and neigh - even neigh == dest
NeighNode->delAdjIGNode(SrcNode);
// set the matrix posn to 0 betn src and neigh - even neigh == dest
const unsigned NInd = NeighNode->getIndex();
( SrcInd > NInd) ? (IG[SrcInd][NInd]=0) : (IG[NInd][SrcInd]=0) ;
if( LR1 != LROfNeigh) { // if the neigh != dest
// add edge betwn Dest and Neigh - if there is no current edge
setInterference(LR1, LROfNeigh );
}
}
IGNodeList[ SrcInd ] = NULL;
// SrcNode is no longer necessary - LR2 must be deleted by the caller
delete( SrcNode );
}
//----------------------------------------------------------------------------
// must be called after modifications to the graph are over but before
// pushing IGNodes on to the stack for coloring.
//----------------------------------------------------------------------------
void InterferenceGraph::setCurDegreeOfIGNodes()
{
unsigned Size = IGNodeList.size();
for( unsigned i=0; i < Size; i++) {
IGNode *Node = IGNodeList[i];
if( Node )
Node->setCurDegree();
}
}
//--------------------- debugging (Printing) methods -----------------------
//----------------------------------------------------------------------------
// Print the IGnodes
//----------------------------------------------------------------------------
void InterferenceGraph::printIG() const {
for(unsigned i=0; i < Size; i++) {
const IGNode *const Node = IGNodeList[i];
if(Node) {
std::cerr << " [" << i << "] ";
for( unsigned int j=0; j < Size; j++)
if(IG[i][j])
std::cerr << "(" << i << "," << j << ") ";
std::cerr << "\n";
}
}
}
//----------------------------------------------------------------------------
// Print the IGnodes in the IGNode List
//----------------------------------------------------------------------------
void InterferenceGraph::printIGNodeList() const {
for(unsigned i=0; i < IGNodeList.size() ; ++i) {
const IGNode *const Node = IGNodeList[i];
if (Node)
std::cerr << " [" << Node->getIndex() << "] " << *Node->getParentLR()
<< "\t <# of Neighbors: " << Node->getNumOfNeighbors() << ">\n";
}
}
} // End llvm namespace

View File

@ -1,75 +0,0 @@
//===-- InterferenceGraph.h - Interference graph for register coloring -*- 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.
//
//===----------------------------------------------------------------------===//
/* Title: InterferenceGraph.h -*- C++ -*-
Author: Ruchira Sasanka
Date: July 20, 01
Purpose: Interference Graph used for register coloring.
Notes:
Adj Info is stored in the lower trangular matrix (i.e., row > col )
This class must be used in the following way:
* Construct class
* call addLRToIG as many times to add ALL LRs to this IG
* call createGraph to create the actual matrix
* Then setInterference, getInterference, mergeIGNodesOfLRs can be
called as desired to modify the graph.
* Once the modifications to the graph are over, call
setCurDegreeOfIGNodes() before pushing IGNodes on to stack for coloring.
*/
#ifndef INTERFERENCEGRAPH_H
#define INTERFERENCEGRAPH_H
#include <vector>
namespace llvm {
class V9LiveRange;
class RegClass;
class IGNode;
class InterferenceGraph {
char **IG; // a poiner to the interference graph
unsigned int Size; // size of a side of the IG
RegClass *const RegCl; // RegCl contains this IG
std::vector<IGNode *> IGNodeList; // a list of all IGNodes in a reg class
public:
// the matrix is not yet created by the constructor. Call createGraph()
// to create it after adding all IGNodes to the IGNodeList
InterferenceGraph(RegClass *RC);
~InterferenceGraph();
void createGraph();
void addLRToIG(V9LiveRange *LR);
void setInterference(const V9LiveRange *LR1,
const V9LiveRange *LR2);
unsigned getInterference(const V9LiveRange *LR1,
const V9LiveRange *LR2) const ;
void mergeIGNodesOfLRs(const V9LiveRange *LR1, V9LiveRange *LR2);
std::vector<IGNode *> &getIGNodeList() { return IGNodeList; }
const std::vector<IGNode *> &getIGNodeList() const { return IGNodeList; }
void setCurDegreeOfIGNodes();
void printIG() const;
void printIGNodeList() const;
};
} // End llvm namespace
#endif

View File

@ -1,195 +0,0 @@
//===-- LiveRange.h - Store info about a live range -------------*- 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.
//
//===----------------------------------------------------------------------===//
//
// Implements a live range using a SetVector of Value *s. We keep only
// defs in a V9LiveRange.
//
//===----------------------------------------------------------------------===//
#ifndef LIVERANGE_H
#define LIVERANGE_H
#include "llvm/Value.h"
#include "llvm/ADT/SetVector.h"
#include <iostream>
namespace llvm {
class RegClass;
class IGNode;
class V9LiveRange {
public:
typedef SetVector<const Value *> ValueContainerType;
typedef ValueContainerType::iterator iterator;
typedef ValueContainerType::const_iterator const_iterator;
private:
ValueContainerType MyValues; // Values in this V9LiveRange
RegClass *MyRegClass; // register class (e.g., int, FP) for this LR
/// doesSpanAcrossCalls - Does this live range span across calls?
/// This information is used by graph coloring algo to avoid allocating
/// volatile colors to live ranges that span across calls (since they have to
/// be saved/restored)
///
bool doesSpanAcrossCalls;
IGNode *UserIGNode; // IGNode which uses this LR
int Color; // color assigned to this live range
bool mustSpill; // whether this LR must be spilt
/// SuggestedColor - if this LR has a suggested color, can it
/// really be allocated? A suggested color cannot be allocated when the
/// suggested color is volatile and when there are call
/// interferences.
///
int SuggestedColor; // The suggested color for this LR
/// CanUseSuggestedCol - It is possible that a suggested color for
/// this live range is not available before graph coloring (e.g., it
/// can be allocated to another live range which interferes with
/// this)
///
bool CanUseSuggestedCol;
/// SpilledStackOffsetFromFP - If this LR is spilled, its stack
/// offset from *FP*. The spilled offsets must always be relative to
/// the FP.
///
int SpilledStackOffsetFromFP;
/// HasSpillOffset - True iff this live range has a spill offset.
///
bool HasSpillOffset;
/// SpillCost - The spill cost of this live range. Calculated using loop depth
/// of each reference to each Value in the live range.
///
unsigned SpillCost;
public:
iterator begin() { return MyValues.begin(); }
const_iterator begin() const { return MyValues.begin(); }
iterator end() { return MyValues.end(); }
const_iterator end() const { return MyValues.end(); }
bool insert(const Value *&X) { return MyValues.insert (X); }
void insert(iterator b, iterator e) { MyValues.insert (b, e); }
V9LiveRange() {
Color = SuggestedColor = -1; // not yet colored
mustSpill = false;
MyRegClass = 0;
UserIGNode = 0;
doesSpanAcrossCalls = false;
CanUseSuggestedCol = true;
HasSpillOffset = false;
SpillCost = 0;
}
void setRegClass(RegClass *RC) { MyRegClass = RC; }
RegClass *getRegClass() const { assert(MyRegClass); return MyRegClass; }
unsigned getRegClassID() const;
bool hasColor() const { return Color != -1; }
unsigned getColor() const { assert(Color != -1); return (unsigned)Color; }
void setColor(unsigned Col) { Color = (int)Col; }
inline void setCallInterference() {
doesSpanAcrossCalls = 1;
}
inline void clearCallInterference() {
doesSpanAcrossCalls = 0;
}
inline bool isCallInterference() const {
return doesSpanAcrossCalls == 1;
}
inline void markForSpill() { mustSpill = true; }
inline bool isMarkedForSpill() const { return mustSpill; }
inline void setSpillOffFromFP(int StackOffset) {
assert(mustSpill && "This LR is not spilled");
SpilledStackOffsetFromFP = StackOffset;
HasSpillOffset = true;
}
inline void modifySpillOffFromFP(int StackOffset) {
assert(mustSpill && "This LR is not spilled");
SpilledStackOffsetFromFP = StackOffset;
HasSpillOffset = true;
}
inline bool hasSpillOffset() const {
return HasSpillOffset;
}
inline int getSpillOffFromFP() const {
assert(HasSpillOffset && "This LR is not spilled");
return SpilledStackOffsetFromFP;
}
inline void setUserIGNode(IGNode *IGN) {
assert(!UserIGNode); UserIGNode = IGN;
}
// getUserIGNode - NULL if the user is not allocated
inline IGNode *getUserIGNode() const { return UserIGNode; }
inline const Type *getType() const {
return (*begin())->getType(); // set's don't have a front
}
inline void setSuggestedColor(int Col) {
if (SuggestedColor == -1)
SuggestedColor = Col;
}
inline unsigned getSuggestedColor() const {
assert(SuggestedColor != -1); // only a valid color is obtained
return (unsigned)SuggestedColor;
}
inline bool hasSuggestedColor() const {
return SuggestedColor != -1;
}
inline bool isSuggestedColorUsable() const {
assert(hasSuggestedColor() && "No suggested color");
return CanUseSuggestedCol;
}
inline void setSuggestedColorUsable(bool val) {
assert(hasSuggestedColor() && "No suggested color");
CanUseSuggestedCol = val;
}
inline void addSpillCost(unsigned cost) {
SpillCost += cost;
}
inline unsigned getSpillCost() const {
return SpillCost;
}
};
static inline std::ostream &operator << (std::ostream &os,
const V9LiveRange &lr) {
os << "LiveRange@" << (void *)(&lr);
return os;
};
} // End llvm namespace
#endif

View File

@ -1,415 +0,0 @@
//===-- LiveRangeInfo.cpp -------------------------------------------------===//
//
// 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.
//
//===----------------------------------------------------------------------===//
//
// Live range construction for coloring-based register allocation for LLVM.
//
//===----------------------------------------------------------------------===//
#include "IGNode.h"
#include "LiveRangeInfo.h"
#include "RegAllocCommon.h"
#include "RegClass.h"
#include "llvm/Function.h"
#include "llvm/Type.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "../SparcV9RegInfo.h"
#include "llvm/ADT/SetOperations.h"
#include <iostream>
namespace llvm {
unsigned V9LiveRange::getRegClassID() const { return getRegClass()->getID(); }
LiveRangeInfo::LiveRangeInfo(const Function *F, const TargetMachine &tm,
std::vector<RegClass *> &RCL)
: Meth(F), TM(tm), RegClassList(RCL), MRI(*tm.getRegInfo()) { }
LiveRangeInfo::~LiveRangeInfo() {
for (LiveRangeMapType::iterator MI = LiveRangeMap.begin();
MI != LiveRangeMap.end(); ++MI) {
if (MI->first && MI->second) {
V9LiveRange *LR = MI->second;
// we need to be careful in deleting LiveRanges in LiveRangeMap
// since two/more Values in the live range map can point to the same
// live range. We have to make the other entries NULL when we delete
// a live range.
for (V9LiveRange::iterator LI = LR->begin(); LI != LR->end(); ++LI)
LiveRangeMap[*LI] = 0;
delete LR;
}
}
}
//---------------------------------------------------------------------------
// union two live ranges into one. The 2nd LR is deleted. Used for coalescing.
// Note: the caller must make sure that L1 and L2 are distinct and both
// LRs don't have suggested colors
//---------------------------------------------------------------------------
void LiveRangeInfo::unionAndUpdateLRs(V9LiveRange *L1, V9LiveRange *L2) {
assert(L1 != L2 && (!L1->hasSuggestedColor() || !L2->hasSuggestedColor()));
assert(! (L1->hasColor() && L2->hasColor()) ||
L1->getColor() == L2->getColor());
L2->insert (L1->begin(), L1->end()); // add elements of L2 to L1
for(V9LiveRange::iterator L2It = L2->begin(); L2It != L2->end(); ++L2It) {
L1->insert(*L2It); // add the var in L2 to L1
LiveRangeMap[*L2It] = L1; // now the elements in L2 should map
//to L1
}
// set call interference for L1 from L2
if (L2->isCallInterference())
L1->setCallInterference();
// add the spill costs
L1->addSpillCost(L2->getSpillCost());
// If L2 has a color, give L1 that color. Note that L1 may have had the same
// color or none, but would not have a different color as asserted above.
if (L2->hasColor())
L1->setColor(L2->getColor());
// Similarly, if LROfUse(L2) has a suggested color, the new range
// must have the same color.
if (L2->hasSuggestedColor())
L1->setSuggestedColor(L2->getSuggestedColor());
delete L2; // delete L2 as it is no longer needed
}
//---------------------------------------------------------------------------
// Method for creating a single live range for a definition.
// The definition must be represented by a virtual register (a Value).
// Note: this function does *not* check that no live range exists for def.
//---------------------------------------------------------------------------
V9LiveRange*
LiveRangeInfo::createNewLiveRange(const Value* Def, bool isCC /* = false*/)
{
V9LiveRange* DefRange = new V9LiveRange(); // Create a new live range,
DefRange->insert(Def); // add Def to it,
LiveRangeMap[Def] = DefRange; // and update the map.
// set the register class of the new live range
DefRange->setRegClass(RegClassList[MRI.getRegClassIDOfType(Def->getType(),
isCC)]);
if (DEBUG_RA >= RA_DEBUG_LiveRanges) {
std::cerr << " Creating a LR for def ";
if (isCC) std::cerr << " (CC Register!)";
std::cerr << " : " << RAV(Def) << "\n";
}
return DefRange;
}
V9LiveRange*
LiveRangeInfo::createOrAddToLiveRange(const Value* Def, bool isCC /* = false*/)
{
V9LiveRange *DefRange = LiveRangeMap[Def];
// check if the LR is already there (because of multiple defs)
if (!DefRange) {
DefRange = createNewLiveRange(Def, isCC);
} else { // live range already exists
DefRange->insert(Def); // add the operand to the range
LiveRangeMap[Def] = DefRange; // make operand point to merged set
if (DEBUG_RA >= RA_DEBUG_LiveRanges)
std::cerr << " Added to existing LR for def: " << RAV(Def) << "\n";
}
return DefRange;
}
//---------------------------------------------------------------------------
// Method for constructing all live ranges in a function. It creates live
// ranges for all values defined in the instruction stream. Also, it
// creates live ranges for all incoming arguments of the function.
//---------------------------------------------------------------------------
void LiveRangeInfo::constructLiveRanges() {
if (DEBUG_RA >= RA_DEBUG_LiveRanges)
std::cerr << "Constructing Live Ranges ...\n";
// first find the live ranges for all incoming args of the function since
// those LRs start from the start of the function
for (Function::const_arg_iterator AI = Meth->arg_begin(); AI != Meth->arg_end(); ++AI)
createNewLiveRange(AI, /*isCC*/ false);
// Now suggest hardware registers for these function args
MRI.suggestRegs4MethodArgs(Meth, *this);
// Now create LRs for machine instructions. A new LR will be created
// only for defs in the machine instr since, we assume that all Values are
// defined before they are used. However, there can be multiple defs for
// the same Value in machine instructions.
//
// Also, find CALL and RETURN instructions, which need extra work.
//
MachineFunction &MF = MachineFunction::get(Meth);
for (MachineFunction::iterator BBI = MF.begin(); BBI != MF.end(); ++BBI) {
MachineBasicBlock &MBB = *BBI;
// iterate over all the machine instructions in BB
for(MachineBasicBlock::iterator MInstIterator = MBB.begin();
MInstIterator != MBB.end(); ++MInstIterator) {
MachineInstr *MInst = MInstIterator;
// If the machine instruction is a call/return instruction, add it to
// CallRetInstrList for processing its args, ret value, and ret addr.
//
if(TM.getInstrInfo()->isReturn(MInst->getOpcode()) ||
TM.getInstrInfo()->isCall(MInst->getOpcode()))
CallRetInstrList.push_back(MInst);
// iterate over explicit MI operands and create a new LR
// for each operand that is defined by the instruction
for (MachineInstr::val_op_iterator OpI = MInst->begin(),
OpE = MInst->end(); OpI != OpE; ++OpI)
if (OpI.isDef()) {
const Value *Def = *OpI;
bool isCC = (OpI.getMachineOperand().getType()
== MachineOperand::MO_CCRegister);
V9LiveRange* LR = createOrAddToLiveRange(Def, isCC);
// If the operand has a pre-assigned register,
// set it directly in the V9LiveRange
if (OpI.getMachineOperand().hasAllocatedReg()) {
unsigned getClassId;
LR->setColor(MRI.getClassRegNum(OpI.getMachineOperand().getReg(),
getClassId));
}
}
// iterate over implicit MI operands and create a new LR
// for each operand that is defined by the instruction
for (unsigned i = 0; i < MInst->getNumImplicitRefs(); ++i)
if (MInst->getImplicitOp(i).isDef()) {
const Value *Def = MInst->getImplicitRef(i);
V9LiveRange* LR = createOrAddToLiveRange(Def, /*isCC*/ false);
// If the implicit operand has a pre-assigned register,
// set it directly in the V9LiveRange
if (MInst->getImplicitOp(i).hasAllocatedReg()) {
unsigned getClassId;
LR->setColor(MRI.getClassRegNum(
MInst->getImplicitOp(i).getReg(),
getClassId));
}
}
} // for all machine instructions in the BB
} // for all BBs in function
// Now we have to suggest clors for call and return arg live ranges.
// Also, if there are implicit defs (e.g., retun value of a call inst)
// they must be added to the live range list
//
suggestRegs4CallRets();
if( DEBUG_RA >= RA_DEBUG_LiveRanges)
std::cerr << "Initial Live Ranges constructed!\n";
}
//---------------------------------------------------------------------------
// If some live ranges must be colored with specific hardware registers
// (e.g., for outgoing call args), suggesting of colors for such live
// ranges is done using target specific function. Those functions are called
// from this function. The target specific methods must:
// 1) suggest colors for call and return args.
// 2) create new LRs for implicit defs in machine instructions
//---------------------------------------------------------------------------
void LiveRangeInfo::suggestRegs4CallRets() {
std::vector<MachineInstr*>::iterator It = CallRetInstrList.begin();
for( ; It != CallRetInstrList.end(); ++It) {
MachineInstr *MInst = *It;
MachineOpCode OpCode = MInst->getOpcode();
if (TM.getInstrInfo()->isReturn(OpCode))
MRI.suggestReg4RetValue(MInst, *this);
else if (TM.getInstrInfo()->isCall(OpCode))
MRI.suggestRegs4CallArgs(MInst, *this);
else
assert( 0 && "Non call/ret instr in CallRetInstrList" );
}
}
//--------------------------------------------------------------------------
// The following method coalesces live ranges when possible. This method
// must be called after the interference graph has been constructed.
/* Algorithm:
for each BB in function
for each machine instruction (inst)
for each definition (def) in inst
for each operand (op) of inst that is a use
if the def and op are of the same register type
if the def and op do not interfere //i.e., not simultaneously live
if (degree(LR of def) + degree(LR of op)) <= # avail regs
if both LRs do not have suggested colors
merge2IGNodes(def, op) // i.e., merge 2 LRs
*/
//---------------------------------------------------------------------------
// Checks if live range LR interferes with any node assigned or suggested to
// be assigned the specified color
//
inline bool InterferesWithColor(const V9LiveRange& LR, unsigned color) {
IGNode* lrNode = LR.getUserIGNode();
for (unsigned n=0, NN = lrNode->getNumOfNeighbors(); n < NN; n++) {
V9LiveRange *neighLR = lrNode->getAdjIGNode(n)->getParentLR();
if (neighLR->hasColor() && neighLR->getColor() == color)
return true;
if (neighLR->hasSuggestedColor() && neighLR->getSuggestedColor() == color)
return true;
}
return false;
}
// Cannot coalesce if any of the following is true:
// (1) Both LRs have suggested colors (should be "different suggested colors"?)
// (2) Both LR1 and LR2 have colors and the colors are different
// (but if the colors are the same, it is definitely safe to coalesce)
// (3) LR1 has color and LR2 interferes with any LR that has the same color
// (4) LR2 has color and LR1 interferes with any LR that has the same color
//
inline bool InterfsPreventCoalescing(const V9LiveRange& LROfDef,
const V9LiveRange& LROfUse) {
// (4) if they have different suggested colors, cannot coalesce
if (LROfDef.hasSuggestedColor() && LROfUse.hasSuggestedColor())
return true;
// if neither has a color, nothing more to do.
if (! LROfDef.hasColor() && ! LROfUse.hasColor())
return false;
// (2, 3) if L1 has color...
if (LROfDef.hasColor()) {
if (LROfUse.hasColor())
return (LROfUse.getColor() != LROfDef.getColor());
return InterferesWithColor(LROfUse, LROfDef.getColor());
}
// (4) else only LROfUse has a color: check if that could interfere
return InterferesWithColor(LROfDef, LROfUse.getColor());
}
void LiveRangeInfo::coalesceLRs()
{
if(DEBUG_RA >= RA_DEBUG_LiveRanges)
std::cerr << "\nCoalescing LRs ...\n";
MachineFunction &MF = MachineFunction::get(Meth);
for (MachineFunction::iterator BBI = MF.begin(); BBI != MF.end(); ++BBI) {
MachineBasicBlock &MBB = *BBI;
// iterate over all the machine instructions in BB
for(MachineBasicBlock::iterator MII = MBB.begin(); MII != MBB.end(); ++MII){
const MachineInstr *MI = MII;
if( DEBUG_RA >= RA_DEBUG_LiveRanges) {
std::cerr << " *Iterating over machine instr ";
MI->dump();
std::cerr << "\n";
}
// iterate over MI operands to find defs
for(MachineInstr::const_val_op_iterator DefI = MI->begin(),
DefE = MI->end(); DefI != DefE; ++DefI) {
if (DefI.isDef()) { // this operand is modified
V9LiveRange *LROfDef = getLiveRangeForValue( *DefI );
RegClass *RCOfDef = LROfDef->getRegClass();
MachineInstr::const_val_op_iterator UseI = MI->begin(),
UseE = MI->end();
for( ; UseI != UseE; ++UseI) { // for all uses
V9LiveRange *LROfUse = getLiveRangeForValue( *UseI );
if (!LROfUse) { // if LR of use is not found
//don't warn about labels
if (!isa<BasicBlock>(*UseI) && DEBUG_RA >= RA_DEBUG_LiveRanges)
std::cerr << " !! Warning: No LR for use " << RAV(*UseI)<< "\n";
continue; // ignore and continue
}
if (LROfUse == LROfDef) // nothing to merge if they are same
continue;
if (MRI.getRegTypeForLR(LROfDef) ==
MRI.getRegTypeForLR(LROfUse)) {
// If the two RegTypes are the same
if (!RCOfDef->getInterference(LROfDef, LROfUse) ) {
unsigned CombinedDegree =
LROfDef->getUserIGNode()->getNumOfNeighbors() +
LROfUse->getUserIGNode()->getNumOfNeighbors();
if (CombinedDegree > RCOfDef->getNumOfAvailRegs()) {
// get more precise estimate of combined degree
CombinedDegree = LROfDef->getUserIGNode()->
getCombinedDegree(LROfUse->getUserIGNode());
}
if (CombinedDegree <= RCOfDef->getNumOfAvailRegs()) {
// if both LRs do not have different pre-assigned colors
// and both LRs do not have suggested colors
if (! InterfsPreventCoalescing(*LROfDef, *LROfUse)) {
RCOfDef->mergeIGNodesOfLRs(LROfDef, LROfUse);
unionAndUpdateLRs(LROfDef, LROfUse);
}
} // if combined degree is less than # of regs
} // if def and use do not interfere
}// if reg classes are the same
} // for all uses
} // if def
} // for all defs
} // for all machine instructions
} // for all BBs
if (DEBUG_RA >= RA_DEBUG_LiveRanges)
std::cerr << "\nCoalescing Done!\n";
}
/*--------------------------- Debug code for printing ---------------*/
void LiveRangeInfo::printLiveRanges() {
LiveRangeMapType::iterator HMI = LiveRangeMap.begin(); // hash map iterator
std::cerr << "\nPrinting Live Ranges from Hash Map:\n";
for( ; HMI != LiveRangeMap.end(); ++HMI) {
if (HMI->first && HMI->second) {
std::cerr << " Value* " << RAV(HMI->first) << "\t: ";
if (IGNode* igNode = HMI->second->getUserIGNode())
std::cerr << "LR# " << igNode->getIndex();
else
std::cerr << "LR# " << "<no-IGNode>";
std::cerr << "\t:Values = " << *HMI->second << "\n";
}
}
}
} // End llvm namespace

View File

@ -1,121 +0,0 @@
//===-- LiveRangeInfo.h - Track all LiveRanges for a Function ----*- 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 contains the class LiveRangeInfo which constructs and keeps
// the LiveRangeMap which contains all the live ranges used in a method.
//
// Assumptions:
//
// All variables (llvm Values) are defined before they are used. However, a
// constant may not be defined in the machine instruction stream if it can be
// used as an immediate value within a machine instruction. However, register
// allocation does not have to worry about immediate constants since they
// do not require registers.
//
// Since an llvm Value has a list of uses associated, it is sufficient to
// record only the defs in a Live Range.
//
//===----------------------------------------------------------------------===//
#ifndef LIVERANGEINFO_H
#define LIVERANGEINFO_H
#include "llvm/CodeGen/ValueSet.h"
#include "llvm/ADT/hash_map"
namespace llvm {
class V9LiveRange;
class MachineInstr;
class RegClass;
class SparcV9RegInfo;
class TargetMachine;
class Value;
class Function;
class Instruction;
typedef hash_map<const Value*, V9LiveRange*> LiveRangeMapType;
//----------------------------------------------------------------------------
// Class LiveRangeInfo
//
// Constructs and keeps the LiveRangeMap which contains all the live
// ranges used in a method. Also contain methods to coalesce live ranges.
//----------------------------------------------------------------------------
class LiveRangeInfo {
const Function *const Meth; // Func for which live range info is held
LiveRangeMapType LiveRangeMap; // A map from Value * to V9LiveRange * to
// record all live ranges in a method
// created by constructLiveRanges
const TargetMachine& TM; // target machine description
std::vector<RegClass *> & RegClassList;// vector containing register classess
const SparcV9RegInfo& MRI; // machine reg info
std::vector<MachineInstr*> CallRetInstrList; // a list of all call/ret instrs
//------------ Private methods (see LiveRangeInfo.cpp for description)-------
V9LiveRange* createNewLiveRange (const Value* Def,
bool isCC = false);
V9LiveRange* createOrAddToLiveRange (const Value* Def,
bool isCC = false);
void unionAndUpdateLRs (V9LiveRange *L1,
V9LiveRange *L2);
void suggestRegs4CallRets ();
public:
LiveRangeInfo(const Function *F,
const TargetMachine& tm,
std::vector<RegClass *> & RCList);
/// Destructor to destroy all LiveRanges in the V9LiveRange Map
///
~LiveRangeInfo();
// Main entry point for live range construction
//
void constructLiveRanges();
/// return the common live range map for this method
///
inline const LiveRangeMapType *getLiveRangeMap() const
{ return &LiveRangeMap; }
/// Method used to get the live range containing a Value.
/// This may return NULL if no live range exists for a Value (eg, some consts)
///
inline V9LiveRange *getLiveRangeForValue(const Value *Val) {
return LiveRangeMap[Val];
}
inline const V9LiveRange *getLiveRangeForValue(const Value *Val) const {
LiveRangeMapType::const_iterator I = LiveRangeMap.find(Val);
return I->second;
}
/// Method for coalescing live ranges. Called only after interference info
/// is calculated.
///
void coalesceLRs();
/// debugging method to print the live ranges
///
void printLiveRanges();
};
} // End llvm namespace
#endif

View File

@ -1,14 +0,0 @@
##===- lib/CodeGen/RegAlloc/Makefile -----------------------*- Makefile -*-===##
#
# 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.
#
##===----------------------------------------------------------------------===##
LEVEL = ../../../..
DIRS =
LIBRARYNAME = LLVMSparcV9RegAlloc
include $(LEVEL)/Makefile.common

File diff suppressed because it is too large Load Diff

View File

@ -1,186 +0,0 @@
//===-- PhyRegAlloc.h - Graph Coloring Register Allocator -------*- 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 is the main entry point for register allocation.
//
// Notes:
// * RegisterClasses: Each RegClass accepts a
// TargetRegClass which contains machine specific info about that register
// class. The code in the RegClass is machine independent and they use
// access functions in the TargetRegClass object passed into it to get
// machine specific info.
//
// * Machine dependent work: All parts of the register coloring algorithm
// except coloring of an individual node are machine independent.
//
//===----------------------------------------------------------------------===//
#ifndef PHYREGALLOC_H
#define PHYREGALLOC_H
#include "LiveRangeInfo.h"
#include "llvm/Pass.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/Target/TargetMachine.h"
#include "../SparcV9RegInfo.h"
#include <map>
namespace llvm {
class MachineFunction;
class FunctionLiveVarInfo;
class MachineInstr;
class LoopInfo;
class RegClass;
class Constant;
//----------------------------------------------------------------------------
// Class AddedInstrns:
// When register allocator inserts new instructions in to the existing
// instruction stream, it does NOT directly modify the instruction stream.
// Rather, it creates an object of AddedInstrns and stick it in the
// AddedInstrMap for an existing instruction. This class contains two vectors
// to store such instructions added before and after an existing instruction.
//----------------------------------------------------------------------------
struct AddedInstrns {
std::vector<MachineInstr*> InstrnsBefore;//Insts added BEFORE an existing inst
std::vector<MachineInstr*> InstrnsAfter; //Insts added AFTER an existing inst
inline void clear () { InstrnsBefore.clear (); InstrnsAfter.clear (); }
};
//----------------------------------------------------------------------------
// class PhyRegAlloc:
// Main class the register allocator. Call runOnFunction() to allocate
// registers for a Function.
//----------------------------------------------------------------------------
class PhyRegAlloc : public FunctionPass {
std::vector<RegClass *> RegClassList; // vector of register classes
const TargetMachine &TM; // target machine
const Function *Fn; // name of the function we work on
MachineFunction *MF; // descriptor for method's native code
FunctionLiveVarInfo *LVI; // LV information for this method
// (already computed for BBs)
LiveRangeInfo *LRI; // LR info (will be computed)
const SparcV9RegInfo &MRI; // Machine Register information
const unsigned NumOfRegClasses; // recorded here for efficiency
// Map to indicate whether operands of each MachineInstr have been
// updated according to their assigned colors. This is only used in
// assertion checking (debug builds).
std::map<const MachineInstr *, bool> OperandsColoredMap;
// AddedInstrMap - Used to store instrns added in this phase
std::map<const MachineInstr *, AddedInstrns> AddedInstrMap;
// ScratchRegsUsed - Contains scratch register uses for a particular MI.
typedef std::multimap<const MachineInstr*, int> ScratchRegsUsedTy;
ScratchRegsUsedTy ScratchRegsUsed;
AddedInstrns AddedInstrAtEntry; // to store instrns added at entry
const LoopInfo *LoopDepthCalc; // to calculate loop depths
PhyRegAlloc(const PhyRegAlloc&); // DO NOT IMPLEMENT
void operator=(const PhyRegAlloc&); // DO NOT IMPLEMENT
public:
typedef std::map<const Function *, std::vector<AllocInfo> > SavedStateMapTy;
inline PhyRegAlloc (const TargetMachine &TM_) :
TM (TM_), MRI (*TM.getRegInfo ()),
NumOfRegClasses (MRI.getNumOfRegClasses ()) { }
virtual ~PhyRegAlloc() { }
/// runOnFunction - Main method called for allocating registers.
///
virtual bool runOnFunction (Function &F);
virtual bool doFinalization (Module &M);
virtual void getAnalysisUsage (AnalysisUsage &AU) const;
const char *getPassName () const {
return "Traditional graph-coloring reg. allocator";
}
inline const RegClass* getRegClassByID(unsigned id) const {
return RegClassList[id];
}
inline RegClass *getRegClassByID(unsigned id) { return RegClassList[id]; }
private:
SavedStateMapTy FnAllocState;
void addInterference(const Value *Def, const ValueSet *LVSet,
bool isCallInst);
bool markAllocatedRegs(MachineInstr* MInst);
void addInterferencesForArgs();
void createIGNodeListsAndIGs();
void buildInterferenceGraphs();
void saveStateForValue (std::vector<AllocInfo> &state,
const Value *V, int Insn, int Opnd);
void saveState();
void finishSavingState(Module &M);
void setCallInterferences(const MachineInstr *MI,
const ValueSet *LVSetAft);
void move2DelayedInstr(const MachineInstr *OrigMI,
const MachineInstr *DelayedMI);
void markUnusableSugColors();
void allocateStackSpace4SpilledLRs();
void insertCode4SpilledLR(const V9LiveRange *LR,
MachineBasicBlock::iterator& MII,
MachineBasicBlock &MBB, unsigned OpNum);
/// Method for inserting caller saving code. The caller must save all the
/// volatile registers live across a call.
///
void insertCallerSavingCode(std::vector<MachineInstr*>& instrnsBefore,
std::vector<MachineInstr*>& instrnsAfter,
MachineInstr *CallMI,
const BasicBlock *BB);
void colorIncomingArgs();
void colorCallRetArgs();
void updateMachineCode();
void updateInstruction(MachineBasicBlock::iterator& MII,
MachineBasicBlock &MBB);
int getUsableUniRegAtMI(int RegType, const ValueSet *LVSetBef,
MachineInstr *MI,
std::vector<MachineInstr*>& MIBef,
std::vector<MachineInstr*>& MIAft);
/// Callback method used to find unused registers.
/// LVSetBef is the live variable set to search for an unused register.
/// If it is not specified, the LV set before the current MI is used.
/// This is sufficient as long as no new copy instructions are generated
/// to copy the free register to memory.
///
int getUnusedUniRegAtMI(RegClass *RC, int RegType,
const MachineInstr *MI,
const ValueSet *LVSetBef = 0);
void setRelRegsUsedByThisInst(RegClass *RC, int RegType,
const MachineInstr *MI);
int getUniRegNotUsedByThisInst(RegClass *RC, int RegType,
const MachineInstr *MI);
void addInterf4PseudoInstr(const MachineInstr *MI);
};
} // End llvm namespace
#endif

View File

@ -1,32 +0,0 @@
//===-- RegAllocCommon.h --------------------------------------------------===//
//
// 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.
//
//===----------------------------------------------------------------------===//
//
// Shared declarations for register allocation.
//
//===----------------------------------------------------------------------===//
#ifndef REGALLOCCOMMON_H
#define REGALLOCCOMMON_H
namespace llvm {
enum RegAllocDebugLevel_t {
RA_DEBUG_None = 0,
RA_DEBUG_Results = 1,
RA_DEBUG_Coloring = 2,
RA_DEBUG_Interference = 3,
RA_DEBUG_LiveRanges = 4,
RA_DEBUG_Verbose = 5
};
extern RegAllocDebugLevel_t DEBUG_RA;
} // End llvm namespace
#endif

View File

@ -1,251 +0,0 @@
//===-- RegClass.cpp -----------------------------------------------------===//
//
// 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.
//
//===----------------------------------------------------------------------===//
//
// class RegClass for coloring-based register allocation for LLVM.
//
//===----------------------------------------------------------------------===//
#include "IGNode.h"
#include "RegAllocCommon.h"
#include "RegClass.h"
#include "../SparcV9RegInfo.h"
#include <iostream>
namespace llvm {
//----------------------------------------------------------------------------
// This constructor inits IG. The actual matrix is created by a call to
// createInterferenceGraph() above.
//----------------------------------------------------------------------------
RegClass::RegClass(const Function *M,
const SparcV9RegInfo *_MRI_,
const TargetRegClassInfo *_MRC_)
: Meth(M), MRI(_MRI_), MRC(_MRC_),
RegClassID( _MRC_->getRegClassID() ),
IG(this), IGNodeStack() {
if (DEBUG_RA >= RA_DEBUG_Interference)
std::cerr << "Created Reg Class: " << RegClassID << "\n";
IsColorUsedArr.resize(MRC->getNumOfAllRegs());
}
//----------------------------------------------------------------------------
// Main entry point for coloring a register class.
//----------------------------------------------------------------------------
void RegClass::colorAllRegs()
{
if (DEBUG_RA >= RA_DEBUG_Coloring)
std::cerr << "Coloring IG of reg class " << RegClassID << " ...\n";
// pre-color IGNodes
pushAllIGNodes(); // push all IG Nodes
unsigned int StackSize = IGNodeStack.size();
IGNode *CurIGNode;
// for all LRs on stack
for (unsigned int IGN=0; IGN < StackSize; IGN++) {
CurIGNode = IGNodeStack.top(); // pop the IGNode on top of stack
IGNodeStack.pop();
colorIGNode (CurIGNode); // color it
}
}
//----------------------------------------------------------------------------
// The method for pushing all IGNodes on to the stack.
//----------------------------------------------------------------------------
void RegClass::pushAllIGNodes()
{
bool NeedMoreSpills;
IG.setCurDegreeOfIGNodes(); // calculate degree of IGNodes
// push non-constrained IGNodes
bool PushedAll = pushUnconstrainedIGNodes();
if (DEBUG_RA >= RA_DEBUG_Coloring) {
std::cerr << " Puhsed all-unconstrained IGNodes. ";
if( PushedAll ) std::cerr << " No constrained nodes left.";
std::cerr << "\n";
}
if (PushedAll) // if NO constrained nodes left
return;
// now, we have constrained nodes. So, push one of them (the one with min
// spill cost) and try to push the others as unConstrained nodes.
// Repeat this.
do {
//get node with min spill cost
IGNode *IGNodeSpill = getIGNodeWithMinSpillCost();
// push that node on to stack
IGNodeStack.push(IGNodeSpill);
// set its OnStack flag and decrement degree of neighs
IGNodeSpill->pushOnStack();
// now push NON-constrained ones, if any
NeedMoreSpills = !pushUnconstrainedIGNodes();
if (DEBUG_RA >= RA_DEBUG_Coloring)
std::cerr << "\nConstrained IG Node found !@!" << IGNodeSpill->getIndex();
} while(NeedMoreSpills); // repeat until we have pushed all
}
//--------------------------------------------------------------------------
// This method goes thru all IG nodes in the IGNodeList of an IG of a
// register class and push any unconstrained IG node left (that is not
// already pushed)
//--------------------------------------------------------------------------
bool RegClass::pushUnconstrainedIGNodes()
{
// # of LRs for this reg class
unsigned int IGNodeListSize = IG.getIGNodeList().size();
bool pushedall = true;
// a pass over IGNodeList
for (unsigned i =0; i < IGNodeListSize; i++) {
// get IGNode i from IGNodeList
IGNode *IGNode = IG.getIGNodeList()[i];
if (!IGNode ) // can be null due to merging
continue;
// if already pushed on stack, continue. This can happen since this
// method can be called repeatedly until all constrained nodes are
// pushed
if (IGNode->isOnStack() )
continue;
// if the degree of IGNode is lower
if ((unsigned) IGNode->getCurDegree() < MRC->getNumOfAvailRegs()) {
IGNodeStack.push( IGNode ); // push IGNode on to the stack
IGNode->pushOnStack(); // set OnStack and dec deg of neighs
if (DEBUG_RA >= RA_DEBUG_Coloring) {
std::cerr << " pushed un-constrained IGNode " << IGNode->getIndex()
<< " on to stack\n";
}
}
else pushedall = false; // we didn't push all live ranges
} // for
// returns true if we pushed all live ranges - else false
return pushedall;
}
//----------------------------------------------------------------------------
// Get the IGNode with the minimum spill cost
//----------------------------------------------------------------------------
IGNode * RegClass::getIGNodeWithMinSpillCost() {
unsigned int IGNodeListSize = IG.getIGNodeList().size();
double MinSpillCost = 0;
IGNode *MinCostIGNode = NULL;
bool isFirstNode = true;
// pass over IGNodeList to find the IGNode with minimum spill cost
// among all IGNodes that are not yet pushed on to the stack
for (unsigned int i =0; i < IGNodeListSize; i++) {
IGNode *IGNode = IG.getIGNodeList()[i];
if (!IGNode) // can be null due to merging
continue;
if (!IGNode->isOnStack()) {
double SpillCost = (double) IGNode->getParentLR()->getSpillCost() /
(double) (IGNode->getCurDegree() + 1);
if (isFirstNode) { // for the first IG node
MinSpillCost = SpillCost;
MinCostIGNode = IGNode;
isFirstNode = false;
} else if (MinSpillCost > SpillCost) {
MinSpillCost = SpillCost;
MinCostIGNode = IGNode;
}
}
}
assert (MinCostIGNode && "No IGNode to spill");
return MinCostIGNode;
}
//----------------------------------------------------------------------------
// Color the IGNode using the machine specific code.
//----------------------------------------------------------------------------
void RegClass::colorIGNode(IGNode *const Node) {
if (! Node->hasColor()) { // not colored as an arg etc.
// init all elements of to IsColorUsedAr false;
clearColorsUsed();
// initialize all colors used by neighbors of this node to true
V9LiveRange *LR = Node->getParentLR();
unsigned NumNeighbors = Node->getNumOfNeighbors();
for (unsigned n=0; n < NumNeighbors; n++) {
IGNode *NeighIGNode = Node->getAdjIGNode(n);
V9LiveRange *NeighLR = NeighIGNode->getParentLR();
// Don't use a color if it is in use by the neighbor,
// or is suggested for use by the neighbor,
// markColorsUsed() should be given the color and the reg type for
// LR, not for NeighLR, because it should mark registers used based on
// the type we are looking for, not on the regType for the neighbour.
if (NeighLR->hasColor())
this->markColorsUsed(NeighLR->getColor(),
MRI->getRegTypeForLR(NeighLR),
MRI->getRegTypeForLR(LR)); // use LR, not NeighLR
else if (NeighLR->hasSuggestedColor() &&
NeighLR->isSuggestedColorUsable())
this->markColorsUsed(NeighLR->getSuggestedColor(),
MRI->getRegTypeForLR(NeighLR),
MRI->getRegTypeForLR(LR)); // use LR, not NeighLR
}
// call the target specific code for coloring
//
MRC->colorIGNode(Node, IsColorUsedArr);
} else {
if (DEBUG_RA >= RA_DEBUG_Coloring) {
std::cerr << " Node " << Node->getIndex();
std::cerr << " already colored with color " << Node->getColor() << "\n";
}
}
if (!Node->hasColor() ) {
if (DEBUG_RA >= RA_DEBUG_Coloring) {
std::cerr << " Node " << Node->getIndex();
std::cerr << " - could not find a color (needs spilling)\n";
}
}
}
void RegClass::printIGNodeList() const {
std::cerr << "IG Nodes for Register Class " << RegClassID << ":" << "\n";
IG.printIGNodeList();
}
void RegClass::printIG() {
std::cerr << "IG for Register Class " << RegClassID << ":" << "\n";
IG.printIG();
}
} // End llvm namespace

View File

@ -1,147 +0,0 @@
//===-- RegClass.h - Machine Independent register coloring ------*- 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.
//
//===----------------------------------------------------------------------===//
/* Title: RegClass.h -*- C++ -*-
Author: Ruchira Sasanka
Date: Aug 20, 01
Purpose: Contains machine independent methods for register coloring.
*/
#ifndef REGCLASS_H
#define REGCLASS_H
#include "../SparcV9RegInfo.h"
#include "InterferenceGraph.h"
#include <stack>
namespace llvm {
class TargetRegClassInfo;
//-----------------------------------------------------------------------------
// Class RegClass
//
// Implements a machine independent register class.
//
// This is the class that contains all data structures and common algos
// for coloring a particular register class (e.g., int class, fp class).
// This class is hardware independent. This class accepts a hardware
// dependent description of machine registers (TargetRegInfo class) to
// get hardware specific info and to color an individual IG node.
//
// This class contains the InterferenceGraph (IG).
// Also it contains an IGNode stack that can be used for coloring.
// The class provides some easy access methods to the IG methods, since these
// methods are called thru a register class.
//
//-----------------------------------------------------------------------------
class RegClass {
const Function *const Meth; // Function we are working on
const SparcV9RegInfo *MRI; // Machine register information
const TargetRegClassInfo *const MRC; // Machine reg. class for this RegClass
const unsigned RegClassID; // my int ID
InterferenceGraph IG; // Interference graph - constructed by
// buildInterferenceGraph
std::stack<IGNode *> IGNodeStack; // the stack used for coloring
// IsColorUsedArr - An array used for coloring each node. This array must be
// of size MRC->getNumOfAllRegs(). Allocated once in the constructor for
// efficiency.
//
std::vector<bool> IsColorUsedArr;
//--------------------------- private methods ------------------------------
void pushAllIGNodes();
bool pushUnconstrainedIGNodes();
IGNode * getIGNodeWithMinSpillCost();
void colorIGNode(IGNode *const Node);
// This directly marks the colors used by a particular register number
// within the register class. External users should use the public
// versions of this function below.
inline void markColorUsed(unsigned classRegNum) {
assert(classRegNum < IsColorUsedArr.size() && "Invalid register used?");
IsColorUsedArr[classRegNum] = true;
}
inline bool isColorUsed(unsigned regNum) const {
assert(regNum < IsColorUsedArr.size() && "Invalid register used?");
return IsColorUsedArr[regNum];
}
public:
RegClass(const Function *M,
const SparcV9RegInfo *_MRI_,
const TargetRegClassInfo *_MRC_);
inline void createInterferenceGraph() { IG.createGraph(); }
inline InterferenceGraph &getIG() { return IG; }
inline const unsigned getID() const { return RegClassID; }
inline const TargetRegClassInfo* getTargetRegClass() const { return MRC; }
// main method called for coloring regs
//
void colorAllRegs();
inline unsigned getNumOfAvailRegs() const
{ return MRC->getNumOfAvailRegs(); }
// --- following methods are provided to access the IG contained within this
// ---- RegClass easilly.
inline void addLRToIG(V9LiveRange *const LR)
{ IG.addLRToIG(LR); }
inline void setInterference(const V9LiveRange *const LR1,
const V9LiveRange *const LR2)
{ IG.setInterference(LR1, LR2); }
inline unsigned getInterference(const V9LiveRange *const LR1,
const V9LiveRange *const LR2) const
{ return IG.getInterference(LR1, LR2); }
inline void mergeIGNodesOfLRs(const V9LiveRange *const LR1,
V9LiveRange *const LR2)
{ IG.mergeIGNodesOfLRs(LR1, LR2); }
inline void clearColorsUsed() {
IsColorUsedArr.clear();
IsColorUsedArr.resize(MRC->getNumOfAllRegs());
}
inline void markColorsUsed(unsigned ClassRegNum,
int UserRegType,
int RegTypeWanted) {
MRC->markColorsUsed(ClassRegNum, UserRegType, RegTypeWanted,IsColorUsedArr);
}
inline int getUnusedColor(int machineRegType) const {
return MRC->findUnusedColor(machineRegType, IsColorUsedArr);
}
void printIGNodeList() const;
void printIG();
};
} // End llvm namespace
#endif

View File

@ -1,349 +0,0 @@
%{ // -*- 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.
//
//===----------------------------------------------------------------------===*/
Xinclude <cstdio>
Xinclude "SparcV9InstrForest.h"
typedef llvm::InstrTreeNode* NODEPTR_TYPE;
Xdefine OP_LABEL(p) ((p)->opLabel)
Xdefine LEFT_CHILD(p) ((p)->LeftChild)
Xdefine RIGHT_CHILD(p) ((p)->RightChild)
Xdefine STATE_LABEL(p) ((p)->state)
Xdefine PANIC printf
// Get definitions for various instruction values that we will need...
#define HANDLE_TERM_INST(N, OPC, CLASS) Ydefine OPC##OPCODE N
#define HANDLE_UNARY_INST(N, OPC, CLASS) Ydefine OPC##OPCODE N
#define HANDLE_BINARY_INST(N, OPC, CLASS) Ydefine OPC##OPCODE N
#define HANDLE_MEMORY_INST(N, OPC, CLASS) Ydefine OPC##OPCODE N
#define HANDLE_OTHER_INST(N, OPC, CLASS) Ydefine OPC##OPCODE N
#include "llvm/Instruction.def"
%}
%start stmt
%term Ret=RetOPCODE /* return void from a function */
%term RetValue=101 /* return a value from a function */
%term BrUncond=BrOPCODE
%term BrCond=102
%term Switch=SwitchOPCODE
/* 4 is unused */
%term Add=AddOPCODE
%term Sub=SubOPCODE
%term Mul=MulOPCODE
%term Div=DivOPCODE
%term Rem=RemOPCODE
%term And=AndOPCODE
%term Or=OrOPCODE
%term Xor=XorOPCODE
/* Use the next 4 to distinguish bitwise operators from
* logical operators. This is no longer used for SparcV9,
* but may be useful for other target machines.
* The last one is the bitwise Not(val) == XOR val, 11..1.
* Note that it is also a binary operator, not unary.
*/
%term BAnd=112
%term BOr=113
%term BXor=114
%term BNot=214
/* The next one is the boolean Not(val) == bool XOR val, true
* Note that it is also a binary operator, not unary.
*/
%term Not=314
%term SetCC=115 /* use this to match all SetCC instructions */
/* %term SetEQ=13 */
/* %term SetNE=14 */
/* %term SetLE=15 */
/* %term SetGE=16 */
/* %term SetLT=17 */
/* %term SetGT=18 */
%term Malloc=MallocOPCODE
%term Free=FreeOPCODE
%term Alloca=AllocaOPCODE
%term AllocaN=123 /* alloca with arg N */
%term Load=LoadOPCODE
%term Store=StoreOPCODE
%term GetElemPtr=GetElementPtrOPCODE
%term GetElemPtrIdx=126 /* getElemPtr with index vector */
%term Phi=PHIOPCODE
%term Cast=CastOPCODE /* cast that will be ignored. others are made explicit */
%term ToBoolTy=128
%term ToUByteTy=129
%term ToSByteTy=130
%term ToUShortTy=131
%term ToShortTy=132
%term ToUIntTy=133
%term ToIntTy=134
%term ToULongTy=135
%term ToLongTy=136
%term ToFloatTy=137
%term ToDoubleTy=138
%term ToArrayTy=139
%term ToPointerTy=140
%term Call=CallOPCODE
%term Shl=ShlOPCODE
%term Shr=ShrOPCODE
%term VAArg=VAArgOPCODE
/* 33...46 are unused */
/*
* The foll. values should match the constants in InstrForest.h
*/
%term VRegList=97
%term VReg=98
%term Constant=99
%term Label=100
/* 50+i is a variant of i, as defined above */
%%
/*-----------------------------------------------------------------------*
* The productions of the grammar.
* Note that all chain rules are numbered 101 and above.
* Also, a special case of production X is numbered 100+X, 200+X, etc.
* The cost of a 1-cycle operation is represented as 10, to allow
* finer comparisons of costs (effectively, fractions of 1/10).
*-----------------------------------------------------------------------*/
/*
* The top-level statements
*/
stmt: Ret = 1 (30);
stmt: RetValue(reg) = 2 (30);
stmt: Store(reg,reg) = 3 (10);
stmt: Store(reg,ptrreg) = 4 (10);
stmt: BrUncond = 5 (20);
stmt: BrCond(setCC) = 6 (20); /* branch on cond. code */
stmt: BrCond(setCCconst) = 206 (10); /* may save one instruction */
stmt: BrCond(reg) = 8 (20); /* may avoid an extra instr */
stmt: BrCond(Constant) = 208 (20); /* may avoid an extra instr */
stmt: Switch(reg) = 9 (30); /* cost = load + branch */
stmt: reg = 111 (0);
/*
* List node used for nodes with more than 2 children
*/
reg: VRegList(reg,reg) = 10 (0);
/*
* Special case non-terminals to help combine unary instructions.
* Eg1: zdouble <- todouble(xfloat) * todouble(yfloat)
* Eg2: c <- a AND (NOT b).
* Note that the costs are counted for the special non-terminals here,
* and should not be counted again for the reg productions later.
*/
not: Not(reg,reg) = 21 (10);
tobool: ToBoolTy(reg) = 22 (10);
not: Not(tobool, reg) = 322 (10); // fold cast-to-bool into not
toubyte: ToUByteTy(reg) = 23 (10);
tosbyte: ToSByteTy(reg) = 24 (10);
toushort: ToUShortTy(reg) = 25 (10);
toshort: ToShortTy(reg) = 26 (10);
touint: ToUIntTy(reg) = 27 (10);
toint: ToIntTy(reg) = 28 (10);
toulong: ToULongTy(reg) = 29 (10);
tolong: ToLongTy(reg) = 30 (10);
tofloat: ToFloatTy(reg) = 31 (10);
todouble: ToDoubleTy(reg) = 32 (10);
todoubleConst: ToDoubleTy(Constant) = 232 (10);
/*
* All the ways to produce a boolean value (Not and ToBoolTy are above):
* -- boolean operators: Not, And, Or, ..., ToBoolTy, SetCC
* -- an existing boolean register not in the same tree
* -- a boolean constant
*
* For And, Or, Xor, we add special cases for when:
* (a) one operand is a constant.
* (b) one operand is a NOT, to use the ANDN, ORN, and XORN instrns.
* We do not need the cases when both operands are constant
* because constant folding should take care of that beforehand.
*/
reg: And(reg,reg) = 38 (10);
reg: And(reg,not) = 138 (0); /* cost is counted for not */
reg: And(reg,Constant) = 238 (10);
reg: Or (reg,reg) = 39 (10);
reg: Or (reg,not) = 139 (0); /* cost is counted for not */
reg: Or (reg,Constant) = 239 (10);
reg: Xor(reg,reg) = 40 (10);
reg: Xor(reg,not) = 140 (0); /* cost is counted for not */
reg: Xor(reg,Constant) = 240 (10);
/* Special case non-terms for BrCond(setCC) and BrCond(setCCconst) */
setCCconst: SetCC(reg,Constant) = 41 (5);
setCC: SetCC(reg,reg) = 42 (10);
reg: not = 221 (0);
reg: tobool = 222 (0);
reg: setCCconst = 241 (0);
reg: setCC = 242 (0);
/*
* Special case non-terminals for the unary cast operators.
* Some of these can be folded into other operations (e.g., todouble).
* The rest are just for uniformity.
*/
reg: toubyte = 123 (0);
reg: tosbyte = 124 (0);
reg: toushort = 125 (0);
reg: toshort = 126 (0);
reg: touint = 127 (0);
reg: toint = 128 (0);
reg: toulong = 129 (0);
reg: tolong = 130 (0);
reg: tofloat = 131 (0);
reg: todouble = 132 (0);
reg: todoubleConst = 133 (0);
reg: ToArrayTy(reg) = 19 (10);
reg: ToPointerTy(reg) = 20 (10);
/*
* The binary arithmetic operators.
*/
reg: Add(reg,reg) = 33 (10);
reg: Sub(reg,reg) = 34 (10);
reg: Mul(reg,reg) = 35 (30);
reg: Mul(todouble,todouble) = 135 (20); /* avoids 1-2 type converts */
reg: Div(reg,reg) = 36 (60);
reg: Rem(reg,reg) = 37 (60);
/*
* The binary bitwise logical operators.
*/
reg: BAnd(reg,reg) = 338 (10);
reg: BAnd(reg,bnot) = 438 ( 0); /* cost is counted for not */
reg: BOr( reg,reg) = 339 (10);
reg: BOr( reg,bnot) = 439 ( 0); /* cost is counted for not */
reg: BXor(reg,reg) = 340 (10);
reg: BXor(reg,bnot) = 440 ( 0); /* cost is counted for not */
reg: bnot = 321 ( 0);
bnot: BNot(reg,reg) = 421 (10);
/*
* Special cases for the binary operators with one constant argument.
* Not and BNot are effectively just one argument, so not needed here.
*/
reg: Add(reg,Constant) = 233 (10);
reg: Sub(reg,Constant) = 234 (10);
reg: Mul(reg,Constant) = 235 (30);
reg: Mul(todouble,todoubleConst) = 335 (20); /* avoids 1-2 type converts */
reg: Div(reg,Constant) = 236 (60);
reg: Rem(reg,Constant) = 237 (60);
reg: BAnd(reg,Constant) = 538 (0);
reg: BOr( reg,Constant) = 539 (0);
reg: BXor(reg,Constant) = 540 (0);
/*
* Memory access instructions
*/
reg: Load(reg) = 51 (30);
reg: Load(ptrreg) = 52 (20); /* 1 counted for ptrreg */
reg: ptrreg = 155 (0);
ptrreg: GetElemPtr(reg) = 55 (10);
ptrreg: GetElemPtrIdx(reg,reg) = 56 (10);
reg: Alloca = 57 (10);
reg: AllocaN(reg) = 58 (10);
/*
* Other operators producing register values
*/
reg: Call = 61 (20); /* just ignore the operands! */
reg: Shl(reg,reg) = 62 (20); /* 1 for issue restrictions */
reg: Shr(reg,reg) = 63 (20); /* 1 for issue restrictions */
reg: Phi(reg,reg) = 64 (0);
reg: VAArg(reg) = 66 (40); /* get a vararg */
/*
* Finally, leaf nodes of expression trees.
*/
reg: VReg = 71 (0);
reg: Constant = 72 (3); /* prefer direct use */
%%
/*-----------------------------------------------------------------------*
* The rest of this file provides code to print the cover produced
* by BURG and information about computed tree cost and matches.
* This code was taken from sample.gr provided with BURG.
*-----------------------------------------------------------------------*/
void printcover(NODEPTR_TYPE p, int goalnt, int indent) {
int eruleno = burm_rule(STATE_LABEL(p), goalnt);
short *nts = burm_nts[eruleno];
NODEPTR_TYPE kids[10];
int i;
if (eruleno == 0) {
printf("no cover\n");
return;
}
for (i = 0; i < indent; i++)
printf(".");
printf("%s\n", burm_string[eruleno]);
burm_kids(p, eruleno, kids);
for (i = 0; nts[i]; i++)
printcover(kids[i], nts[i], indent+1);
}
void printtree(NODEPTR_TYPE p) {
int op = burm_op_label(p);
printf("%s", burm_opname[op]);
switch (burm_arity[op]) {
case 0:
break;
case 1:
printf("(");
printtree(burm_child(p, 0));
printf(")");
break;
case 2:
printf("(");
printtree(burm_child(p, 0));
printf(", ");
printtree(burm_child(p, 1));
printf(")");
break;
}
}
int treecost(NODEPTR_TYPE p, int goalnt, int costindex) {
int eruleno = burm_rule(STATE_LABEL(p), goalnt);
int cost = burm_cost[eruleno][costindex], i;
short *nts = burm_nts[eruleno];
NODEPTR_TYPE kids[10];
burm_kids(p, eruleno, kids);
for (i = 0; nts[i]; i++)
cost += treecost(kids[i], nts[i], costindex);
return cost;
}
void printMatches(NODEPTR_TYPE p) {
int nt;
int eruleno;
printf("Node 0x%lx= ", (unsigned long)p);
printtree(p);
printf(" matched rules:\n");
for (nt = 1; burm_ntname[nt] != (char*)NULL; nt++)
if ((eruleno = burm_rule(STATE_LABEL(p), nt)) != 0)
printf("\t%s\n", burm_string[eruleno]);
}

View File

@ -1,52 +0,0 @@
//===- SparcV9.td - Target Description for SparcV9 Target --*- tablegen -*-===//
//
// 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.
//
//===----------------------------------------------------------------------===//
//
// TableGen target description file for the SparcV9. This is currently used
// primarily to generate part of the SparcV9CodeEmitter automatically.
//
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
// Target-independent interfaces which we are implementing
//===----------------------------------------------------------------------===//
include "../Target.td"
//===----------------------------------------------------------------------===//
// Register File Description
//===----------------------------------------------------------------------===//
include "SparcV9RegisterInfo.td"
//===----------------------------------------------------------------------===//
// Instruction Descriptions
//===----------------------------------------------------------------------===//
include "SparcV9InstrInfo.td"
def SparcV9InstrInfo : InstrInfo {
// Define how we want to layout our TargetSpecific information field.
let TSFlagsFields = [];
let TSFlagsShifts = [];
}
//===----------------------------------------------------------------------===//
// Declare the target which we are implementing
//===----------------------------------------------------------------------===//
def SparcV9 : Target {
// FIXME: Specify the callee saved registers.
let CalleeSavedRegisters = [];
// Pointers are 64-bits in size.
let PointerType = i64;
// Information about the instructions...
let InstructionSet = SparcV9InstrInfo;
}

View File

@ -1,803 +0,0 @@
//===-- SparcV9AsmPrinter.cpp - Emit SparcV9 Specific .s File --------------==//
//
// 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 all of the stuff necessary to output a .s file from
// LLVM. The code in this file assumes that the specified module has already
// been compiled into the internal data structures of the Module.
//
// This code largely consists of two LLVM Pass's: a FunctionPass and a Pass.
// The FunctionPass is pipelined together with all of the rest of the code
// generation stages, and the Pass runs at the end to emit code for global
// variables and such.
//
//===----------------------------------------------------------------------===//
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Module.h"
#include "llvm/Pass.h"
#include "llvm/Assembly/Writer.h"
#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/Support/Mangler.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/Statistic.h"
#include "SparcV9Internals.h"
#include "MachineFunctionInfo.h"
#include <string>
using namespace llvm;
namespace {
Statistic<> EmittedInsts("asm-printer", "Number of machine instrs printed");
//===--------------------------------------------------------------------===//
// Utility functions
/// getAsCString - Return the specified array as a C compatible string, only
/// if the predicate isString() is true.
///
std::string getAsCString(const ConstantArray *CVA) {
assert(CVA->isString() && "Array is not string compatible!");
std::string Result = "\"";
for (unsigned i = 0; i != CVA->getNumOperands(); ++i) {
unsigned char C = cast<ConstantInt>(CVA->getOperand(i))->getRawValue();
if (C == '"') {
Result += "\\\"";
} else if (C == '\\') {
Result += "\\\\";
} else if (isprint(C)) {
Result += C;
} else {
Result += '\\'; // print all other chars as octal value
// Convert C to octal representation
Result += ((C >> 6) & 7) + '0';
Result += ((C >> 3) & 7) + '0';
Result += ((C >> 0) & 7) + '0';
}
}
Result += "\"";
return Result;
}
inline bool ArrayTypeIsString(const ArrayType* arrayType) {
return (arrayType->getElementType() == Type::UByteTy ||
arrayType->getElementType() == Type::SByteTy);
}
unsigned findOptimalStorageSize(const TargetMachine &TM, const Type *Ty) {
// All integer types smaller than ints promote to 4 byte integers.
if (Ty->isIntegral() && Ty->getPrimitiveSize() < 4)
return 4;
return TM.getTargetData().getTypeSize(Ty);
}
inline const std::string
TypeToDataDirective(const Type* type) {
switch(type->getTypeID()) {
case Type::BoolTyID: case Type::UByteTyID: case Type::SByteTyID:
return ".byte";
case Type::UShortTyID: case Type::ShortTyID:
return ".half";
case Type::UIntTyID: case Type::IntTyID:
return ".word";
case Type::ULongTyID: case Type::LongTyID: case Type::PointerTyID:
return ".xword";
case Type::FloatTyID:
return ".word";
case Type::DoubleTyID:
return ".xword";
case Type::ArrayTyID:
if (ArrayTypeIsString((ArrayType*) type))
return ".ascii";
else
return "<InvaliDataTypeForPrinting>";
default:
return "<InvaliDataTypeForPrinting>";
}
}
/// Get the size of the constant for the given target.
/// If this is an unsized array, return 0.
///
inline unsigned int
ConstantToSize(const Constant* CV, const TargetMachine& target) {
if (const ConstantArray* CVA = dyn_cast<ConstantArray>(CV)) {
const ArrayType *aty = cast<ArrayType>(CVA->getType());
if (ArrayTypeIsString(aty))
return 1 + CVA->getNumOperands();
}
return findOptimalStorageSize(target, CV->getType());
}
/// Align data larger than one L1 cache line on L1 cache line boundaries.
/// Align all smaller data on the next higher 2^x boundary (4, 8, ...).
///
inline unsigned int
SizeToAlignment(unsigned int size, const TargetMachine& target) {
const unsigned short cacheLineSize = 16;
if (size > (unsigned) cacheLineSize / 2)
return cacheLineSize;
else
for (unsigned sz=1; /*no condition*/; sz *= 2)
if (sz >= size)
return sz;
}
/// Get the size of the type and then use SizeToAlignment.
///
inline unsigned int
TypeToAlignment(const Type* type, const TargetMachine& target) {
return SizeToAlignment(findOptimalStorageSize(target, type), target);
}
/// Get the size of the constant and then use SizeToAlignment.
/// Handles strings as a special case;
inline unsigned int
ConstantToAlignment(const Constant* CV, const TargetMachine& target) {
if (const ConstantArray* CVA = dyn_cast<ConstantArray>(CV))
if (ArrayTypeIsString(cast<ArrayType>(CVA->getType())))
return SizeToAlignment(1 + CVA->getNumOperands(), target);
return TypeToAlignment(CV->getType(), target);
}
} // End anonymous namespace
namespace {
enum Sections {
Unknown,
Text,
ReadOnlyData,
InitRWData,
ZeroInitRWData,
};
class AsmPrinter {
// Mangle symbol names appropriately
Mangler *Mang;
public:
std::ostream &O;
const TargetMachine &TM;
enum Sections CurSection;
AsmPrinter(std::ostream &os, const TargetMachine &T)
: /* idTable(0), */ O(os), TM(T), CurSection(Unknown) {}
~AsmPrinter() {
delete Mang;
}
// (start|end)(Module|Function) - Callback methods invoked by subclasses
void startModule(Module &M) {
Mang = new Mangler(M);
}
void PrintZeroBytesToPad(int numBytes) {
//
// Always use single unsigned bytes for padding. We don't know upon
// what data size the beginning address is aligned, so using anything
// other than a byte may cause alignment errors in the assembler.
//
while (numBytes--)
printSingleConstantValue(Constant::getNullValue(Type::UByteTy));
}
/// Print a single constant value.
///
void printSingleConstantValue(const Constant* CV);
/// Print a constant value or values (it may be an aggregate).
/// Uses printSingleConstantValue() to print each individual value.
///
void printConstantValueOnly(const Constant* CV, int numPadBytesAfter = 0);
// Print a constant (which may be an aggregate) prefixed by all the
// appropriate directives. Uses printConstantValueOnly() to print the
// value or values.
void printConstant(const Constant* CV, unsigned Alignment,
std::string valID = "") {
if (valID.length() == 0)
valID = getID(CV);
if (Alignment == 0)
Alignment = ConstantToAlignment(CV, TM);
if (Alignment != 1)
O << "\t.align\t" << Alignment << "\n";
// Print .size and .type only if it is not a string.
if (const ConstantArray *CVA = dyn_cast<ConstantArray>(CV))
if (CVA->isString()) {
// print it as a string and return
O << valID << ":\n";
O << "\t" << ".ascii" << "\t" << getAsCString(CVA) << "\n";
return;
}
O << "\t.type" << "\t" << valID << ",#object\n";
unsigned int constSize = ConstantToSize(CV, TM);
if (constSize)
O << "\t.size" << "\t" << valID << "," << constSize << "\n";
O << valID << ":\n";
printConstantValueOnly(CV);
}
// enterSection - Use this method to enter a different section of the output
// executable. This is used to only output necessary section transitions.
//
void enterSection(enum Sections S) {
if (S == CurSection) return; // Only switch section if necessary
CurSection = S;
O << "\n\t.section ";
switch (S)
{
default: assert(0 && "Bad section name!");
case Text: O << "\".text\""; break;
case ReadOnlyData: O << "\".rodata\",#alloc"; break;
case InitRWData: O << "\".data\",#alloc,#write"; break;
case ZeroInitRWData: O << "\".bss\",#alloc,#write"; break;
}
O << "\n";
}
// getID Wrappers - Ensure consistent usage
// Symbol names in SparcV9 assembly language have these rules:
// (a) Must match { letter | _ | . | $ } { letter | _ | . | $ | digit }*
// (b) A name beginning in "." is treated as a local name.
std::string getID(const Function *F) {
return Mang->getValueName(F);
}
std::string getID(const BasicBlock *BB) {
return ".L_" + getID(BB->getParent()) + "_" + Mang->getValueName(BB);
}
std::string getID(const GlobalVariable *GV) {
return Mang->getValueName(GV);
}
std::string getID(const Constant *CV) {
return ".C_" + Mang->getValueName(CV);
}
std::string getID(const GlobalValue *GV) {
if (const GlobalVariable *V = dyn_cast<GlobalVariable>(GV))
return getID(V);
else if (const Function *F = dyn_cast<Function>(GV))
return getID(F);
assert(0 && "Unexpected type of GlobalValue!");
return "";
}
// Combines expressions
inline std::string ConstantArithExprToString(const ConstantExpr* CE,
const TargetMachine &TM,
const std::string &op) {
return "(" + valToExprString(CE->getOperand(0), TM) + op
+ valToExprString(CE->getOperand(1), TM) + ")";
}
/// ConstantExprToString() - Convert a ConstantExpr to an asm expression
/// and return this as a string.
///
std::string ConstantExprToString(const ConstantExpr* CE,
const TargetMachine& target);
/// valToExprString - Helper function for ConstantExprToString().
/// Appends result to argument string S.
///
std::string valToExprString(const Value* V, const TargetMachine& target);
};
} // End anonymous namespace
/// Print a single constant value.
///
void AsmPrinter::printSingleConstantValue(const Constant* CV) {
assert(CV->getType() != Type::VoidTy &&
CV->getType() != Type::LabelTy &&
"Unexpected type for Constant");
assert((!isa<ConstantArray>(CV) && ! isa<ConstantStruct>(CV))
&& "Aggregate types should be handled outside this function");
O << "\t" << TypeToDataDirective(CV->getType()) << "\t";
if (const GlobalValue* GV = dyn_cast<GlobalValue>(CV)) {
O << getID(GV) << "\n";
} else if (isa<ConstantPointerNull>(CV) || isa<UndefValue>(CV)) {
// Null pointer value
O << "0\n";
} else if (const ConstantExpr* CE = dyn_cast<ConstantExpr>(CV)) {
// Constant expression built from operators, constants, and symbolic addrs
O << ConstantExprToString(CE, TM) << "\n";
} else if (CV->getType()->isPrimitiveType()) {
// Check primitive types last
if (isa<UndefValue>(CV)) {
O << "0\n";
} else if (CV->getType()->isFloatingPoint()) {
// FP Constants are printed as integer constants to avoid losing
// precision...
double Val = cast<ConstantFP>(CV)->getValue();
if (CV->getType() == Type::FloatTy) {
float FVal = (float)Val;
char *ProxyPtr = (char*)&FVal; // Abide by C TBAA rules
O << *(unsigned int*)ProxyPtr;
} else if (CV->getType() == Type::DoubleTy) {
char *ProxyPtr = (char*)&Val; // Abide by C TBAA rules
O << *(uint64_t*)ProxyPtr;
} else {
assert(0 && "Unknown floating point type!");
}
O << "\t! " << CV->getType()->getDescription()
<< " value: " << Val << "\n";
} else if (const ConstantBool *CB = dyn_cast<ConstantBool>(CV)) {
O << (int)CB->getValue() << "\n";
} else {
WriteAsOperand(O, CV, false, false) << "\n";
}
} else {
assert(0 && "Unknown elementary type for constant");
}
}
/// Print a constant value or values (it may be an aggregate).
/// Uses printSingleConstantValue() to print each individual value.
///
void AsmPrinter::printConstantValueOnly(const Constant* CV,
int numPadBytesAfter) {
if (const ConstantArray *CVA = dyn_cast<ConstantArray>(CV)) {
if (CVA->isString()) {
// print the string alone and return
O << "\t" << ".ascii" << "\t" << getAsCString(CVA) << "\n";
} else {
// Not a string. Print the values in successive locations
for (unsigned i = 0, e = CVA->getNumOperands(); i != e; ++i)
printConstantValueOnly(CVA->getOperand(i));
}
} else if (const ConstantStruct *CVS = dyn_cast<ConstantStruct>(CV)) {
// Print the fields in successive locations. Pad to align if needed!
const StructLayout *cvsLayout =
TM.getTargetData().getStructLayout(CVS->getType());
unsigned sizeSoFar = 0;
for (unsigned i = 0, e = CVS->getNumOperands(); i != e; ++i) {
const Constant* field = CVS->getOperand(i);
// Check if padding is needed and insert one or more 0s.
unsigned fieldSize =
TM.getTargetData().getTypeSize(field->getType());
int padSize = ((i == e-1? cvsLayout->StructSize
: cvsLayout->MemberOffsets[i+1])
- cvsLayout->MemberOffsets[i]) - fieldSize;
sizeSoFar += (fieldSize + padSize);
// Now print the actual field value
printConstantValueOnly(field, padSize);
}
assert(sizeSoFar == cvsLayout->StructSize &&
"Layout of constant struct may be incorrect!");
} else if (isa<ConstantAggregateZero>(CV) || isa<UndefValue>(CV)) {
PrintZeroBytesToPad(TM.getTargetData().getTypeSize(CV->getType()));
} else
printSingleConstantValue(CV);
if (numPadBytesAfter)
PrintZeroBytesToPad(numPadBytesAfter);
}
/// ConstantExprToString() - Convert a ConstantExpr to an asm expression
/// and return this as a string.
///
std::string AsmPrinter::ConstantExprToString(const ConstantExpr* CE,
const TargetMachine& target) {
std::string S;
switch(CE->getOpcode()) {
case Instruction::GetElementPtr:
{ // generate a symbolic expression for the byte address
const Value* ptrVal = CE->getOperand(0);
std::vector<Value*> idxVec(CE->op_begin()+1, CE->op_end());
const TargetData &TD = target.getTargetData();
S += "(" + valToExprString(ptrVal, target) + ") + ("
+ utostr(TD.getIndexedOffset(ptrVal->getType(),idxVec)) + ")";
break;
}
case Instruction::Cast:
// Support only non-converting casts for now, i.e., a no-op.
// This assertion is not a complete check.
assert(target.getTargetData().getTypeSize(CE->getType()) ==
target.getTargetData().getTypeSize(CE->getOperand(0)->getType()));
S += "(" + valToExprString(CE->getOperand(0), target) + ")";
break;
case Instruction::Add:
S += ConstantArithExprToString(CE, target, ") + (");
break;
case Instruction::Sub:
S += ConstantArithExprToString(CE, target, ") - (");
break;
case Instruction::Mul:
S += ConstantArithExprToString(CE, target, ") * (");
break;
case Instruction::Div:
S += ConstantArithExprToString(CE, target, ") / (");
break;
case Instruction::Rem:
S += ConstantArithExprToString(CE, target, ") % (");
break;
case Instruction::And:
// Logical && for booleans; bitwise & otherwise
S += ConstantArithExprToString(CE, target,
((CE->getType() == Type::BoolTy)? ") && (" : ") & ("));
break;
case Instruction::Or:
// Logical || for booleans; bitwise | otherwise
S += ConstantArithExprToString(CE, target,
((CE->getType() == Type::BoolTy)? ") || (" : ") | ("));
break;
case Instruction::Xor:
// Bitwise ^ for all types
S += ConstantArithExprToString(CE, target, ") ^ (");
break;
default:
assert(0 && "Unsupported operator in ConstantExprToString()");
break;
}
return S;
}
/// valToExprString - Helper function for ConstantExprToString().
/// Appends result to argument string S.
///
std::string AsmPrinter::valToExprString(const Value* V,
const TargetMachine& target) {
std::string S;
bool failed = false;
if (const GlobalValue* GV = dyn_cast<GlobalValue>(V)) {
S += getID(GV);
} else if (const Constant* CV = dyn_cast<Constant>(V)) { // symbolic or known
if (const ConstantBool *CB = dyn_cast<ConstantBool>(CV))
S += std::string(CB == ConstantBool::True ? "1" : "0");
else if (const ConstantSInt *CI = dyn_cast<ConstantSInt>(CV))
S += itostr(CI->getValue());
else if (const ConstantUInt *CI = dyn_cast<ConstantUInt>(CV))
S += utostr(CI->getValue());
else if (const ConstantFP *CFP = dyn_cast<ConstantFP>(CV))
S += ftostr(CFP->getValue());
else if (isa<ConstantPointerNull>(CV) || isa<UndefValue>(CV))
S += "0";
else if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(CV))
S += ConstantExprToString(CE, target);
else
failed = true;
} else
failed = true;
if (failed) {
assert(0 && "Cannot convert value to string");
S += "<illegal-value>";
}
return S;
}
namespace {
struct SparcV9AsmPrinter : public FunctionPass, public AsmPrinter {
inline SparcV9AsmPrinter(std::ostream &os, const TargetMachine &t)
: AsmPrinter(os, t) {}
const Function *currFunction;
const char *getPassName() const {
return "Output SparcV9 Assembly for Functions";
}
virtual bool doInitialization(Module &M) {
startModule(M);
return false;
}
virtual bool runOnFunction(Function &F) {
currFunction = &F;
emitFunction(F);
return false;
}
virtual bool doFinalization(Module &M) {
emitGlobals(M);
return false;
}
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
AU.setPreservesAll();
}
void emitFunction(const Function &F);
private :
void emitBasicBlock(const MachineBasicBlock &MBB);
void emitMachineInst(const MachineInstr *MI);
unsigned int printOperands(const MachineInstr *MI, unsigned int opNum);
void printOneOperand(const MachineOperand &Op, MachineOpCode opCode);
bool OpIsBranchTargetLabel(const MachineInstr *MI, unsigned int opNum);
bool OpIsMemoryAddressBase(const MachineInstr *MI, unsigned int opNum);
unsigned getOperandMask(unsigned Opcode) {
switch (Opcode) {
case V9::SUBccr:
case V9::SUBcci: return 1 << 3; // Remove CC argument
default: return 0; // By default, don't hack operands...
}
}
void emitGlobals(const Module &M);
void printGlobalVariable(const GlobalVariable *GV);
};
} // End anonymous namespace
inline bool
SparcV9AsmPrinter::OpIsBranchTargetLabel(const MachineInstr *MI,
unsigned int opNum) {
switch (MI->getOpcode()) {
case V9::JMPLCALLr:
case V9::JMPLCALLi:
case V9::JMPLRETr:
case V9::JMPLRETi:
return (opNum == 0);
default:
return false;
}
}
inline bool
SparcV9AsmPrinter::OpIsMemoryAddressBase(const MachineInstr *MI,
unsigned int opNum) {
if (TM.getInstrInfo()->isLoad(MI->getOpcode()))
return (opNum == 0);
else if (TM.getInstrInfo()->isStore(MI->getOpcode()))
return (opNum == 1);
else
return false;
}
unsigned int
SparcV9AsmPrinter::printOperands(const MachineInstr *MI, unsigned opNum) {
const MachineOperand& mop = MI->getOperand(opNum);
if (OpIsBranchTargetLabel(MI, opNum)) {
printOneOperand(mop, MI->getOpcode());
O << "+";
printOneOperand(MI->getOperand(opNum+1), MI->getOpcode());
return 2;
} else if (OpIsMemoryAddressBase(MI, opNum)) {
O << "[";
printOneOperand(mop, MI->getOpcode());
O << "+";
printOneOperand(MI->getOperand(opNum+1), MI->getOpcode());
O << "]";
return 2;
} else {
printOneOperand(mop, MI->getOpcode());
return 1;
}
}
void
SparcV9AsmPrinter::printOneOperand(const MachineOperand &mop,
MachineOpCode opCode)
{
bool needBitsFlag = true;
if (mop.isHiBits32())
O << "%lm(";
else if (mop.isLoBits32())
O << "%lo(";
else if (mop.isHiBits64())
O << "%hh(";
else if (mop.isLoBits64())
O << "%hm(";
else
needBitsFlag = false;
switch (mop.getType())
{
case MachineOperand::MO_VirtualRegister:
case MachineOperand::MO_CCRegister:
case MachineOperand::MO_MachineRegister:
{
int regNum = (int)mop.getReg();
if (regNum == TM.getRegInfo()->getInvalidRegNum()) {
// better to print code with NULL registers than to die
O << "<NULL VALUE>";
} else {
O << "%" << TM.getRegInfo()->getUnifiedRegName(regNum);
}
break;
}
case MachineOperand::MO_ConstantPoolIndex:
{
O << ".CPI_" << getID(currFunction)
<< "_" << mop.getConstantPoolIndex();
break;
}
case MachineOperand::MO_PCRelativeDisp:
{
const Value *Val = mop.getVRegValue();
assert(Val && "\tNULL Value in SparcV9AsmPrinter");
if (const BasicBlock *BB = dyn_cast<BasicBlock>(Val))
O << getID(BB);
else if (const Function *F = dyn_cast<Function>(Val))
O << getID(F);
else if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(Val))
O << getID(GV);
else if (const Constant *CV = dyn_cast<Constant>(Val))
O << getID(CV);
else
assert(0 && "Unrecognized value in SparcV9AsmPrinter");
break;
}
case MachineOperand::MO_SignExtendedImmed:
O << mop.getImmedValue();
break;
case MachineOperand::MO_UnextendedImmed:
O << (uint64_t) mop.getImmedValue();
break;
default:
O << mop; // use dump field
break;
}
if (needBitsFlag)
O << ")";
}
void SparcV9AsmPrinter::emitMachineInst(const MachineInstr *MI) {
unsigned Opcode = MI->getOpcode();
if (Opcode == V9::PHI)
return; // Ignore Machine-PHI nodes.
O << "\t" << TM.getInstrInfo()->getName(Opcode) << "\t";
unsigned Mask = getOperandMask(Opcode);
bool NeedComma = false;
unsigned N = 1;
for (unsigned OpNum = 0; OpNum < MI->getNumOperands(); OpNum += N)
if (! ((1 << OpNum) & Mask)) { // Ignore this operand?
if (NeedComma) O << ", "; // Handle comma outputting
NeedComma = true;
N = printOperands(MI, OpNum);
} else
N = 1;
O << "\n";
++EmittedInsts;
}
void SparcV9AsmPrinter::emitBasicBlock(const MachineBasicBlock &MBB) {
// Emit a label for the basic block
O << getID(MBB.getBasicBlock()) << ":\n";
// Loop over all of the instructions in the basic block...
for (MachineBasicBlock::const_iterator MII = MBB.begin(), MIE = MBB.end();
MII != MIE; ++MII)
emitMachineInst(MII);
O << "\n"; // Separate BB's with newlines
}
void SparcV9AsmPrinter::emitFunction(const Function &F) {
std::string CurrentFnName = getID(&F);
MachineFunction &MF = MachineFunction::get(&F);
O << "!****** Outputing Function: " << CurrentFnName << " ******\n";
// Emit constant pool for this function
const MachineConstantPool *MCP = MF.getConstantPool();
const std::vector<MachineConstantPoolEntry> &CP = MCP->getConstants();
enterSection(ReadOnlyData);
O << "\t.align\t" << (1 << MCP->getConstantPoolAlignment()) << "\n";
for (unsigned i = 0, e = CP.size(); i != e; ++i) {
std::string cpiName = ".CPI_" + CurrentFnName + "_" + utostr(i);
printConstant(CP[i].Val, 1, cpiName);
if (i != e-1) {
unsigned EntSize = TM.getTargetData().getTypeSize(CP[i].Val->getType());
unsigned ValEnd = CP[i].Offset + EntSize;
// Emit inter-object padding for alignment.
for (unsigned NumZeros = CP[i+1].Offset-ValEnd; NumZeros; --NumZeros)
O << "\t.byte 0\n";
}
}
enterSection(Text);
O << "\t.align\t4\n\t.global\t" << CurrentFnName << "\n";
//O << "\t.type\t" << CurrentFnName << ",#function\n";
O << "\t.type\t" << CurrentFnName << ", 2\n";
O << CurrentFnName << ":\n";
// Output code for all of the basic blocks in the function...
for (MachineFunction::const_iterator I = MF.begin(), E = MF.end(); I != E;++I)
emitBasicBlock(*I);
// Output a .size directive so the debugger knows the extents of the function
O << ".EndOf_" << CurrentFnName << ":\n\t.size "
<< CurrentFnName << ", .EndOf_"
<< CurrentFnName << "-" << CurrentFnName << "\n";
// Put some spaces between the functions
O << "\n\n";
}
void SparcV9AsmPrinter::printGlobalVariable(const GlobalVariable* GV) {
if (GV->hasExternalLinkage())
O << "\t.global\t" << getID(GV) << "\n";
if (GV->hasInitializer() &&
!(GV->getInitializer()->isNullValue() ||
isa<UndefValue>(GV->getInitializer()))) {
printConstant(GV->getInitializer(), 0, getID(GV));
} else {
O << "\t.align\t" << TypeToAlignment(GV->getType()->getElementType(),
TM) << "\n";
O << "\t.type\t" << getID(GV) << ",#object\n";
O << "\t.reserve\t" << getID(GV) << ","
<< findOptimalStorageSize(TM, GV->getType()->getElementType())
<< "\n";
}
}
void SparcV9AsmPrinter::emitGlobals(const Module &M) {
// Output global variables...
for (Module::const_global_iterator GI = M.global_begin(), GE = M.global_end(); GI != GE; ++GI)
if (! GI->isExternal()) {
assert(GI->hasInitializer());
if (GI->isConstant())
enterSection(ReadOnlyData); // read-only, initialized data
else if (GI->getInitializer()->isNullValue() ||
isa<UndefValue>(GI->getInitializer()))
enterSection(ZeroInitRWData); // read-write zero data
else
enterSection(InitRWData); // read-write non-zero data
printGlobalVariable(GI);
}
O << "\n";
}
FunctionPass *llvm::createAsmPrinterPass(std::ostream &Out, TargetMachine &TM) {
return new SparcV9AsmPrinter(Out, TM);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,56 +0,0 @@
//===-- SparcV9BurgISel.h ---------------------------------------*- 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.
//
//===----------------------------------------------------------------------===//
//
// Global functions exposed by the BURG-based instruction selector
// for the SparcV9 target.
//
//===----------------------------------------------------------------------===//
#ifndef SPARCV9BURGISEL_H
#define SPARCV9BURGISEL_H
//#include "llvm/DerivedTypes.h"
//#include "llvm/Instruction.h"
//#include "SparcV9Internals.h"
namespace llvm {
class Constant;
class Instruction;
class TargetMachine;
class Function;
class Value;
class MachineInstr;
class MachineCodeForInstruction;
class FunctionPass;
/// ConstantMayNotFitInImmedField - Test if this constant may not fit in the
/// immediate field of the machine instructions (probably) generated for this
/// instruction.
///
bool ConstantMayNotFitInImmedField (const Constant *CV, const Instruction *I);
/// CreateCodeToLoadConst - Create an instruction sequence to put the
/// constant `val' into the virtual register `dest'. `val' may be a Constant
/// or a GlobalValue, viz., the constant address of a global variable or
/// function. The generated instructions are returned in `mvec'. Any temp.
/// registers (TmpInstruction) created are recorded in mcfi.
///
void CreateCodeToLoadConst (const TargetMachine &target, Function *F,
Value *val, Instruction *dest, std::vector<MachineInstr*> &mvec,
MachineCodeForInstruction &mcfi);
/// createSparcV9BurgInstSelector - Creates and returns a new SparcV9
/// BURG-based instruction selection pass.
///
FunctionPass *createSparcV9BurgInstSelector(TargetMachine &TM);
} // End llvm namespace
#endif

View File

@ -1,304 +0,0 @@
//===-- SparcV9CodeEmitter.cpp --------------------------------------------===//
//
// 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.
//
//===----------------------------------------------------------------------===//
//
// SPARC-specific backend for emitting machine code to memory.
//
// This module also contains the code for lazily resolving the targets of call
// instructions, including the callback used to redirect calls to functions for
// which the code has not yet been generated into the JIT compiler.
//
// This file #includes SparcV9GenCodeEmitter.inc, which contains the code for
// getBinaryCodeForInstr(), a method that converts a MachineInstr into the
// corresponding binary machine code word.
//
//===----------------------------------------------------------------------===//
#include "llvm/Constants.h"
#include "llvm/Function.h"
#include "llvm/GlobalVariable.h"
#include "llvm/PassManager.h"
#include "llvm/CodeGen/MachineCodeEmitter.h"
#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Support/Debug.h"
#include "SparcV9Internals.h"
#include "SparcV9TargetMachine.h"
#include "SparcV9RegInfo.h"
#include "SparcV9CodeEmitter.h"
#include "SparcV9Relocations.h"
#include "MachineFunctionInfo.h"
#include <iostream>
using namespace llvm;
bool SparcV9TargetMachine::addPassesToEmitMachineCode(FunctionPassManager &PM,
MachineCodeEmitter &MCE) {
PM.add(new SparcV9CodeEmitter(*this, MCE));
PM.add(createSparcV9MachineCodeDestructionPass());
return false;
}
SparcV9CodeEmitter::SparcV9CodeEmitter(TargetMachine &tm,
MachineCodeEmitter &M): TM(tm), MCE(M) {}
void SparcV9CodeEmitter::emitWord(unsigned Val) {
MCE.emitWord(Val);
}
unsigned
SparcV9CodeEmitter::getRealRegNum(unsigned fakeReg,
MachineInstr &MI) {
const SparcV9RegInfo &RI = *TM.getRegInfo();
unsigned regClass = 0, regType = RI.getRegType(fakeReg);
// At least map fakeReg into its class
fakeReg = RI.getClassRegNum(fakeReg, regClass);
switch (regClass) {
case SparcV9RegInfo::IntRegClassID: {
// SparcV9 manual, p31
static const unsigned IntRegMap[] = {
// "o0", "o1", "o2", "o3", "o4", "o5", "o7",
8, 9, 10, 11, 12, 13, 15,
// "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
16, 17, 18, 19, 20, 21, 22, 23,
// "i0", "i1", "i2", "i3", "i4", "i5", "i6", "i7",
24, 25, 26, 27, 28, 29, 30, 31,
// "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
0, 1, 2, 3, 4, 5, 6, 7,
// "o6"
14
};
return IntRegMap[fakeReg];
break;
}
case SparcV9RegInfo::FloatRegClassID: {
DEBUG(std::cerr << "FP reg: " << fakeReg << "\n");
if (regType == SparcV9RegInfo::FPSingleRegType) {
// only numbered 0-31, hence can already fit into 5 bits (and 6)
DEBUG(std::cerr << "FP single reg, returning: " << fakeReg << "\n");
} else if (regType == SparcV9RegInfo::FPDoubleRegType) {
// FIXME: This assumes that we only have 5-bit register fields!
// From SparcV9 Manual, page 40.
// The bit layout becomes: b[4], b[3], b[2], b[1], b[5]
fakeReg |= (fakeReg >> 5) & 1;
fakeReg &= 0x1f;
DEBUG(std::cerr << "FP double reg, returning: " << fakeReg << "\n");
}
return fakeReg;
}
case SparcV9RegInfo::IntCCRegClassID: {
/* xcc, icc, ccr */
static const unsigned IntCCReg[] = { 6, 4, 2 };
assert(fakeReg < sizeof(IntCCReg)/sizeof(IntCCReg[0])
&& "CC register out of bounds for IntCCReg map");
DEBUG(std::cerr << "IntCC reg: " << IntCCReg[fakeReg] << "\n");
return IntCCReg[fakeReg];
}
case SparcV9RegInfo::FloatCCRegClassID: {
/* These are laid out %fcc0 - %fcc3 => 0 - 3, so are correct */
DEBUG(std::cerr << "FP CC reg: " << fakeReg << "\n");
return fakeReg;
}
case SparcV9RegInfo::SpecialRegClassID: {
// Currently only "special" reg is %fsr, which is encoded as 1 in
// instructions and 0 in SparcV9SpecialRegClass.
static const unsigned SpecialReg[] = { 1 };
assert(fakeReg < sizeof(SpecialReg)/sizeof(SpecialReg[0])
&& "Special register out of bounds for SpecialReg map");
DEBUG(std::cerr << "Special reg: " << SpecialReg[fakeReg] << "\n");
return SpecialReg[fakeReg];
}
default:
assert(0 && "Invalid unified register number in getRealRegNum");
return fakeReg;
}
}
int64_t SparcV9CodeEmitter::getMachineOpValue(MachineInstr &MI,
MachineOperand &MO) {
int64_t rv = 0; // Return value; defaults to 0 for unhandled cases
// or things that get fixed up later by the JIT.
if (MO.isPCRelativeDisp() || MO.isGlobalAddress()) {
DEBUG(std::cerr << "PCRelativeDisp: ");
Value *V = MO.getVRegValue();
if (BasicBlock *BB = dyn_cast<BasicBlock>(V)) {
DEBUG(std::cerr << "Saving reference to BB (VReg)\n");
unsigned* CurrPC = (unsigned*)(intptr_t)MCE.getCurrentPCValue();
BBRefs.push_back(std::make_pair(BB, std::make_pair(CurrPC, &MI)));
} else if (const ConstantInt *CI = dyn_cast<ConstantInt>(V)) {
// The real target of the branch is CI = PC + (rv * 4)
// So undo that: give the instruction (CI - PC) / 4
rv = (CI->getRawValue() - MCE.getCurrentPCValue()) / 4;
} else if (GlobalValue *GV = dyn_cast<GlobalValue>(V)) {
unsigned Reloc = 0;
if (MI.getOpcode() == V9::CALL) {
Reloc = V9::reloc_pcrel_call;
} else if (MI.getOpcode() == V9::SETHI) {
if (MO.isHiBits64())
Reloc = V9::reloc_sethi_hh;
else if (MO.isHiBits32())
Reloc = V9::reloc_sethi_lm;
else
assert(0 && "Unknown relocation!");
} else if (MI.getOpcode() == V9::ORi) {
if (MO.isLoBits32())
Reloc = V9::reloc_or_lo;
else if (MO.isLoBits64())
Reloc = V9::reloc_or_hm;
else
assert(0 && "Unknown relocation!");
} else {
assert(0 && "Unknown relocation!");
}
MCE.addRelocation(MachineRelocation(MCE.getCurrentPCOffset(), Reloc, GV));
rv = 0;
} else {
std::cerr << "ERROR: PC relative disp unhandled:" << MO << "\n";
abort();
}
} else if (MO.isRegister() || MO.getType() == MachineOperand::MO_CCRegister)
{
// This is necessary because the SparcV9 backend doesn't actually lay out
// registers in the real fashion -- it skips those that it chooses not to
// allocate, i.e. those that are the FP, SP, etc.
unsigned fakeReg = MO.getReg();
unsigned realRegByClass = getRealRegNum(fakeReg, MI);
DEBUG(std::cerr << MO << ": Reg[" << std::dec << fakeReg << "] => "
<< realRegByClass << " (LLC: "
<< TM.getRegInfo()->getUnifiedRegName(fakeReg) << ")\n");
rv = realRegByClass;
} else if (MO.isImmediate()) {
rv = MO.getImmedValue();
DEBUG(std::cerr << "immed: " << rv << "\n");
} else if (MO.isMachineBasicBlock()) {
// Duplicate code of the above case for VirtualRegister, BasicBlock...
// It should really hit this case, but SparcV9 backend uses VRegs instead
DEBUG(std::cerr << "Saving reference to MBB\n");
const BasicBlock *BB = MO.getMachineBasicBlock()->getBasicBlock();
unsigned* CurrPC = (unsigned*)(intptr_t)MCE.getCurrentPCValue();
BBRefs.push_back(std::make_pair(BB, std::make_pair(CurrPC, &MI)));
} else if (MO.isExternalSymbol()) {
// SparcV9 backend doesn't generate this (yet...)
std::cerr << "ERROR: External symbol unhandled: " << MO << "\n";
abort();
} else if (MO.isFrameIndex()) {
// SparcV9 backend doesn't generate this (yet...)
int FrameIndex = MO.getFrameIndex();
std::cerr << "ERROR: Frame index unhandled.\n";
abort();
} else if (MO.isConstantPoolIndex()) {
unsigned Index = MO.getConstantPoolIndex();
rv = MCE.getConstantPoolEntryAddress(Index);
} else {
std::cerr << "ERROR: Unknown type of MachineOperand: " << MO << "\n";
abort();
}
// Finally, deal with the various bitfield-extracting functions that
// are used in SPARC assembly. (Some of these make no sense in combination
// with some of the above; we'll trust that the instruction selector
// will not produce nonsense, and not check for valid combinations here.)
if (MO.isLoBits32()) { // %lo(val) == %lo() in SparcV9 ABI doc
return rv & 0x03ff;
} else if (MO.isHiBits32()) { // %lm(val) == %hi() in SparcV9 ABI doc
return (rv >> 10) & 0x03fffff;
} else if (MO.isLoBits64()) { // %hm(val) == %ulo() in SparcV9 ABI doc
return (rv >> 32) & 0x03ff;
} else if (MO.isHiBits64()) { // %hh(val) == %uhi() in SparcV9 ABI doc
return rv >> 42;
} else { // (unadorned) val
return rv;
}
}
unsigned SparcV9CodeEmitter::getValueBit(int64_t Val, unsigned bit) {
Val >>= bit;
return (Val & 1);
}
bool SparcV9CodeEmitter::runOnMachineFunction(MachineFunction &MF) {
MCE.startFunction(MF);
DEBUG(std::cerr << "Starting function " << MF.getFunction()->getName()
<< ", address: " << "0x" << std::hex
<< (long)MCE.getCurrentPCValue() << "\n");
MCE.emitConstantPool(MF.getConstantPool());
for (MachineFunction::iterator I = MF.begin(), E = MF.end(); I != E; ++I)
emitBasicBlock(*I);
MCE.finishFunction(MF);
DEBUG(std::cerr << "Finishing fn " << MF.getFunction()->getName() << "\n");
// Resolve branches to BasicBlocks for the entire function
for (unsigned i = 0, e = BBRefs.size(); i != e; ++i) {
long Location = BBLocations[BBRefs[i].first];
unsigned *Ref = BBRefs[i].second.first;
MachineInstr *MI = BBRefs[i].second.second;
DEBUG(std::cerr << "Fixup @ " << std::hex << Ref << " to 0x" << Location
<< " in instr: " << std::dec << *MI);
for (unsigned ii = 0, ee = MI->getNumOperands(); ii != ee; ++ii) {
MachineOperand &op = MI->getOperand(ii);
if (op.isPCRelativeDisp()) {
// the instruction's branch target is made such that it branches to
// PC + (branchTarget * 4), so undo that arithmetic here:
// Location is the target of the branch
// Ref is the location of the instruction, and hence the PC
int64_t branchTarget = (Location - (long)Ref) >> 2;
// Save the flags.
bool loBits32=false, hiBits32=false, loBits64=false, hiBits64=false;
if (op.isLoBits32()) { loBits32=true; }
if (op.isHiBits32()) { hiBits32=true; }
if (op.isLoBits64()) { loBits64=true; }
if (op.isHiBits64()) { hiBits64=true; }
MI->SetMachineOperandConst(ii, MachineOperand::MO_SignExtendedImmed,
branchTarget);
if (loBits32) { MI->getOperand(ii).markLo32(); }
else if (hiBits32) { MI->getOperand(ii).markHi32(); }
else if (loBits64) { MI->getOperand(ii).markLo64(); }
else if (hiBits64) { MI->getOperand(ii).markHi64(); }
DEBUG(std::cerr << "Rewrote BB ref: ");
unsigned fixedInstr = SparcV9CodeEmitter::getBinaryCodeForInstr(*MI);
MCE.emitWordAt (fixedInstr, Ref);
break;
}
}
}
BBRefs.clear();
BBLocations.clear();
return false;
}
void SparcV9CodeEmitter::emitBasicBlock(MachineBasicBlock &MBB) {
currBB = MBB.getBasicBlock();
BBLocations[currBB] = MCE.getCurrentPCValue();
for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); I != E; ++I)
if (I->getOpcode() != V9::RDCCR) {
emitWord(getBinaryCodeForInstr(*I));
} else {
// FIXME: The tblgen produced code emitter cannot deal with the fact that
// machine operand #0 of the RDCCR instruction should be ignored. This is
// really a bug in the representation of the RDCCR instruction (which has
// no need to explicitly represent the CCR dest), but we hack around it
// here.
unsigned RegNo = getMachineOpValue(*I, I->getOperand(1));
RegNo &= (1<<5)-1;
emitWord((RegNo << 25) | 2168487936U);
}
}
#include "SparcV9GenCodeEmitter.inc"

View File

@ -1,87 +0,0 @@
//===-- SparcV9CodeEmitter.h ------------------------------------*- 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.
//
//===----------------------------------------------------------------------===//
//
// Target-specific portions of the machine code emitter for the SparcV9.
// This class interfaces with the JIT's Emitter in order to turn MachineInstrs
// into words of binary machine code. Its code is partially generated by
// TableGen's CodeEmitterGenerator.
//
//===----------------------------------------------------------------------===//
#ifndef SPARCV9CODEEMITTER_H
#define SPARCV9CODEEMITTER_H
#include "llvm/BasicBlock.h"
#include "llvm/CodeGen/MachineCodeEmitter.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/Target/TargetMachine.h"
namespace llvm {
class GlobalValue;
class MachineInstr;
class MachineOperand;
class SparcV9CodeEmitter : public MachineFunctionPass {
TargetMachine &TM;
MachineCodeEmitter &MCE;
const BasicBlock *currBB;
// Tracks which instruction references which BasicBlock
std::vector<std::pair<const BasicBlock*,
std::pair<unsigned*,MachineInstr*> > > BBRefs;
// Tracks where each BasicBlock starts
std::map<const BasicBlock*, long> BBLocations;
public:
SparcV9CodeEmitter(TargetMachine &T, MachineCodeEmitter &M);
~SparcV9CodeEmitter() {}
const char *getPassName() const { return "SparcV9 Machine Code Emitter"; }
/// runOnMachineFunction - emits the given machine function to memory.
///
bool runOnMachineFunction(MachineFunction &F);
/// emitWord - writes out the given 32-bit value to memory at the current PC.
///
void emitWord(unsigned Val);
/// getBinaryCodeForInstr - This function, generated by the
/// CodeEmitterGenerator using TableGen, produces the binary encoding for
/// machine instructions.
///
unsigned getBinaryCodeForInstr(MachineInstr &MI);
private:
/// getMachineOpValue -
///
int64_t getMachineOpValue(MachineInstr &MI, MachineOperand &MO);
/// emitBasicBlock -
///
void emitBasicBlock(MachineBasicBlock &MBB);
/// getValueBit -
///
unsigned getValueBit(int64_t Val, unsigned bit);
/// getGlobalAddress -
///
void* getGlobalAddress(GlobalValue *V, MachineInstr &MI,
bool isPCRelative);
/// emitFarCall -
///
unsigned getRealRegNum(unsigned fakeReg, MachineInstr &MI);
};
} // End llvm namespace
#endif

View File

@ -1,57 +0,0 @@
//===-- SparcV9FrameInfo.cpp - Stack frame layout info for SparcV9 --------===//
//
// 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.
//
//===----------------------------------------------------------------------===//
//
// Interface to stack frame layout info for the UltraSPARC.
//
//===----------------------------------------------------------------------===//
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/Target/TargetFrameInfo.h"
#include "MachineFunctionInfo.h"
#include "SparcV9FrameInfo.h"
using namespace llvm;
int
SparcV9FrameInfo::getRegSpillAreaOffset(MachineFunction& mcInfo, bool& pos) const
{
// ensure no more auto vars are added
mcInfo.getInfo<SparcV9FunctionInfo>()->freezeAutomaticVarsArea();
pos = false; // static stack area grows downwards
unsigned autoVarsSize = mcInfo.getInfo<SparcV9FunctionInfo>()->getAutomaticVarsSize();
return StaticAreaOffsetFromFP - autoVarsSize;
}
int SparcV9FrameInfo::getTmpAreaOffset(MachineFunction& mcInfo, bool& pos) const {
SparcV9FunctionInfo *MFI = mcInfo.getInfo<SparcV9FunctionInfo>();
MFI->freezeAutomaticVarsArea(); // ensure no more auto vars are added
MFI->freezeSpillsArea(); // ensure no more spill slots are added
pos = false; // static stack area grows downwards
unsigned autoVarsSize = MFI->getAutomaticVarsSize();
unsigned spillAreaSize = MFI->getRegSpillsSize();
int offset = autoVarsSize + spillAreaSize;
return StaticAreaOffsetFromFP - offset;
}
int
SparcV9FrameInfo::getDynamicAreaOffset(MachineFunction& mcInfo, bool& pos) const {
// Dynamic stack area grows downwards starting at top of opt-args area.
// The opt-args, required-args, and register-save areas are empty except
// during calls and traps, so they are shifted downwards on each
// dynamic-size alloca.
pos = false;
unsigned optArgsSize = mcInfo.getInfo<SparcV9FunctionInfo>()->getMaxOptionalArgsSize();
if (int extra = optArgsSize % 16)
optArgsSize += (16 - extra);
int offset = optArgsSize + FirstOptionalOutgoingArgOffsetFromSP;
assert((offset - OFFSET) % 16 == 0);
return offset;
}

View File

@ -1,117 +0,0 @@
//===-- SparcV9FrameInfo.h - Define TargetFrameInfo for SparcV9 -*- 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.
//
//===----------------------------------------------------------------------===//
//
// Interface to stack frame layout info for the UltraSPARC.
//
//----------------------------------------------------------------------------
#ifndef SPARC_FRAMEINFO_H
#define SPARC_FRAMEINFO_H
#include "llvm/Target/TargetFrameInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "SparcV9RegInfo.h"
namespace llvm {
class SparcV9FrameInfo: public TargetFrameInfo {
const TargetMachine &target;
public:
SparcV9FrameInfo(const TargetMachine &TM)
: TargetFrameInfo(StackGrowsDown, StackFrameSizeAlignment, 0), target(TM) {}
// This method adjusts a stack offset to meet alignment rules of target.
// The fixed OFFSET (0x7ff) must be subtracted and the result aligned.
virtual int adjustAlignment(int unalignedOffset, bool growUp,
unsigned int align) const {
return unalignedOffset + (growUp? +1:-1)*((unalignedOffset-OFFSET) % align);
}
// These methods compute offsets using the frame contents for a
// particular function. The frame contents are obtained from the
// MachineCodeInfoForMethod object for the given function.
//
int getFirstAutomaticVarOffset(MachineFunction& mcInfo, bool& growUp) const {
growUp = false;
return StaticAreaOffsetFromFP;
}
int getRegSpillAreaOffset(MachineFunction& mcInfo, bool& growUp) const;
int getTmpAreaOffset(MachineFunction& mcInfo, bool& growUp) const;
int getDynamicAreaOffset(MachineFunction& mcInfo, bool& growUp) const;
virtual int getIncomingArgOffset(MachineFunction& mcInfo,
unsigned argNum) const {
unsigned relativeOffset = argNum * SizeOfEachArgOnStack;
int firstArg = FirstIncomingArgOffsetFromFP;
return firstArg + relativeOffset;
}
virtual int getOutgoingArgOffset(MachineFunction& mcInfo,
unsigned argNum) const {
return FirstOutgoingArgOffsetFromSP + argNum * SizeOfEachArgOnStack;
}
/*----------------------------------------------------------------------
This diagram shows the stack frame layout used by llc on SparcV9 V9.
Note that only the location of automatic variables, spill area,
temporary storage, and dynamically allocated stack area are chosen
by us. The rest conform to the SparcV9 V9 ABI.
All stack addresses are offset by OFFSET = 0x7ff (2047).
Alignment assumptions and other invariants:
(1) %sp+OFFSET and %fp+OFFSET are always aligned on 16-byte boundary
(2) Variables in automatic, spill, temporary, or dynamic regions
are aligned according to their size as in all memory accesses.
(3) Everything below the dynamically allocated stack area is only used
during a call to another function, so it is never needed when
the current function is active. This is why space can be allocated
dynamically by incrementing %sp any time within the function.
STACK FRAME LAYOUT:
...
%fp+OFFSET+176 Optional extra incoming arguments# 1..N
%fp+OFFSET+168 Incoming argument #6
... ...
%fp+OFFSET+128 Incoming argument #1
... ...
---%fp+OFFSET-0--------Bottom of caller's stack frame--------------------
%fp+OFFSET-8 Automatic variables <-- ****TOP OF STACK FRAME****
Spill area
Temporary storage
...
%sp+OFFSET+176+8N Bottom of dynamically allocated stack area
%sp+OFFSET+168+8N Optional extra outgoing argument# N
... ...
%sp+OFFSET+176 Optional extra outgoing argument# 1
%sp+OFFSET+168 Outgoing argument #6
... ...
%sp+OFFSET+128 Outgoing argument #1
%sp+OFFSET+120 Save area for %i7
... ...
%sp+OFFSET+0 Save area for %l0 <-- ****BOTTOM OF STACK FRAME****
*----------------------------------------------------------------------*/
// All stack addresses must be offset by 0x7ff (2047) on SparcV9 V9.
static const int OFFSET = (int) 0x7ff;
static const int StackFrameSizeAlignment = 16;
static const int MinStackFrameSize = 176;
static const int SizeOfEachArgOnStack = 8;
static const int FirstIncomingArgOffsetFromFP = 128 + OFFSET;
static const int FirstOptionalIncomingArgOffsetFromFP = 176 + OFFSET;
static const int StaticAreaOffsetFromFP = 0 + OFFSET;
static const int FirstOutgoingArgOffsetFromSP = 128 + OFFSET;
static const int FirstOptionalOutgoingArgOffsetFromSP = 176 + OFFSET;
};
} // End llvm namespace
#endif

View File

@ -1,547 +0,0 @@
//===-- SparcV9Instr.def - SparcV9 Instruction Information -------*- 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 describes all of the instructions that the sparc backend uses. It
// relys on an external 'I' macro being defined that takes the arguments
// specified below, and is used to make all of the information relevant to an
// instruction be in one place.
//
//===----------------------------------------------------------------------===//
// NOTE: No include guards desired
#ifndef I
#errror "Must define I macro before including SparcInstr.def!"
#endif
// Constants for defining the maximum constant size field.
// One #define per bit size
//
#define B5 ((1 << 5) - 1)
#define B6 ((1 << 6) - 1)
#define B12 ((1 << 12) - 1)
#define B15 ((1 << 15) - 1)
#define B18 ((1 << 18) - 1)
#define B21 ((1 << 21) - 1)
#define B22 ((1 << 22) - 1)
#define B29 ((1 << 29) - 1)
// Arguments passed into the I macro
// enum name,
// opCodeString,
// numOperands,
// resultPosition (0-based; -1 if no result),
// maxImmedConst,
// immedIsSignExtended,
// numDelaySlots (in cycles)
// latency (in cycles)
// instr sched class (defined above)
// instr class flags (defined in TargetInstrInfo.h)
#define BRANCHFLAGS M_BRANCH_FLAG|M_TERMINATOR_FLAG
#define RETFLAGS M_RET_FLAG|M_TERMINATOR_FLAG
I(NOP, "nop", 0, -1, 0, false, 0, 1, SPARC_NONE, M_NOP_FLAG)
// Set high-order bits of register and clear low-order bits
I(SETHI, "sethi", 2, 1, B22, false, 0, 1, SPARC_IEUN, 0)
// Add or add with carry.
I(ADDr , "add", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0)
I(ADDi , "add", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0)
I(ADDccr, "addcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_CC_FLAG )
I(ADDcci, "addcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_CC_FLAG )
I(ADDCr , "addc", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0)
I(ADDCi , "addc", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0)
I(ADDCccr, "addccc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_CC_FLAG )
I(ADDCcci, "addccc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_CC_FLAG )
// Subtract or subtract with carry.
I(SUBr , "sub", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0)
I(SUBi , "sub", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0)
I(SUBccr , "subcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_CC_FLAG )
I(SUBcci , "subcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_CC_FLAG )
I(SUBCr , "subc", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0)
I(SUBCi , "subc", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0)
I(SUBCccr, "subccc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_CC_FLAG )
I(SUBCcci, "subccc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_CC_FLAG )
// Integer multiply, signed divide, unsigned divide.
// Note that the deprecated 32-bit multiply and multiply-step are not used.
I(MULXr , "mulx", 3, 2, B12, true , 0, 3, SPARC_IEUN, 0)
I(MULXi , "mulx", 3, 2, B12, true , 0, 3, SPARC_IEUN, 0)
I(SDIVXr, "sdivx", 3, 2, B12, true , 0, 6, SPARC_IEUN, 0)
I(SDIVXi, "sdivx", 3, 2, B12, true , 0, 6, SPARC_IEUN, 0)
I(UDIVXr, "udivx", 3, 2, B12, true , 0, 6, SPARC_IEUN, 0)
I(UDIVXi, "udivx", 3, 2, B12, true , 0, 6, SPARC_IEUN, 0)
// Floating point add, subtract, compare.
// Note that destination of FCMP* instructions is operand 0, not operand 2.
I(FADDS, "fadds", 3, 2, 0, false, 0, 3, SPARC_FPA, 0)
I(FADDD, "faddd", 3, 2, 0, false, 0, 3, SPARC_FPA, 0)
I(FADDQ, "faddq", 3, 2, 0, false, 0, 3, SPARC_FPA, 0)
I(FSUBS, "fsubs", 3, 2, 0, false, 0, 3, SPARC_FPA, 0)
I(FSUBD, "fsubd", 3, 2, 0, false, 0, 3, SPARC_FPA, 0)
I(FSUBQ, "fsubq", 3, 2, 0, false, 0, 3, SPARC_FPA, 0)
I(FCMPS, "fcmps", 3, 0, 0, false, 0, 3, SPARC_FPA, M_CC_FLAG )
I(FCMPD, "fcmpd", 3, 0, 0, false, 0, 3, SPARC_FPA, M_CC_FLAG )
I(FCMPQ, "fcmpq", 3, 0, 0, false, 0, 3, SPARC_FPA, M_CC_FLAG )
// NOTE: FCMPE{S,D,Q}: FP Compare With Exception are currently unused!
// Floating point multiply or divide.
I(FMULS , "fmuls", 3, 2, 0, false, 0, 3, SPARC_FPM, 0)
I(FMULD , "fmuld", 3, 2, 0, false, 0, 3, SPARC_FPM, 0)
I(FMULQ , "fmulq", 3, 2, 0, false, 0, 0, SPARC_FPM, 0)
I(FSMULD, "fsmuld", 3, 2, 0, false, 0, 3, SPARC_FPM, 0)
I(FDMULQ, "fdmulq", 3, 2, 0, false, 0, 0, SPARC_FPM, 0)
I(FDIVS , "fdivs", 3, 2, 0, false, 0, 12, SPARC_FPM, 0)
I(FDIVD , "fdivd", 3, 2, 0, false, 0, 22, SPARC_FPM, 0)
I(FDIVQ , "fdivq", 3, 2, 0, false, 0, 0, SPARC_FPM, 0)
I(FSQRTS, "fsqrts", 3, 2, 0, false, 0, 12, SPARC_FPM, 0)
I(FSQRTD, "fsqrtd", 3, 2, 0, false, 0, 22, SPARC_FPM, 0)
I(FSQRTQ, "fsqrtq", 3, 2, 0, false, 0, 0, SPARC_FPM, 0)
// Logical operations
I(ANDr , "and", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0)
I(ANDi , "and", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0)
I(ANDccr , "andcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, 0)
I(ANDcci , "andcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, 0)
I(ANDNr , "andn", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0)
I(ANDNi , "andn", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0)
I(ANDNccr, "andncc", 4, 2, B12, true , 0, 1, SPARC_IEU1, 0)
I(ANDNcci, "andncc", 4, 2, B12, true , 0, 1, SPARC_IEU1, 0)
I(ORr , "or", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0)
I(ORi , "or", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0)
I(ORccr , "orcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, 0)
I(ORcci , "orcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, 0)
I(ORNr , "orn", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0)
I(ORNi , "orn", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0)
I(ORNccr, "orncc", 4, 2, B12, true , 0, 1, SPARC_IEU1, 0)
I(ORNcci, "orncc", 4, 2, B12, true , 0, 1, SPARC_IEU1, 0)
I(XORr , "xor", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0)
I(XORi , "xor", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0)
I(XORccr , "xorcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, 0)
I(XORcci , "xorcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, 0)
I(XNORr , "xnor", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0)
I(XNORi , "xnor", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0)
I(XNORccr, "xnorcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, 0)
I(XNORcci, "xnorcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, 0)
// Shift operations
I(SLLr5 , "sll", 3, 2, B5, true , 0, 1, SPARC_IEU0, 0)
I(SLLi5 , "sll", 3, 2, B5, true , 0, 1, SPARC_IEU0, 0)
I(SRLr5 , "srl", 3, 2, B5, true , 0, 1, SPARC_IEU0, 0)
I(SRLi5 , "srl", 3, 2, B5, true , 0, 1, SPARC_IEU0, 0)
I(SRAr5 , "sra", 3, 2, B5, true , 0, 1, SPARC_IEU0, 0)
I(SRAi5 , "sra", 3, 2, B5, true , 0, 1, SPARC_IEU0, 0)
I(SLLXr6, "sllx", 3, 2, B6, true , 0, 1, SPARC_IEU0, 0)
I(SLLXi6, "sllx", 3, 2, B6, true , 0, 1, SPARC_IEU0, 0)
I(SRLXr6, "srlx", 3, 2, B6, true , 0, 1, SPARC_IEU0, 0)
I(SRLXi6, "srlx", 3, 2, B6, true , 0, 1, SPARC_IEU0, 0)
I(SRAXr6, "srax", 3, 2, B6, true , 0, 1, SPARC_IEU0, 0)
I(SRAXi6, "srax", 3, 2, B6, true , 0, 1, SPARC_IEU0, 0)
// Floating point move, negate, and abs instructions
I(FMOVS, "fmovs", 2, 1, 0, false, 0, 1, SPARC_FPA, 0)
I(FMOVD, "fmovd", 2, 1, 0, false, 0, 1, SPARC_FPA, 0)
//I(FMOVQ, "fmovq", 2, 1, 0, false, 0, ?, SPARC_FPA, 0)
I(FNEGS, "fnegs", 2, 1, 0, false, 0, 1, SPARC_FPA, 0)
I(FNEGD, "fnegd", 2, 1, 0, false, 0, 1, SPARC_FPA, 0)
//I(FNEGQ, "fnegq", 2, 1, 0, false, 0, ?, SPARC_FPA, 0)
I(FABSS, "fabss", 2, 1, 0, false, 0, 1, SPARC_FPA, 0)
I(FABSD, "fabsd", 2, 1, 0, false, 0, 1, SPARC_FPA, 0)
//I(FABSQ, "fabsq", 2, 1, 0, false, 0, ?, SPARC_FPA, 0)
// Convert from floating point to floating point formats
I(FSTOD, "fstod", 2, 1, 0, false, 0, 3, SPARC_FPA, 0)
I(FSTOQ, "fstoq", 2, 1, 0, false, 0, 0, SPARC_FPA, 0)
I(FDTOS, "fdtos", 2, 1, 0, false, 0, 3, SPARC_FPA, 0)
I(FDTOQ, "fdtoq", 2, 1, 0, false, 0, 0, SPARC_FPA, 0)
I(FQTOS, "fqtos", 2, 1, 0, false, 0, 0, SPARC_FPA, 0)
I(FQTOD, "fqtod", 2, 1, 0, false, 0, 0, SPARC_FPA, 0)
// Convert from floating point to integer formats.
// Note that this accesses both integer and floating point registers.
I(FSTOX, "fstox", 2, 1, 0, false, 0, 3, SPARC_FPA, 0)
I(FDTOX, "fdtox", 2, 1, 0, false, 0, 0, SPARC_FPA, 0)
I(FQTOX, "fqtox", 2, 1, 0, false, 0, 2, SPARC_FPA, 0)
I(FSTOI, "fstoi", 2, 1, 0, false, 0, 3, SPARC_FPA, 0)
I(FDTOI, "fdtoi", 2, 1, 0, false, 0, 3, SPARC_FPA, 0)
I(FQTOI, "fqtoi", 2, 1, 0, false, 0, 0, SPARC_FPA, 0)
// Convert from integer to floating point formats
// Note that this accesses both integer and floating point registers.
I(FXTOS, "fxtos", 2, 1, 0, false, 0, 3, SPARC_FPA, 0)
I(FXTOD, "fxtod", 2, 1, 0, false, 0, 3, SPARC_FPA, 0)
I(FXTOQ, "fxtoq", 2, 1, 0, false, 0, 0, SPARC_FPA, 0)
I(FITOS, "fitos", 2, 1, 0, false, 0, 3, SPARC_FPA, 0)
I(FITOD, "fitod", 2, 1, 0, false, 0, 3, SPARC_FPA, 0)
I(FITOQ, "fitoq", 2, 1, 0, false, 0, 0, SPARC_FPA, 0)
// Branch on integer comparison with zero.
// Latency excludes the delay slot since it can be issued in same cycle.
I(BRZ , "brz", 2, -1, B15, true , 1, 1, SPARC_CTI, BRANCHFLAGS)
I(BRLEZ, "brlez", 2, -1, B15, true , 1, 1, SPARC_CTI, BRANCHFLAGS)
I(BRLZ , "brlz", 2, -1, B15, true , 1, 1, SPARC_CTI, BRANCHFLAGS)
I(BRNZ , "brnz", 2, -1, B15, true , 1, 1, SPARC_CTI, BRANCHFLAGS)
I(BRGZ , "brgz", 2, -1, B15, true , 1, 1, SPARC_CTI, BRANCHFLAGS)
I(BRGEZ, "brgez", 2, -1, B15, true , 1, 1, SPARC_CTI, BRANCHFLAGS)
// Branch on integer condition code.
// The first argument specifies the ICC register: %icc or %xcc
// Latency includes the delay slot.
I(BA , "ba", 1, -1, B21, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS)
I(BN , "bn", 2, -1, B21, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS)
I(BNE , "bne", 2, -1, B21, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS)
I(BE , "be", 2, -1, B21, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS)
I(BG , "bg", 2, -1, B21, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS)
I(BLE , "ble", 2, -1, B21, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS)
I(BGE , "bge", 2, -1, B21, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS)
I(BL , "bl", 2, -1, B21, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS)
I(BGU , "bgu", 2, -1, B21, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS)
I(BLEU, "bleu", 2, -1, B21, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS)
I(BCC , "bcc", 2, -1, B21, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS)
I(BCS , "bcs", 2, -1, B21, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS)
I(BPOS, "bpos", 2, -1, B21, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS)
I(BNEG, "bneg", 2, -1, B21, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS)
I(BVC , "bvc", 2, -1, B21, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS)
I(BVS , "bvs", 2, -1, B21, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS)
// Branch on floating point condition code.
// The first argument is the FCCn register (0 <= n <= 3).
// Latency includes the delay slot.
I(FBA , "fba", 2, -1, B18, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS)
I(FBN , "fbn", 2, -1, B18, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS)
I(FBU , "fbu", 2, -1, B18, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS)
I(FBG , "fbg", 2, -1, B18, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS)
I(FBUG , "fbug", 2, -1, B18, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS)
I(FBL , "fbl", 2, -1, B18, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS)
I(FBUL , "fbul", 2, -1, B18, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS)
I(FBLG , "fblg", 2, -1, B18, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS)
I(FBNE , "fbne", 2, -1, B18, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS)
I(FBE , "fbe", 2, -1, B18, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS)
I(FBUE , "fbue", 2, -1, B18, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS)
I(FBGE , "fbge", 2, -1, B18, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS)
I(FBUGE, "fbuge", 2, -1, B18, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS)
I(FBLE , "fble", 2, -1, B18, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS)
I(FBULE, "fbule", 2, -1, B18, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS)
I(FBO , "fbo", 2, -1, B18, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS)
// Conditional move on integer comparison with zero.
I(MOVRZr , "movrz", 3, 2, B12, true , 0, 2, SPARC_SINGLE, 0)
I(MOVRZi , "movrz", 3, 2, B12, true , 0, 2, SPARC_SINGLE, 0)
I(MOVRLEZr, "movrlez", 3, 2, B12, true , 0, 2, SPARC_SINGLE, 0)
I(MOVRLEZi, "movrlez", 3, 2, B12, true , 0, 2, SPARC_SINGLE, 0)
I(MOVRLZr , "movrlz", 3, 2, B12, true , 0, 2, SPARC_SINGLE, 0)
I(MOVRLZi , "movrlz", 3, 2, B12, true , 0, 2, SPARC_SINGLE, 0)
I(MOVRNZr , "movrnz", 3, 2, B12, true , 0, 2, SPARC_SINGLE, 0)
I(MOVRNZi , "movrnz", 3, 2, B12, true , 0, 2, SPARC_SINGLE, 0)
I(MOVRGZr , "movrgz", 3, 2, B12, true , 0, 2, SPARC_SINGLE, 0)
I(MOVRGZi , "movrgz", 3, 2, B12, true , 0, 2, SPARC_SINGLE, 0)
I(MOVRGEZr, "movrgez", 3, 2, B12, true , 0, 2, SPARC_SINGLE, 0)
I(MOVRGEZi, "movrgez", 3, 2, B12, true , 0, 2, SPARC_SINGLE, 0)
// Conditional move on integer condition code.
// The first argument specifies the ICC register: %icc or %xcc
I(MOVAr , "mova", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVAi , "mova", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVNr , "movn", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVNi , "movn", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVNEr , "movne", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVNEi , "movne", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVEr , "move", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVEi , "move", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVGr , "movg", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVGi , "movg", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVLEr , "movle", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVLEi , "movle", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVGEr , "movge", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVGEi , "movge", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVLr , "movl", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVLi , "movl", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVGUr , "movgu", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVGUi , "movgu", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVLEUr, "movleu", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVLEUi, "movleu", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVCCr , "movcc", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVCCi , "movcc", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVCSr , "movcs", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVCSi , "movcs", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVPOSr, "movpos", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVPOSi, "movpos", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVNEGr, "movneg", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVNEGi, "movneg", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVVCr , "movvc", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVVCi , "movvc", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVVSr , "movvs", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVVSi , "movvs", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
// Conditional move (of integer register) on floating point condition code.
// The first argument is the FCCn register (0 <= n <= 3).
// Note that the enum name above is not the same as the assembly mnemonic
// because some of the assembly mnemonics are the same as the move on
// integer CC (e.g., MOVG), and we cannot have the same enum entry twice.
I(MOVFAr , "mova", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVFAi , "mova", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVFNr , "movn", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVFNi , "movn", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVFUr , "movu", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVFUi , "movu", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVFGr , "movg", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVFGi , "movg", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVFUGr , "movug", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVFUGi , "movug", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVFLr , "movl", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVFLi , "movl", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVFULr , "movul", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVFULi , "movul", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVFLGr , "movlg", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVFLGi , "movlg", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVFNEr , "movne", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVFNEi , "movne", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVFEr , "move", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVFEi , "move", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVFUEr , "movue", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVFUEi , "movue", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVFGEr , "movge", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVFGEi , "movge", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVFUGEr, "movuge", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVFUGEi, "movuge", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVFLEr , "movle", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVFLEi , "movle", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVFULEr, "movule", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVFULEi, "movule", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVFOr , "movo", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(MOVFOi , "movo", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG )
// Conditional move of floating point register on each of the above:
// i. on integer comparison with zero.
// ii. on integer condition code
// iii. on floating point condition code
// Note that the same set is repeated for S,D,Q register classes.
I(FMOVRSZ ,"fmovrsz", 3, 2, 0, false, 0, 2, SPARC_SINGLE, 0)
I(FMOVRSLEZ,"fmovrslez",3, 2, 0, false, 0, 2, SPARC_SINGLE, 0)
I(FMOVRSLZ ,"fmovrslz", 3, 2, 0, false, 0, 2, SPARC_SINGLE, 0)
I(FMOVRSNZ ,"fmovrsnz", 3, 2, 0, false, 0, 2, SPARC_SINGLE, 0)
I(FMOVRSGZ ,"fmovrsgz", 3, 2, 0, false, 0, 2, SPARC_SINGLE, 0)
I(FMOVRSGEZ,"fmovrsgez",3, 2, 0, false, 0, 2, SPARC_SINGLE, 0)
I(FMOVSA , "fmovsa", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVSN , "fmovsn", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVSNE , "fmovsne", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVSE , "fmovse", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVSG , "fmovsg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVSLE , "fmovsle", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVSGE , "fmovsge", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVSL , "fmovsl", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVSGU , "fmovsgu", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVSLEU, "fmovsleu", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVSCC , "fmovscc", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVSCS , "fmovscs", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVSPOS, "fmovspos", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVSNEG, "fmovsneg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVSVC , "fmovsvc", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVSVS , "fmovsvs", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVSFA , "fmovsa", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVSFN , "fmovsn", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVSFU , "fmovsu", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVSFG , "fmovsg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVSFUG , "fmovsug", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVSFL , "fmovsl", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVSFUL , "fmovsul", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVSFLG , "fmovslg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVSFNE , "fmovsne", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVSFE , "fmovse", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVSFUE , "fmovsue", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVSFGE , "fmovsge", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVSFUGE, "fmovsuge",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVSFLE , "fmovsle", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVSFULE, "fmovslue",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVSFO , "fmovso", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVRDZ , "fmovrdz", 3, 2, 0, false, 0, 2, SPARC_SINGLE, 0)
I(FMOVRDLEZ, "fmovrdlez",3, 2, 0, false, 0, 2, SPARC_SINGLE, 0)
I(FMOVRDLZ , "fmovrdlz",3, 2, 0, false, 0, 2, SPARC_SINGLE, 0)
I(FMOVRDNZ , "fmovrdnz",3, 2, 0, false, 0, 2, SPARC_SINGLE, 0)
I(FMOVRDGZ , "fmovrdgz",3, 2, 0, false, 0, 2, SPARC_SINGLE, 0)
I(FMOVRDGEZ, "fmovrdgez",3, 2, 0, false, 0, 2, SPARC_SINGLE, 0)
I(FMOVDA , "fmovda", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVDN , "fmovdn", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVDNE , "fmovdne", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVDE , "fmovde", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVDG , "fmovdg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVDLE , "fmovdle", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVDGE , "fmovdge", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVDL , "fmovdl", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVDGU , "fmovdgu", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVDLEU, "fmovdleu", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVDCC , "fmovdcc", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVDCS , "fmovdcs", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVDPOS, "fmovdpos", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVDNEG, "fmovdneg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVDVC , "fmovdvc", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVDVS , "fmovdvs", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVDFA , "fmovda", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVDFN , "fmovdn", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVDFU , "fmovdu", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVDFG , "fmovdg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVDFUG , "fmovdug", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVDFL , "fmovdl", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVDFUL , "fmovdul", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVDFLG , "fmovdlg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVDFNE , "fmovdne", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVDFE , "fmovde", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVDFUE , "fmovdue", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVDFGE , "fmovdge", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVDFUGE, "fmovduge",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVDFLE , "fmovdle", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVDFULE, "fmovdule",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVDFO , "fmovdo", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVRQZ , "fmovrqz", 3, 2, 0, false, 0, 2, SPARC_SINGLE, 0)
I(FMOVRQLEZ, "fmovrqlez",3, 2, 0, false, 0, 2, SPARC_SINGLE, 0)
I(FMOVRQLZ , "fmovrqlz",3, 2, 0, false, 0, 2, SPARC_SINGLE, 0)
I(FMOVRQNZ , "fmovrqnz",3, 2, 0, false, 0, 2, SPARC_SINGLE, 0)
I(FMOVRQGZ , "fmovrqgz",3, 2, 0, false, 0, 2, SPARC_SINGLE, 0)
I(FMOVRQGEZ, "fmovrqgez",3, 2, 0, false, 0, 2, SPARC_SINGLE, 0)
I(FMOVQA , "fmovqa", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVQN , "fmovqn", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVQNE , "fmovqne", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVQE , "fmovqe", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVQG , "fmovqg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVQLE , "fmovqle", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVQGE , "fmovqge", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVQL , "fmovql", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVQGU , "fmovqgu", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVQLEU, "fmovqleu", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVQCC , "fmovqcc", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVQCS , "fmovqcs", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVQPOS, "fmovqpos", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVQNEG, "fmovqneg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVQVC , "fmovqvc", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVQVS , "fmovqvs", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVQFA , "fmovqa", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVQFN , "fmovqn", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVQFU , "fmovqu", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVQFG , "fmovqg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVQFUG , "fmovqug", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVQFL , "fmovql", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVQFUL , "fmovqul", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVQFLG , "fmovqlg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVQFNE , "fmovqne", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVQFE , "fmovqe", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVQFUE , "fmovque", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVQFGE , "fmovqge", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVQFUGE, "fmovquge",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVQFLE , "fmovqle", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVQFULE, "fmovqule",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG )
I(FMOVQFO , "fmovqo", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG)
// Load integer instructions
// Latency includes 1 cycle for address generation (Sparc IIi),
// plus 3 cycles assumed for average miss penalty (bias towards L1 hits).
// Signed loads of less than 64 bits need an extra cycle for sign-extension.
//
// Not reflected here: After a 3-cycle loads, all subsequent consecutive
// loads also require 3 cycles to avoid contention for the load return
// stage. Latency returns to 2 cycles after the first cycle with no load.
I(LDSBr, "ldsb", 3, 2, B12, true , 0, 6, SPARC_LD, M_LOAD_FLAG)
I(LDSBi, "ldsb", 3, 2, B12, true , 0, 6, SPARC_LD, M_LOAD_FLAG)
I(LDSHr, "ldsh", 3, 2, B12, true , 0, 6, SPARC_LD, M_LOAD_FLAG)
I(LDSHi, "ldsh", 3, 2, B12, true , 0, 6, SPARC_LD, M_LOAD_FLAG)
I(LDSWr, "ldsw", 3, 2, B12, true , 0, 6, SPARC_LD, M_LOAD_FLAG)
I(LDSWi, "ldsw", 3, 2, B12, true , 0, 6, SPARC_LD, M_LOAD_FLAG)
I(LDUBr, "ldub", 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG)
I(LDUBi, "ldub", 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG)
I(LDUHr, "lduh", 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG)
I(LDUHi, "lduh", 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG)
I(LDUWr, "lduw", 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG)
I(LDUWi, "lduw", 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG)
I(LDXr , "ldx" , 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG)
I(LDXi , "ldx" , 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG)
// Load floating-point instructions
// Latency includes 1 cycle for address generation (Sparc IIi)
I(LDFr , "ld", 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG)
I(LDFi , "ld", 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG)
I(LDDFr, "ldd", 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG)
I(LDDFi, "ldd", 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG)
I(LDQFr, "ldq", 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG)
I(LDQFi, "ldq", 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG)
I(LDFSRr, "ld", 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG)
I(LDFSRi, "ld", 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG)
I(LDXFSRr, "ldx", 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG)
I(LDXFSRi, "ldx", 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG)
// Store integer instructions.
// Requires 1 cycle for address generation (Sparc IIi).
// Default latency is 0 because value is not explicitly used.
I(STBr, "stb", 3, -1, B12, true , 0, 0, SPARC_ST, M_STORE_FLAG)
I(STBi, "stb", 3, -1, B12, true , 0, 0, SPARC_ST, M_STORE_FLAG)
I(STHr, "sth", 3, -1, B12, true , 0, 0, SPARC_ST, M_STORE_FLAG)
I(STHi, "sth", 3, -1, B12, true , 0, 0, SPARC_ST, M_STORE_FLAG)
I(STWr, "stw", 3, -1, B12, true , 0, 0, SPARC_ST, M_STORE_FLAG)
I(STWi, "stw", 3, -1, B12, true , 0, 0, SPARC_ST, M_STORE_FLAG)
I(STXr, "stx", 3, -1, B12, true , 0, 0, SPARC_ST, M_STORE_FLAG)
I(STXi, "stx", 3, -1, B12, true , 0, 0, SPARC_ST, M_STORE_FLAG)
// Store floating-point instructions (Sparc IIi)
I(STFr, "st", 3, -1, B12, true , 0, 0, SPARC_ST, M_STORE_FLAG)
I(STFi, "st", 3, -1, B12, true , 0, 0, SPARC_ST, M_STORE_FLAG)
I(STDFr, "std", 3, -1, B12, true , 0, 0, SPARC_ST, M_STORE_FLAG)
I(STDFi, "std", 3, -1, B12, true , 0, 0, SPARC_ST, M_STORE_FLAG)
I(STFSRr, "st", 3, -1, B12, true , 0, 0, SPARC_ST, M_STORE_FLAG)
I(STFSRi, "st", 3, -1, B12, true , 0, 0, SPARC_ST, M_STORE_FLAG)
I(STXFSRr, "stx", 3, -1, B12, true , 0, 0, SPARC_ST, M_STORE_FLAG)
I(STXFSRi, "stx", 3, -1, B12, true , 0, 0, SPARC_ST, M_STORE_FLAG)
// Call, Return and "Jump and link". Operand (2) for JMPL is marked as
// a "result" because JMPL stores the return address for the call in it.
// Latency includes the delay slot.
I(CALL, "call", 1, -1, B29, true , 1, 2, SPARC_CTI, M_CALL_FLAG)
I(JMPLCALLr, "jmpl", 3, 2, B12, true , 1, 2, SPARC_CTI, M_CALL_FLAG)
I(JMPLCALLi, "jmpl", 3, 2, B12, true , 1, 2, SPARC_CTI, M_CALL_FLAG)
I(JMPLRETr, "jmpl", 3, 2, B12, true , 1, 2, SPARC_CTI, RETFLAGS)
I(JMPLRETi, "jmpl", 3, 2, B12, true , 1, 2, SPARC_CTI, RETFLAGS)
// SAVE and restore instructions
I(SAVEr, "save", 3, 2, B12, true , 0, 1, SPARC_SINGLE, 0)
I(SAVEi, "save", 3, 2, B12, true , 0, 1, SPARC_SINGLE, 0)
I(RESTOREr, "restore", 3, 2, B12, true , 0, 1, SPARC_SINGLE, 0)
I(RESTOREi, "restore", 3, 2, B12, true , 0, 1, SPARC_SINGLE, 0)
// Read and Write CCR register from/to an int reg
I(RDCCR, "rd", 2, 1, 0, false, 0, 1, SPARC_SINGLE, M_CC_FLAG)
I(WRCCRr, "wr", 3, 2, 0, false, 0, 1, SPARC_SINGLE, M_CC_FLAG)
I(WRCCRi, "wr", 3, 2, 0, false, 0, 1, SPARC_SINGLE, M_CC_FLAG)
// Synthetic phi operation for near-SSA form of machine code
// Number of operands is variable, indicated by -1. Result is the first op.
I(PHI, "<phi>", -1, 0, 0, false, 0, 0, SPARC_NONE, 0)
#undef B5
#undef B6
#undef B12
#undef B15
#undef B18
#undef B21
#undef B22
#undef B29
#undef BRANCHFLAGS
#undef RETFLAGS
#undef I

View File

@ -1,134 +0,0 @@
//===- SparcV9InstrForest.h - SparcV9 BURG Instruction Selector Trees -----===//
//
// 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.
//
//===----------------------------------------------------------------------===//
//
// A forest of BURG instruction trees (class InstrForest) which represents
// a function to the BURG-based instruction selector, and a bunch of constants
// and declarations used by the generated BURG code.
//
//===----------------------------------------------------------------------===//
#ifndef SPARCV9INSTRFOREST_H
#define SPARCV9INSTRFOREST_H
#include "llvm/Instruction.h"
using namespace llvm;
/// OpLabel values for special-case nodes created for instruction selection.
/// All op-labels not defined here are identical to the instruction
/// opcode returned by Instruction::getOpcode().
///
static const int
InvalidOp = -1,
VRegListOp = 97,
VRegNodeOp = 98,
ConstantNodeOp = 99,
LabelNodeOp = 100,
RetValueOp = 100 + Instruction::Ret, // 101
BrCondOp = 100 + Instruction::Br, // 102
BAndOp = 100 + Instruction::And, // 111
BOrOp = 100 + Instruction::Or, // 112
BXorOp = 100 + Instruction::Xor, // 113
BNotOp = 200 + Instruction::Xor, // 213
NotOp = 300 + Instruction::Xor, // 313
SetCCOp = 100 + Instruction::SetEQ, // 114
AllocaN = 100 + Instruction::Alloca, // 122
LoadIdx = 100 + Instruction::Load, // 123
GetElemPtrIdx = 100 + Instruction::GetElementPtr, // 125
ToBoolTy = 100 + Instruction::Cast; // 127
static const int
ToUByteTy = ToBoolTy + 1,
ToSByteTy = ToBoolTy + 2,
ToUShortTy = ToBoolTy + 3,
ToShortTy = ToBoolTy + 4,
ToUIntTy = ToBoolTy + 5,
ToIntTy = ToBoolTy + 6,
ToULongTy = ToBoolTy + 7,
ToLongTy = ToBoolTy + 8,
ToFloatTy = ToBoolTy + 9,
ToDoubleTy = ToBoolTy + 10,
ToArrayTy = ToBoolTy + 11,
ToPointerTy = ToBoolTy + 12;
/// Data types needed by BURG
///
typedef int OpLabel;
typedef int StateLabel;
/// Declarations of data and functions created by BURG
///
namespace llvm {
class InstrTreeNode;
};
extern short* burm_nts[];
extern StateLabel burm_label (InstrTreeNode* p);
extern StateLabel burm_state (OpLabel op, StateLabel leftState,
StateLabel rightState);
extern StateLabel burm_rule (StateLabel state, int goalNT);
extern InstrTreeNode** burm_kids (InstrTreeNode* p, int eruleno,
InstrTreeNode* kids[]);
extern void printcover (InstrTreeNode*, int, int);
extern void printtree (InstrTreeNode*);
extern int treecost (InstrTreeNode*, int, int);
extern void printMatches (InstrTreeNode*);
namespace llvm {
/// InstrTreeNode - A single tree node in the instruction tree used for
/// instruction selection via BURG.
///
class InstrTreeNode {
InstrTreeNode(const InstrTreeNode &); // DO NOT IMPLEMENT
void operator=(const InstrTreeNode &); // DO NOT IMPLEMENT
public:
enum InstrTreeNodeType { NTInstructionNode,
NTVRegListNode,
NTVRegNode,
NTConstNode,
NTLabelNode };
InstrTreeNode* LeftChild;
InstrTreeNode* RightChild;
InstrTreeNode* Parent;
OpLabel opLabel;
StateLabel state;
protected:
InstrTreeNodeType treeNodeType;
Value* val;
public:
InstrTreeNode(InstrTreeNodeType nodeType, Value* _val)
: treeNodeType(nodeType), val(_val) {
LeftChild = RightChild = Parent = 0;
opLabel = InvalidOp;
}
virtual ~InstrTreeNode() {
delete LeftChild;
delete RightChild;
}
InstrTreeNodeType getNodeType () const { return treeNodeType; }
Value* getValue () const { return val; }
inline OpLabel getOpLabel () const { return opLabel; }
inline InstrTreeNode *leftChild () const { return LeftChild; }
inline InstrTreeNode *parent () const { return Parent; }
// If right child is a list node, recursively get its *left* child
inline InstrTreeNode* rightChild() const {
return (!RightChild ? 0 :
(RightChild->getOpLabel() == VRegListOp
? RightChild->LeftChild : RightChild));
}
void dump(int dumpChildren, int indent) const;
protected:
virtual void dumpNode(int indent) const = 0;
friend class InstrForest;
};
} // end namespace llvm.
#endif

View File

@ -1,77 +0,0 @@
//===-- SparcV9InstrInfo.h - Define TargetInstrInfo for SparcV9 -*- 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 class contains information about individual instructions.
// Also see the SparcV9MachineInstrDesc array, which can be found in
// SparcV9TargetMachine.cpp.
// Other information is computed on demand, and most such functions
// default to member functions in base class TargetInstrInfo.
//
//===----------------------------------------------------------------------===//
#ifndef SPARCV9INSTRINFO_H
#define SPARCV9INSTRINFO_H
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "SparcV9Internals.h"
#include "SparcV9RegisterInfo.h"
namespace llvm {
/// SparcV9InstrInfo - TargetInstrInfo specialized for the SparcV9 target.
///
struct SparcV9InstrInfo : public TargetInstrInfo {
const SparcV9RegisterInfo RI;
public:
SparcV9InstrInfo()
: TargetInstrInfo(SparcV9MachineInstrDesc, V9::NUM_TOTAL_OPCODES) { }
/// getRegisterInfo - TargetInstrInfo is a superset of MRegister info. As
/// such, whenever a client has an instance of instruction info, it should
/// always be able to get register info as well (through this method).
///
virtual const MRegisterInfo &getRegisterInfo() const { return RI; }
// All immediate constants are in position 1 except the
// store instructions and SETxx.
//
virtual int getImmedConstantPos(MachineOpCode opCode) const {
bool ignore;
if (this->maxImmedConstant(opCode, ignore) != 0) {
// 1st store opcode
assert(! this->isStore((MachineOpCode) V9::STBr - 1));
// last store opcode
assert(! this->isStore((MachineOpCode) V9::STXFSRi + 1));
if (opCode == V9::SETHI)
return 0;
if (opCode >= V9::STBr && opCode <= V9::STXFSRi)
return 2;
return 1;
}
else
return -1;
}
virtual bool hasResultInterlock(MachineOpCode opCode) const
{
// All UltraSPARC instructions have interlocks (note that delay slots
// are not considered here).
// However, instructions that use the result of an FCMP produce a
// 9-cycle stall if they are issued less than 3 cycles after the FCMP.
// Force the compiler to insert a software interlock (i.e., gap of
// 2 other groups, including NOPs if necessary).
return (opCode == V9::FCMPS || opCode == V9::FCMPD || opCode == V9::FCMPQ);
}
};
} // End llvm namespace
#endif

View File

@ -1,777 +0,0 @@
//===- SparcV9InstrInfo.td - SparcV9 Instruction defs ------*- tablegen -*-===//
//
// 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 files declares the set of instructions used in the SparcV9 backend.
//
//===----------------------------------------------------------------------===//
class InstV9 : Instruction { // SparcV9 instruction baseline
field bits<32> Inst;
let Namespace = "V9";
bits<2> op;
let Inst{31-30} = op; // Top two bits are the 'op' field
// Bit attributes specific to SparcV9 instructions
bit isPasi = 0; // Does this instruction affect an alternate addr space?
bit isDeprecated = 0; // Is this instruction deprecated?
bit isPrivileged = 0; // Is this a privileged instruction?
}
class Pseudo<string n> : InstV9 {
let Name = n;
let Inst{0-31} = 0;
}
include "SparcV9_F2.td"
include "SparcV9_F3.td"
include "SparcV9_F4.td"
//===----------------------------------------------------------------------===//
// Instruction list
//===----------------------------------------------------------------------===//
// Section A.2: Add - p137
def ADDr : F3_1<2, 0b000000, "add">; // add rs1, rs2, rd
def ADDi : F3_2<2, 0b000000, "add">; // add rs1, imm, rd
def ADDccr : F3_1<2, 0b010000, "addcc">; // addcc rs1, rs2, rd
def ADDcci : F3_2<2, 0b010000, "addcc">; // addcc rs1, imm, rd
def ADDCr : F3_1<2, 0b001000, "addC">; // addC rs1, rs2, rd
def ADDCi : F3_2<2, 0b001000, "addC">; // addC rs1, imm, rd
def ADDCccr : F3_1<2, 0b011000, "addCcc">; // addCcc rs1, rs2, rd
def ADDCcci : F3_2<2, 0b011000, "addCcc">; // addCcc rs1, imm, rd
// Section A.3: Branch on Integer Register with Prediction - p138
let op2 = 0b011 in {
def BRZ : F2_4<0b001, "brz">; // Branch on rs1 == 0
def BRLEZ : F2_4<0b010, "brlez">; // Branch on rs1 <= 0
def BRLZ : F2_4<0b011, "brlz">; // Branch on rs1 < 0
def BRNZ : F2_4<0b101, "brnz">; // Branch on rs1 != 0
def BRGZ : F2_4<0b110, "brgz">; // Branch on rs1 > 0
def BRGEZ : F2_4<0b111, "brgez">; // Branch on rs1 >= 0
}
// Section A.4: Branch on Floating-Point Condition Codes (FBfcc) p140
// The following deprecated instructions don't seem to play nice on SparcV9
/*
let isDeprecated = 1 in {
let op2 = 0b110 in {
def FBA : F2_2<0b1000, "fba">; // Branch always
def FBN : F2_2<0b0000, "fbn">; // Branch never
def FBU : F2_2<0b0111, "fbu">; // Branch on unordered
def FBG : F2_2<0b0110, "fbg">; // Branch >
def FBUG : F2_2<0b0101, "fbug">; // Branch on unordered or >
def FBL : F2_2<0b0100, "fbl">; // Branch <
def FBUL : F2_2<0b0011, "fbul">; // Branch on unordered or <
def FBLG : F2_2<0b0010, "fblg">; // Branch < or >
def FBNE : F2_2<0b0001, "fbne">; // Branch !=
def FBE : F2_2<0b1001, "fbe">; // Branch ==
def FBUE : F2_2<0b1010, "fbue">; // Branch on unordered or ==
def FBGE : F2_2<0b1011, "fbge">; // Branch > or ==
def FBUGE : F2_2<0b1100, "fbuge">; // Branch unord or > or ==
def FBLE : F2_2<0b1101, "fble">; // Branch < or ==
def FBULE : F2_2<0b1110, "fbule">; // Branch unord or < or ==
def FBO : F2_2<0b1111, "fbo">; // Branch on ordered
}
}
*/
// We now make these same opcodes represent the FBPfcc instructions
let op2 = 0b101 in {
def FBA : F2_3<0b1000, "fba">; // Branch always
def FBN : F2_3<0b0000, "fbn">; // Branch never
def FBU : F2_3<0b0111, "fbu">; // Branch on unordered
def FBG : F2_3<0b0110, "fbg">; // Branch >
def FBUG : F2_3<0b0101, "fbug">; // Branch on unordered or >
def FBL : F2_3<0b0100, "fbl">; // Branch <
def FBUL : F2_3<0b0011, "fbul">; // Branch on unordered or <
def FBLG : F2_3<0b0010, "fblg">; // Branch < or >
def FBNE : F2_3<0b0001, "fbne">; // Branch !=
def FBE : F2_3<0b1001, "fbe">; // Branch ==
def FBUE : F2_3<0b1010, "fbue">; // Branch on unordered or ==
def FBGE : F2_3<0b1011, "fbge">; // Branch > or ==
def FBUGE : F2_3<0b1100, "fbuge">; // Branch unord or > or ==
def FBLE : F2_3<0b1101, "fble">; // Branch < or ==
def FBULE : F2_3<0b1110, "fbule">; // Branch unord or < or ==
def FBO : F2_3<0b1111, "fbo">; // Branch on ordered
}
// Section A.5: Branch on FP condition codes with prediction - p143
// Not used in the SparcV9 backend (directly)
/*
let op2 = 0b101 in {
def FBPA : F2_3<0b1000, "fba">; // Branch always
def FBPN : F2_3<0b0000, "fbn">; // Branch never
def FBPU : F2_3<0b0111, "fbu">; // Branch on unordered
def FBPG : F2_3<0b0110, "fbg">; // Branch >
def FBPUG : F2_3<0b0101, "fbug">; // Branch on unordered or >
def FBPL : F2_3<0b0100, "fbl">; // Branch <
def FBPUL : F2_3<0b0011, "fbul">; // Branch on unordered or <
def FBPLG : F2_3<0b0010, "fblg">; // Branch < or >
def FBPNE : F2_3<0b0001, "fbne">; // Branch !=
def FBPE : F2_3<0b1001, "fbe">; // Branch ==
def FBPUE : F2_3<0b1010, "fbue">; // Branch on unordered or ==
def FBPGE : F2_3<0b1011, "fbge">; // Branch > or ==
def FBPUGE : F2_3<0b1100, "fbuge">; // Branch unord or > or ==
def FBPLE : F2_3<0b1101, "fble">; // Branch < or ==
def FBPULE : F2_3<0b1110, "fbule">; // Branch unord or < or ==
def FBPO : F2_3<0b1111, "fbo">; // Branch on ordered
}
*/
// Section A.6: Branch on Integer condition codes (Bicc) - p146
/*
let isDeprecated = 1 in {
let op2 = 0b010 in {
def BA : F2_2<0b1000, "ba">; // Branch always
def BN : F2_2<0b0000, "bn">; // Branch never
def BNE : F2_2<0b1001, "bne">; // Branch !=
def BE : F2_2<0b0001, "be">; // Branch ==
def BG : F2_2<0b1010, "bg">; // Branch >
def BLE : F2_2<0b0010, "ble">; // Branch <=
def BGE : F2_2<0b1011, "bge">; // Branch >=
def BL : F2_2<0b0011, "bl">; // Branch <
def BGU : F2_2<0b1100, "bgu">; // Branch unsigned >
def BLEU : F2_2<0b0100, "bleu">; // Branch unsigned <=
def BCC : F2_2<0b1101, "bcc">; // Branch unsigned >=
def BCS : F2_2<0b0101, "bcs">; // Branch unsigned <=
def BPOS : F2_2<0b1110, "bpos">; // Branch on positive
def BNEG : F2_2<0b0110, "bneg">; // Branch on negative
def BVC : F2_2<0b1111, "bvc">; // Branch on overflow clear
def BVS : F2_2<0b0111, "bvs">; // Branch on overflow set
}
}
*/
// Using the format of A.7 instructions...
let op2 = 0b001 in {
let cc = 0 in { // BA and BN don't read condition codes
def BA : F2_3<0b1000, "ba">; // Branch always
def BN : F2_3<0b0000, "bn">; // Branch never
}
def BNE : F2_3<0b1001, "bne">; // Branch !=
def BE : F2_3<0b0001, "be">; // Branch ==
def BG : F2_3<0b1010, "bg">; // Branch >
def BLE : F2_3<0b0010, "ble">; // Branch <=
def BGE : F2_3<0b1011, "bge">; // Branch >=
def BL : F2_3<0b0011, "bl">; // Branch <
def BGU : F2_3<0b1100, "bgu">; // Branch unsigned >
def BLEU : F2_3<0b0100, "bleu">; // Branch unsigned <=
def BCC : F2_3<0b1101, "bcc">; // Branch unsigned >=
def BCS : F2_3<0b0101, "bcs">; // Branch unsigned <=
def BPOS : F2_3<0b1110, "bpos">; // Branch on positive
def BNEG : F2_3<0b0110, "bneg">; // Branch on negative
def BVC : F2_3<0b1111, "bvc">; // Branch on overflow clear
def BVS : F2_3<0b0111, "bvs">; // Branch on overflow set
}
// Section A.7: Branch on integer condition codes with prediction - p148
// Not used in the SparcV9 backend
/*
let op2 = 0b001 in {
def BPA : F2_3<0b1000, "bpa">; // Branch always
def BPN : F2_3<0b0000, "bpn">; // Branch never
def BPNE : F2_3<0b1001, "bpne">; // Branch !=
def BPE : F2_3<0b0001, "bpe">; // Branch ==
def BPG : F2_3<0b1010, "bpg">; // Branch >
def BPLE : F2_3<0b0010, "bple">; // Branch <=
def BPGE : F2_3<0b1011, "bpge">; // Branch >=
def BPL : F2_3<0b0011, "bpl">; // Branch <
def BPGU : F2_3<0b1100, "bpgu">; // Branch unsigned >
def BPLEU : F2_3<0b0100, "bpleu">; // Branch unsigned <=
def BPCC : F2_3<0b1101, "bpcc">; // Branch unsigned >=
def BPCS : F2_3<0b0101, "bpcs">; // Branch unsigned <=
def BPPOS : F2_3<0b1110, "bppos">; // Branch on positive
def BPNEG : F2_3<0b0110, "bpneg">; // Branch on negative
def BPVC : F2_3<0b1111, "bpvc">; // Branch on overflow clear
def BPVS : F2_3<0b0111, "bpvs">; // Branch on overflow set
}
*/
// Section A.8: CALL - p151, the only Format #1 instruction
def CALL : InstV9 {
bits<30> disp;
let op = 1;
let Inst{29-0} = disp;
let Name = "call";
let isCall = 1;
}
// Section A.9: Compare and Swap - p176
// CASA/CASXA: are for alternate address spaces! Ignore them
// Section A.10: Divide (64-bit / 32-bit) - p178
// Not used in the SparcV9 backend
/*
let isDeprecated = 1 in {
def UDIVr : F3_1<2, 0b001110, "udiv">; // udiv r, r, r
def UDIVi : F3_2<2, 0b001110, "udiv">; // udiv r, r, i
def SDIVr : F3_1<2, 0b001111, "sdiv">; // sdiv r, r, r
def SDIVi : F3_2<2, 0b001111, "sdiv">; // sdiv r, r, i
def UDIVCCr : F3_1<2, 0b011110, "udivcc">; // udivcc r, r, r
def UDIVCCi : F3_2<2, 0b011110, "udivcc">; // udivcc r, r, i
def SDIVCCr : F3_1<2, 0b011111, "sdivcc">; // sdivcc r, r, r
def SDIVCCi : F3_2<2, 0b011111, "sdivcc">; // sdivcc r, r, i
}
*/
// Section A.11: DONE and RETRY - p181
// Not used in the SparcV9 backend
/*
let isPrivileged = 1 in {
def DONE : F3_18<0, "done">; // done
def RETRY : F3_18<1, "retry">; // retry
}
*/
// Section A.12: Floating-Point Add and Subtract - p156
def FADDS : F3_16<2, 0b110100, 0x41, "fadds">; // fadds frs1, frs2, frd
def FADDD : F3_16<2, 0b110100, 0x42, "faddd">; // faddd frs1, frs2, frd
def FADDQ : F3_16<2, 0b110100, 0x43, "faddq">; // faddq frs1, frs2, frd
def FSUBS : F3_16<2, 0b110100, 0x45, "fsubs">; // fsubs frs1, frs2, frd
def FSUBD : F3_16<2, 0b110100, 0x46, "fsubd">; // fsubd frs1, frs2, frd
def FSUBQ : F3_16<2, 0b110100, 0x47, "fsubq">; // fsubq frs1, frs2, frd
// Section A.13: Floating-point compare - p159
def FCMPS : F3_15<2, 0b110101, 0b001010001, "fcmps">; // fcmps %fcc, r1, r2
def FCMPD : F3_15<2, 0b110101, 0b001010010, "fcmpd">; // fcmpd %fcc, r1, r2
def FCMPQ : F3_15<2, 0b110101, 0b001010011, "fcmpq">; // fcmpq %fcc, r1, r2
// Currently unused in the SparcV9 backend
/*
def FCMPES : F3_15<2, 0b110101, 0b001010101, "fcmpes">; // fcmpes %fcc, r1, r2
def FCMPED : F3_15<2, 0b110101, 0b001010110, "fcmped">; // fcmped %fcc, r1, r2
def FCMPEQ : F3_15<2, 0b110101, 0b001010111, "fcmpeq">; // fcmpeq %fcc, r1, r2
*/
// Section A.14: Convert floating-point to integer - p161
def FSTOX : F3_14<2, 0b110100, 0b010000001, "fstox">; // fstox rs2, rd
def FDTOX : F3_14<2, 0b110100, 0b010000010, "fstox">; // fstox rs2, rd
def FQTOX : F3_14<2, 0b110100, 0b010000011, "fstox">; // fstox rs2, rd
def FSTOI : F3_14<2, 0b110100, 0b011010001, "fstoi">; // fstoi rs2, rd
def FDTOI : F3_14<2, 0b110100, 0b011010010, "fdtoi">; // fdtoi rs2, rd
def FQTOI : F3_14<2, 0b110100, 0b011010011, "fqtoi">; // fqtoi rs2, rd
// Section A.15: Convert between floating-point formats - p162
def FSTOD : F3_14<2, 0b110100, 0b011001001, "fstod">; // fstod rs2, rd
def FSTOQ : F3_14<2, 0b110100, 0b011001101, "fstoq">; // fstoq rs2, rd
def FDTOS : F3_14<2, 0b110100, 0b011000110, "fstos">; // fstos rs2, rd
def FDTOQ : F3_14<2, 0b110100, 0b011001110, "fdtoq">; // fdtoq rs2, rd
def FQTOS : F3_14<2, 0b110100, 0b011000111, "fqtos">; // fqtos rs2, rd
def FQTOD : F3_14<2, 0b110100, 0b011001011, "fqtod">; // fqtod rs2, rd
// Section A.16: Convert integer to floating-point - p163
def FXTOS : F3_14<2, 0b110100, 0b010000100, "fxtos">; // fxtos rs2, rd
def FXTOD : F3_14<2, 0b110100, 0b010001000, "fxtod">; // fxtod rs2, rd
def FXTOQ : F3_14<2, 0b110100, 0b010001100, "fxtoq">; // fxtoq rs2, rd
def FITOS : F3_14<2, 0b110100, 0b011000100, "fitos">; // fitos rs2, rd
def FITOD : F3_14<2, 0b110100, 0b011001000, "fitod">; // fitod rs2, rd
def FITOQ : F3_14<2, 0b110100, 0b011001100, "fitoq">; // fitoq rs2, rd
// Section A.17: Floating-Point Move - p164
def FMOVS : F3_14<2, 0b110100, 0b000000001, "fmovs">; // fmovs r, r
def FMOVD : F3_14<2, 0b110100, 0b000000010, "fmovs">; // fmovd r, r
//def FMOVQ : F3_14<2, 0b110100, 0b000000011, "fmovs">; // fmovq r, r
def FNEGS : F3_14<2, 0b110100, 0b000000101, "fnegs">; // fnegs r, r
def FNEGD : F3_14<2, 0b110100, 0b000000110, "fnegs">; // fnegs r, r
//def FNEGQ : F3_14<2, 0b110100, 0b000000111, "fnegs">; // fnegs r, r
def FABSS : F3_14<2, 0b110100, 0b000001001, "fabss">; // fabss r, r
def FABSD : F3_14<2, 0b110100, 0b000001010, "fabss">; // fabss r, r
//def FABSQ : F3_14<2, 0b110100, 0b000001011, "fabss">; // fabss r, r
// Section A.18: Floating-Point Multiply and Divide - p165
def FMULS : F3_16<2, 0b110100, 0b001001001, "fmuls">; // fmuls r, r, r
def FMULD : F3_16<2, 0b110100, 0b001001010, "fmuld">; // fmuld r, r, r
def FMULQ : F3_16<2, 0b110100, 0b001001011, "fmulq">; // fmulq r, r, r
def FSMULD : F3_16<2, 0b110100, 0b001101001, "fsmuld">; // fsmuls r, r, r
def FDMULQ : F3_16<2, 0b110100, 0b001101110, "fdmulq">; // fdmuls r, r, r
def FDIVS : F3_16<2, 0b110100, 0b001001101, "fdivs">; // fdivs r, r, r
def FDIVD : F3_16<2, 0b110100, 0b001001110, "fdivs">; // fdivd r, r, r
def FDIVQ : F3_16<2, 0b110100, 0b001001111, "fdivs">; // fdivq r, r, r
// Section A.19: Floating-Point Square Root - p166
def FSQRTS : F3_14<2, 0b110100, 0b000101001, "fsqrts">; // fsqrts r, r
def FSQRTD : F3_14<2, 0b110100, 0b000101010, "fsqrts">; // fsqrts r, r
def FSQRTQ : F3_14<2, 0b110100, 0b000101011, "fsqrts">; // fsqrts r, r
// A.20: Flush Instruction Memory - p167
// Not currently used
// A.21: Flush Register Windows - p169
// Not currently used
// A.22: Illegal instruction Trap - p170
// Not currently used
// A.23: Implementation-Dependent Instructions - p171
// Not currently used
// Section A.24: Jump and Link - p172
// Mimicking the SparcV9's instr def...
def JMPLCALLr : F3_1<2, 0b111000, "jmpl">; // jmpl [rs1+rs2], rd
def JMPLCALLi : F3_2<2, 0b111000, "jmpl">; // jmpl [rs1+imm], rd
def JMPLRETr : F3_1<2, 0b111000, "jmpl">; // jmpl [rs1+rs2], rd
def JMPLRETi : F3_2<2, 0b111000, "jmpl">; // jmpl [rs1+imm], rd
// Section A.25: Load Floating-Point - p173
def LDFr : F3_1<3, 0b100000, "ld">; // ld [rs1+rs2], rd
def LDFi : F3_2<3, 0b100000, "ld">; // ld [rs1+imm], rd
def LDDFr : F3_1<3, 0b100011, "ldd">; // ldd [rs1+rs2], rd
def LDDFi : F3_2<3, 0b100011, "ldd">; // ldd [rs1+imm], rd
def LDQFr : F3_1<3, 0b100010, "ldq">; // ldq [rs1+rs2], rd
def LDQFi : F3_2<3, 0b100010, "ldq">; // ldq [rs1+imm], rd
let isDeprecated = 1 in {
let rd = 0 in {
def LDFSRr : F3_1<3, 0b100001, "ld">; // ld [rs1+rs2], rd
def LDFSRi : F3_2<3, 0b100001, "ld">; // ld [rs1+imm], rd
}
}
let rd = 1 in {
def LDXFSRr : F3_1<3, 0b100001, "ldx">; // ldx [rs1+rs2], rd
def LDXFSRi : F3_2<3, 0b100001, "ldx">; // ldx [rs1+imm], rd
}
// Section A.27: Load Integer - p178
def LDSBr : F3_1<3, 0b001001, "ldsb">; // ldsb [rs1+rs2], rd
def LDSBi : F3_2<3, 0b001001, "ldsb">; // ldsb [rs1+imm], rd
def LDSHr : F3_1<3, 0b001010, "ldsh">; // ldsh [rs1+rs2], rd
def LDSHi : F3_2<3, 0b001010, "ldsh">; // ldsh [rs1+imm], rd
def LDSWr : F3_1<3, 0b001000, "ldsw">; // ldsh [rs1+rs2], rd
def LDSWi : F3_2<3, 0b001000, "ldsw">; // ldsh [rs1+imm], rd
def LDUBr : F3_1<3, 0b000001, "ldub">; // ldub [rs1+rs2], rd
def LDUBi : F3_2<3, 0b000001, "ldub">; // ldub [rs1+imm], rd
def LDUHr : F3_1<3, 0b000010, "lduh">; // lduh [rs1+rs2], rd
def LDUHi : F3_2<3, 0b000010, "lduh">; // lduh [rs1+imm], rd
// synonym: LD
def LDUWr : F3_1<3, 0b000000, "lduw">; // lduw [rs1+rs2], rd
def LDUWi : F3_2<3, 0b000000, "lduw">; // lduw [rs1+imm], rd
def LDXr : F3_1<3, 0b001011, "ldx">; // ldx [rs1+rs2], rd
def LDXi : F3_2<3, 0b001011, "ldx">; // ldx [rs1+imm], rd
/*
let isDeprecated = 1 in {
def LDDr : F3_1<3, 0b000011, "ldd">; // ldd [rs1+rs2], rd
def LDDi : F3_2<3, 0b000011, "ldd">; // ldd [rs1+imm], rd
}
*/
// Section A.31: Logical operations
def ANDr : F3_1<2, 0b000001, "and">; // and rs1, rs2, rd
def ANDi : F3_2<2, 0b000001, "and">; // and rs1, imm, rd
def ANDccr : F3_1<2, 0b010001, "andcc">; // andcc rs1, rs2, rd
def ANDcci : F3_2<2, 0b010001, "andcc">; // andcc rs1, imm, rd
def ANDNr : F3_1<2, 0b000101, "andn">; // andn rs1, rs2, rd
def ANDNi : F3_2<2, 0b000101, "andn">; // andn rs1, imm, rd
def ANDNccr : F3_1<2, 0b010101, "andncc">; // andncc rs1, rs2, rd
def ANDNcci : F3_2<2, 0b010101, "andncc">; // andncc rs1, imm, rd
def ORr : F3_1<2, 0b000010, "or">; // or rs1, rs2, rd
def ORi : F3_2<2, 0b000010, "or">; // or rs1, imm, rd
def ORccr : F3_1<2, 0b010010, "orcc">; // orcc rs1, rs2, rd
def ORcci : F3_2<2, 0b010010, "orcc">; // orcc rs1, imm, rd
def ORNr : F3_1<2, 0b000110, "orn">; // orn rs1, rs2, rd
def ORNi : F3_2<2, 0b000110, "orn">; // orn rs1, imm, rd
def ORNccr : F3_1<2, 0b010110, "orncc">; // orncc rs1, rs2, rd
def ORNcci : F3_2<2, 0b010110, "orncc">; // orncc rs1, imm, rd
def XORr : F3_1<2, 0b000011, "xor">; // xor rs1, rs2, rd
def XORi : F3_2<2, 0b000011, "xor">; // xor rs1, imm, rd
def XORccr : F3_1<2, 0b010011, "xorcc">; // xorcc rs1, rs2, rd
def XORcci : F3_2<2, 0b010011, "xorcc">; // xorcc rs1, imm, rd
def XNORr : F3_1<2, 0b000111, "xnor">; // xnor rs1, rs2, rd
def XNORi : F3_2<2, 0b000111, "xnor">; // xnor rs1, imm, rd
def XNORccr : F3_1<2, 0b010111, "xnorcc">; // xnorcc rs1, rs2, rd
def XNORcci : F3_2<2, 0b010111, "xnorcc">; // xnorcc rs1, imm, rd
// Section A.32: Memory Barrier - p186
// Not currently used in the SparcV9 backend
// Section A.33: Move Floating-Point Register on Condition (FMOVcc)
// ======================= Single Floating Point ======================
// For integer condition codes
def FMOVSA : F4_7<2, 0b110101, 0b1000, 0b000001, "fmovsa">; // fmovsa cc, r, r
def FMOVSN : F4_7<2, 0b110101, 0b0000, 0b000001, "fmovsn">; // fmovsn cc, r, r
def FMOVSNE : F4_7<2, 0b110101, 0b1001, 0b000001, "fmovsne">; // fmovsne cc, r, r
def FMOVSE : F4_7<2, 0b110101, 0b0000, 0b000001, "fmovse">; // fmovse cc, r, r
def FMOVSG : F4_7<2, 0b110101, 0b1010, 0b000001, "fmovsg">; // fmovsg cc, r, r
def FMOVSLE : F4_7<2, 0b110101, 0b0000, 0b000001, "fmovsle">; // fmovsle cc, r, r
def FMOVSGE : F4_7<2, 0b110101, 0b1011, 0b000001, "fmovsge">; // fmovsge cc, r, r
def FMOVSL : F4_7<2, 0b110101, 0b0011, 0b000001, "fmovsl">; // fmovsl cc, r, r
def FMOVSGU : F4_7<2, 0b110101, 0b1100, 0b000001, "fmovsgu">; // fmovsgu cc, r, r
def FMOVSLEU : F4_7<2, 0b110101, 0b0100, 0b000001, "fmovsleu">; // fmovsleu cc, r, r
def FMOVSCC : F4_7<2, 0b110101, 0b1101, 0b000001, "fmovscc">; // fmovscc cc, r, r
def FMOVSCS : F4_7<2, 0b110101, 0b0101, 0b000001, "fmovscs">; // fmovscs cc, r, r
def FMOVSPOS : F4_7<2, 0b110101, 0b1110, 0b000001, "fmovspos">; // fmovspos cc, r, r
def FMOVSNEG : F4_7<2, 0b110101, 0b0110, 0b000001, "fmovsneg">; // fmovsneg cc, r, r
def FMOVSVC : F4_7<2, 0b110101, 0b1111, 0b000001, "fmovsvc">; // fmovsvc cc, r, r
def FMOVSVS : F4_7<2, 0b110101, 0b0111, 0b000001, "fmovsvs">; // fmovsvs cc, r, r
// For floating-point condition codes
def FMOVSFA : F4_7<2, 0b110101, 0b0100, 0b000001, "fmovsfa">; // fmovsfa cc,r,r
def FMOVSFN : F4_7<2, 0b110101, 0b0000, 0b000001, "fmovsfn">; // fmovsfa cc,r,r
def FMOVSFU : F4_7<2, 0b110101, 0b0111, 0b000001, "fmovsfu">; // fmovsfu cc,r,r
def FMOVSFG : F4_7<2, 0b110101, 0b0110, 0b000001, "fmovsfg">; // fmovsfg cc,r,r
def FMOVSFUG : F4_7<2, 0b110101, 0b0101, 0b000001, "fmovsfug">; // fmovsfug cc,r,r
def FMOVSFL : F4_7<2, 0b110101, 0b0100, 0b000001, "fmovsfl">; // fmovsfl cc,r,r
def FMOVSFUL : F4_7<2, 0b110101, 0b0011, 0b000001, "fmovsful">; // fmovsful cc,r,r
def FMOVSFLG : F4_7<2, 0b110101, 0b0010, 0b000001, "fmovsflg">; // fmovsflg cc,r,r
def FMOVSFNE : F4_7<2, 0b110101, 0b0001, 0b000001, "fmovsfne">; // fmovsfne cc,r,r
def FMOVSFE : F4_7<2, 0b110101, 0b1001, 0b000001, "fmovsfe">; // fmovsfe cc,r,r
def FMOVSFUE : F4_7<2, 0b110101, 0b1010, 0b000001, "fmovsfue">; // fmovsfue cc,r,r
def FMOVSFGE : F4_7<2, 0b110101, 0b1011, 0b000001, "fmovsge">; // fmovsge cc,r,r
def FMOVSFUGE : F4_7<2, 0b110101, 0b1100, 0b000001, "fmovsfuge">;// fmovsfuge cc,r,r
def FMOVSFLE : F4_7<2, 0b110101, 0b1101, 0b000001, "fmovsfle">; // fmovsfle cc,r,r
def FMOVSFULE : F4_7<2, 0b110101, 0b1110, 0b000001, "fmovsfule">;// fmovsfule cc,r,r
def FMOVSFO : F4_7<2, 0b110101, 0b1111, 0b000001, "fmovsfo">; // fmovsfo cc,r,r
// ======================= Double Floating Point ======================
// For integer condition codes
def FMOVDA : F4_7<2, 0b110101, 0b1000, 0b000010, "fmovda">; // fmovda cc, r, r
def FMOVDN : F4_7<2, 0b110101, 0b0000, 0b000010, "fmovdn">; // fmovdn cc, r, r
def FMOVDNE : F4_7<2, 0b110101, 0b1001, 0b000010, "fmovdne">; // fmovdne cc, r, r
def FMOVDE : F4_7<2, 0b110101, 0b0000, 0b000010, "fmovde">; // fmovde cc, r, r
def FMOVDG : F4_7<2, 0b110101, 0b1010, 0b000010, "fmovdg">; // fmovdg cc, r, r
def FMOVDLE : F4_7<2, 0b110101, 0b0000, 0b000010, "fmovdle">; // fmovdle cc, r, r
def FMOVDGE : F4_7<2, 0b110101, 0b1011, 0b000010, "fmovdge">; // fmovdge cc, r, r
def FMOVDL : F4_7<2, 0b110101, 0b0011, 0b000010, "fmovdl">; // fmovdl cc, r, r
def FMOVDGU : F4_7<2, 0b110101, 0b1100, 0b000010, "fmovdgu">; // fmovdgu cc, r, r
def FMOVDLEU : F4_7<2, 0b110101, 0b0100, 0b000010, "fmovdleu">; // fmovdleu cc, r, r
def FMOVDCC : F4_7<2, 0b110101, 0b1101, 0b000010, "fmovdcc">; // fmovdcc cc, r, r
def FMOVDCS : F4_7<2, 0b110101, 0b0101, 0b000010, "fmovdcs">; // fmovdcs cc, r, r
def FMOVDPOS : F4_7<2, 0b110101, 0b1110, 0b000010, "fmovdpos">; // fmovdpos cc, r, r
def FMOVDNEG : F4_7<2, 0b110101, 0b0110, 0b000010, "fmovdneg">; // fmovdneg cc, r, r
def FMOVDVC : F4_7<2, 0b110101, 0b1111, 0b000010, "fmovdvc">; // fmovdvc cc, r, r
def FMOVDVS : F4_7<2, 0b110101, 0b0111, 0b000010, "fmovdvs">; // fmovdvs cc, r, r
// For floating-point condition codes
def FMOVDFA : F4_7<2, 0b110101, 0b0100, 0b000010, "fmovdfa">; // fmovdfa cc,r,r
def FMOVDFN : F4_7<2, 0b110101, 0b0000, 0b000010, "fmovdfn">; // fmovdfa cc,r,r
def FMOVDFU : F4_7<2, 0b110101, 0b0111, 0b000010, "fmovdfu">; // fmovdfu cc,r,r
def FMOVDFG : F4_7<2, 0b110101, 0b0110, 0b000010, "fmovdfg">; // fmovdfg cc,r,r
def FMOVDFUG : F4_7<2, 0b110101, 0b0101, 0b000010, "fmovdfug">; // fmovdfug cc,r,r
def FMOVDFL : F4_7<2, 0b110101, 0b0100, 0b000010, "fmovdfl">; // fmovdfl cc,r,r
def FMOVDFUL : F4_7<2, 0b110101, 0b0011, 0b000010, "fmovdful">; // fmovdful cc,r,r
def FMOVDFLG : F4_7<2, 0b110101, 0b0010, 0b000010, "fmovdflg">; // fmovdflg cc,r,r
def FMOVDFNE : F4_7<2, 0b110101, 0b0001, 0b000010, "fmovdfne">; // fmovdfne cc,r,r
def FMOVDFE : F4_7<2, 0b110101, 0b1001, 0b000010, "fmovdfe">; // fmovdfe cc,r,r
def FMOVDFUE : F4_7<2, 0b110101, 0b1010, 0b000010, "fmovdfue">; // fmovdfue cc,r,r
def FMOVDFGE : F4_7<2, 0b110101, 0b1011, 0b000010, "fmovdge">; // fmovdge cc,r,r
def FMOVDFUGE : F4_7<2, 0b110101, 0b1100, 0b000010, "fmovdfuge">;// fmovdfuge cc,r,r
def FMOVDFLE : F4_7<2, 0b110101, 0b1101, 0b000010, "fmovdfle">; // fmovdfle cc,r,r
def FMOVDFULE : F4_7<2, 0b110101, 0b1110, 0b000010, "fmovdfule">;// fmovdfule cc,r,r
def FMOVDFO : F4_7<2, 0b110101, 0b1111, 0b000010, "fmovdfo">; // fmovdfo cc,r,r
// ======================= Quad Floating Point ======================
// For integer condition codes
def FMOVQA : F4_7<2, 0b110101, 0b1000, 0b000011, "fmovqa">; // fmovqa cc, r, r
def FMOVQN : F4_7<2, 0b110101, 0b0000, 0b000011, "fmovqn">; // fmovqn cc, r, r
def FMOVQNE : F4_7<2, 0b110101, 0b1001, 0b000011, "fmovqne">; // fmovqne cc, r, r
def FMOVQE : F4_7<2, 0b110101, 0b0000, 0b000011, "fmovqe">; // fmovqe cc, r, r
def FMOVQG : F4_7<2, 0b110101, 0b1010, 0b000011, "fmovqg">; // fmovqg cc, r, r
def FMOVQLE : F4_7<2, 0b110101, 0b0000, 0b000011, "fmovqle">; // fmovqle cc, r, r
def FMOVQGE : F4_7<2, 0b110101, 0b1011, 0b000011, "fmovqge">; // fmovqge cc, r, r
def FMOVQL : F4_7<2, 0b110101, 0b0011, 0b000011, "fmovql">; // fmovql cc, r, r
def FMOVQGU : F4_7<2, 0b110101, 0b1100, 0b000011, "fmovqgu">; // fmovqgu cc, r, r
def FMOVQLEU : F4_7<2, 0b110101, 0b0100, 0b000011, "fmovqleu">; // fmovqleu cc, r, r
def FMOVQCC : F4_7<2, 0b110101, 0b1101, 0b000011, "fmovqcc">; // fmovqcc cc, r, r
def FMOVQCS : F4_7<2, 0b110101, 0b0101, 0b000011, "fmovqcs">; // fmovqcs cc, r, r
def FMOVQPOS : F4_7<2, 0b110101, 0b1110, 0b000011, "fmovqpos">; // fmovqpos cc, r, r
def FMOVQNEG : F4_7<2, 0b110101, 0b0110, 0b000011, "fmovqneg">; // fmovqneg cc, r, r
def FMOVQVC : F4_7<2, 0b110101, 0b1111, 0b000011, "fmovqvc">; // fmovqvc cc, r, r
def FMOVQVS : F4_7<2, 0b110101, 0b0111, 0b000011, "fmovqvs">; // fmovqvs cc, r, r
// For floating-point condition codes
def FMOVQFA : F4_7<2, 0b110101, 0b0100, 0b000011, "fmovqfa">; // fmovqfa cc,r,r
def FMOVQFN : F4_7<2, 0b110101, 0b0000, 0b000011, "fmovqfn">; // fmovqfa cc,r,r
def FMOVQFU : F4_7<2, 0b110101, 0b0111, 0b000011, "fmovqfu">; // fmovqfu cc,r,r
def FMOVQFG : F4_7<2, 0b110101, 0b0110, 0b000011, "fmovqfg">; // fmovqfg cc,r,r
def FMOVQFUG : F4_7<2, 0b110101, 0b0101, 0b000011, "fmovqfug">; // fmovqfug cc,r,r
def FMOVQFL : F4_7<2, 0b110101, 0b0100, 0b000011, "fmovqfl">; // fmovqfl cc,r,r
def FMOVQFUL : F4_7<2, 0b110101, 0b0011, 0b000011, "fmovqful">; // fmovqful cc,r,r
def FMOVQFLG : F4_7<2, 0b110101, 0b0010, 0b000011, "fmovqflg">; // fmovqflg cc,r,r
def FMOVQFNE : F4_7<2, 0b110101, 0b0001, 0b000011, "fmovqfne">; // fmovqfne cc,r,r
def FMOVQFE : F4_7<2, 0b110101, 0b1001, 0b000011, "fmovqfe">; // fmovqfe cc,r,r
def FMOVQFUE : F4_7<2, 0b110101, 0b1010, 0b000011, "fmovqfue">; // fmovqfue cc,r,r
def FMOVQFGE : F4_7<2, 0b110101, 0b1011, 0b000011, "fmovqge">; // fmovqge cc,r,r
def FMOVQFUGE : F4_7<2, 0b110101, 0b1100, 0b000011, "fmovqfuge">;// fmovqfuge cc,r,r
def FMOVQFLE : F4_7<2, 0b110101, 0b1101, 0b000011, "fmovqfle">; // fmovqfle cc,r,r
def FMOVQFULE : F4_7<2, 0b110101, 0b1110, 0b000011, "fmovqfule">;// fmovqfule cc,r,r
def FMOVQFO : F4_7<2, 0b110101, 0b1111, 0b000011, "fmovqfo">; // fmovqfo cc,r,r
// Section A.34: Move FP Register on Integer Register condition (FMOVr) - p192
def FMOVRSZ : F4_6<2, 0b110101, 0b001, 0b00101, "fmovrsz">; //fmovsrz r,r,rd
def FMOVRSLEZ : F4_6<2, 0b110101, 0b010, 0b00101, "fmovrslez">;//fmovsrz r,r,rd
def FMOVRSLZ : F4_6<2, 0b110101, 0b011, 0b00101, "fmovrslz">; //fmovsrz r,r,rd
def FMOVRSNZ : F4_6<2, 0b110101, 0b101, 0b00101, "fmovrsne">; //fmovsrz r,r,rd
def FMOVRSGZ : F4_6<2, 0b110101, 0b110, 0b00101, "fmovrsgz">; //fmovsrz r,r,rd
def FMOVRSGEZ : F4_6<2, 0b110101, 0b111, 0b00101, "fmovrsgez">;//fmovsrz r,r,rd
def FMOVRDZ : F4_6<2, 0b110101, 0b001, 0b00110, "fmovrdz">; //fmovsrz r,r,rd
def FMOVRDLEZ : F4_6<2, 0b110101, 0b010, 0b00110, "fmovrdlez">;//fmovsrz r,r,rd
def FMOVRDLZ : F4_6<2, 0b110101, 0b011, 0b00110, "fmovrdlz">; //fmovsrz r,r,rd
def FMOVRDNZ : F4_6<2, 0b110101, 0b101, 0b00110, "fmovrdne">; //fmovsrz r,r,rd
def FMOVRDGZ : F4_6<2, 0b110101, 0b110, 0b00110, "fmovrdgz">; //fmovsrz r,r,rd
def FMOVRDGEZ : F4_6<2, 0b110101, 0b111, 0b00110, "fmovrdgez">;//fmovsrz r,r,rd
def FMOVRQZ : F4_6<2, 0b110101, 0b001, 0b00111, "fmovrqz">; //fmovsrz r,r,rd
def FMOVRQLEZ : F4_6<2, 0b110101, 0b010, 0b00111, "fmovrqlez">;//fmovsrz r,r,rd
def FMOVRQLZ : F4_6<2, 0b110101, 0b011, 0b00111, "fmovrqlz">; //fmovsrz r,r,rd
def FMOVRQNZ : F4_6<2, 0b110101, 0b101, 0b00111, "fmovrqne">; //fmovsrz r,r,rd
def FMOVRQGZ : F4_6<2, 0b110101, 0b110, 0b00111, "fmovrqgz">; //fmovsrz r,r,rd
def FMOVRQGEZ : F4_6<2, 0b110101, 0b111, 0b00111, "fmovrqgez">;//fmovsrz r,r,rd
// Section A.35: Move Integer Register on Condition (MOVcc) - p194
// For integer condition codes
def MOVAr : F4_3<2, 0b101100, 0b1000, "mova">; // mova i/xcc, rs2, rd
def MOVAi : F4_4<2, 0b101100, 0b1000, "mova">; // mova i/xcc, imm, rd
def MOVNr : F4_3<2, 0b101100, 0b0000, "movn">; // movn i/xcc, rs2, rd
def MOVNi : F4_4<2, 0b101100, 0b0000, "movn">; // movn i/xcc, imm, rd
def MOVNEr : F4_3<2, 0b101100, 0b1001, "movne">; // movne i/xcc, rs2, rd
def MOVNEi : F4_4<2, 0b101100, 0b1001, "movne">; // movne i/xcc, imm, rd
def MOVEr : F4_3<2, 0b101100, 0b0001, "move">; // move i/xcc, rs2, rd
def MOVEi : F4_4<2, 0b101100, 0b0001, "move">; // move i/xcc, imm, rd
def MOVGr : F4_3<2, 0b101100, 0b1010, "movg">; // movg i/xcc, rs2, rd
def MOVGi : F4_4<2, 0b101100, 0b1010, "movg">; // movg i/xcc, imm, rd
def MOVLEr : F4_3<2, 0b101100, 0b0010, "movle">; // movle i/xcc, rs2, rd
def MOVLEi : F4_4<2, 0b101100, 0b0010, "movle">; // movle i/xcc, imm, rd
def MOVGEr : F4_3<2, 0b101100, 0b1011, "movge">; // movge i/xcc, rs2, rd
def MOVGEi : F4_4<2, 0b101100, 0b1011, "movge">; // movge i/xcc, imm, rd
def MOVLr : F4_3<2, 0b101100, 0b0011, "movl">; // movl i/xcc, rs2, rd
def MOVLi : F4_4<2, 0b101100, 0b0011, "movl">; // movl i/xcc, imm, rd
def MOVGUr : F4_3<2, 0b101100, 0b1100, "movgu">; // movgu i/xcc, rs2, rd
def MOVGUi : F4_4<2, 0b101100, 0b1100, "movgu">; // movgu i/xcc, imm, rd
def MOVLEUr : F4_3<2, 0b101100, 0b0100, "movleu">; // movleu i/xcc, rs2, rd
def MOVLEUi : F4_4<2, 0b101100, 0b0100, "movleu">; // movleu i/xcc, imm, rd
def MOVCCr : F4_3<2, 0b101100, 0b1101, "movcc">; // movcc i/xcc, rs2, rd
def MOVCCi : F4_4<2, 0b101100, 0b1101, "movcc">; // movcc i/xcc, imm, rd
def MOVCSr : F4_3<2, 0b101100, 0b0101, "movcs">; // movcs i/xcc, rs2, rd
def MOVCSi : F4_4<2, 0b101100, 0b0101, "movcs">; // movcs i/xcc, imm, rd
def MOVPOSr : F4_3<2, 0b101100, 0b1110, "movpos">; // movpos i/xcc, rs2, rd
def MOVPOSi : F4_4<2, 0b101100, 0b1110, "movpos">; // movpos i/xcc, imm, rd
def MOVNEGr : F4_3<2, 0b101100, 0b0110, "movneg">; // movneg i/xcc, rs2, rd
def MOVNEGi : F4_4<2, 0b101100, 0b0110, "movneg">; // movneg i/xcc, imm, rd
def MOVVCr : F4_3<2, 0b101100, 0b1111, "movvc">; // movvc i/xcc, rs2, rd
def MOVVCi : F4_4<2, 0b101100, 0b1111, "movvc">; // movvc i/xcc, imm, rd
def MOVVSr : F4_3<2, 0b101100, 0b0111, "movvs">; // movvs i/xcc, rs2, rd
def MOVVSi : F4_4<2, 0b101100, 0b0111, "movvs">; // movvs i/xcc, imm, rd
// For floating-point condition codes
def MOVFAr : F4_3<2, 0b101100, 0b1000, "movfa">; // movfa i/xcc, rs2, rd
def MOVFAi : F4_4<2, 0b101100, 0b1000, "movfa">; // movfa i/xcc, imm, rd
def MOVFNr : F4_3<2, 0b101100, 0b0000, "movfn">; // movfn i/xcc, rs2, rd
def MOVFNi : F4_4<2, 0b101100, 0b0000, "movfn">; // movfn i/xcc, imm, rd
def MOVFUr : F4_3<2, 0b101100, 0b0111, "movfu">; // movfu i/xcc, rs2, rd
def MOVFUi : F4_4<2, 0b101100, 0b0111, "movfu">; // movfu i/xcc, imm, rd
def MOVFGr : F4_3<2, 0b101100, 0b0110, "movfg">; // movfg i/xcc, rs2, rd
def MOVFGi : F4_4<2, 0b101100, 0b0110, "movfg">; // movfg i/xcc, imm, rd
def MOVFUGr : F4_3<2, 0b101100, 0b0101, "movfug">; // movfug i/xcc, rs2, rd
def MOVFUGi : F4_4<2, 0b101100, 0b0101, "movfug">; // movfug i/xcc, imm, rd
def MOVFLr : F4_3<2, 0b101100, 0b0100, "movfl">; // movfl i/xcc, rs2, rd
def MOVFLi : F4_4<2, 0b101100, 0b0100, "movfl">; // movfl i/xcc, imm, rd
def MOVFULr : F4_3<2, 0b101100, 0b0011, "movful">; // movful i/xcc, rs2, rd
def MOVFULi : F4_4<2, 0b101100, 0b0011, "movful">; // movful i/xcc, imm, rd
def MOVFLGr : F4_3<2, 0b101100, 0b0010, "movflg">; // movflg i/xcc, rs2, rd
def MOVFLGi : F4_4<2, 0b101100, 0b0010, "movflg">; // movflg i/xcc, imm, rd
def MOVFNEr : F4_3<2, 0b101100, 0b0001, "movfne">; // movfne i/xcc, rs2, rd
def MOVFNEi : F4_4<2, 0b101100, 0b0001, "movfne">; // movfne i/xcc, imm, rd
def MOVFEr : F4_3<2, 0b101100, 0b1001, "movfe">; // movfe i/xcc, rs2, rd
def MOVFEi : F4_4<2, 0b101100, 0b1001, "movfe">; // movfe i/xcc, imm, rd
def MOVFUEr : F4_3<2, 0b101100, 0b1010, "movfue">; // movfue i/xcc, rs2, rd
def MOVFUEi : F4_4<2, 0b101100, 0b1010, "movfue">; // movfue i/xcc, imm, rd
def MOVFGEr : F4_3<2, 0b101100, 0b1011, "movfge">; // movfge i/xcc, rs2, rd
def MOVFGEi : F4_4<2, 0b101100, 0b1011, "movfge">; // movfge i/xcc, imm, rd
def MOVFUGEr : F4_3<2, 0b101100, 0b1100, "movfuge">; // movfuge i/xcc, rs2, rd
def MOVFUGEi : F4_4<2, 0b101100, 0b1100, "movfuge">; // movfuge i/xcc, imm, rd
def MOVFLEr : F4_3<2, 0b101100, 0b1101, "movfle">; // movfle i/xcc, rs2, rd
def MOVFLEi : F4_4<2, 0b101100, 0b1101, "movfle">; // movfle i/xcc, imm, rd
def MOVFULEr : F4_3<2, 0b101100, 0b1110, "movfule">; // movfule i/xcc, rs2, rd
def MOVFULEi : F4_4<2, 0b101100, 0b1110, "movfule">; // movfule i/xcc, imm, rd
def MOVFOr : F4_3<2, 0b101100, 0b1111, "movfo">; // movfo i/xcc, rs2, rd
def MOVFOi : F4_4<2, 0b101100, 0b1111, "movfo">; // movfo i/xcc, imm, rd
// Section A.36: Move Integer Register on Register Condition (MOVR) - p198
def MOVRZr : F3_5<2, 0b101111, 0b001, "movrz">; // movrz rs1, rs2, rd
def MOVRZi : F3_6<2, 0b101111, 0b001, "movrz">; // movrz rs1, imm, rd
def MOVRLEZr : F3_5<2, 0b101111, 0b010, "movrlez">; // movrlez rs1, rs2, rd
def MOVRLEZi : F3_6<2, 0b101111, 0b010, "movrlez">; // movrlez rs1, imm, rd
def MOVRLZr : F3_5<2, 0b101111, 0b011, "movrlz">; // movrlz rs1, rs2, rd
def MOVRLZi : F3_6<2, 0b101111, 0b011, "movrlz">; // movrlz rs1, imm, rd
def MOVRNZr : F3_5<2, 0b101111, 0b101, "movrnz">; // movrnz rs1, rs2, rd
def MOVRNZi : F3_6<2, 0b101111, 0b101, "movrnz">; // movrnz rs1, imm, rd
def MOVRGZr : F3_5<2, 0b101111, 0b110, "movrgz">; // movrgz rs1, rs2, rd
def MOVRGZi : F3_6<2, 0b101111, 0b110, "movrgz">; // movrgz rs1, imm, rd
def MOVRGEZr : F3_5<2, 0b101111, 0b111, "movrgez">; // movrgez rs1, rs2, rd
def MOVRGEZi : F3_6<2, 0b101111, 0b111, "movrgez">; // movrgez rs1, imm, rd
// Section A.37: Multiply and Divide (64-bit) - p199
def MULXr : F3_1<2, 0b001001, "mulx">; // mulx r, r, r
def MULXi : F3_2<2, 0b001001, "mulx">; // mulx r, i, r
def SDIVXr : F3_1<2, 0b101101, "sdivx">; // sdivx r, r, r
def SDIVXi : F3_2<2, 0b101101, "sdivx">; // sdivx r, i, r
def UDIVXr : F3_1<2, 0b001101, "udivx">; // udivx r, r, r
def UDIVXi : F3_2<2, 0b001101, "udivx">; // udivx r, i, r
// Section A.38: Multiply (32-bit) - p200
// Not used in the SparcV9 backend
/*
let Inst{13} = 0 in {
def UMULr : F3_1<2, 0b001010, "umul">; // umul r, r, r
def SMULr : F3_1<2, 0b001011, "smul">; // smul r, r, r
def UMULCCr : F3_1<2, 0b011010, "umulcc">; // mulcc r, r, r
def SMULCCr : F3_1<2, 0b011011, "smulcc">; // smulcc r, r, r
}
let Inst{13} = 1 in {
def UMULi : F3_1<2, 0b001010, "umul">; // umul r, i, r
def SMULi : F3_1<2, 0b001011, "smul">; // smul r, i, r
def UMULCCi : F3_1<2, 0b011010, "umulcc">; // umulcc r, i, r
def SMULCCi : F3_1<2, 0b011011, "smulcc">; // smulcc r, i, r
}
*/
// Section A.39: Multiply Step - p202
// Not currently used in the SparcV9 backend
// Section A.40: No operation - p204
// NOP is really a pseudo-instruction (special case of SETHI)
let op2 = 0b100 in {
let rd = 0 in {
let imm = 0 in {
def NOP : F2_1<"nop">; // nop
}
}
}
// Section A.41: Population Count - p205
// Not currently used in the SparcV9 backend
// Section A.42: Prefetch Data - p206
// Not currently used in the SparcV9 backend
// Section A.43: Read Privileged Register - p211
// Not currently used in the SparcV9 backend
// Section A.44: Read State Register
// The only instr from this section currently used is RDCCR
let rs1 = 2 in {
def RDCCR : F3_17<2, 0b101000, "rd">; // rd %ccr, r
}
// Section A.46: SAVE and RESTORE - p217
def SAVEr : F3_1<2, 0b111100, "save">; // save r, r, r
def SAVEi : F3_2<2, 0b111100, "save">; // save r, i, r
def RESTOREr : F3_1<2, 0b111101, "restore">; // restore r, r, r
def RESTOREi : F3_2<2, 0b111101, "restore">; // restore r, i, r
// Section A.47: SAVED and RESTORED - p219
// Not currently used in SparcV9 backend
// Section A.48: SETHI - p220
let op2 = 0b100 in {
def SETHI : F2_1<"sethi">; // sethi
}
// Section A.49: Shift - p221
// Not currently used in the SparcV9 backend
/*
uses 5 least significant bits of rs2
let x = 0 in {
def SLLr5 : F3_11<2, 0b100101, "sll">; // sll r, r, r
def SRLr5 : F3_11<2, 0b100110, "srl">; // srl r, r, r
def SRAr5 : F3_11<2, 0b100111, "sra">; // sra r, r, r
def SLLXr5 : F3_11<2, 0b100101, "sllx">; // sllx r, r, r
def SRLXr5 : F3_11<2, 0b100110, "srlx">; // srlx r, r, r
def SRAXr5 : F3_11<2, 0b100111, "srax">; // srax r, r, r
}
*/
// uses 6 least significant bits of rs2
let x = 0 in {
def SLLr5 : F3_11<2, 0b100101, "sll">; // sll r, r, r
def SRLr5 : F3_11<2, 0b100110, "srl">; // srl r, r, r
def SRAr5 : F3_11<2, 0b100111, "sra">; // sra r, r, r
}
let x = 1 in {
def SLLXr6 : F3_11<2, 0b100101, "sllx">; // sllx r, r, r
def SRLXr6 : F3_11<2, 0b100110, "srlx">; // srlx r, r, r
def SRAXr6 : F3_11<2, 0b100111, "srax">; // srax r, r, r
}
def SLLi5 : F3_12<2, 0b100101, "sll">; // sll r, shcnt32, r
def SRLi5 : F3_12<2, 0b100110, "srl">; // srl r, shcnt32, r
def SRAi5 : F3_12<2, 0b100111, "sra">; // sra r, shcnt32, r
def SLLXi6 : F3_13<2, 0b100101, "sllx">; // sllx r, shcnt64, r
def SRLXi6 : F3_13<2, 0b100110, "srlx">; // srlx r, shcnt64, r
def SRAXi6 : F3_13<2, 0b100111, "srax">; // srax r, shcnt64, r
// Section A.50: Sofware-Initiated Reset - p223
// Not currently used in the SparcV9 backend
// Section A.51: Store Barrier - p224
// Not currently used in the SparcV9 backend
// Section A.52: Store Floating-point - p225
// Store instructions all want their rd register first
def STFr : F3_1rd<3, 0b100100, "st">; // st r, [r+r]
def STFi : F3_2rd<3, 0b100100, "st">; // st r, [r+i]
def STDFr : F3_1rd<3, 0b100111, "std">; // std r, [r+r]
def STDFi : F3_2rd<3, 0b100111, "std">; // std r, [r+i]
// Not currently used in the SparcV9 backend
/*
def STQFr : F3_1rd<3, 0b100110, "stq">; // stq r, [r+r]
def STQFi : F3_2rd<3, 0b100110, "stq">; // stq r, [r+i]
*/
// WARNING: We encode %fsr as 1, because we only use STXFSRx, but STFSRx wants
// you to encode %fsr as 0. If STFSRx instrs are ever enabled, this will
// need to be worked around.
/*
let isDeprecated = 1 in {
def STFSRr : F3_1rd<3, 0b100101, "st">; // st %fsr, [r+r]
def STFSRi : F3_2rd<3, 0b100101, "st">; // st %fsr, [r+i]
}
*/
def STXFSRr : F3_1rd<3, 0b100101, "stx">; // stx %fsr, [r+r]
def STXFSRi : F3_2rd<3, 0b100101, "stx">; // stx %fsr, [r+i]
// Section A.53: Store Floating-Point into Alternate Space - p227
// Not currently used in the SparcV9 backend
// Section A.54: Store Integer - p229
// Store instructions all want their rd register first
def STBr : F3_1rd<3, 0b000101, "stb">; // stb r, [r+r]
def STBi : F3_2rd<3, 0b000101, "stb">; // stb r, [r+i]
def STHr : F3_1rd<3, 0b000110, "sth">; // sth r, [r+r]
def STHi : F3_2rd<3, 0b000110, "sth">; // sth r, [r+i]
def STWr : F3_1rd<3, 0b000100, "stw">; // stw r, [r+r]
def STWi : F3_2rd<3, 0b000100, "stw">; // stw r, [r+i]
def STXr : F3_1rd<3, 0b001110, "stx">; // stx r, [r+r]
def STXi : F3_2rd<3, 0b001110, "stx">; // stx r, [r+i]
// Section A.55: Store Integer into Alternate Space - p231
// Not currently used in the SparcV9 backend
// Section A.56: Subtract - p233
def SUBr : F3_1<2, 0b000100, "sub">; // sub r, r, r
def SUBi : F3_2<2, 0b000100, "sub">; // sub r, i, r
def SUBccr : F3_1<2, 0b010100, "subcc">; // subcc r, r, r
def SUBcci : F3_2<2, 0b010100, "subcc">; // subcc r, i, r
def SUBCr : F3_1<2, 0b001100, "subc">; // subc r, r, r
def SUBCi : F3_2<2, 0b001100, "subc">; // subc r, i, r
def SUBCccr : F3_1<2, 0b011100, "subccc">; // subccc r, r, r
def SUBCcci : F3_2<2, 0b011100, "subccc">; // subccc r, i, r
// FIXME: More...?
// Section A.63: Write State Register - p244
let rd = 2 in {
def WRCCRr : F3_1<2, 0b110000, "wr">; // wr r, r, %y/ccr/etc
def WRCCRi : F3_2<2, 0b110000, "wr">; // wr r, i, %y/ccr/etc
}

View File

@ -1,133 +0,0 @@
//===-- SparcV9Internals.h --------------------------------------*- 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 defines stuff that is to be private to the SparcV9 backend, but is
// shared among different portions of the backend.
//
//===----------------------------------------------------------------------===//
#ifndef SPARCV9INTERNALS_H
#define SPARCV9INTERNALS_H
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetSchedInfo.h"
#include "llvm/Target/TargetFrameInfo.h"
#include "SparcV9RegInfo.h"
#include "llvm/Type.h"
#include "SparcV9RegClassInfo.h"
namespace llvm {
class V9LiveRange;
class SparcV9TargetMachine;
class ModulePass;
class GetElementPtrInst;
enum SparcV9InstrSchedClass {
SPARC_NONE, /* Instructions with no scheduling restrictions */
SPARC_IEUN, /* Integer class that can use IEU0 or IEU1 */
SPARC_IEU0, /* Integer class IEU0 */
SPARC_IEU1, /* Integer class IEU1 */
SPARC_FPM, /* FP Multiply or Divide instructions */
SPARC_FPA, /* All other FP instructions */
SPARC_CTI, /* Control-transfer instructions */
SPARC_LD, /* Load instructions */
SPARC_ST, /* Store instructions */
SPARC_SINGLE, /* Instructions that must issue by themselves */
SPARC_INV, /* This should stay at the end for the next value */
SPARC_NUM_SCHED_CLASSES = SPARC_INV
};
//---------------------------------------------------------------------------
// enum SparcV9MachineOpCode.
// const TargetInstrDescriptor SparcV9MachineInstrDesc[]
//
// Purpose:
// Description of UltraSparcV9 machine instructions.
//
//---------------------------------------------------------------------------
namespace V9 {
enum SparcV9MachineOpCode {
#define I(ENUM, OPCODESTRING, NUMOPERANDS, RESULTPOS, MAXIMM, IMMSE, \
NUMDELAYSLOTS, LATENCY, SCHEDCLASS, INSTFLAGS) \
ENUM,
#include "SparcV9Instr.def"
// End-of-array marker
INVALID_OPCODE,
NUM_REAL_OPCODES = PHI, // number of valid opcodes
NUM_TOTAL_OPCODES = INVALID_OPCODE
};
}
// Array of machine instruction descriptions...
extern const TargetInstrDescriptor SparcV9MachineInstrDesc[];
//---------------------------------------------------------------------------
// class SparcV9SchedInfo
//
// Purpose:
// Interface to instruction scheduling information for UltraSPARC.
// The parameter values above are based on UltraSPARC IIi.
//---------------------------------------------------------------------------
class SparcV9SchedInfo: public TargetSchedInfo {
public:
SparcV9SchedInfo(const TargetMachine &tgt);
protected:
virtual void initializeResources();
};
/// createStackSlotsPass - External interface to stack-slots pass that enters 2
/// empty slots at the top of each function stack
///
FunctionPass *createStackSlotsPass(const TargetMachine &TM);
/// Specializes LLVM code for a target machine.
///
FunctionPass *createPreSelectionPass(const TargetMachine &TM);
// DecomposeMultiDimRefs - Convert multi-dimensional references consisting of
// any combination of 2 or more array and structure indices into a sequence of
// instructions (using getelementpr and cast) so that each instruction has at
// most one index (except structure references, which need an extra leading
// index of [0]).
// This pass decomposes all multi-dimensional references in a function.
FunctionPass *createDecomposeMultiDimRefsPass();
// This function decomposes a single instance of such a reference.
// Return value: true if the instruction was replaced; false otherwise.
//
bool DecomposeArrayRef(GetElementPtrInst* GEP);
/// Peephole optimization pass operating on machine code
///
FunctionPass *createPeepholeOptsPass(const TargetMachine &TM);
/// Writes out assembly code for the module, one function at a time
///
FunctionPass *createAsmPrinterPass(std::ostream &Out, TargetMachine &TM);
/// getPrologEpilogInsertionPass - Inserts prolog/epilog code.
///
FunctionPass* createPrologEpilogInsertionPass();
/// getBytecodeAsmPrinterPass - Emits final LLVM bytecode to assembly file.
///
ModulePass* createBytecodeAsmPrinterPass(std::ostream &Out);
FunctionPass *createSparcV9MachineCodeDestructionPass();
} // End llvm namespace
#endif

View File

@ -1,355 +0,0 @@
//===-- SparcJITInfo.cpp - Implement the JIT interfaces for SparcV9 -------===//
//
// 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 JIT interfaces for the SparcV9 target.
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "jit"
#include "SparcV9JITInfo.h"
#include "SparcV9Relocations.h"
#include "llvm/CodeGen/MachineCodeEmitter.h"
#include "llvm/Config/alloca.h"
#include "llvm/Support/Debug.h"
#include <iostream>
using namespace llvm;
/// JITCompilerFunction - This contains the address of the JIT function used to
/// compile a function lazily.
static TargetJITInfo::JITCompilerFn JITCompilerFunction;
/// BUILD_SETHI/BUILD_ORI/BUILD_BA/BUILD_CALL - These macros build sparc machine
/// instructions using lots of magic defined by the Sparc ISA.
#define BUILD_SETHI(RD, C) (((RD) << 25) | (4 << 22) | (C & ((1 << 22)-1)))
#define BUILD_ORI(RS, C, RD) ((2 << 30) | (RD << 25) | (2 << 19) | (RS << 14) |\
(1 << 13) | (C & ((1 << 12)-1)))
#define BUILD_BA(DISP) ((8 << 25) | (2 << 22) | (DISP & ((1 << 22)-1)))
#define BUILD_CALL(OFFSET) ((1 << 30) | (OFFSET & (1 << 30)-1))
static void InsertJumpAtAddr(int64_t JumpTarget, unsigned *Addr) {
// If the target function is close enough to fit into the 19bit disp of
// BA, we should use this version, as it's much cheaper to generate.
int64_t BranchTarget = (JumpTarget-(intptr_t)Addr) >> 2;
if (BranchTarget < (1 << 19) && BranchTarget > -(1 << 19)) {
// ba <target>
Addr[0] = BUILD_BA(BranchTarget);
// nop
Addr[1] = 0x01000000;
} else {
enum { G0 = 0, G1 = 1, G5 = 5 };
// Get address to branch into %g1, using %g5 as a temporary
//
// sethi %uhi(Target), %g5 ;; get upper 22 bits of Target into %g5
Addr[0] = BUILD_SETHI(G5, JumpTarget >> 42);
// or %g5, %ulo(Target), %g5 ;; get 10 lower bits of upper word into %1
Addr[1] = BUILD_ORI(G5, JumpTarget >> 32, G5);
// sllx %g5, 32, %g5 ;; shift those 10 bits to the upper word
Addr[2] = 0x8B297020;
// sethi %hi(Target), %g1 ;; extract bits 10-31 into the dest reg
Addr[3] = BUILD_SETHI(G1, JumpTarget >> 10);
// or %g5, %g1, %g1 ;; get upper word (in %g5) into %g1
Addr[4] = 0x82114001;
// or %g1, %lo(Target), %g1 ;; get lowest 10 bits of Target into %g1
Addr[5] = BUILD_ORI(G1, JumpTarget, G1);
// jmpl %g1, %g0, %g0 ;; indirect branch on %g1
Addr[6] = 0x81C00001;
// nop ;; delay slot
Addr[7] = 0x01000000;
}
}
void SparcV9JITInfo::replaceMachineCodeForFunction (void *Old, void *New) {
InsertJumpAtAddr((intptr_t)New, (unsigned*)Old);
}
static void SaveRegisters(uint64_t DoubleFP[], uint64_t CC[],
uint64_t Globals[]) {
#if defined(__sparcv9)
__asm__ __volatile__ (// Save condition-code registers
"stx %%fsr, %0;\n\t"
"rd %%fprs, %1;\n\t"
"rd %%ccr, %2;\n\t"
: "=m"(CC[0]), "=r"(CC[1]), "=r"(CC[2]));
__asm__ __volatile__ (// Save globals g1 and g5
"stx %%g1, %0;\n\t"
"stx %%g5, %0;\n\t"
: "=m"(Globals[0]), "=m"(Globals[1]));
// GCC says: `asm' only allows up to thirty parameters!
__asm__ __volatile__ (// Save Single/Double FP registers, part 1
"std %%f0, %0;\n\t" "std %%f2, %1;\n\t"
"std %%f4, %2;\n\t" "std %%f6, %3;\n\t"
"std %%f8, %4;\n\t" "std %%f10, %5;\n\t"
"std %%f12, %6;\n\t" "std %%f14, %7;\n\t"
"std %%f16, %8;\n\t" "std %%f18, %9;\n\t"
"std %%f20, %10;\n\t" "std %%f22, %11;\n\t"
"std %%f24, %12;\n\t" "std %%f26, %13;\n\t"
"std %%f28, %14;\n\t" "std %%f30, %15;\n\t"
: "=m"(DoubleFP[ 0]), "=m"(DoubleFP[ 1]),
"=m"(DoubleFP[ 2]), "=m"(DoubleFP[ 3]),
"=m"(DoubleFP[ 4]), "=m"(DoubleFP[ 5]),
"=m"(DoubleFP[ 6]), "=m"(DoubleFP[ 7]),
"=m"(DoubleFP[ 8]), "=m"(DoubleFP[ 9]),
"=m"(DoubleFP[10]), "=m"(DoubleFP[11]),
"=m"(DoubleFP[12]), "=m"(DoubleFP[13]),
"=m"(DoubleFP[14]), "=m"(DoubleFP[15]));
__asm__ __volatile__ (// Save Double FP registers, part 2
"std %%f32, %0;\n\t" "std %%f34, %1;\n\t"
"std %%f36, %2;\n\t" "std %%f38, %3;\n\t"
"std %%f40, %4;\n\t" "std %%f42, %5;\n\t"
"std %%f44, %6;\n\t" "std %%f46, %7;\n\t"
"std %%f48, %8;\n\t" "std %%f50, %9;\n\t"
"std %%f52, %10;\n\t" "std %%f54, %11;\n\t"
"std %%f56, %12;\n\t" "std %%f58, %13;\n\t"
"std %%f60, %14;\n\t" "std %%f62, %15;\n\t"
: "=m"(DoubleFP[16]), "=m"(DoubleFP[17]),
"=m"(DoubleFP[18]), "=m"(DoubleFP[19]),
"=m"(DoubleFP[20]), "=m"(DoubleFP[21]),
"=m"(DoubleFP[22]), "=m"(DoubleFP[23]),
"=m"(DoubleFP[24]), "=m"(DoubleFP[25]),
"=m"(DoubleFP[26]), "=m"(DoubleFP[27]),
"=m"(DoubleFP[28]), "=m"(DoubleFP[29]),
"=m"(DoubleFP[30]), "=m"(DoubleFP[31]));
#else
std::cerr << "ERROR: RUNNING CODE THAT ONLY WORKS ON A SPARCV9 HOST!\n";
abort();
#endif
}
static void RestoreRegisters(uint64_t DoubleFP[], uint64_t CC[],
uint64_t Globals[]) {
#if defined(__sparcv9)
__asm__ __volatile__ (// Restore condition-code registers
"ldx %0, %%fsr;\n\t"
"wr %1, 0, %%fprs;\n\t"
"wr %2, 0, %%ccr;\n\t"
:: "m"(CC[0]), "r"(CC[1]), "r"(CC[2]));
__asm__ __volatile__ (// Restore globals g1 and g5
"ldx %0, %%g1;\n\t"
"ldx %0, %%g5;\n\t"
:: "m"(Globals[0]), "m"(Globals[1]));
// GCC says: `asm' only allows up to thirty parameters!
__asm__ __volatile__ (// Restore Single/Double FP registers, part 1
"ldd %0, %%f0;\n\t" "ldd %1, %%f2;\n\t"
"ldd %2, %%f4;\n\t" "ldd %3, %%f6;\n\t"
"ldd %4, %%f8;\n\t" "ldd %5, %%f10;\n\t"
"ldd %6, %%f12;\n\t" "ldd %7, %%f14;\n\t"
"ldd %8, %%f16;\n\t" "ldd %9, %%f18;\n\t"
"ldd %10, %%f20;\n\t" "ldd %11, %%f22;\n\t"
"ldd %12, %%f24;\n\t" "ldd %13, %%f26;\n\t"
"ldd %14, %%f28;\n\t" "ldd %15, %%f30;\n\t"
:: "m"(DoubleFP[0]), "m"(DoubleFP[1]),
"m"(DoubleFP[2]), "m"(DoubleFP[3]),
"m"(DoubleFP[4]), "m"(DoubleFP[5]),
"m"(DoubleFP[6]), "m"(DoubleFP[7]),
"m"(DoubleFP[8]), "m"(DoubleFP[9]),
"m"(DoubleFP[10]), "m"(DoubleFP[11]),
"m"(DoubleFP[12]), "m"(DoubleFP[13]),
"m"(DoubleFP[14]), "m"(DoubleFP[15]));
__asm__ __volatile__ (// Restore Double FP registers, part 2
"ldd %0, %%f32;\n\t" "ldd %1, %%f34;\n\t"
"ldd %2, %%f36;\n\t" "ldd %3, %%f38;\n\t"
"ldd %4, %%f40;\n\t" "ldd %5, %%f42;\n\t"
"ldd %6, %%f44;\n\t" "ldd %7, %%f46;\n\t"
"ldd %8, %%f48;\n\t" "ldd %9, %%f50;\n\t"
"ldd %10, %%f52;\n\t" "ldd %11, %%f54;\n\t"
"ldd %12, %%f56;\n\t" "ldd %13, %%f58;\n\t"
"ldd %14, %%f60;\n\t" "ldd %15, %%f62;\n\t"
:: "m"(DoubleFP[16]), "m"(DoubleFP[17]),
"m"(DoubleFP[18]), "m"(DoubleFP[19]),
"m"(DoubleFP[20]), "m"(DoubleFP[21]),
"m"(DoubleFP[22]), "m"(DoubleFP[23]),
"m"(DoubleFP[24]), "m"(DoubleFP[25]),
"m"(DoubleFP[26]), "m"(DoubleFP[27]),
"m"(DoubleFP[28]), "m"(DoubleFP[29]),
"m"(DoubleFP[30]), "m"(DoubleFP[31]));
#else
std::cerr << "ERROR: RUNNING CODE THAT ONLY WORKS ON A SPARCV9 HOST!\n";
abort();
#endif
}
static void CompilationCallback() {
// Local space to save the registers
uint64_t DoubleFP[32];
uint64_t CC[3];
uint64_t Globals[2];
SaveRegisters(DoubleFP, CC, Globals);
unsigned *CameFrom = (unsigned*)__builtin_return_address(0);
unsigned *CameFrom1 = (unsigned*)__builtin_return_address(1);
int64_t Target = (intptr_t)JITCompilerFunction(CameFrom);
DEBUG(std::cerr << "In callback! Addr=" << (void*)CameFrom << "\n");
// If we can rewrite the ORIGINAL caller, we eliminate the whole need for a
// trampoline function stub!!
unsigned OrigCallInst = *CameFrom1;
int64_t OrigTarget = (Target-(intptr_t)CameFrom1) >> 2;
if ((OrigCallInst >> 30) == 1 &&
(OrigTarget <= (1 << 30) && OrigTarget >= -(1 << 30))) {
// The original call instruction was CALL <immed>, which means we can
// overwrite it directly, since the offset will fit into 30 bits
*CameFrom1 = BUILD_CALL(OrigTarget);
//++OverwrittenCalls;
} else {
//++UnmodifiedCalls;
}
// Rewrite the call target so that we don't fault every time we execute it.
//
unsigned OrigStubCallInst = *CameFrom;
// Subtract enough to overwrite up to the 'save' instruction
// This depends on whether we made a short call (1 instruction) or the
// farCall (7 instructions)
int Offset = ((OrigStubCallInst >> 30) == 1) ? 1 : 7;
unsigned *CodeBegin = CameFrom - Offset;
// FIXME: __builtin_frame_address doesn't work if frame pointer elimination
// has been performed. Having a variable sized alloca disables frame pointer
// elimination currently, even if it's dead. This is a gross hack.
alloca(42+Offset);
// Make sure that what we're about to overwrite is indeed "save".
if (*CodeBegin != 0x9DE3BF40) {
std::cerr << "About to overwrite smthg not a save instr!";
abort();
}
// Overwrite it
InsertJumpAtAddr(Target, CodeBegin);
// Flush the I-Cache: FLUSH clears out a doubleword at a given address
// Self-modifying code MUST clear out the I-Cache to be portable
#if defined(__sparcv9)
for (int i = -Offset*4, e = 32-((int64_t)Offset*4); i < e; i += 8)
__asm__ __volatile__ ("flush %%i7 + %0" : : "r" (i));
#endif
// Change the return address to re-execute the restore, then the jump.
DEBUG(std::cerr << "Callback returning to: 0x"
<< std::hex << (CameFrom-Offset*4-12) << "\n");
#if defined(__sparcv9)
__asm__ __volatile__ ("sub %%i7, %0, %%i7" : : "r" (Offset*4+12));
#endif
RestoreRegisters(DoubleFP, CC, Globals);
}
/// emitStubForFunction - This method is used by the JIT when it needs to emit
/// the address of a function for a function whose code has not yet been
/// generated. In order to do this, it generates a stub which jumps to the lazy
/// function compiler, which will eventually get fixed to call the function
/// directly.
///
void *SparcV9JITInfo::emitFunctionStub(void *Fn, MachineCodeEmitter &MCE) {
if (Fn != CompilationCallback) {
// If this is just a call to an external function,
MCE.startFunctionStub(4*8);
unsigned *Stub = (unsigned*)(intptr_t)MCE.getCurrentPCValue();
for (unsigned i = 0; i != 8; ++i)
MCE.emitWord(0);
InsertJumpAtAddr((intptr_t)Fn, Stub);
return MCE.finishFunctionStub(0); // 1 instr past the restore
}
MCE.startFunctionStub(44);
MCE.emitWord(0x81e82000); // restore %g0, 0, %g0
MCE.emitWord(0x9DE3BF40); // save %sp, -192, %sp
int64_t CurrPC = MCE.getCurrentPCValue();
int64_t Addr = (intptr_t)Fn;
int64_t CallTarget = (Addr-CurrPC) >> 2;
if (CallTarget < (1 << 29) && CallTarget > -(1 << 29)) {
// call CallTarget
MCE.emitWord((0x01 << 30) | CallTarget);
} else {
enum {G5 = 5, G1 = 1 };
// Otherwise, we need to emit a sequence of instructions to call a distant
// function. We use %g5 as a temporary, and compute the value into %g1
// sethi %uhi(Target), %g5 ;; get upper 22 bits of Target into %g5
MCE.emitWord(BUILD_SETHI(G5, Addr >> 42));
// or %g5, %ulo(Target), %g5 ;; get 10 lower bits of upper word into %1
MCE.emitWord(BUILD_ORI(G5, Addr >> 32, G5));
// sllx %g5, 32, %g5 ;; shift those 10 bits to the upper word
MCE.emitWord(0x8B297020);
// sethi %hi(Target), %g1 ;; extract bits 10-31 into the dest reg
MCE.emitWord(BUILD_SETHI(G1, Addr >> 10));
// or %g5, %g1, %g1 ;; get upper word (in %g5) into %g1
MCE.emitWord(0x82114001);
// or %g1, %lo(Target), %g1 ;; get lowest 10 bits of Target into %g1
MCE.emitWord(BUILD_ORI(G1, Addr, G1));
// call %g1 ;; indirect call on %g1
MCE.emitWord(0x9FC04000);
}
// nop ;; call delay slot
MCE.emitWord(0x1000000);
// FIXME: Should have a restore and return!
MCE.emitWord(0xDEADBEEF); // marker so that we know it's really a stub
return (char*)MCE.finishFunctionStub(0)+4; // 1 instr past the restore
}
TargetJITInfo::LazyResolverFn
SparcV9JITInfo::getLazyResolverFunction(JITCompilerFn F) {
JITCompilerFunction = F;
return CompilationCallback;
}
void SparcV9JITInfo::relocate(void *Function, MachineRelocation *MR,
unsigned NumRelocs, unsigned char* GOTBase) {
for (unsigned i = 0; i != NumRelocs; ++i, ++MR) {
unsigned *RelocPos = (unsigned*)Function + MR->getMachineCodeOffset()/4;
intptr_t ResultPtr = (intptr_t)MR->getResultPointer();
switch ((V9::RelocationType)MR->getRelocationType()) {
default: assert(0 && "Unknown relocation type!");
case V9::reloc_pcrel_call:
ResultPtr = (ResultPtr-(intptr_t)RelocPos) >> 2; // PC relative.
assert((ResultPtr < (1 << 29) && ResultPtr > -(1 << 29)) &&
"reloc_pcrel_call is out of range!");
// The high two bits of the call are always set to 01.
*RelocPos = (1 << 30) | (ResultPtr & ((1 << 30)-1)) ;
break;
case V9::reloc_sethi_hh:
case V9::reloc_sethi_lm:
ResultPtr >>= (MR->getRelocationType() == V9::reloc_sethi_hh ? 32 : 0);
ResultPtr >>= 10;
ResultPtr &= (1 << 22)-1;
*RelocPos |= (unsigned)ResultPtr;
break;
case V9::reloc_or_hm:
case V9::reloc_or_lo:
ResultPtr >>= (MR->getRelocationType() == V9::reloc_or_hm ? 32 : 0);
ResultPtr &= (1 << 12)-1;
*RelocPos |= (unsigned)ResultPtr;
break;
}
}
}

View File

@ -1,62 +0,0 @@
//===- SparcV9JITInfo.h - SparcV9 Target JIT interface ----------*- 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 contains the SparcV9 implementation of the TargetJITInfo class,
// which makes target-specific hooks available to the target-independent
// LLVM JIT compiler.
//
//===----------------------------------------------------------------------===//
#ifndef SPARCV9JITINFO_H
#define SPARCV9JITINFO_H
#include "llvm/Target/TargetJITInfo.h"
namespace llvm {
class TargetMachine;
class SparcV9JITInfo : public TargetJITInfo {
TargetMachine &TM;
public:
SparcV9JITInfo(TargetMachine &tm) : TM(tm) {useGOT = 0;}
/// addPassesToJITCompile - Add passes to the specified pass manager to
/// implement a fast dynamic compiler for this target. Return true if this
/// is not supported for this target.
///
virtual void addPassesToJITCompile(FunctionPassManager &PM);
/// replaceMachineCodeForFunction - Make it so that calling the function
/// whose machine code is at OLD turns into a call to NEW, perhaps by
/// overwriting OLD with a branch to NEW. This is used for self-modifying
/// code.
///
virtual void replaceMachineCodeForFunction (void *Old, void *New);
/// emitFunctionStub - Use the specified MachineCodeEmitter object to emit a
/// small native function that simply calls the function at the specified
/// address. Return the address of the resultant function.
virtual void *emitFunctionStub(void *Fn, MachineCodeEmitter &MCE);
/// getLazyResolverFunction - This method is used to initialize the JIT,
/// giving the target the function that should be used to compile a
/// function, and giving the JIT the target function used to do the lazy
/// resolving.
virtual LazyResolverFn getLazyResolverFunction(JITCompilerFn);
/// relocate - Before the JIT can run a block of code that has been emitted,
/// it must rewrite the code to contain the actual addresses of any
/// referenced global symbols.
virtual void relocate(void *Function, MachineRelocation *MR,
unsigned NumRelocs, unsigned char* GOTBase);
};
}
#endif

View File

@ -1,163 +0,0 @@
//===-- SparcV9PeepholeOpts.cpp -------------------------------------------===//
//
// 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.
//
//===----------------------------------------------------------------------===//
//
// Support for performing several peephole opts in one or a few passes over the
// machine code of a method.
//
//===----------------------------------------------------------------------===//
#include "SparcV9Internals.h"
#include "llvm/BasicBlock.h"
#include "llvm/Pass.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/ADT/STLExtras.h"
namespace llvm {
//************************* Internal Functions *****************************/
static inline void
DeleteInstruction(MachineBasicBlock& mvec,
MachineBasicBlock::iterator& BBI,
const TargetMachine& target) {
// Check if this instruction is in a delay slot of its predecessor.
if (BBI != mvec.begin()) {
const TargetInstrInfo& mii = *target.getInstrInfo();
MachineBasicBlock::iterator predMI = prior(BBI);
if (unsigned ndelay = mii.getNumDelaySlots(predMI->getOpcode())) {
// This instruction is in a delay slot of its predecessor, so
// replace it with a nop. By replacing in place, we save having
// to update the I-I maps.
//
assert(ndelay == 1 && "Not yet handling multiple-delay-slot targets");
BBI->replace(V9::NOP, 0);
return;
}
}
// The instruction is not in a delay slot, so we can simply erase it.
mvec.erase(BBI);
BBI = mvec.end();
}
//******************* Individual Peephole Optimizations ********************/
//----------------------------------------------------------------------------
// Function: IsUselessCopy
// Decide whether a machine instruction is a redundant copy:
// -- ADD with g0 and result and operand are identical, or
// -- OR with g0 and result and operand are identical, or
// -- FMOVS or FMOVD and result and operand are identical.
// Other cases are possible but very rare that they would be useless copies,
// so it's not worth analyzing them.
//----------------------------------------------------------------------------
static bool IsUselessCopy(const TargetMachine &target, const MachineInstr* MI) {
if (MI->getOpcode() == V9::FMOVS || MI->getOpcode() == V9::FMOVD) {
return (// both operands are allocated to the same register
MI->getOperand(0).getReg() == MI->getOperand(1).getReg());
} else if (MI->getOpcode() == V9::ADDr || MI->getOpcode() == V9::ORr ||
MI->getOpcode() == V9::ADDi || MI->getOpcode() == V9::ORi) {
unsigned srcWithDestReg;
for (srcWithDestReg = 0; srcWithDestReg < 2; ++srcWithDestReg)
if (MI->getOperand(srcWithDestReg).hasAllocatedReg() &&
MI->getOperand(srcWithDestReg).getReg()
== MI->getOperand(2).getReg())
break;
if (srcWithDestReg == 2)
return false;
else {
// else source and dest are allocated to the same register
unsigned otherOp = 1 - srcWithDestReg;
return (// either operand otherOp is register %g0
(MI->getOperand(otherOp).hasAllocatedReg() &&
MI->getOperand(otherOp).getReg() ==
target.getRegInfo()->getZeroRegNum()) ||
// or operand otherOp == 0
(MI->getOperand(otherOp).getType()
== MachineOperand::MO_SignExtendedImmed &&
MI->getOperand(otherOp).getImmedValue() == 0));
}
}
else
return false;
}
inline bool
RemoveUselessCopies(MachineBasicBlock& mvec,
MachineBasicBlock::iterator& BBI,
const TargetMachine& target) {
if (IsUselessCopy(target, BBI)) {
DeleteInstruction(mvec, BBI, target);
return true;
}
return false;
}
//************************ Class Implementations **************************/
class PeepholeOpts: public BasicBlockPass {
const TargetMachine &target;
bool visit(MachineBasicBlock& mvec,
MachineBasicBlock::iterator BBI) const;
public:
PeepholeOpts(const TargetMachine &TM): target(TM) { }
bool runOnBasicBlock(BasicBlock &BB); // apply this pass to each BB
virtual const char *getPassName() const { return "Peephole Optimization"; }
// getAnalysisUsage - this pass preserves the CFG
void getAnalysisUsage(AnalysisUsage &AU) const {
AU.setPreservesCFG();
}
};
// Apply a list of peephole optimizations to this machine instruction
// within its local context. They are allowed to delete MI or any
// instruction before MI, but not
//
bool PeepholeOpts::visit(MachineBasicBlock& mvec,
MachineBasicBlock::iterator BBI) const {
// Remove redundant copy instructions
return RemoveUselessCopies(mvec, BBI, target);
}
bool PeepholeOpts::runOnBasicBlock(BasicBlock &BB) {
// Get the machine instructions for this BB
// FIXME: MachineBasicBlock::get() is deprecated, hence inlining the function
const Function *F = BB.getParent();
MachineFunction &MF = MachineFunction::get(F);
MachineBasicBlock *MBB = NULL;
for (MachineFunction::iterator I = MF.begin(), E = MF.end(); I != E; ++I)
if (I->getBasicBlock() == &BB)
MBB = I;
assert(MBB && "MachineBasicBlock object not found for specified block!");
MachineBasicBlock &mvec = *MBB;
for (MachineBasicBlock::iterator I = mvec.begin(), E = mvec.end(); I != E; )
visit(mvec, I++);
return true;
}
/// createPeepholeOptsPass - Public entry point for peephole optimization
///
FunctionPass* createPeepholeOptsPass(const TargetMachine &TM) {
return new PeepholeOpts(TM);
}
} // End llvm namespace

View File

@ -1,308 +0,0 @@
//===- SparcV9PreSelection.cpp - Specialize LLVM code for SparcV9 ---------===//
//
// 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 defines the PreSelection pass which specializes LLVM code for
// the SparcV9 instruction selector, while remaining in legal portable LLVM
// form and preserving type information and type safety. This is meant to enable
// dataflow optimizations on SparcV9-specific operations such as accesses to
// constants, globals, and array indexing.
//
//===----------------------------------------------------------------------===//
#include "SparcV9Internals.h"
#include "SparcV9BurgISel.h"
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Instructions.h"
#include "llvm/Module.h"
#include "llvm/Pass.h"
#include "llvm/Support/InstVisitor.h"
#include "llvm/Support/GetElementPtrTypeIterator.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Transforms/Scalar.h"
#include <algorithm>
using namespace llvm;
namespace {
//===--------------------------------------------------------------------===//
// PreSelection Pass - Specialize LLVM code for the SparcV9 instr. selector.
//
class PreSelection : public FunctionPass, public InstVisitor<PreSelection> {
const TargetInstrInfo &instrInfo;
public:
PreSelection(const TargetMachine &T)
: instrInfo(*T.getInstrInfo()) {}
// runOnFunction - apply this pass to each Function
bool runOnFunction(Function &F) {
visit(F);
return true;
}
const char *getPassName() const { return "SparcV9 Instr. Pre-selection"; }
// These methods do the actual work of specializing code
void visitInstruction(Instruction &I); // common work for every instr.
void visitGetElementPtrInst(GetElementPtrInst &I);
void visitCallInst(CallInst &I);
void visitPHINode(PHINode &PN);
void visitBasicBlock(BasicBlock &BB) {
if (isa<UnreachableInst>(BB.getTerminator())) {
BB.getInstList().pop_back();
const Type *RetTy = BB.getParent()->getReturnType();
Value *RetVal = RetTy == Type::VoidTy ? 0 : UndefValue::get(RetTy);
new ReturnInst(RetVal, &BB);
}
}
// Helper functions for visiting operands of every instruction
//
// visitOperands() works on every operand in [firstOp, lastOp-1].
// If lastOp==0, lastOp defaults to #operands or #incoming Phi values.
//
// visitOneOperand() does all the work for one operand.
//
void visitOperands(Instruction &I, int firstOp=0);
void visitOneOperand(Instruction &I, Value* Op, unsigned opNum,
Instruction& insertBefore);
};
#if 0
// Register the pass...
RegisterPass<PreSelection> X("preselect",
"Specialize LLVM code for a target machine"
createPreselectionPass);
#endif
} // end anonymous namespace
//------------------------------------------------------------------------------
// Helper functions used by methods of class PreSelection
//------------------------------------------------------------------------------
// getGlobalAddr(): Put address of a global into a v. register.
static GetElementPtrInst* getGlobalAddr(Value* ptr, Instruction& insertBefore) {
return (isa<GlobalVariable>(ptr))
? new GetElementPtrInst(ptr,
std::vector<Value*>(1, ConstantSInt::get(Type::LongTy, 0U)),
"addrOfGlobal:" + ptr->getName(), &insertBefore)
: NULL;
}
// Wrapper on Constant::classof to use in find_if
inline static bool nonConstant(const Use& U) {
return ! isa<Constant>(U);
}
static Instruction* DecomposeConstantExpr(ConstantExpr* CE,
Instruction& insertBefore)
{
Value *getArg1, *getArg2;
switch(CE->getOpcode())
{
case Instruction::Cast:
getArg1 = CE->getOperand(0);
if (ConstantExpr* CEarg = dyn_cast<ConstantExpr>(getArg1))
getArg1 = DecomposeConstantExpr(CEarg, insertBefore);
return new CastInst(getArg1, CE->getType(), "constantCast",&insertBefore);
case Instruction::GetElementPtr:
assert(std::find_if(CE->op_begin()+1, CE->op_end(),
nonConstant) == CE->op_end()
&& "All indices in ConstantExpr getelementptr must be constant!");
getArg1 = CE->getOperand(0);
if (ConstantExpr* CEarg = dyn_cast<ConstantExpr>(getArg1))
getArg1 = DecomposeConstantExpr(CEarg, insertBefore);
else if (GetElementPtrInst* gep = getGlobalAddr(getArg1, insertBefore))
getArg1 = gep;
return new GetElementPtrInst(getArg1,
std::vector<Value*>(CE->op_begin()+1, CE->op_end()),
"constantGEP:" + getArg1->getName(), &insertBefore);
case Instruction::Select: {
Value *C, *S1, *S2;
C = CE->getOperand (0);
if (ConstantExpr* CEarg = dyn_cast<ConstantExpr> (C))
C = DecomposeConstantExpr (CEarg, insertBefore);
S1 = CE->getOperand (1);
if (ConstantExpr* CEarg = dyn_cast<ConstantExpr> (S1))
S1 = DecomposeConstantExpr (CEarg, insertBefore);
S2 = CE->getOperand (2);
if (ConstantExpr* CEarg = dyn_cast<ConstantExpr> (S2))
S2 = DecomposeConstantExpr (CEarg, insertBefore);
return new SelectInst (C, S1, S2, "constantSelect", &insertBefore);
}
case Instruction::Shr: {
getArg1 = CE->getOperand(0);
if (ConstantExpr* CEarg = dyn_cast<ConstantExpr>(getArg1))
getArg1 = DecomposeConstantExpr(CEarg, insertBefore);
getArg2 = CE->getOperand(1);
if (ConstantExpr* CEarg = dyn_cast<ConstantExpr>(getArg2))
getArg2 = DecomposeConstantExpr(CEarg, insertBefore);
return new ShiftInst (static_cast<Instruction::OtherOps>(CE->getOpcode()),
getArg1, getArg2,
"constantShr:" + getArg1->getName(), &insertBefore);
}
case Instruction::Shl: {
getArg1 = CE->getOperand(0);
if (ConstantExpr* CEarg = dyn_cast<ConstantExpr>(getArg1))
getArg1 = DecomposeConstantExpr(CEarg, insertBefore);
getArg2 = CE->getOperand(1);
if (ConstantExpr* CEarg = dyn_cast<ConstantExpr>(getArg2))
getArg2 = DecomposeConstantExpr(CEarg, insertBefore);
return new ShiftInst (static_cast<Instruction::OtherOps>(CE->getOpcode()),
getArg1, getArg2,
"constantShl:" + getArg1->getName(), &insertBefore);
}
default: // must be a binary operator
assert(CE->getOpcode() >= Instruction::BinaryOpsBegin &&
CE->getOpcode() < Instruction::BinaryOpsEnd &&
"Unhandled opcode in ConstantExpr");
getArg1 = CE->getOperand(0);
if (ConstantExpr* CEarg = dyn_cast<ConstantExpr>(getArg1))
getArg1 = DecomposeConstantExpr(CEarg, insertBefore);
getArg2 = CE->getOperand(1);
if (ConstantExpr* CEarg = dyn_cast<ConstantExpr>(getArg2))
getArg2 = DecomposeConstantExpr(CEarg, insertBefore);
return BinaryOperator::create((Instruction::BinaryOps) CE->getOpcode(),
getArg1, getArg2,
"constantBinaryOp", &insertBefore);
}
}
static inline bool ConstantTypeMustBeLoaded(const Type* CVT) {
assert(CVT->isPrimitiveType() || isa<PointerType>(CVT));
return !(CVT->isIntegral() || isa<PointerType>(CVT));
}
//------------------------------------------------------------------------------
// Instruction visitor methods to perform instruction-specific operations
//------------------------------------------------------------------------------
inline void
PreSelection::visitOneOperand(Instruction &I, Value* Op, unsigned opNum,
Instruction& insertBefore)
{
assert(&insertBefore != NULL && "Must have instruction to insert before.");
if (GetElementPtrInst* gep = getGlobalAddr(Op, insertBefore)) {
I.setOperand(opNum, gep); // replace global operand
return; // nothing more to do for this op.
}
Constant* CV = dyn_cast<Constant>(Op);
if (CV == NULL)
return;
if (ConstantExpr* CE = dyn_cast<ConstantExpr>(CV)) {
// load-time constant: factor it out so we optimize as best we can
Instruction* computeConst = DecomposeConstantExpr(CE, insertBefore);
I.setOperand(opNum, computeConst); // replace expr operand with result
} else if (ConstantTypeMustBeLoaded(CV->getType())) {
// load address of constant into a register, then load the constant
// this is now done during instruction selection
// the constant will live in the MachineConstantPool later on
} else if (ConstantMayNotFitInImmedField(CV, &I)) {
// put the constant into a virtual register using a cast
CastInst* castI = new CastInst(CV, CV->getType(), "copyConst",
&insertBefore);
I.setOperand(opNum, castI); // replace operand with copy in v.reg.
}
}
/// visitOperands - transform individual operands of all instructions:
/// -- Load "large" int constants into a virtual register. What is large
/// depends on the type of instruction and on the target architecture.
/// -- For any constants that cannot be put in an immediate field,
/// load address into virtual register first, and then load the constant.
///
/// firstOp and lastOp can be used to skip leading and trailing operands.
/// If lastOp is 0, it defaults to #operands or #incoming Phi values.
///
inline void PreSelection::visitOperands(Instruction &I, int firstOp) {
// For any instruction other than PHI, copies go just before the instr.
for (unsigned i = firstOp, e = I.getNumOperands(); i != e; ++i)
visitOneOperand(I, I.getOperand(i), i, I);
}
void PreSelection::visitPHINode(PHINode &PN) {
// For a PHI, operand copies must be before the terminator of the
// appropriate predecessor basic block. Remaining logic is simple
// so just handle PHIs and other instructions separately.
//
for (unsigned i = 0, e = PN.getNumIncomingValues(); i != e; ++i)
visitOneOperand(PN, PN.getIncomingValue(i),
PN.getOperandNumForIncomingValue(i),
*PN.getIncomingBlock(i)->getTerminator());
// do not call visitOperands!
}
// Common work for *all* instructions. This needs to be called explicitly
// by other visit<InstructionType> functions.
inline void PreSelection::visitInstruction(Instruction &I) {
visitOperands(I); // Perform operand transformations
}
// GetElementPtr instructions: check if pointer is a global
void PreSelection::visitGetElementPtrInst(GetElementPtrInst &I) {
Instruction* curI = &I;
// The Sparc backend doesn't handle array indexes that are not long types, so
// insert a cast from whatever it is to long, if the sequential type index is
// not a long already.
unsigned Idx = 1;
for (gep_type_iterator TI = gep_type_begin(I), E = gep_type_end(I); TI != E;
++TI, ++Idx)
if (isa<SequentialType>(*TI) &&
I.getOperand(Idx)->getType() != Type::LongTy) {
Value *Op = I.getOperand(Idx);
if (Op->getType()->isUnsigned()) // Must sign extend!
Op = new CastInst(Op, Op->getType()->getSignedVersion(), "v9", &I);
if (Op->getType() != Type::LongTy)
Op = new CastInst(Op, Type::LongTy, "v9", &I);
I.setOperand(Idx, Op);
}
// Decompose multidimensional array references
if (I.getNumIndices() >= 2) {
// DecomposeArrayRef() replaces I and deletes it, if successful,
// so remember predecessor in order to find the replacement instruction.
// Also remember the basic block in case there is no predecessor.
Instruction* prevI = I.getPrev();
BasicBlock* bb = I.getParent();
if (DecomposeArrayRef(&I))
// first instr. replacing I
curI = cast<GetElementPtrInst>(prevI? prevI->getNext() : &bb->front());
}
// Perform other transformations common to all instructions
visitInstruction(*curI);
}
void PreSelection::visitCallInst(CallInst &I) {
// Tell visitOperands to ignore the function name if this is a direct call.
visitOperands(I, (/*firstOp=*/ I.getCalledFunction()? 1 : 0));
}
/// createPreSelectionPass - Public entry point for the PreSelection pass
///
FunctionPass* llvm::createPreSelectionPass(const TargetMachine &TM) {
return new PreSelection(TM);
}

View File

@ -1,184 +0,0 @@
//===-- SparcV9PrologEpilogCodeInserter.cpp - Insert Fn Prolog & Epilog ---===//
//
// 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 is the SparcV9 target's own PrologEpilogInserter. It creates prolog and
// epilog instructions for functions which have not been compiled using "leaf
// function optimizations". These instructions include the SAVE and RESTORE
// instructions used to rotate the SPARC register windows. Prologs are
// attached to the unique function entry, and epilogs are attached to each
// function exit.
//
//===----------------------------------------------------------------------===//
#include "SparcV9Internals.h"
#include "SparcV9RegClassInfo.h"
#include "SparcV9RegisterInfo.h"
#include "SparcV9FrameInfo.h"
#include "MachineFunctionInfo.h"
#include "MachineCodeForInstruction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/Pass.h"
#include "llvm/Function.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Intrinsics.h"
namespace llvm {
namespace {
struct InsertPrologEpilogCode : public MachineFunctionPass {
const char *getPassName() const { return "SparcV9 Prolog/Epilog Inserter"; }
bool runOnMachineFunction(MachineFunction &F) {
if (!F.getInfo<SparcV9FunctionInfo>()->isCompiledAsLeafMethod()) {
InsertPrologCode(F);
InsertEpilogCode(F);
}
return false;
}
void InsertPrologCode(MachineFunction &F);
void InsertEpilogCode(MachineFunction &F);
};
} // End anonymous namespace
static unsigned getStaticStackSize (MachineFunction &MF) {
const TargetFrameInfo& frameInfo = *MF.getTarget().getFrameInfo();
unsigned staticStackSize = MF.getInfo<SparcV9FunctionInfo>()->getStaticStackSize();
if (staticStackSize < (unsigned)SparcV9FrameInfo::MinStackFrameSize)
staticStackSize = SparcV9FrameInfo::MinStackFrameSize;
if (unsigned padsz = staticStackSize %
SparcV9FrameInfo::StackFrameSizeAlignment)
staticStackSize += SparcV9FrameInfo::StackFrameSizeAlignment - padsz;
return staticStackSize;
}
void InsertPrologEpilogCode::InsertPrologCode(MachineFunction &MF)
{
std::vector<MachineInstr*> mvec;
const TargetMachine &TM = MF.getTarget();
const TargetFrameInfo& frameInfo = *TM.getFrameInfo();
// The second operand is the stack size. If it does not fit in the
// immediate field, we have to use a free register to hold the size.
// See the comments below for the choice of this register.
unsigned staticStackSize = getStaticStackSize (MF);
int32_t C = - (int) staticStackSize;
int SP = TM.getRegInfo()->getStackPointer();
if (TM.getInstrInfo()->constantFitsInImmedField(V9::SAVEi,staticStackSize)) {
mvec.push_back(BuildMI(V9::SAVEi, 3).addMReg(SP).addSImm(C)
.addMReg(SP, MachineOperand::Def));
} else {
// We have to put the stack size value into a register before SAVE.
// Use register %g1 since it is volatile across calls. Note that the
// local (%l) and in (%i) registers cannot be used before the SAVE!
// Do this by creating a code sequence equivalent to:
// SETSW -(stackSize), %g1
int uregNum = TM.getRegInfo()->getUnifiedRegNum(
TM.getRegInfo()->getRegClassIDOfType(Type::IntTy),
SparcV9IntRegClass::g1);
MachineInstr* M = BuildMI(V9::SETHI, 2).addSImm(C)
.addMReg(uregNum, MachineOperand::Def);
M->getOperand(0).markHi32();
mvec.push_back(M);
M = BuildMI(V9::ORi, 3).addMReg(uregNum).addSImm(C)
.addMReg(uregNum, MachineOperand::Def);
M->getOperand(1).markLo32();
mvec.push_back(M);
M = BuildMI(V9::SRAi5, 3).addMReg(uregNum).addZImm(0)
.addMReg(uregNum, MachineOperand::Def);
mvec.push_back(M);
// Now generate the SAVE using the value in register %g1
M = BuildMI(V9::SAVEr,3).addMReg(SP).addMReg(uregNum)
.addMReg(SP,MachineOperand::Def);
mvec.push_back(M);
}
// For varargs function bodies, insert instructions to copy incoming
// register arguments for the ... list to the stack.
// The first K=6 arguments are always received via int arg regs
// (%i0 ... %i5 if K=6) .
// By copying the varargs arguments to the stack, va_arg() then can
// simply assume that all vararg arguments are in an array on the stack.
if (MF.getFunction()->getFunctionType()->isVarArg()) {
int numFixedArgs = MF.getFunction()->getFunctionType()->getNumParams();
int numArgRegs = TM.getRegInfo()->getNumOfIntArgRegs();
if (numFixedArgs < numArgRegs) {
const TargetFrameInfo &FI = *TM.getFrameInfo();
int firstArgReg = TM.getRegInfo()->getUnifiedRegNum(
TM.getRegInfo()->getRegClassIDOfType(Type::IntTy),
SparcV9IntRegClass::i0);
int fpReg = SparcV9::i6;
int argSize = 8;
int firstArgOffset= SparcV9FrameInfo::FirstIncomingArgOffsetFromFP;
int nextArgOffset = firstArgOffset + numFixedArgs * argSize;
for (int i=numFixedArgs; i < numArgRegs; ++i) {
mvec.push_back(BuildMI(V9::STXi, 3).addMReg(firstArgReg+i).
addMReg(fpReg).addSImm(nextArgOffset));
nextArgOffset += argSize;
}
}
}
MF.front().insert(MF.front().begin(), mvec.begin(), mvec.end());
}
void InsertPrologEpilogCode::InsertEpilogCode(MachineFunction &MF)
{
const TargetMachine &TM = MF.getTarget();
const TargetInstrInfo &MII = *TM.getInstrInfo();
for (MachineFunction::iterator I = MF.begin(), E = MF.end(); I != E; ++I) {
MachineBasicBlock &MBB = *I;
const BasicBlock &BB = *I->getBasicBlock();
const Instruction *TermInst = (Instruction*)BB.getTerminator();
if (TermInst->getOpcode() == Instruction::Ret)
{
int ZR = TM.getRegInfo()->getZeroRegNum();
MachineInstr *Restore =
BuildMI(V9::RESTOREi, 3).addMReg(ZR).addSImm(0)
.addMReg(ZR, MachineOperand::Def);
MachineCodeForInstruction &termMvec =
MachineCodeForInstruction::get(TermInst);
// Remove the NOPs in the delay slots of the return instruction
unsigned numNOPs = 0;
while (termMvec.back()->getOpcode() == V9::NOP)
{
assert( termMvec.back() == &MBB.back());
termMvec.pop_back();
MBB.erase(&MBB.back());
++numNOPs;
}
assert(termMvec.back() == &MBB.back());
// Check that we found the right number of NOPs and have the right
// number of instructions to replace them.
unsigned ndelays = MII.getNumDelaySlots(termMvec.back()->getOpcode());
assert(numNOPs == ndelays && "Missing NOPs in delay slots?");
assert(ndelays == 1 && "Cannot use epilog code for delay slots?");
// Append the epilog code to the end of the basic block.
MBB.push_back(Restore);
}
}
}
FunctionPass *createPrologEpilogInsertionPass() {
return new InsertPrologEpilogCode();
}
} // End llvm namespace

View File

@ -1,397 +0,0 @@
//===-- SparcV9RegClassInfo.cpp - Register class def'ns for SparcV9 -------===//
//
// 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 defines the methods used by the SparcV9 register allocator
// to pick registers of various classes. Most of this code should be
// considered part of the register allocator.
//
//===----------------------------------------------------------------------===//
#include "llvm/Type.h"
#include "SparcV9RegClassInfo.h"
#include "SparcV9Internals.h"
#include "SparcV9RegInfo.h"
#include "RegAlloc/RegAllocCommon.h"
#include "RegAlloc/IGNode.h"
#include <iostream>
namespace llvm {
//-----------------------------------------------------------------------------
// Int Register Class - method for coloring a node in the interference graph.
//
// Algorithm:
// Record the colors/suggested colors of all neighbors.
//
// If there is a suggested color, try to allocate it
// If there is no call interf, try to allocate volatile, then non volatile
// If there is call interf, try to allocate non-volatile. If that fails
// try to allocate a volatile and insert save across calls
// If both above fail, spill.
//
//-----------------------------------------------------------------------------
void SparcV9IntRegClass::colorIGNode(IGNode * Node,
const std::vector<bool> &IsColorUsedArr) const
{
V9LiveRange *LR = Node->getParentLR();
if (DEBUG_RA)
std::cerr << "\nColoring LR [CallInt=" << LR->isCallInterference() <<"]:"
<< *LR << "\n";
if (LR->hasSuggestedColor()) {
unsigned SugCol = LR->getSuggestedColor();
if (!IsColorUsedArr[SugCol]) {
if (LR->isSuggestedColorUsable()) {
// if the suggested color is volatile, we should use it only if
// there are no call interferences. Otherwise, it will get spilled.
if (DEBUG_RA)
std::cerr << "\n -Coloring with sug color: " << SugCol;
LR->setColor(LR->getSuggestedColor());
return;
} else if(DEBUG_RA) {
std::cerr << "\n Couldn't alloc Sug col - LR volatile & calls interf";
}
} else if (DEBUG_RA) { // can't allocate the suggested col
std::cerr << "\n Could NOT allocate the suggested color (already used) "
<< *LR << "\n";
}
}
unsigned SearchStart; // start pos of color in pref-order
bool ColorFound= false; // have we found a color yet?
//if this Node is between calls
if (! LR->isCallInterference()) {
// start with volatiles (we can allocate volatiles safely)
SearchStart = SparcV9IntRegClass::StartOfAllRegs;
} else {
// start with non volatiles (no non-volatiles)
SearchStart = SparcV9IntRegClass::StartOfNonVolatileRegs;
}
unsigned c=0; // color
// find first unused color
for (c=SearchStart; c < SparcV9IntRegClass::NumOfAvailRegs; c++) {
if (!IsColorUsedArr[c]) {
ColorFound = true;
break;
}
}
if (ColorFound) {
LR->setColor(c); // first color found in preferred order
if (DEBUG_RA) std::cerr << "\n Colored after first search with col " << c;
}
// if color is not found because of call interference
// try even finding a volatile color and insert save across calls
//
else if (LR->isCallInterference()) {
// start from 0 - try to find even a volatile this time
SearchStart = SparcV9IntRegClass::StartOfAllRegs;
// find first unused volatile color
for(c=SearchStart; c < SparcV9IntRegClass::StartOfNonVolatileRegs; c++) {
if (! IsColorUsedArr[c]) {
ColorFound = true;
break;
}
}
if (ColorFound) {
LR->setColor(c);
// get the live range corresponding to live var
// since LR span across calls, must save across calls
//
if (DEBUG_RA)
std::cerr << "\n Colored after SECOND search with col " << c;
}
}
// If we couldn't find a color regardless of call interference - i.e., we
// don't have either a volatile or non-volatile color left
//
if (!ColorFound)
LR->markForSpill(); // no color found - must spill
}
//-----------------------------------------------------------------------------
// Int CC Register Class - method for coloring a node in the interference graph.
//
// Algorithm:
//
// If (node has any interferences)
// /* all interference operations can use only one register! */
// mark the LR for spilling
// else {
// if (the LR is a 64-bit comparison) use %xcc
// else /*32-bit or smaller*/ use %icc
// }
//
// Note: The third name (%ccr) is essentially an assembly mnemonic and
// depends solely on the opcode, so the name can be chosen in EmitAssembly.
//-----------------------------------------------------------------------------
void SparcV9IntCCRegClass::colorIGNode(IGNode *Node,
const std::vector<bool> &IsColorUsedArr) const
{
if (Node->getNumOfNeighbors() > 0)
Node->getParentLR()->markForSpill();
// Mark the appropriate register in any case (even if it needs to be spilled)
// because there is only one possible register, but more importantly, the
// spill algorithm cannot find it. In particular, we have to choose
// whether to use %xcc or %icc based on type of value compared
//
const V9LiveRange* ccLR = Node->getParentLR();
const Type* setCCType = (* ccLR->begin())->getType(); // any Value in LR
assert(setCCType->isIntegral() || isa<PointerType>(setCCType));
int ccReg = ((isa<PointerType>(setCCType) || setCCType == Type::LongTy)
? xcc : icc);
#ifndef NDEBUG
// Let's just make sure values of two different types have not been
// coalesced into this LR.
for (V9LiveRange::const_iterator I=ccLR->begin(), E=ccLR->end(); I!=E; ++I) {
const Type* ccType = (*I)->getType();
assert((ccReg == xcc && (isa<PointerType>(ccType)
|| ccType == Type::LongTy)) ||
(ccReg == icc && ccType->isIntegral() && ccType != Type::LongTy)
&& "Comparisons needing different intCC regs coalesced in LR!");
}
#endif
Node->setColor(ccReg); // only one int cc reg is available
}
void SparcV9FloatCCRegClass::colorIGNode(IGNode *Node,
const std::vector<bool> &IsColorUsedArr) const {
for(unsigned c = 0; c != 4; ++c)
if (!IsColorUsedArr[c]) { // find unused color
Node->setColor(c);
return;
}
Node->getParentLR()->markForSpill();
}
//-----------------------------------------------------------------------------
// Float Register Class - method for coloring a node in the interference graph.
//
// Algorithm:
//
// If the LR is a double try to allocate f32 - f63
// If the above fails or LR is single precision
// If the LR does not interfere with a call
// start allocating from f0
// Else start allocating from f6
// If a color is still not found because LR interferes with a call
// Search in f0 - f6. If found mark for spill across calls.
// If a color is still not fond, mark for spilling
//
//----------------------------------------------------------------------------
void SparcV9FloatRegClass::colorIGNode(IGNode * Node,
const std::vector<bool> &IsColorUsedArr) const
{
V9LiveRange *LR = Node->getParentLR();
#ifndef NDEBUG
// Check that the correct colors have been are marked for fp-doubles.
//
// FIXME: This is old code that is no longer needed. Temporarily converting
// it into a big assertion just to check that the replacement logic
// (invoking SparcV9FloatRegClass::markColorsUsed() directly from
// RegClass::colorIGNode) works correctly.
//
// In fact, this entire function should be identical to
// SparcV9IntRegClass::colorIGNode(), and perhaps can be
// made into a general case in CodeGen/RegAlloc/RegClass.cpp.
//
unsigned NumNeighbors = Node->getNumOfNeighbors(); // total # of neighbors
for(unsigned n=0; n < NumNeighbors; n++) { // for each neigh
IGNode *NeighIGNode = Node->getAdjIGNode(n);
V9LiveRange *NeighLR = NeighIGNode->getParentLR();
if (NeighLR->hasColor()) {
assert(IsColorUsedArr[ NeighLR->getColor() ]);
if (NeighLR->getType() == Type::DoubleTy)
assert(IsColorUsedArr[ NeighLR->getColor()+1 ]);
} else if (NeighLR->hasSuggestedColor() &&
NeighLR-> isSuggestedColorUsable() ) {
// if the neighbour can use the suggested color
assert(IsColorUsedArr[ NeighLR->getSuggestedColor() ]);
if (NeighLR->getType() == Type::DoubleTy)
assert(IsColorUsedArr[ NeighLR->getSuggestedColor()+1 ]);
}
}
#endif
// **NOTE: We don't check for call interferences in allocating suggested
// color in this class since ALL registers are volatile. If this fact
// changes, we should change the following part
//- see SparcV9IntRegClass::colorIGNode()
//
if( LR->hasSuggestedColor() ) {
if( ! IsColorUsedArr[ LR->getSuggestedColor() ] ) {
LR->setColor( LR->getSuggestedColor() );
return;
} else if (DEBUG_RA) { // can't allocate the suggested col
std::cerr << " Could NOT allocate the suggested color for LR " << *LR
<< "\n";
}
}
int ColorFound = -1; // have we found a color yet?
bool isCallInterf = LR->isCallInterference();
// if value is a double - search the double only region (f32 - f63)
// i.e. we try to allocate f32 - f63 first for doubles since singles
// cannot go there. By doing that, we provide more space for singles
// in f0 - f31
//
if (LR->getType() == Type::DoubleTy)
ColorFound = findFloatColor( LR, 32, 64, IsColorUsedArr );
if (ColorFound >= 0) { // if we could find a color
LR->setColor(ColorFound);
return;
} else {
// if we didn't find a color because the LR was single precision or
// all f32-f63 range is filled, we try to allocate a register from
// the f0 - f31 region
unsigned SearchStart; // start pos of color in pref-order
//if this Node is between calls (i.e., no call interferences )
if (! isCallInterf) {
// start with volatiles (we can allocate volatiles safely)
SearchStart = SparcV9FloatRegClass::StartOfAllRegs;
} else {
// start with non volatiles (no non-volatiles)
SearchStart = SparcV9FloatRegClass::StartOfNonVolatileRegs;
}
ColorFound = findFloatColor(LR, SearchStart, 32, IsColorUsedArr);
}
if (ColorFound >= 0) { // if we could find a color
LR->setColor(ColorFound);
return;
} else if (isCallInterf) {
// We are here because there is a call interference and no non-volatile
// color could be found.
// Now try to allocate even a volatile color
ColorFound = findFloatColor(LR, SparcV9FloatRegClass::StartOfAllRegs,
SparcV9FloatRegClass::StartOfNonVolatileRegs,
IsColorUsedArr);
}
if (ColorFound >= 0) {
LR->setColor(ColorFound); // first color found in preferred order
} else {
// we are here because no color could be found
LR->markForSpill(); // no color found - must spill
}
}
//-----------------------------------------------------------------------------
// This method marks the registers used for a given register number.
// This marks a single register for Float regs, but the R,R+1 pair
// for double-precision registers.
//-----------------------------------------------------------------------------
void SparcV9FloatRegClass::markColorsUsed(unsigned RegInClass,
int UserRegType,
int RegTypeWanted,
std::vector<bool> &IsColorUsedArr) const
{
if (UserRegType == SparcV9RegInfo::FPDoubleRegType ||
RegTypeWanted == SparcV9RegInfo::FPDoubleRegType) {
// This register is used as or is needed as a double-precision reg.
// We need to mark the [even,odd] pair corresponding to this reg.
// Get the even numbered register corresponding to this reg.
unsigned EvenRegInClass = RegInClass & ~1u;
assert(EvenRegInClass+1 < NumOfAllRegs &&
EvenRegInClass+1 < IsColorUsedArr.size());
IsColorUsedArr[EvenRegInClass] = true;
IsColorUsedArr[EvenRegInClass+1] = true;
}
else {
assert(RegInClass < NumOfAllRegs && RegInClass < IsColorUsedArr.size());
assert(UserRegType == RegTypeWanted
&& "Something other than FP single/double types share a reg class?");
IsColorUsedArr[RegInClass] = true;
}
}
// This method finds unused registers of the specified register type,
// using the given "used" flag array IsColorUsedArr. It checks a single
// entry in the array directly for float regs, and checks the pair [R,R+1]
// for double-precision registers
// It returns -1 if no unused color is found.
//
int SparcV9FloatRegClass::findUnusedColor(int RegTypeWanted,
const std::vector<bool> &IsColorUsedArr) const
{
if (RegTypeWanted == SparcV9RegInfo::FPDoubleRegType) {
unsigned NC = 2 * this->getNumOfAvailRegs();
assert(IsColorUsedArr.size() == NC && "Invalid colors-used array");
for (unsigned c = 0; c < NC; c+=2)
if (!IsColorUsedArr[c]) {
assert(!IsColorUsedArr[c+1] && "Incorrect used regs for FP double!");
return c;
}
return -1;
}
else
return TargetRegClassInfo::findUnusedColor(RegTypeWanted, IsColorUsedArr);
}
//-----------------------------------------------------------------------------
// Helper method for coloring a node of Float Reg class.
// Finds the first available color in the range [Start,End] depending on the
// type of the Node (i.e., float/double)
//-----------------------------------------------------------------------------
int SparcV9FloatRegClass::findFloatColor(const V9LiveRange *LR,
unsigned Start,
unsigned End,
const std::vector<bool> &IsColorUsedArr) const
{
if (LR->getType() == Type::DoubleTy) {
// find first unused color for a double
assert(Start % 2 == 0 && "Odd register number could be used for double!");
for (unsigned c=Start; c < End ; c+= 2)
if (!IsColorUsedArr[c]) {
assert(!IsColorUsedArr[c+1] &&
"Incorrect marking of used regs for SparcV9 FP double!");
return c;
}
} else {
// find first unused color for a single
for (unsigned c = Start; c < End; c++)
if (!IsColorUsedArr[c])
return c;
}
return -1;
}
} // End llvm namespace

View File

@ -1,224 +0,0 @@
//===-- SparcV9RegClassInfo.h - Register class def'ns for SparcV9 -*- 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 defines the register classes used by the SparcV9 target. It
// implicitly defines (using enums) the "class register numbers" used in
// the SparcV9 target, which are converted using a formula in the SparcV9RegInfo
// class to "unified register numbers".
//
//===----------------------------------------------------------------------===//
#ifndef SPARCV9REGCLASSINFO_H
#define SPARCV9REGCLASSINFO_H
#include "SparcV9RegInfo.h"
namespace llvm {
//-----------------------------------------------------------------------------
// Integer Register Class
//-----------------------------------------------------------------------------
struct SparcV9IntRegClass : public TargetRegClassInfo {
SparcV9IntRegClass(unsigned ID)
: TargetRegClassInfo(ID, NumOfAvailRegs, NumOfAllRegs) { }
void colorIGNode(IGNode *Node,
const std::vector<bool> &IsColorUsedArr) const;
inline bool isRegVolatile(int Reg) const {
return (Reg < (int)StartOfNonVolatileRegs);
}
inline bool modifiedByCall(int Reg) const {
return Reg==(int)ModifiedByCall;
}
enum { // colors possible for a LR (in preferred order)
// --- following colors are volatile across function calls
// %g0 can't be used for coloring - always 0
o0, o1, o2, o3, o4, o5, o7, // %o0-%o5,
// %o6 is sp,
// all %0's can get modified by a call
// --- following colors are NON-volatile across function calls
l0, l1, l2, l3, l4, l5, l6, l7, // %l0-%l7
i0, i1, i2, i3, i4, i5, // %i0-%i5: i's need not be preserved
// %i6 is the fp - so not allocated
// %i7 is the ret address by convention - can be used for others
// max # of colors reg coloring can allocate (NumOfAvailRegs)
// --- following colors are not available for allocation within this phase
// --- but can appear for pre-colored ranges
i6, i7, g0, g1, g2, g3, g4, g5, g6, g7, o6,
NumOfAllRegs, // Must be first AFTER registers...
//*** NOTE: If we decide to use some %g regs, they are volatile
// (see sparc64ABI)
// Move the %g regs from the end of the enumeration to just above the
// enumeration of %o0 (change StartOfAllRegs below)
// change isRegVloatile method below
// Also change IntRegNames above.
// max # of colors reg coloring can allocate
NumOfAvailRegs = i6,
StartOfNonVolatileRegs = l0,
StartOfAllRegs = o0,
ModifiedByCall = o7,
};
const char * const getRegName(unsigned reg) const;
};
//-----------------------------------------------------------------------------
// Float Register Class
//-----------------------------------------------------------------------------
class SparcV9FloatRegClass : public TargetRegClassInfo {
int findFloatColor(const V9LiveRange *LR, unsigned Start,
unsigned End,
const std::vector<bool> &IsColorUsedArr) const;
public:
SparcV9FloatRegClass(unsigned ID)
: TargetRegClassInfo(ID, NumOfAvailRegs, NumOfAllRegs) {}
// This method marks the registers used for a given register number.
// This marks a single register for Float regs, but the R,R+1 pair
// for double-precision registers.
//
virtual void markColorsUsed(unsigned RegInClass,
int UserRegType,
int RegTypeWanted,
std::vector<bool> &IsColorUsedArr) const;
// This method finds unused registers of the specified register type,
// using the given "used" flag array IsColorUsedArr. It checks a single
// entry in the array directly for float regs, and checks the pair [R,R+1]
// for double-precision registers
// It returns -1 if no unused color is found.
//
virtual int findUnusedColor(int RegTypeWanted,
const std::vector<bool> &IsColorUsedArr) const;
void colorIGNode(IGNode *Node,
const std::vector<bool> &IsColorUsedArr) const;
// according to SparcV9 64 ABI, all %fp regs are volatile
inline bool isRegVolatile(int Reg) const { return true; }
enum {
f0, f1, f2, f3, f4, f5, f6, f7, f8, f9,
f10, f11, f12, f13, f14, f15, f16, f17, f18, f19,
f20, f21, f22, f23, f24, f25, f26, f27, f28, f29,
f30, f31, f32, f33, f34, f35, f36, f37, f38, f39,
f40, f41, f42, f43, f44, f45, f46, f47, f48, f49,
f50, f51, f52, f53, f54, f55, f56, f57, f58, f59,
f60, f61, f62, f63,
// there are 64 regs alltogether but only 32 regs can be allocated at
// a time.
//
NumOfAvailRegs = 32,
NumOfAllRegs = 64,
StartOfNonVolatileRegs = f32,
StartOfAllRegs = f0,
};
const char * const getRegName(unsigned reg) const;
};
//-----------------------------------------------------------------------------
// Int CC Register Class
// Only one integer cc register is available. However, this register is
// referred to as %xcc or %icc when instructions like subcc are executed but
// referred to as %ccr (i.e., %xcc . %icc") when this register is moved
// into an integer register using RD or WR instrcutions. So, three ids are
// allocated for the three names.
//-----------------------------------------------------------------------------
struct SparcV9IntCCRegClass : public TargetRegClassInfo {
SparcV9IntCCRegClass(unsigned ID)
: TargetRegClassInfo(ID, 1, 3) { }
void colorIGNode(IGNode *Node,
const std::vector<bool> &IsColorUsedArr) const;
// according to the 64-bit SparcV9 ABI, all integer CC regs are
// volatile.
inline bool isRegVolatile(int Reg) const { return true; }
enum {
xcc, icc, ccr // only one is available - see the note above
};
const char * const getRegName(unsigned reg) const;
};
//-----------------------------------------------------------------------------
// Float CC Register Class
// Only 4 Float CC registers are available for allocation.
//-----------------------------------------------------------------------------
struct SparcV9FloatCCRegClass : public TargetRegClassInfo {
SparcV9FloatCCRegClass(unsigned ID)
: TargetRegClassInfo(ID, 4, 4) { }
void colorIGNode(IGNode *Node,
const std::vector<bool> &IsColorUsedArr) const;
// according to the 64-bit SparcV9 ABI, all floating-point CC regs are
// volatile.
inline bool isRegVolatile(int Reg) const { return true; }
enum {
fcc0, fcc1, fcc2, fcc3
};
const char * const getRegName(unsigned reg) const;
};
//-----------------------------------------------------------------------------
// SparcV9 special register class. These registers are not used for allocation
// but are used as arguments of some instructions.
//-----------------------------------------------------------------------------
struct SparcV9SpecialRegClass : public TargetRegClassInfo {
SparcV9SpecialRegClass(unsigned ID)
: TargetRegClassInfo(ID, 0, 1) { }
void colorIGNode(IGNode *Node,
const std::vector<bool> &IsColorUsedArr) const {
assert(0 && "SparcV9SpecialRegClass should never be used for allocation");
}
// all currently included special regs are volatile
inline bool isRegVolatile(int Reg) const { return true; }
enum {
fsr // floating point state register
};
const char * const getRegName(unsigned reg) const;
};
} // End llvm namespace
#endif

View File

@ -1,973 +0,0 @@
//===-- SparcV9RegInfo.cpp - SparcV9 Target Register Information ----------===//
//
// 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 contains implementations of SparcV9 specific helper methods
// used for register allocation.
//
//===----------------------------------------------------------------------===//
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "MachineFunctionInfo.h"
#include "MachineCodeForInstruction.h"
#include "MachineInstrAnnot.h"
#include "RegAlloc/LiveRangeInfo.h"
#include "RegAlloc/LiveRange.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Function.h"
#include "llvm/Instructions.h"
#include "SparcV9Internals.h"
#include "SparcV9RegClassInfo.h"
#include "SparcV9RegInfo.h"
#include "SparcV9FrameInfo.h"
#include "SparcV9TargetMachine.h"
#include "SparcV9TmpInstr.h"
#include <iostream>
namespace llvm {
enum {
BadRegClass = ~0
};
SparcV9RegInfo::SparcV9RegInfo(const SparcV9TargetMachine &tgt)
: target (tgt), NumOfIntArgRegs (6), NumOfFloatArgRegs (32)
{
MachineRegClassArr.push_back(new SparcV9IntRegClass(IntRegClassID));
MachineRegClassArr.push_back(new SparcV9FloatRegClass(FloatRegClassID));
MachineRegClassArr.push_back(new SparcV9IntCCRegClass(IntCCRegClassID));
MachineRegClassArr.push_back(new SparcV9FloatCCRegClass(FloatCCRegClassID));
MachineRegClassArr.push_back(new SparcV9SpecialRegClass(SpecialRegClassID));
assert(SparcV9FloatRegClass::StartOfNonVolatileRegs == 32 &&
"32 Float regs are used for float arg passing");
}
// getZeroRegNum - returns the register that contains always zero.
// this is the unified register number
//
unsigned SparcV9RegInfo::getZeroRegNum() const {
return getUnifiedRegNum(SparcV9RegInfo::IntRegClassID,
SparcV9IntRegClass::g0);
}
// getCallAddressReg - returns the reg used for pushing the address when a
// method is called. This can be used for other purposes between calls
//
unsigned SparcV9RegInfo::getCallAddressReg() const {
return getUnifiedRegNum(SparcV9RegInfo::IntRegClassID,
SparcV9IntRegClass::o7);
}
// Returns the register containing the return address.
// It should be made sure that this register contains the return
// value when a return instruction is reached.
//
unsigned SparcV9RegInfo::getReturnAddressReg() const {
return getUnifiedRegNum(SparcV9RegInfo::IntRegClassID,
SparcV9IntRegClass::i7);
}
// Register get name implementations...
// Int register names in same order as enum in class SparcV9IntRegClass
static const char * const IntRegNames[] = {
"o0", "o1", "o2", "o3", "o4", "o5", "o7",
"l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
"i0", "i1", "i2", "i3", "i4", "i5",
"i6", "i7",
"g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
"o6"
};
const char * const SparcV9IntRegClass::getRegName(unsigned reg) const {
assert(reg < NumOfAllRegs);
return IntRegNames[reg];
}
static const char * const FloatRegNames[] = {
"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9",
"f10", "f11", "f12", "f13", "f14", "f15", "f16", "f17", "f18", "f19",
"f20", "f21", "f22", "f23", "f24", "f25", "f26", "f27", "f28", "f29",
"f30", "f31", "f32", "f33", "f34", "f35", "f36", "f37", "f38", "f39",
"f40", "f41", "f42", "f43", "f44", "f45", "f46", "f47", "f48", "f49",
"f50", "f51", "f52", "f53", "f54", "f55", "f56", "f57", "f58", "f59",
"f60", "f61", "f62", "f63"
};
const char * const SparcV9FloatRegClass::getRegName(unsigned reg) const {
assert (reg < NumOfAllRegs);
return FloatRegNames[reg];
}
static const char * const IntCCRegNames[] = {
"xcc", "icc", "ccr"
};
const char * const SparcV9IntCCRegClass::getRegName(unsigned reg) const {
assert(reg < 3);
return IntCCRegNames[reg];
}
static const char * const FloatCCRegNames[] = {
"fcc0", "fcc1", "fcc2", "fcc3"
};
const char * const SparcV9FloatCCRegClass::getRegName(unsigned reg) const {
assert (reg < 4);
return FloatCCRegNames[reg];
}
static const char * const SpecialRegNames[] = {
"fsr"
};
const char * const SparcV9SpecialRegClass::getRegName(unsigned reg) const {
assert (reg < 1);
return SpecialRegNames[reg];
}
// Get unified reg number for frame pointer
unsigned SparcV9RegInfo::getFramePointer() const {
return getUnifiedRegNum(SparcV9RegInfo::IntRegClassID,
SparcV9IntRegClass::i6);
}
// Get unified reg number for stack pointer
unsigned SparcV9RegInfo::getStackPointer() const {
return getUnifiedRegNum(SparcV9RegInfo::IntRegClassID,
SparcV9IntRegClass::o6);
}
//---------------------------------------------------------------------------
// Finds whether a call is an indirect call
//---------------------------------------------------------------------------
inline bool
isVarArgsFunction(const Type *funcType) {
return cast<FunctionType>(cast<PointerType>(funcType)
->getElementType())->isVarArg();
}
inline bool
isVarArgsCall(const MachineInstr *CallMI) {
Value* callee = CallMI->getOperand(0).getVRegValue();
// const Type* funcType = isa<Function>(callee)? callee->getType()
// : cast<PointerType>(callee->getType())->getElementType();
const Type* funcType = callee->getType();
return isVarArgsFunction(funcType);
}
// Get the register number for the specified argument #argNo,
//
// Return value:
// getInvalidRegNum(), if there is no int register available for the arg.
// regNum, otherwise (this is NOT the unified reg. num).
// regClassId is set to the register class ID.
//
int
SparcV9RegInfo::regNumForIntArg(bool inCallee, bool isVarArgsCall,
unsigned argNo, unsigned& regClassId) const
{
regClassId = IntRegClassID;
if (argNo >= NumOfIntArgRegs)
return getInvalidRegNum();
else
return argNo + (inCallee? SparcV9IntRegClass::i0 : SparcV9IntRegClass::o0);
}
// Get the register number for the specified FP argument #argNo,
// Use INT regs for FP args if this is a varargs call.
//
// Return value:
// getInvalidRegNum(), if there is no int register available for the arg.
// regNum, otherwise (this is NOT the unified reg. num).
// regClassId is set to the register class ID.
//
int
SparcV9RegInfo::regNumForFPArg(unsigned regType,
bool inCallee, bool isVarArgsCall,
unsigned argNo, unsigned& regClassId) const
{
if (isVarArgsCall)
return regNumForIntArg(inCallee, isVarArgsCall, argNo, regClassId);
else
{
regClassId = FloatRegClassID;
if (regType == FPSingleRegType)
return (argNo*2+1 >= NumOfFloatArgRegs)?
getInvalidRegNum() : SparcV9FloatRegClass::f0 + (argNo * 2 + 1);
else if (regType == FPDoubleRegType)
return (argNo*2 >= NumOfFloatArgRegs)?
getInvalidRegNum() : SparcV9FloatRegClass::f0 + (argNo * 2);
else
assert(0 && "Illegal FP register type");
return 0;
}
}
//---------------------------------------------------------------------------
// Finds the return address of a call sparc specific call instruction
//---------------------------------------------------------------------------
// The following 4 methods are used to find the RegType (SparcV9Internals.h)
// of a V9LiveRange, a Value, and for a given register unified reg number.
//
int SparcV9RegInfo::getRegTypeForClassAndType(unsigned regClassID,
const Type* type) const
{
switch (regClassID) {
case IntRegClassID: return IntRegType;
case FloatRegClassID:
if (type == Type::FloatTy) return FPSingleRegType;
else if (type == Type::DoubleTy) return FPDoubleRegType;
assert(0 && "Unknown type in FloatRegClass"); return 0;
case IntCCRegClassID: return IntCCRegType;
case FloatCCRegClassID: return FloatCCRegType;
case SpecialRegClassID: return SpecialRegType;
default: assert( 0 && "Unknown reg class ID"); return 0;
}
}
int SparcV9RegInfo::getRegTypeForDataType(const Type* type) const
{
return getRegTypeForClassAndType(getRegClassIDOfType(type), type);
}
int SparcV9RegInfo::getRegTypeForLR(const V9LiveRange *LR) const
{
return getRegTypeForClassAndType(LR->getRegClassID(), LR->getType());
}
int SparcV9RegInfo::getRegType(int unifiedRegNum) const
{
if (unifiedRegNum < 32)
return IntRegType;
else if (unifiedRegNum < (32 + 32))
return FPSingleRegType;
else if (unifiedRegNum < (64 + 32))
return FPDoubleRegType;
else if (unifiedRegNum < (64+32+3))
return IntCCRegType;
else if (unifiedRegNum < (64+32+3+4))
return FloatCCRegType;
else if (unifiedRegNum < (64+32+3+4+1))
return SpecialRegType;
else
assert(0 && "Invalid unified register number in getRegType");
return 0;
}
// To find the register class used for a specified Type
//
unsigned SparcV9RegInfo::getRegClassIDOfType(const Type *type,
bool isCCReg) const {
Type::TypeID ty = type->getTypeID();
unsigned res;
// FIXME: Comparing types like this isn't very safe...
if ((ty && ty <= Type::LongTyID) || (ty == Type::LabelTyID) ||
(ty == Type::FunctionTyID) || (ty == Type::PointerTyID) )
res = IntRegClassID; // sparc int reg (ty=0: void)
else if (ty <= Type::DoubleTyID)
res = FloatRegClassID; // sparc float reg class
else {
//std::cerr << "TypeID: " << ty << "\n";
assert(0 && "Cannot resolve register class for type");
return 0;
}
if (isCCReg)
return res + 2; // corresponding condition code register
else
return res;
}
unsigned SparcV9RegInfo::getRegClassIDOfRegType(int regType) const {
switch(regType) {
case IntRegType: return IntRegClassID;
case FPSingleRegType:
case FPDoubleRegType: return FloatRegClassID;
case IntCCRegType: return IntCCRegClassID;
case FloatCCRegType: return FloatCCRegClassID;
case SpecialRegType: return SpecialRegClassID;
default:
assert(0 && "Invalid register type in getRegClassIDOfRegType");
return 0;
}
}
//---------------------------------------------------------------------------
// Suggests a register for the ret address in the RET machine instruction.
// We always suggest %i7 by convention.
//---------------------------------------------------------------------------
void SparcV9RegInfo::suggestReg4RetAddr(MachineInstr *RetMI,
LiveRangeInfo& LRI) const {
assert(target.getInstrInfo()->isReturn(RetMI->getOpcode()));
// return address is always mapped to i7 so set it immediately
RetMI->SetRegForOperand(0, getUnifiedRegNum(IntRegClassID,
SparcV9IntRegClass::i7));
// Possible Optimization:
// Instead of setting the color, we can suggest one. In that case,
// we have to test later whether it received the suggested color.
// In that case, a LR has to be created at the start of method.
// It has to be done as follows (remove the setRegVal above):
// MachineOperand & MO = RetMI->getOperand(0);
// const Value *RetAddrVal = MO.getVRegValue();
// assert( RetAddrVal && "LR for ret address must be created at start");
// V9LiveRange * RetAddrLR = LRI.getLiveRangeForValue( RetAddrVal);
// RetAddrLR->setSuggestedColor(getUnifiedRegNum( IntRegClassID,
// SparcV9IntRegOrdr::i7) );
}
//---------------------------------------------------------------------------
// Suggests a register for the ret address in the JMPL/CALL machine instr.
// SparcV9 ABI dictates that %o7 be used for this purpose.
//---------------------------------------------------------------------------
void
SparcV9RegInfo::suggestReg4CallAddr(MachineInstr * CallMI,
LiveRangeInfo& LRI) const
{
CallArgsDescriptor* argDesc = CallArgsDescriptor::get(CallMI);
const Value *RetAddrVal = argDesc->getReturnAddrReg();
assert(RetAddrVal && "INTERNAL ERROR: Return address value is required");
// A LR must already exist for the return address.
V9LiveRange *RetAddrLR = LRI.getLiveRangeForValue(RetAddrVal);
assert(RetAddrLR && "INTERNAL ERROR: No LR for return address of call!");
unsigned RegClassID = RetAddrLR->getRegClassID();
RetAddrLR->setColor(getUnifiedRegNum(IntRegClassID, SparcV9IntRegClass::o7));
}
//---------------------------------------------------------------------------
// This method will suggest colors to incoming args to a method.
// According to the SparcV9 ABI, the first 6 incoming args are in
// %i0 - %i5 (if they are integer) OR in %f0 - %f31 (if they are float).
// If the arg is passed on stack due to the lack of regs, NOTHING will be
// done - it will be colored (or spilled) as a normal live range.
//---------------------------------------------------------------------------
void SparcV9RegInfo::suggestRegs4MethodArgs(const Function *Meth,
LiveRangeInfo& LRI) const
{
// Check if this is a varArgs function. needed for choosing regs.
bool isVarArgs = isVarArgsFunction(Meth->getType());
// Count the arguments, *ignoring* whether they are int or FP args.
// Use this common arg numbering to pick the right int or fp register.
unsigned argNo=0;
for(Function::const_arg_iterator I = Meth->arg_begin(), E = Meth->arg_end();
I != E; ++I, ++argNo) {
V9LiveRange *LR = LRI.getLiveRangeForValue(I);
assert(LR && "No live range found for method arg");
unsigned regType = getRegTypeForLR(LR);
unsigned regClassIDOfArgReg = BadRegClass; // for chosen reg (unused)
int regNum = (regType == IntRegType)
? regNumForIntArg(/*inCallee*/ true, isVarArgs, argNo, regClassIDOfArgReg)
: regNumForFPArg(regType, /*inCallee*/ true, isVarArgs, argNo,
regClassIDOfArgReg);
if (regNum != getInvalidRegNum())
LR->setSuggestedColor(regNum);
}
}
//---------------------------------------------------------------------------
// This method is called after graph coloring to move incoming args to
// the correct hardware registers if they did not receive the correct
// (suggested) color through graph coloring.
//---------------------------------------------------------------------------
void SparcV9RegInfo::colorMethodArgs(const Function *Meth,
LiveRangeInfo &LRI,
std::vector<MachineInstr*>& InstrnsBefore,
std::vector<MachineInstr*>& InstrnsAfter) const {
// check if this is a varArgs function. needed for choosing regs.
bool isVarArgs = isVarArgsFunction(Meth->getType());
MachineInstr *AdMI;
// for each argument
// for each argument. count INT and FP arguments separately.
unsigned argNo=0, intArgNo=0, fpArgNo=0;
for(Function::const_arg_iterator I = Meth->arg_begin(), E = Meth->arg_end();
I != E; ++I, ++argNo) {
// get the LR of arg
V9LiveRange *LR = LRI.getLiveRangeForValue(I);
assert( LR && "No live range found for method arg");
unsigned regType = getRegTypeForLR(LR);
unsigned RegClassID = LR->getRegClassID();
// Find whether this argument is coming in a register (if not, on stack)
// Also find the correct register the argument must use (UniArgReg)
//
bool isArgInReg = false;
unsigned UniArgReg = getInvalidRegNum(); // reg that LR MUST be colored with
unsigned regClassIDOfArgReg = BadRegClass; // reg class of chosen reg
int regNum = (regType == IntRegType)
? regNumForIntArg(/*inCallee*/ true, isVarArgs,
argNo, regClassIDOfArgReg)
: regNumForFPArg(regType, /*inCallee*/ true, isVarArgs,
argNo, regClassIDOfArgReg);
if(regNum != getInvalidRegNum()) {
isArgInReg = true;
UniArgReg = getUnifiedRegNum( regClassIDOfArgReg, regNum);
}
if( ! LR->isMarkedForSpill() ) { // if this arg received a register
unsigned UniLRReg = getUnifiedRegNum( RegClassID, LR->getColor() );
// if LR received the correct color, nothing to do
//
if( UniLRReg == UniArgReg )
continue;
// We are here because the LR did not receive the suggested
// but LR received another register.
// Now we have to copy the %i reg (or stack pos of arg)
// to the register the LR was colored with.
// if the arg is coming in UniArgReg register, it MUST go into
// the UniLRReg register
//
if( isArgInReg ) {
if( regClassIDOfArgReg != RegClassID ) {
// NOTE: This code has not been well-tested.
// It is a variable argument call: the float reg must go in a %o reg.
// We have to move an int reg to a float reg via memory.
//
assert(isVarArgs &&
RegClassID == FloatRegClassID &&
regClassIDOfArgReg == IntRegClassID &&
"This should only be an Int register for an FP argument");
int TmpOff = MachineFunction::get(Meth).getInfo<SparcV9FunctionInfo>()->pushTempValue(
getSpilledRegSize(regType));
cpReg2MemMI(InstrnsBefore,
UniArgReg, getFramePointer(), TmpOff, IntRegType);
cpMem2RegMI(InstrnsBefore,
getFramePointer(), TmpOff, UniLRReg, regType);
}
else {
cpReg2RegMI(InstrnsBefore, UniArgReg, UniLRReg, regType);
}
}
else {
// Now the arg is coming on stack. Since the LR received a register,
// we just have to load the arg on stack into that register
//
const TargetFrameInfo& frameInfo = *target.getFrameInfo();
int offsetFromFP =
frameInfo.getIncomingArgOffset(MachineFunction::get(Meth),
argNo);
// float arguments on stack are right justified so adjust the offset!
// int arguments are also right justified but they are always loaded as
// a full double-word so the offset does not need to be adjusted.
if (regType == FPSingleRegType) {
unsigned argSize = target.getTargetData().getTypeSize(LR->getType());
unsigned slotSize = SparcV9FrameInfo::SizeOfEachArgOnStack;
assert(argSize <= slotSize && "Insufficient slot size!");
offsetFromFP += slotSize - argSize;
}
cpMem2RegMI(InstrnsBefore,
getFramePointer(), offsetFromFP, UniLRReg, regType);
}
} // if LR received a color
else {
// Now, the LR did not receive a color. But it has a stack offset for
// spilling.
// So, if the arg is coming in UniArgReg register, we can just move
// that on to the stack pos of LR
if( isArgInReg ) {
if( regClassIDOfArgReg != RegClassID ) {
assert(0 &&
"FP arguments to a varargs function should be explicitly "
"copied to/from int registers by instruction selection!");
// It must be a float arg for a variable argument call, which
// must come in a %o reg. Move the int reg to the stack.
//
assert(isVarArgs && regClassIDOfArgReg == IntRegClassID &&
"This should only be an Int register for an FP argument");
cpReg2MemMI(InstrnsBefore, UniArgReg,
getFramePointer(), LR->getSpillOffFromFP(), IntRegType);
}
else {
cpReg2MemMI(InstrnsBefore, UniArgReg,
getFramePointer(), LR->getSpillOffFromFP(), regType);
}
}
else {
// Now the arg is coming on stack. Since the LR did NOT
// received a register as well, it is allocated a stack position. We
// can simply change the stack position of the LR. We can do this,
// since this method is called before any other method that makes
// uses of the stack pos of the LR (e.g., updateMachineInstr)
//
const TargetFrameInfo& frameInfo = *target.getFrameInfo();
int offsetFromFP =
frameInfo.getIncomingArgOffset(MachineFunction::get(Meth),
argNo);
// FP arguments on stack are right justified so adjust offset!
// int arguments are also right justified but they are always loaded as
// a full double-word so the offset does not need to be adjusted.
if (regType == FPSingleRegType) {
unsigned argSize = target.getTargetData().getTypeSize(LR->getType());
unsigned slotSize = SparcV9FrameInfo::SizeOfEachArgOnStack;
assert(argSize <= slotSize && "Insufficient slot size!");
offsetFromFP += slotSize - argSize;
}
LR->modifySpillOffFromFP( offsetFromFP );
}
}
} // for each incoming argument
}
//---------------------------------------------------------------------------
// This method is called before graph coloring to suggest colors to the
// outgoing call args and the return value of the call.
//---------------------------------------------------------------------------
void SparcV9RegInfo::suggestRegs4CallArgs(MachineInstr *CallMI,
LiveRangeInfo& LRI) const {
assert ( (target.getInstrInfo())->isCall(CallMI->getOpcode()) );
CallArgsDescriptor* argDesc = CallArgsDescriptor::get(CallMI);
suggestReg4CallAddr(CallMI, LRI);
// First color the return value of the call instruction, if any.
// The return value will be in %o0 if the value is an integer type,
// or in %f0 if the value is a float type.
//
if (const Value *RetVal = argDesc->getReturnValue()) {
V9LiveRange *RetValLR = LRI.getLiveRangeForValue(RetVal);
assert(RetValLR && "No LR for return Value of call!");
unsigned RegClassID = RetValLR->getRegClassID();
// now suggest a register depending on the register class of ret arg
if( RegClassID == IntRegClassID )
RetValLR->setSuggestedColor(SparcV9IntRegClass::o0);
else if (RegClassID == FloatRegClassID )
RetValLR->setSuggestedColor(SparcV9FloatRegClass::f0 );
else assert( 0 && "Unknown reg class for return value of call\n");
}
// Now suggest colors for arguments (operands) of the call instruction.
// Colors are suggested only if the arg number is smaller than the
// the number of registers allocated for argument passing.
// Now, go thru call args - implicit operands of the call MI
unsigned NumOfCallArgs = argDesc->getNumArgs();
for(unsigned argNo=0, i=0, intArgNo=0, fpArgNo=0;
i < NumOfCallArgs; ++i, ++argNo) {
const Value *CallArg = argDesc->getArgInfo(i).getArgVal();
// get the LR of call operand (parameter)
V9LiveRange *const LR = LRI.getLiveRangeForValue(CallArg);
if (!LR)
continue; // no live ranges for constants and labels
unsigned regType = getRegTypeForLR(LR);
unsigned regClassIDOfArgReg = BadRegClass; // chosen reg class (unused)
// Choose a register for this arg depending on whether it is
// an INT or FP value. Here we ignore whether or not it is a
// varargs calls, because FP arguments will be explicitly copied
// to an integer Value and handled under (argCopy != NULL) below.
int regNum = (regType == IntRegType)
? regNumForIntArg(/*inCallee*/ false, /*isVarArgs*/ false,
argNo, regClassIDOfArgReg)
: regNumForFPArg(regType, /*inCallee*/ false, /*isVarArgs*/ false,
argNo, regClassIDOfArgReg);
// If a register could be allocated, use it.
// If not, do NOTHING as this will be colored as a normal value.
if(regNum != getInvalidRegNum())
LR->setSuggestedColor(regNum);
} // for all call arguments
}
//---------------------------------------------------------------------------
// this method is called for an LLVM return instruction to identify which
// values will be returned from this method and to suggest colors.
//---------------------------------------------------------------------------
void SparcV9RegInfo::suggestReg4RetValue(MachineInstr *RetMI,
LiveRangeInfo& LRI) const {
assert( target.getInstrInfo()->isReturn( RetMI->getOpcode() ) );
suggestReg4RetAddr(RetMI, LRI);
// To find the return value (if any), we can get the LLVM return instr.
// from the return address register, which is the first operand
Value* tmpI = RetMI->getOperand(0).getVRegValue();
ReturnInst* retI=cast<ReturnInst>(cast<TmpInstruction>(tmpI)->getOperand(0));
if (const Value *RetVal = retI->getReturnValue())
if (V9LiveRange *const LR = LRI.getLiveRangeForValue(RetVal))
LR->setSuggestedColor(LR->getRegClassID() == IntRegClassID
? (unsigned) SparcV9IntRegClass::i0
: (unsigned) SparcV9FloatRegClass::f0);
}
//---------------------------------------------------------------------------
// Check if a specified register type needs a scratch register to be
// copied to/from memory. If it does, the reg. type that must be used
// for scratch registers is returned in scratchRegType.
//
// Only the int CC register needs such a scratch register.
// The FP CC registers can (and must) be copied directly to/from memory.
//---------------------------------------------------------------------------
bool
SparcV9RegInfo::regTypeNeedsScratchReg(int RegType,
int& scratchRegType) const
{
if (RegType == IntCCRegType)
{
scratchRegType = IntRegType;
return true;
}
return false;
}
//---------------------------------------------------------------------------
// Copy from a register to register. Register number must be the unified
// register number.
//---------------------------------------------------------------------------
void
SparcV9RegInfo::cpReg2RegMI(std::vector<MachineInstr*>& mvec,
unsigned SrcReg,
unsigned DestReg,
int RegType) const {
assert( ((int)SrcReg != getInvalidRegNum()) &&
((int)DestReg != getInvalidRegNum()) &&
"Invalid Register");
MachineInstr * MI = NULL;
switch( RegType ) {
case IntCCRegType:
if (getRegType(DestReg) == IntRegType) {
// copy intCC reg to int reg
MI = (BuildMI(V9::RDCCR, 2)
.addMReg(getUnifiedRegNum(SparcV9RegInfo::IntCCRegClassID,
SparcV9IntCCRegClass::ccr))
.addMReg(DestReg,MachineOperand::Def));
} else {
// copy int reg to intCC reg
assert(getRegType(SrcReg) == IntRegType
&& "Can only copy CC reg to/from integer reg");
MI = (BuildMI(V9::WRCCRr, 3)
.addMReg(SrcReg)
.addMReg(SparcV9IntRegClass::g0)
.addMReg(getUnifiedRegNum(SparcV9RegInfo::IntCCRegClassID,
SparcV9IntCCRegClass::ccr),
MachineOperand::Def));
}
break;
case FloatCCRegType:
assert(0 && "Cannot copy FPCC register to any other register");
break;
case IntRegType:
MI = BuildMI(V9::ADDr, 3).addMReg(SrcReg).addMReg(getZeroRegNum())
.addMReg(DestReg, MachineOperand::Def);
break;
case FPSingleRegType:
MI = BuildMI(V9::FMOVS, 2).addMReg(SrcReg)
.addMReg(DestReg, MachineOperand::Def);
break;
case FPDoubleRegType:
MI = BuildMI(V9::FMOVD, 2).addMReg(SrcReg)
.addMReg(DestReg, MachineOperand::Def);
break;
default:
assert(0 && "Unknown RegType");
break;
}
if (MI)
mvec.push_back(MI);
}
/// cpReg2MemMI - Generate SparcV9 MachineInstrs to store a register
/// (SrcReg) to memory, at [PtrReg + Offset]. Register numbers must be the
/// unified register numbers. RegType must be the SparcV9 register type
/// of SrcReg. When SrcReg is %ccr, scratchReg must be the
/// number of a free integer register. The newly-generated MachineInstrs
/// are appended to mvec.
///
void SparcV9RegInfo::cpReg2MemMI(std::vector<MachineInstr*>& mvec,
unsigned SrcReg, unsigned PtrReg, int Offset,
int RegType, int scratchReg) const {
unsigned OffReg = SparcV9::g4; // Use register g4 for holding large offsets
bool useImmediateOffset = true;
// If the Offset will not fit in the signed-immediate field, we put it in
// register g4. This takes advantage of the fact that all the opcodes
// used below have the same size immed. field.
if (RegType != IntCCRegType
&& !target.getInstrInfo()->constantFitsInImmedField(V9::LDXi, Offset)) {
// Put the offset into a register. We could do this in fewer steps,
// in some cases (see CreateSETSWConst()) but we're being lazy.
MachineInstr *MI = BuildMI(V9::SETHI, 2).addZImm(Offset).addMReg(OffReg,
MachineOperand::Def);
MI->getOperand(0).markHi32();
mvec.push_back(MI);
MI = BuildMI(V9::ORi,3).addMReg(OffReg).addZImm(Offset).addMReg(OffReg,
MachineOperand::Def);
MI->getOperand(1).markLo32();
mvec.push_back(MI);
MI = BuildMI(V9::SRAi5,3).addMReg(OffReg).addZImm(0).addMReg(OffReg,
MachineOperand::Def);
mvec.push_back(MI);
useImmediateOffset = false;
}
MachineInstr *MI = 0;
switch (RegType) {
case IntRegType:
if (useImmediateOffset)
MI = BuildMI(V9::STXi,3).addMReg(SrcReg).addMReg(PtrReg).addSImm(Offset);
else
MI = BuildMI(V9::STXr,3).addMReg(SrcReg).addMReg(PtrReg).addMReg(OffReg);
break;
case FPSingleRegType:
if (useImmediateOffset)
MI = BuildMI(V9::STFi, 3).addMReg(SrcReg).addMReg(PtrReg).addSImm(Offset);
else
MI = BuildMI(V9::STFr, 3).addMReg(SrcReg).addMReg(PtrReg).addMReg(OffReg);
break;
case FPDoubleRegType:
if (useImmediateOffset)
MI = BuildMI(V9::STDFi,3).addMReg(SrcReg).addMReg(PtrReg).addSImm(Offset);
else
MI = BuildMI(V9::STDFr,3).addMReg(SrcReg).addMReg(PtrReg).addSImm(OffReg);
break;
case IntCCRegType:
assert(scratchReg >= 0 && getRegType(scratchReg) == IntRegType
&& "Need a scratch reg of integer type to load or store %ccr");
MI = BuildMI(V9::RDCCR, 2).addMReg(SparcV9::ccr)
.addMReg(scratchReg, MachineOperand::Def);
mvec.push_back(MI);
cpReg2MemMI(mvec, scratchReg, PtrReg, Offset, IntRegType);
return;
case SpecialRegType: // used only for %fsr itself.
case FloatCCRegType: {
if (useImmediateOffset)
MI = BuildMI(V9::STXFSRi,3).addMReg(SparcV9::fsr).addMReg(PtrReg)
.addSImm(Offset);
else
MI = BuildMI(V9::STXFSRr,3).addMReg(SparcV9::fsr).addMReg(PtrReg)
.addMReg(OffReg);
break;
}
default:
assert(0 && "Unknown RegType in cpReg2MemMI");
}
mvec.push_back(MI);
}
/// cpMem2RegMI - Generate SparcV9 MachineInstrs to load a register
/// (DestReg) from memory, at [PtrReg + Offset]. Register numbers must be the
/// unified register numbers. RegType must be the SparcV9 register type
/// of DestReg. When DestReg is %ccr, scratchReg must be the
/// number of a free integer register. The newly-generated MachineInstrs
/// are appended to mvec.
///
void SparcV9RegInfo::cpMem2RegMI(std::vector<MachineInstr*>& mvec,
unsigned PtrReg, int Offset, unsigned DestReg,
int RegType, int scratchReg) const {
unsigned OffReg = SparcV9::g4; // Use register g4 for holding large offsets
bool useImmediateOffset = true;
// If the Offset will not fit in the signed-immediate field, we put it in
// register g4. This takes advantage of the fact that all the opcodes
// used below have the same size immed. field.
if (RegType != IntCCRegType
&& !target.getInstrInfo()->constantFitsInImmedField(V9::LDXi, Offset)) {
MachineInstr *MI = BuildMI(V9::SETHI, 2).addZImm(Offset).addMReg(OffReg,
MachineOperand::Def);
MI->getOperand(0).markHi32();
mvec.push_back(MI);
MI = BuildMI(V9::ORi,3).addMReg(OffReg).addZImm(Offset).addMReg(OffReg,
MachineOperand::Def);
MI->getOperand(1).markLo32();
mvec.push_back(MI);
MI = BuildMI(V9::SRAi5,3).addMReg(OffReg).addZImm(0).addMReg(OffReg,
MachineOperand::Def);
mvec.push_back(MI);
useImmediateOffset = false;
}
MachineInstr *MI = 0;
switch (RegType) {
case IntRegType:
if (useImmediateOffset)
MI = BuildMI(V9::LDXi, 3).addMReg(PtrReg).addSImm(Offset)
.addMReg(DestReg, MachineOperand::Def);
else
MI = BuildMI(V9::LDXr, 3).addMReg(PtrReg).addMReg(OffReg)
.addMReg(DestReg, MachineOperand::Def);
break;
case FPSingleRegType:
if (useImmediateOffset)
MI = BuildMI(V9::LDFi, 3).addMReg(PtrReg).addSImm(Offset)
.addMReg(DestReg, MachineOperand::Def);
else
MI = BuildMI(V9::LDFr, 3).addMReg(PtrReg).addMReg(OffReg)
.addMReg(DestReg, MachineOperand::Def);
break;
case FPDoubleRegType:
if (useImmediateOffset)
MI= BuildMI(V9::LDDFi, 3).addMReg(PtrReg).addSImm(Offset)
.addMReg(DestReg, MachineOperand::Def);
else
MI= BuildMI(V9::LDDFr, 3).addMReg(PtrReg).addMReg(OffReg)
.addMReg(DestReg, MachineOperand::Def);
break;
case IntCCRegType:
assert(scratchReg >= 0 && getRegType(scratchReg) == IntRegType
&& "Need a scratch reg of integer type to load or store %ccr");
cpMem2RegMI(mvec, PtrReg, Offset, scratchReg, IntRegType);
MI = BuildMI(V9::WRCCRr, 3).addMReg(scratchReg).addMReg(SparcV9::g0)
.addMReg(SparcV9::ccr, MachineOperand::Def);
break;
case SpecialRegType: // used only for %fsr itself
case FloatCCRegType: {
if (useImmediateOffset)
MI = BuildMI(V9::LDXFSRi, 3).addMReg(PtrReg).addSImm(Offset)
.addMReg(SparcV9::fsr, MachineOperand::Def);
else
MI = BuildMI(V9::LDXFSRr, 3).addMReg(PtrReg).addMReg(OffReg)
.addMReg(SparcV9::fsr, MachineOperand::Def);
break;
}
default:
assert(0 && "Unknown RegType in cpMem2RegMI");
}
mvec.push_back(MI);
}
//---------------------------------------------------------------------------
// Generate a copy instruction to copy a value to another. Temporarily
// used by PhiElimination code.
//---------------------------------------------------------------------------
void
SparcV9RegInfo::cpValue2Value(Value *Src, Value *Dest,
std::vector<MachineInstr*>& mvec) const {
int RegType = getRegTypeForDataType(Src->getType());
MachineInstr * MI = NULL;
switch (RegType) {
case IntRegType:
MI = BuildMI(V9::ADDr, 3).addReg(Src).addMReg(getZeroRegNum())
.addRegDef(Dest);
break;
case FPSingleRegType:
MI = BuildMI(V9::FMOVS, 2).addReg(Src).addRegDef(Dest);
break;
case FPDoubleRegType:
MI = BuildMI(V9::FMOVD, 2).addReg(Src).addRegDef(Dest);
break;
default:
assert(0 && "Unknown RegType in cpValue2Value");
}
mvec.push_back(MI);
}
//---------------------------------------------------------------------------
// Print the register assigned to a LR
//---------------------------------------------------------------------------
void SparcV9RegInfo::printReg(const V9LiveRange *LR) const {
unsigned RegClassID = LR->getRegClassID();
std::cerr << " Node ";
if (!LR->hasColor()) {
std::cerr << " - could not find a color\n";
return;
}
// if a color is found
std::cerr << " colored with color "<< LR->getColor();
unsigned uRegName = getUnifiedRegNum(RegClassID, LR->getColor());
std::cerr << "[";
std::cerr<< getUnifiedRegName(uRegName);
if (RegClassID == FloatRegClassID && LR->getType() == Type::DoubleTy)
std::cerr << "+" << getUnifiedRegName(uRegName+1);
std::cerr << "]\n";
}
} // End llvm namespace

View File

@ -1,381 +0,0 @@
//===-- SparcV9RegInfo.h - SparcV9 Target Register Info ---------*- 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 is used to describe the register file of the SparcV9 target to
// its register allocator.
//
//===----------------------------------------------------------------------===//
#ifndef SPARCV9REGINFO_H
#define SPARCV9REGINFO_H
#include "llvm/ADT/hash_map"
#include <string>
#include <cassert>
namespace llvm {
class TargetMachine;
class IGNode;
class Type;
class Value;
class LiveRangeInfo;
class Function;
class V9LiveRange;
class AddedInstrns;
class MachineInstr;
class BasicBlock;
class SparcV9TargetMachine;
///----------------------------------------------------------------------------
/// Interface to description of machine register class (e.g., int reg class
/// float reg class etc)
///
class TargetRegClassInfo {
protected:
const unsigned RegClassID; // integer ID of a reg class
const unsigned NumOfAvailRegs; // # of avail for coloring -without SP etc.
const unsigned NumOfAllRegs; // # of all registers -including SP,g0 etc.
public:
virtual ~TargetRegClassInfo() {}
inline unsigned getRegClassID() const { return RegClassID; }
inline unsigned getNumOfAvailRegs() const { return NumOfAvailRegs; }
inline unsigned getNumOfAllRegs() const { return NumOfAllRegs; }
// This method marks the registers used for a given register number.
// This defaults to marking a single register but may mark multiple
// registers when a single number denotes paired registers.
//
virtual void markColorsUsed(unsigned RegInClass,
int UserRegType,
int RegTypeWanted,
std::vector<bool> &IsColorUsedArr) const {
assert(RegInClass < NumOfAllRegs && RegInClass < IsColorUsedArr.size());
assert(UserRegType == RegTypeWanted &&
"Default method is probably incorrect for class with multiple types.");
IsColorUsedArr[RegInClass] = true;
}
// This method finds unused registers of the specified register type,
// using the given "used" flag array IsColorUsedArr. It defaults to
// checking a single entry in the array directly, but that can be overridden
// for paired registers and other such silliness.
// It returns -1 if no unused color is found.
//
virtual int findUnusedColor(int RegTypeWanted,
const std::vector<bool> &IsColorUsedArr) const {
// find first unused color in the IsColorUsedArr directly
unsigned NC = this->getNumOfAvailRegs();
assert(IsColorUsedArr.size() >= NC && "Invalid colors-used array");
for (unsigned c = 0; c < NC; c++)
if (!IsColorUsedArr[c])
return c;
return -1;
}
// This method should find a color which is not used by neighbors
// (i.e., a false position in IsColorUsedArr) and
virtual void colorIGNode(IGNode *Node,
const std::vector<bool> &IsColorUsedArr) const = 0;
// Check whether a specific register is volatile, i.e., whether it is not
// preserved across calls
virtual bool isRegVolatile(int Reg) const = 0;
// Check whether a specific register is modified as a side-effect of the
// call instruction itself,
virtual bool modifiedByCall(int Reg) const { return false; }
virtual const char* const getRegName(unsigned reg) const = 0;
TargetRegClassInfo(unsigned ID, unsigned NVR, unsigned NAR)
: RegClassID(ID), NumOfAvailRegs(NVR), NumOfAllRegs(NAR) {}
};
/// SparcV9RegInfo - Interface to register info of SparcV9 target machine
///
class SparcV9RegInfo {
SparcV9RegInfo(const SparcV9RegInfo &); // DO NOT IMPLEMENT
void operator=(const SparcV9RegInfo &); // DO NOT IMPLEMENT
protected:
// A vector of all machine register classes
//
std::vector<const TargetRegClassInfo *> MachineRegClassArr;
public:
const TargetMachine &target;
// A register can be initialized to an invalid number. That number can
// be obtained using this method.
//
static int getInvalidRegNum() { return -1; }
// According the definition of a MachineOperand class, a Value in a
// machine instruction can go into either a normal register or a
// condition code register. If isCCReg is true below, the ID of the condition
// code register class will be returned. Otherwise, the normal register
// class (eg. int, float) must be returned.
// To find the register class used for a specified Type
//
unsigned getRegClassIDOfType (const Type *type,
bool isCCReg = false) const;
// To find the register class to which a specified register belongs
//
unsigned getRegClassIDOfRegType(int regType) const;
unsigned getRegClassIDOfReg(int unifiedRegNum) const {
unsigned classId = 0;
(void) getClassRegNum(unifiedRegNum, classId);
return classId;
}
unsigned int getNumOfRegClasses() const {
return MachineRegClassArr.size();
}
const TargetRegClassInfo *getMachineRegClass(unsigned i) const {
return MachineRegClassArr[i];
}
// getZeroRegNum - returns the register that is hardwired to always contain
// zero, if any (-1 if none). This is the unified register number.
//
unsigned getZeroRegNum() const;
// The following methods are used to color special live ranges (e.g.
// method args and return values etc.) with specific hardware registers
// as required. See SparcRegInfo.cpp for the implementation for Sparc.
//
void suggestRegs4MethodArgs(const Function *Func,
LiveRangeInfo& LRI) const;
void suggestRegs4CallArgs(MachineInstr *CallI,
LiveRangeInfo& LRI) const;
void suggestReg4RetValue(MachineInstr *RetI,
LiveRangeInfo& LRI) const;
void colorMethodArgs(const Function *Func,
LiveRangeInfo &LRI,
std::vector<MachineInstr*>& InstrnsBefore,
std::vector<MachineInstr*>& InstrnsAfter) const;
// Check whether a specific register is volatile, i.e., whether it is not
// preserved across calls
inline bool isRegVolatile(int RegClassID, int Reg) const {
return MachineRegClassArr[RegClassID]->isRegVolatile(Reg);
}
// Check whether a specific register is modified as a side-effect of the
// call instruction itself,
inline bool modifiedByCall(int RegClassID, int Reg) const {
return MachineRegClassArr[RegClassID]->modifiedByCall(Reg);
}
// getCallAddressReg - Returns the reg used for pushing the address
// when a method is called. This can be used for other purposes
// between calls
//
unsigned getCallAddressReg() const;
// Each register class has a separate space for register IDs. To convert
// a regId in a register class to a common Id, or vice versa,
// we use the folloing two methods.
//
// This method converts from class reg. number to unified register number.
int getUnifiedRegNum(unsigned regClassID, int reg) const {
if (reg == getInvalidRegNum()) { return getInvalidRegNum(); }
assert(regClassID < getNumOfRegClasses() && "Invalid register class");
int totalRegs = 0;
for (unsigned rcid = 0; rcid < regClassID; ++rcid)
totalRegs += MachineRegClassArr[rcid]->getNumOfAllRegs();
return reg + totalRegs;
}
// This method converts the unified number to the number in its class,
// and returns the class ID in regClassID.
int getClassRegNum(int uRegNum, unsigned& regClassID) const {
if (uRegNum == getInvalidRegNum()) { return getInvalidRegNum(); }
int totalRegs = 0, rcid = 0, NC = getNumOfRegClasses();
while (rcid < NC &&
uRegNum>= totalRegs+(int)MachineRegClassArr[rcid]->getNumOfAllRegs())
{
totalRegs += MachineRegClassArr[rcid]->getNumOfAllRegs();
rcid++;
}
if (rcid == NC) {
assert(0 && "getClassRegNum(): Invalid register number");
return getInvalidRegNum();
}
regClassID = rcid;
return uRegNum - totalRegs;
}
// Returns the assembly-language name of the specified machine register.
//
const char * const getUnifiedRegName(int UnifiedRegNum) const {
unsigned regClassID = getNumOfRegClasses(); // initialize to invalid value
int regNumInClass = getClassRegNum(UnifiedRegNum, regClassID);
return MachineRegClassArr[regClassID]->getRegName(regNumInClass);
}
// This method gives the the number of bytes of stack space allocated
// to a register when it is spilled to the stack, according to its
// register type.
//
// For SparcV9, currently we allocate 8 bytes on stack for all
// register types. We can optimize this later if necessary to save stack
// space (However, should make sure that stack alignment is correct)
//
int getSpilledRegSize(int RegType) const {
return 8;
}
private:
// Number of registers used for passing int args (usually 6: %o0 - %o5)
//
unsigned const NumOfIntArgRegs;
// Number of registers used for passing float args (usually 32: %f0 - %f31)
//
unsigned const NumOfFloatArgRegs;
// The following methods are used to color special live ranges (e.g.
// function args and return values etc.) with specific hardware registers
// as required. See SparcV9RegInfo.cpp for the implementation.
//
void suggestReg4RetAddr(MachineInstr *RetMI,
LiveRangeInfo &LRI) const;
void suggestReg4CallAddr(MachineInstr *CallMI, LiveRangeInfo &LRI) const;
// Helper used by the all the getRegType() functions.
int getRegTypeForClassAndType(unsigned regClassID, const Type* type) const;
public:
// Type of registers available in SparcV9. There can be several reg types
// in the same class. For instace, the float reg class has Single/Double
// types
//
enum RegTypes {
IntRegType,
FPSingleRegType,
FPDoubleRegType,
IntCCRegType,
FloatCCRegType,
SpecialRegType
};
// The actual register classes in the SparcV9
//
// **** WARNING: If this enum order is changed, also modify
// getRegisterClassOfValue method below since it assumes this particular
// order for efficiency.
//
enum RegClassIDs {
IntRegClassID, // Integer
FloatRegClassID, // Float (both single/double)
IntCCRegClassID, // Int Condition Code
FloatCCRegClassID, // Float Condition code
SpecialRegClassID // Special (unallocated) registers
};
SparcV9RegInfo(const SparcV9TargetMachine &tgt);
~SparcV9RegInfo() {
for (unsigned i = 0, e = MachineRegClassArr.size(); i != e; ++i)
delete MachineRegClassArr[i];
}
// Returns the register containing the return address.
// It should be made sure that this register contains the return
// value when a return instruction is reached.
//
unsigned getReturnAddressReg() const;
// Number of registers used for passing int args (usually 6: %o0 - %o5)
// and float args (usually 32: %f0 - %f31)
//
unsigned const getNumOfIntArgRegs() const { return NumOfIntArgRegs; }
unsigned const getNumOfFloatArgRegs() const { return NumOfFloatArgRegs; }
// Compute which register can be used for an argument, if any
//
int regNumForIntArg(bool inCallee, bool isVarArgsCall,
unsigned argNo, unsigned& regClassId) const;
int regNumForFPArg(unsigned RegType, bool inCallee, bool isVarArgsCall,
unsigned argNo, unsigned& regClassId) const;
// method used for printing a register for debugging purposes
//
void printReg(const V9LiveRange *LR) const;
// To obtain the return value and the indirect call address (if any)
// contained in a CALL machine instruction
//
const Value * getCallInstRetVal(const MachineInstr *CallMI) const;
const Value * getCallInstIndirectAddrVal(const MachineInstr *CallMI) const;
// The following methods are used to generate "copy" machine instructions
// for an architecture. Currently they are used in TargetRegClass
// interface. However, they can be moved to TargetInstrInfo interface if
// necessary.
//
// The function regTypeNeedsScratchReg() can be used to check whether a
// scratch register is needed to copy a register of type `regType' to
// or from memory. If so, such a scratch register can be provided by
// the caller (e.g., if it knows which regsiters are free); otherwise
// an arbitrary one will be chosen and spilled by the copy instructions.
// If a scratch reg is needed, the reg. type that must be used
// for scratch registers is returned in scratchRegType.
//
bool regTypeNeedsScratchReg(int RegType,
int& scratchRegClassId) const;
void cpReg2RegMI(std::vector<MachineInstr*>& mvec,
unsigned SrcReg, unsigned DestReg,
int RegType) const;
void cpReg2MemMI(std::vector<MachineInstr*>& mvec,
unsigned SrcReg, unsigned DestPtrReg,
int Offset, int RegType, int scratchReg = -1) const;
void cpMem2RegMI(std::vector<MachineInstr*>& mvec,
unsigned SrcPtrReg, int Offset, unsigned DestReg,
int RegType, int scratchReg = -1) const;
void cpValue2Value(Value *Src, Value *Dest,
std::vector<MachineInstr*>& mvec) const;
// Get the register type for a register identified different ways.
// Note that getRegTypeForLR(LR) != getRegTypeForDataType(LR->getType())!
// The reg class of a LR depends both on the Value types in it and whether
// they are CC registers or not (for example).
int getRegTypeForDataType(const Type* type) const;
int getRegTypeForLR(const V9LiveRange *LR) const;
int getRegType(int unifiedRegNum) const;
unsigned getFramePointer() const;
unsigned getStackPointer() const;
};
} // End llvm namespace
#endif // SPARCV9REGINFO_H

View File

@ -1,333 +0,0 @@
//===- SparcV9RegisterInfo.cpp - SparcV9 Register Information ---*- 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 contains the SparcV9 implementation of the MRegisterInfo class.
// It also contains stuff needed to instantiate that class, which would
// ordinarily be provided by TableGen.
//
// This is NOT used by the SparcV9 backend to do register allocation, yet.
//
//===----------------------------------------------------------------------===//
//
// The first section of this file (immediately following) is what
// you would find in SparcV9GenRegisterInfo.inc, if we were using
// TableGen to generate the register file description automatically.
// It consists of register classes and register class instances
// for the SparcV9 target.
//
// FIXME: the alignments listed here are wild guesses.
//
//===----------------------------------------------------------------------===//
#include "SparcV9RegisterInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/ValueTypes.h"
using namespace llvm;
namespace llvm {
namespace {
// IR Register Class...
const unsigned IR[] = {
SparcV9::o0, SparcV9::o1, SparcV9::o2, SparcV9::o3, SparcV9::o4,
SparcV9::o5, SparcV9::o7, SparcV9::l0, SparcV9::l1, SparcV9::l2,
SparcV9::l3, SparcV9::l4, SparcV9::l5, SparcV9::l6, SparcV9::l7,
SparcV9::i0, SparcV9::i1, SparcV9::i2, SparcV9::i3, SparcV9::i4,
SparcV9::i5, SparcV9::i6, SparcV9::i7, SparcV9::g0, SparcV9::g1,
SparcV9::g2, SparcV9::g3, SparcV9::g4, SparcV9::g5, SparcV9::g6,
SparcV9::g7, SparcV9::o6
};
const MVT::ValueType IRVTs[] = { MVT::i64, MVT::Other };
struct IRClass : public TargetRegisterClass {
IRClass() : TargetRegisterClass(IRVTs, 8, 8, IR, IR + 32) {}
} IRInstance;
// FR Register Class...
const unsigned FR[] = {
SparcV9::f0, SparcV9::f1, SparcV9::f2, SparcV9::f3, SparcV9::f4,
SparcV9::f5, SparcV9::f6, SparcV9::f7, SparcV9::f8, SparcV9::f9,
SparcV9::f10, SparcV9::f11, SparcV9::f12, SparcV9::f13,
SparcV9::f14, SparcV9::f15, SparcV9::f16, SparcV9::f17,
SparcV9::f18, SparcV9::f19, SparcV9::f20, SparcV9::f21,
SparcV9::f22, SparcV9::f23, SparcV9::f24, SparcV9::f25,
SparcV9::f26, SparcV9::f27, SparcV9::f28, SparcV9::f29,
SparcV9::f30, SparcV9::f31, SparcV9::f32, SparcV9::f33,
SparcV9::f34, SparcV9::f35, SparcV9::f36, SparcV9::f37,
SparcV9::f38, SparcV9::f39, SparcV9::f40, SparcV9::f41,
SparcV9::f42, SparcV9::f43, SparcV9::f44, SparcV9::f45,
SparcV9::f46, SparcV9::f47, SparcV9::f48, SparcV9::f49,
SparcV9::f50, SparcV9::f51, SparcV9::f52, SparcV9::f53,
SparcV9::f54, SparcV9::f55, SparcV9::f56, SparcV9::f57,
SparcV9::f58, SparcV9::f59, SparcV9::f60, SparcV9::f61,
SparcV9::f62, SparcV9::f63
};
const MVT::ValueType FRVTs[] = { MVT::f32, MVT::Other };
// FIXME: The size is correct for the first 32 registers. The
// latter 32 do not all really exist; you can only access every other
// one (32, 34, ...), and they must contain double-fp or quad-fp
// values... see below about the aliasing problems.
struct FRClass : public TargetRegisterClass {
FRClass() : TargetRegisterClass(FRVTs, 4, 8, FR, FR + 64) {}
} FRInstance;
// ICCR Register Class...
const unsigned ICCR[] = {
SparcV9::xcc, SparcV9::icc, SparcV9::ccr
};
const MVT::ValueType ICCRVTs[] = { MVT::i1, MVT::Other };
struct ICCRClass : public TargetRegisterClass {
ICCRClass() : TargetRegisterClass(ICCRVTs, 1, 8, ICCR, ICCR + 3) {}
} ICCRInstance;
// FCCR Register Class...
const unsigned FCCR[] = {
SparcV9::fcc0, SparcV9::fcc1, SparcV9::fcc2, SparcV9::fcc3
};
const MVT::ValueType FCCRVTs[] = { MVT::i1, MVT::Other };
struct FCCRClass : public TargetRegisterClass {
FCCRClass() : TargetRegisterClass(FCCRVTs, 1, 8, FCCR, FCCR + 4) {}
} FCCRInstance;
// SR Register Class...
const unsigned SR[] = {
SparcV9::fsr
};
const MVT::ValueType SRVTs[] = { MVT::i64, MVT::Other };
struct SRClass : public TargetRegisterClass {
SRClass() : TargetRegisterClass(SRVTs, 8, 8, SR, SR + 1) {}
} SRInstance;
// Register Classes...
const TargetRegisterClass* const RegisterClasses[] = {
&IRInstance,
&FRInstance,
&ICCRInstance,
&FCCRInstance,
&SRInstance
};
// Register Alias Sets...
// FIXME: Note that the SparcV9 backend does not currently abstract
// very well over the way that double-fp and quad-fp values may alias
// single-fp values in registers. Therefore those aliases are NOT
// reflected here.
const unsigned Empty_AliasSet[] = { 0 };
const unsigned fcc3_AliasSet[] = { SparcV9::fsr, 0 };
const unsigned fcc2_AliasSet[] = { SparcV9::fsr, 0 };
const unsigned fcc1_AliasSet[] = { SparcV9::fsr, 0 };
const unsigned fcc0_AliasSet[] = { SparcV9::fsr, 0 };
const unsigned fsr_AliasSet[] = { SparcV9::fcc3, SparcV9::fcc2,
SparcV9::fcc1, SparcV9::fcc0, 0 };
const unsigned xcc_AliasSet[] = { SparcV9::ccr, 0 };
const unsigned icc_AliasSet[] = { SparcV9::ccr, 0 };
const unsigned ccr_AliasSet[] = { SparcV9::xcc, SparcV9::icc, 0 };
const TargetRegisterDesc RegisterDescriptors[] = { // Descriptors
{ "o0", Empty_AliasSet },
{ "o1", Empty_AliasSet },
{ "o2", Empty_AliasSet },
{ "o3", Empty_AliasSet },
{ "o4", Empty_AliasSet },
{ "o5", Empty_AliasSet },
{ "o7", Empty_AliasSet },
{ "l0", Empty_AliasSet },
{ "l1", Empty_AliasSet },
{ "l2", Empty_AliasSet },
{ "l3", Empty_AliasSet },
{ "l4", Empty_AliasSet },
{ "l5", Empty_AliasSet },
{ "l6", Empty_AliasSet },
{ "l7", Empty_AliasSet },
{ "i0", Empty_AliasSet },
{ "i1", Empty_AliasSet },
{ "i2", Empty_AliasSet },
{ "i3", Empty_AliasSet },
{ "i4", Empty_AliasSet },
{ "i5", Empty_AliasSet },
{ "i6", Empty_AliasSet },
{ "i7", Empty_AliasSet },
{ "g0", Empty_AliasSet },
{ "g1", Empty_AliasSet },
{ "g2", Empty_AliasSet },
{ "g3", Empty_AliasSet },
{ "g4", Empty_AliasSet },
{ "g5", Empty_AliasSet },
{ "g6", Empty_AliasSet },
{ "g7", Empty_AliasSet },
{ "o6", Empty_AliasSet },
{ "f0", Empty_AliasSet },
{ "f1", Empty_AliasSet },
{ "f2", Empty_AliasSet },
{ "f3", Empty_AliasSet },
{ "f4", Empty_AliasSet },
{ "f5", Empty_AliasSet },
{ "f6", Empty_AliasSet },
{ "f7", Empty_AliasSet },
{ "f8", Empty_AliasSet },
{ "f9", Empty_AliasSet },
{ "f10", Empty_AliasSet },
{ "f11", Empty_AliasSet },
{ "f12", Empty_AliasSet },
{ "f13", Empty_AliasSet },
{ "f14", Empty_AliasSet },
{ "f15", Empty_AliasSet },
{ "f16", Empty_AliasSet },
{ "f17", Empty_AliasSet },
{ "f18", Empty_AliasSet },
{ "f19", Empty_AliasSet },
{ "f20", Empty_AliasSet },
{ "f21", Empty_AliasSet },
{ "f22", Empty_AliasSet },
{ "f23", Empty_AliasSet },
{ "f24", Empty_AliasSet },
{ "f25", Empty_AliasSet },
{ "f26", Empty_AliasSet },
{ "f27", Empty_AliasSet },
{ "f28", Empty_AliasSet },
{ "f29", Empty_AliasSet },
{ "f30", Empty_AliasSet },
{ "f31", Empty_AliasSet },
{ "f32", Empty_AliasSet },
{ "f33", Empty_AliasSet },
{ "f34", Empty_AliasSet },
{ "f35", Empty_AliasSet },
{ "f36", Empty_AliasSet },
{ "f37", Empty_AliasSet },
{ "f38", Empty_AliasSet },
{ "f39", Empty_AliasSet },
{ "f40", Empty_AliasSet },
{ "f41", Empty_AliasSet },
{ "f42", Empty_AliasSet },
{ "f43", Empty_AliasSet },
{ "f44", Empty_AliasSet },
{ "f45", Empty_AliasSet },
{ "f46", Empty_AliasSet },
{ "f47", Empty_AliasSet },
{ "f48", Empty_AliasSet },
{ "f49", Empty_AliasSet },
{ "f50", Empty_AliasSet },
{ "f51", Empty_AliasSet },
{ "f52", Empty_AliasSet },
{ "f53", Empty_AliasSet },
{ "f54", Empty_AliasSet },
{ "f55", Empty_AliasSet },
{ "f56", Empty_AliasSet },
{ "f57", Empty_AliasSet },
{ "f58", Empty_AliasSet },
{ "f59", Empty_AliasSet },
{ "f60", Empty_AliasSet },
{ "f61", Empty_AliasSet },
{ "f62", Empty_AliasSet },
{ "f63", Empty_AliasSet },
{ "xcc", xcc_AliasSet },
{ "icc", icc_AliasSet },
{ "ccr", ccr_AliasSet },
{ "fcc0", fcc0_AliasSet },
{ "fcc1", fcc1_AliasSet },
{ "fcc2", fcc2_AliasSet },
{ "fcc3", fcc3_AliasSet },
{ "fsr", fsr_AliasSet },
};
} // end anonymous namespace
namespace SparcV9 { // Register classes
TargetRegisterClass *IRRegisterClass = &IRInstance;
TargetRegisterClass *FRRegisterClass = &FRInstance;
TargetRegisterClass *ICCRRegisterClass = &ICCRInstance;
TargetRegisterClass *FCCRRegisterClass = &FCCRInstance;
TargetRegisterClass *SRRegisterClass = &SRInstance;
} // end namespace SparcV9
const unsigned *SparcV9RegisterInfo::getCalleeSaveRegs() const {
// FIXME: This should be verified against the SparcV9 ABI at some point.
// These are the registers which the SparcV9 backend considers
// "non-volatile".
static const unsigned CalleeSaveRegs[] = {
SparcV9::l0, SparcV9::l1, SparcV9::l2, SparcV9::l3, SparcV9::l4,
SparcV9::l5, SparcV9::l6, SparcV9::l7, SparcV9::i0, SparcV9::i1,
SparcV9::i2, SparcV9::i3, SparcV9::i4, SparcV9::i5, SparcV9::i6,
SparcV9::i7, SparcV9::g0, SparcV9::g1, SparcV9::g2, SparcV9::g3,
SparcV9::g4, SparcV9::g5, SparcV9::g6, SparcV9::g7, SparcV9::o6,
0
};
return CalleeSaveRegs;
}
} // end namespace llvm
//===----------------------------------------------------------------------===//
//
// The second section of this file (immediately following) contains the
// SparcV9 implementation of the MRegisterInfo class. It currently consists
// entirely of stub functions, because the SparcV9 target does not use the
// same register allocator that the X86 target uses.
//
//===----------------------------------------------------------------------===//
SparcV9RegisterInfo::SparcV9RegisterInfo ()
: MRegisterInfo (RegisterDescriptors, 104, RegisterClasses,
RegisterClasses + 5) {
}
void SparcV9RegisterInfo::storeRegToStackSlot(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI,
unsigned SrcReg, int FrameIndex,
const TargetRegisterClass *RC) const {
abort ();
}
void SparcV9RegisterInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI,
unsigned DestReg, int FrameIndex,
const TargetRegisterClass *RC) const {
abort ();
}
void SparcV9RegisterInfo::copyRegToReg(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI,
unsigned DestReg, unsigned SrcReg,
const TargetRegisterClass *RC) const {
abort ();
}
void SparcV9RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator MI)
const {
abort ();
}
void SparcV9RegisterInfo::emitPrologue(MachineFunction &MF) const {
abort ();
}
void SparcV9RegisterInfo::emitEpilogue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
abort ();
}
int SparcV9RegisterInfo::getDwarfRegNum(unsigned RegNum) const {
abort ();
return 0;
}
unsigned SparcV9RegisterInfo::getRARegister() const {
abort ();
return 0;
}
unsigned SparcV9RegisterInfo::getFrameRegister(MachineFunction &MF) const {
abort ();
return 0;
}

View File

@ -1,117 +0,0 @@
//===- SparcV9RegisterInfo.h - SparcV9 Register Information Impl -*- 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 contains the SparcV9 implementation of the MRegisterInfo class.
// It also contains stuff needed to instantiate that class, which would
// ordinarily be provided by TableGen.
//
//===----------------------------------------------------------------------===//
#ifndef SPARCV9REGISTERINFO_H
#define SPARCV9REGISTERINFO_H
#include "llvm/Target/MRegisterInfo.h"
namespace llvm {
struct SparcV9RegisterInfo : public MRegisterInfo {
SparcV9RegisterInfo ();
const unsigned *getCalleeSaveRegs() const;
const TargetRegisterClass* const *getCalleeSaveRegClasses() const {
return 0;
}
// The rest of these are stubs... for now.
void storeRegToStackSlot(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI,
unsigned SrcReg, int FrameIndex,
const TargetRegisterClass *RC) const;
void loadRegFromStackSlot(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI,
unsigned DestReg, int FrameIndex,
const TargetRegisterClass *RC) const;
void copyRegToReg(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI,
unsigned DestReg, unsigned SrcReg,
const TargetRegisterClass *RC) const;
void eliminateFrameIndex (MachineBasicBlock::iterator MI) const;
void emitPrologue (MachineFunction &MF) const;
void emitEpilogue (MachineFunction &MF, MachineBasicBlock &MBB) const;
// Debug information queries.
int getDwarfRegNum(unsigned RegNum) const;
unsigned getRARegister() const;
unsigned getFrameRegister(MachineFunction &MF) const;
};
} // End llvm namespace
//===----------------------------------------------------------------------===//
//
// The second section of this file (immediately following) contains
// a *handwritten* SparcV9 unified register number enumeration, which
// provides a flat namespace containing all the SparcV9 unified
// register numbers.
//
// It would ordinarily be contained in the file SparcV9GenRegisterNames.inc
// if we were using TableGen to generate the register file description
// automatically.
//
//===----------------------------------------------------------------------===//
namespace llvm {
namespace SparcV9 {
enum {
// FIXME - Register 0 is not a "non-register" like it is on other targets!!
// SparcV9IntRegClass(IntRegClassID)
// - unified register numbers 0 ... 31 (32 regs)
/* 0 */ o0, o1, o2, o3, o4,
/* 5 */ o5, o7, l0, l1, l2,
/* 10 */ l3, l4, l5, l6, l7,
/* 15 */ i0, i1, i2, i3, i4,
/* 20 */ i5, i6, i7, g0, g1, // i6 is frame ptr, i7 is ret addr, g0 is zero
/* 25 */ g2, g3, g4, g5, g6,
/* 30 */ g7, o6, // o6 is stack ptr
// SparcV9FloatRegClass(FloatRegClassID)
// - regs 32 .. 63 are FPSingleRegType, 64 .. 95 are FPDoubleRegType
// - unified register numbers 32 ... 95 (64 regs)
/* 32 */ f0, f1, f2,
/* 35 */ f3, f4, f5, f6, f7,
/* 40 */ f8, f9, f10, f11, f12,
/* 45 */ f13, f14, f15, f16, f17,
/* 50 */ f18, f19, f20, f21, f22,
/* 55 */ f23, f24, f25, f26, f27,
/* 60 */ f28, f29, f30, f31, f32,
/* 65 */ f33, f34, f35, f36, f37,
/* 70 */ f38, f39, f40, f41, f42,
/* 75 */ f43, f44, f45, f46, f47,
/* 80 */ f48, f49, f50, f51, f52,
/* 85 */ f53, f54, f55, f56, f57,
/* 90 */ f58, f59, f60, f61, f62,
/* 95 */ f63,
// SparcV9IntCCRegClass(IntCCRegClassID)
// - unified register numbers 96 ... 98 (3 regs)
/* 96 */ xcc, icc, ccr,
// SparcV9FloatCCRegClass(FloatCCRegClassID)
// - unified register numbers 99 ... 102 (4 regs)
/* 99 */ fcc0, fcc1, fcc2, fcc3,
// SparcV9SpecialRegClass(SpecialRegClassID)
// - unified register number 103 (1 reg)
/* 103 */ fsr
};
} // end namespace SparcV9
} // end namespace llvm
#endif // SPARCV9REGISTERINFO_H

View File

@ -1,49 +0,0 @@
//===- SparcV9RegisterInfo.td - SparcV9 Register defs ------*- tablegen -*-===//
//
// 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.
//
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
// Declarations that describe the SparcV9 register file
//===----------------------------------------------------------------------===//
// Ri - One of the 32 64 bit integer registers
class Ri<bits<5> num, string n> : Register<n> {
field bits<5> Num = num; // Numbers are identified with a 5 bit ID
}
let Namespace = "SparcV9" in {
def G0 : Ri< 0, "G0">; def G1 : Ri< 1, "G1">;
def G2 : Ri< 2, "G2">; def G3 : Ri< 3, "G3">;
def G4 : Ri< 4, "G4">; def G5 : Ri< 5, "G5">;
def G6 : Ri< 6, "G6">; def G7 : Ri< 7, "G7">;
def O0 : Ri< 8, "O0">; def O1 : Ri< 9, "O1">;
def O2 : Ri<10, "O2">; def O3 : Ri<11, "O3">;
def O4 : Ri<12, "O4">; def O5 : Ri<13, "O5">;
def O6 : Ri<14, "O6">; def O7 : Ri<15, "O7">;
def L0 : Ri<16, "L0">; def L1 : Ri<17, "L1">;
def L2 : Ri<18, "L2">; def L3 : Ri<19, "L3">;
def L4 : Ri<20, "L4">; def L5 : Ri<21, "L5">;
def L6 : Ri<22, "L6">; def L7 : Ri<23, "L7">;
def I0 : Ri<24, "I0">; def I1 : Ri<25, "I1">;
def I2 : Ri<26, "I2">; def I3 : Ri<27, "I3">;
def I4 : Ri<28, "I4">; def I5 : Ri<29, "I5">;
def I6 : Ri<30, "I6">; def I7 : Ri<31, "I7">;
// Floating-point registers?
// ...
}
// For fun, specify a register class.
//
// FIXME: the register order should be defined in terms of the preferred
// allocation order...
//
def IntRegs : RegisterClass<"V9", [i64], 64, [G0, G1, G2, G3, G4, G5, G6, G7,
O0, O1, O2, O3, O4, O5, O6, O7,
L0, L1, L2, L3, L4, L5, L6, L7,
I0, I1, I2, I3, I4, I5, I6, I7]>;

View File

@ -1,42 +0,0 @@
//===- SparcV9Relocations.h - SparcV9 Code Relocations ----------*- 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 defines the SparcV9 target-specific relocation types.
//
//===----------------------------------------------------------------------===//
#ifndef SPARCV9RELOCATIONS_H
#define SPARCV9RELOCATIONS_H
#include "llvm/CodeGen/MachineRelocation.h"
namespace llvm {
namespace V9 {
enum RelocationType {
// reloc_pcrel_call - PC relative relocation, shifted right by two bits,
// inserted into a 30 bit field. This is used to relocate direct call
// instructions.
reloc_pcrel_call = 0,
// reloc_sethi_hh - Absolute relocation, for 'sethi %hh(G),reg' operation.
reloc_sethi_hh = 1,
// reloc_sethi_lm - Absolute relocation, for 'sethi %lm(G),reg' operation.
reloc_sethi_lm = 2,
// reloc_or_hm - Absolute relocation, for 'or reg,%hm(G),reg' operation.
reloc_or_hm = 3,
// reloc_or_lo - Absolute relocation, for 'or reg,%lo(G),reg' operation.
reloc_or_lo = 4,
};
}
}
#endif

View File

@ -1,761 +0,0 @@
//===-- SparcV9SchedInfo.cpp ----------------------------------------------===//
//
// 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.
//
//===----------------------------------------------------------------------===//
//
// Describe the scheduling characteristics of the UltraSparc IIi.
//
//===----------------------------------------------------------------------===//
#include "SparcV9Internals.h"
using namespace llvm;
/*---------------------------------------------------------------------------
Scheduling guidelines for SPARC IIi:
I-Cache alignment rules (pg 326)
-- Align a branch target instruction so that it's entire group is within
the same cache line (may be 1-4 instructions).
** Don't let a branch that is predicted taken be the last instruction
on an I-cache line: delay slot will need an entire line to be fetched
-- Make a FP instruction or a branch be the 4th instruction in a group.
For branches, there are tradeoffs in reordering to make this happen
(see pg. 327).
** Don't put a branch in a group that crosses a 32-byte boundary!
An artificial branch is inserted after every 32 bytes, and having
another branch will force the group to be broken into 2 groups.
iTLB rules:
-- Don't let a loop span two memory pages, if possible
Branch prediction performance:
-- Don't make the branch in a delay slot the target of a branch
-- Try not to have 2 predicted branches within a group of 4 instructions
(because each such group has a single branch target field).
-- Try to align branches in slots 0, 2, 4 or 6 of a cache line (to avoid
the wrong prediction bits being used in some cases).
D-Cache timing constraints:
-- Signed int loads of less than 64 bits have 3 cycle latency, not 2
-- All other loads that hit in D-Cache have 2 cycle latency
-- All loads are returned IN ORDER, so a D-Cache miss will delay a later hit
-- Mis-aligned loads or stores cause a trap. In particular, replace
mis-aligned FP double precision l/s with 2 single-precision l/s.
-- Simulations of integer codes show increase in avg. group size of
33% when code (including esp. non-faulting loads) is moved across
one branch, and 50% across 2 branches.
E-Cache timing constraints:
-- Scheduling for E-cache (D-Cache misses) is effective (due to load buffering)
Store buffer timing constraints:
-- Stores can be executed in same cycle as instruction producing the value
-- Stores are buffered and have lower priority for E-cache until
highwater mark is reached in the store buffer (5 stores)
Pipeline constraints:
-- Shifts can only use IEU0.
-- CC setting instructions can only use IEU1.
-- Several other instructions must only use IEU1:
EDGE(?), ARRAY(?), CALL, JMPL, BPr, PST, and FCMP.
-- Two instructions cannot store to the same register file in a single cycle
(single write port per file).
Issue and grouping constraints:
-- FP and branch instructions must use slot 4.
-- Shift instructions cannot be grouped with other IEU0-specific instructions.
-- CC setting instructions cannot be grouped with other IEU1-specific instrs.
-- Several instructions must be issued in a single-instruction group:
MOVcc or MOVr, MULs/x and DIVs/x, SAVE/RESTORE, many others
-- A CALL or JMPL breaks a group, ie, is not combined with subsequent instrs.
--
--
Branch delay slot scheduling rules:
-- A CTI couple (two back-to-back CTI instructions in the dynamic stream)
has a 9-instruction penalty: the entire pipeline is flushed when the
second instruction reaches stage 9 (W-Writeback).
-- Avoid putting multicycle instructions, and instructions that may cause
load misses, in the delay slot of an annulling branch.
-- Avoid putting WR, SAVE..., RESTORE and RETURN instructions in the
delay slot of an annulling branch.
*--------------------------------------------------------------------------- */
//---------------------------------------------------------------------------
// List of CPUResources for UltraSPARC IIi.
//---------------------------------------------------------------------------
static const CPUResource AllIssueSlots( "All Instr Slots", 4);
static const CPUResource IntIssueSlots( "Int Instr Slots", 3);
static const CPUResource First3IssueSlots("Instr Slots 0-3", 3);
static const CPUResource LSIssueSlots( "Load-Store Instr Slot", 1);
static const CPUResource CTIIssueSlots( "Ctrl Transfer Instr Slot", 1);
static const CPUResource FPAIssueSlots( "FP Instr Slot 1", 1);
static const CPUResource FPMIssueSlots( "FP Instr Slot 2", 1);
// IEUN instructions can use either Alu and should use IAluN.
// IEU0 instructions must use Alu 1 and should use both IAluN and IAlu0.
// IEU1 instructions must use Alu 2 and should use both IAluN and IAlu1.
static const CPUResource IAluN("Int ALU 1or2", 2);
static const CPUResource IAlu0("Int ALU 1", 1);
static const CPUResource IAlu1("Int ALU 2", 1);
static const CPUResource LSAluC1("Load/Store Unit Addr Cycle", 1);
static const CPUResource LSAluC2("Load/Store Unit Issue Cycle", 1);
static const CPUResource LdReturn("Load Return Unit", 1);
static const CPUResource FPMAluC1("FP Mul/Div Alu Cycle 1", 1);
static const CPUResource FPMAluC2("FP Mul/Div Alu Cycle 2", 1);
static const CPUResource FPMAluC3("FP Mul/Div Alu Cycle 3", 1);
static const CPUResource FPAAluC1("FP Other Alu Cycle 1", 1);
static const CPUResource FPAAluC2("FP Other Alu Cycle 2", 1);
static const CPUResource FPAAluC3("FP Other Alu Cycle 3", 1);
static const CPUResource IRegReadPorts("Int Reg ReadPorts", INT_MAX); // CHECK
static const CPUResource IRegWritePorts("Int Reg WritePorts", 2); // CHECK
static const CPUResource FPRegReadPorts("FP Reg Read Ports", INT_MAX);// CHECK
static const CPUResource FPRegWritePorts("FP Reg Write Ports", 1); // CHECK
static const CPUResource CTIDelayCycle( "CTI delay cycle", 1);
static const CPUResource FCMPDelayCycle("FCMP delay cycle", 1);
//---------------------------------------------------------------------------
// const InstrClassRUsage SparcV9RUsageDesc[]
//
// Purpose:
// Resource usage information for instruction in each scheduling class.
// The InstrRUsage Objects for individual classes are specified first.
// Note that fetch and decode are decoupled from the execution pipelines
// via an instr buffer, so they are not included in the cycles below.
//---------------------------------------------------------------------------
static const InstrClassRUsage NoneClassRUsage = {
SPARC_NONE,
/*totCycles*/ 7,
/* maxIssueNum */ 4,
/* isSingleIssue */ false,
/* breaksGroup */ false,
/* numBubbles */ 0,
/*numSlots*/ 4,
/* feasibleSlots[] */ { 0, 1, 2, 3 },
/*numEntries*/ 0,
/* V[] */ {
/*Cycle G */
/*Ccle E */
/*Cycle C */
/*Cycle N1*/
/*Cycle N1*/
/*Cycle N1*/
/*Cycle W */
}
};
static const InstrClassRUsage IEUNClassRUsage = {
SPARC_IEUN,
/*totCycles*/ 7,
/* maxIssueNum */ 3,
/* isSingleIssue */ false,
/* breaksGroup */ false,
/* numBubbles */ 0,
/*numSlots*/ 3,
/* feasibleSlots[] */ { 0, 1, 2 },
/*numEntries*/ 4,
/* V[] */ {
/*Cycle G */ { AllIssueSlots.rid, 0, 1 },
{ IntIssueSlots.rid, 0, 1 },
/*Cycle E */ { IAluN.rid, 1, 1 },
/*Cycle C */
/*Cycle N1*/
/*Cycle N1*/
/*Cycle N1*/
/*Cycle W */ { IRegWritePorts.rid, 6, 1 }
}
};
static const InstrClassRUsage IEU0ClassRUsage = {
SPARC_IEU0,
/*totCycles*/ 7,
/* maxIssueNum */ 1,
/* isSingleIssue */ false,
/* breaksGroup */ false,
/* numBubbles */ 0,
/*numSlots*/ 3,
/* feasibleSlots[] */ { 0, 1, 2 },
/*numEntries*/ 5,
/* V[] */ {
/*Cycle G */ { AllIssueSlots.rid, 0, 1 },
{ IntIssueSlots.rid, 0, 1 },
/*Cycle E */ { IAluN.rid, 1, 1 },
{ IAlu0.rid, 1, 1 },
/*Cycle C */
/*Cycle N1*/
/*Cycle N1*/
/*Cycle N1*/
/*Cycle W */ { IRegWritePorts.rid, 6, 1 }
}
};
static const InstrClassRUsage IEU1ClassRUsage = {
SPARC_IEU1,
/*totCycles*/ 7,
/* maxIssueNum */ 1,
/* isSingleIssue */ false,
/* breaksGroup */ false,
/* numBubbles */ 0,
/*numSlots*/ 3,
/* feasibleSlots[] */ { 0, 1, 2 },
/*numEntries*/ 5,
/* V[] */ {
/*Cycle G */ { AllIssueSlots.rid, 0, 1 },
{ IntIssueSlots.rid, 0, 1 },
/*Cycle E */ { IAluN.rid, 1, 1 },
{ IAlu1.rid, 1, 1 },
/*Cycle C */
/*Cycle N1*/
/*Cycle N1*/
/*Cycle N1*/
/*Cycle W */ { IRegWritePorts.rid, 6, 1 }
}
};
static const InstrClassRUsage FPMClassRUsage = {
SPARC_FPM,
/*totCycles*/ 7,
/* maxIssueNum */ 1,
/* isSingleIssue */ false,
/* breaksGroup */ false,
/* numBubbles */ 0,
/*numSlots*/ 4,
/* feasibleSlots[] */ { 0, 1, 2, 3 },
/*numEntries*/ 7,
/* V[] */ {
/*Cycle G */ { AllIssueSlots.rid, 0, 1 },
{ FPMIssueSlots.rid, 0, 1 },
/*Cycle E */ { FPRegReadPorts.rid, 1, 1 },
/*Cycle C */ { FPMAluC1.rid, 2, 1 },
/*Cycle N1*/ { FPMAluC2.rid, 3, 1 },
/*Cycle N1*/ { FPMAluC3.rid, 4, 1 },
/*Cycle N1*/
/*Cycle W */ { FPRegWritePorts.rid, 6, 1 }
}
};
static const InstrClassRUsage FPAClassRUsage = {
SPARC_FPA,
/*totCycles*/ 7,
/* maxIssueNum */ 1,
/* isSingleIssue */ false,
/* breaksGroup */ false,
/* numBubbles */ 0,
/*numSlots*/ 4,
/* feasibleSlots[] */ { 0, 1, 2, 3 },
/*numEntries*/ 7,
/* V[] */ {
/*Cycle G */ { AllIssueSlots.rid, 0, 1 },
{ FPAIssueSlots.rid, 0, 1 },
/*Cycle E */ { FPRegReadPorts.rid, 1, 1 },
/*Cycle C */ { FPAAluC1.rid, 2, 1 },
/*Cycle N1*/ { FPAAluC2.rid, 3, 1 },
/*Cycle N1*/ { FPAAluC3.rid, 4, 1 },
/*Cycle N1*/
/*Cycle W */ { FPRegWritePorts.rid, 6, 1 }
}
};
static const InstrClassRUsage LDClassRUsage = {
SPARC_LD,
/*totCycles*/ 7,
/* maxIssueNum */ 1,
/* isSingleIssue */ false,
/* breaksGroup */ false,
/* numBubbles */ 0,
/*numSlots*/ 3,
/* feasibleSlots[] */ { 0, 1, 2, },
/*numEntries*/ 6,
/* V[] */ {
/*Cycle G */ { AllIssueSlots.rid, 0, 1 },
{ First3IssueSlots.rid, 0, 1 },
{ LSIssueSlots.rid, 0, 1 },
/*Cycle E */ { LSAluC1.rid, 1, 1 },
/*Cycle C */ { LSAluC2.rid, 2, 1 },
{ LdReturn.rid, 2, 1 },
/*Cycle N1*/
/*Cycle N1*/
/*Cycle N1*/
/*Cycle W */ { IRegWritePorts.rid, 6, 1 }
}
};
static const InstrClassRUsage STClassRUsage = {
SPARC_ST,
/*totCycles*/ 7,
/* maxIssueNum */ 1,
/* isSingleIssue */ false,
/* breaksGroup */ false,
/* numBubbles */ 0,
/*numSlots*/ 3,
/* feasibleSlots[] */ { 0, 1, 2 },
/*numEntries*/ 4,
/* V[] */ {
/*Cycle G */ { AllIssueSlots.rid, 0, 1 },
{ First3IssueSlots.rid, 0, 1 },
{ LSIssueSlots.rid, 0, 1 },
/*Cycle E */ { LSAluC1.rid, 1, 1 },
/*Cycle C */ { LSAluC2.rid, 2, 1 }
/*Cycle N1*/
/*Cycle N1*/
/*Cycle N1*/
/*Cycle W */
}
};
static const InstrClassRUsage CTIClassRUsage = {
SPARC_CTI,
/*totCycles*/ 7,
/* maxIssueNum */ 1,
/* isSingleIssue */ false,
/* breaksGroup */ false,
/* numBubbles */ 0,
/*numSlots*/ 4,
/* feasibleSlots[] */ { 0, 1, 2, 3 },
/*numEntries*/ 4,
/* V[] */ {
/*Cycle G */ { AllIssueSlots.rid, 0, 1 },
{ CTIIssueSlots.rid, 0, 1 },
/*Cycle E */ { IAlu0.rid, 1, 1 },
/*Cycles E-C */ { CTIDelayCycle.rid, 1, 2 }
/*Cycle C */
/*Cycle N1*/
/*Cycle N1*/
/*Cycle N1*/
/*Cycle W */
}
};
static const InstrClassRUsage SingleClassRUsage = {
SPARC_SINGLE,
/*totCycles*/ 7,
/* maxIssueNum */ 1,
/* isSingleIssue */ true,
/* breaksGroup */ false,
/* numBubbles */ 0,
/*numSlots*/ 1,
/* feasibleSlots[] */ { 0 },
/*numEntries*/ 5,
/* V[] */ {
/*Cycle G */ { AllIssueSlots.rid, 0, 1 },
{ AllIssueSlots.rid, 0, 1 },
{ AllIssueSlots.rid, 0, 1 },
{ AllIssueSlots.rid, 0, 1 },
/*Cycle E */ { IAlu0.rid, 1, 1 }
/*Cycle C */
/*Cycle N1*/
/*Cycle N1*/
/*Cycle N1*/
/*Cycle W */
}
};
static const InstrClassRUsage SparcV9RUsageDesc[] = {
NoneClassRUsage,
IEUNClassRUsage,
IEU0ClassRUsage,
IEU1ClassRUsage,
FPMClassRUsage,
FPAClassRUsage,
CTIClassRUsage,
LDClassRUsage,
STClassRUsage,
SingleClassRUsage
};
//---------------------------------------------------------------------------
// const InstrIssueDelta SparcV9InstrIssueDeltas[]
//
// Purpose:
// Changes to issue restrictions information in InstrClassRUsage for
// instructions that differ from other instructions in their class.
//---------------------------------------------------------------------------
static const InstrIssueDelta SparcV9InstrIssueDeltas[] = {
// opCode, isSingleIssue, breaksGroup, numBubbles
// Special cases for single-issue only
// Other single issue cases are below.
//{ V9::LDDA, true, true, 0 },
//{ V9::STDA, true, true, 0 },
//{ V9::LDDF, true, true, 0 },
//{ V9::LDDFA, true, true, 0 },
{ V9::ADDCr, true, true, 0 },
{ V9::ADDCi, true, true, 0 },
{ V9::ADDCccr, true, true, 0 },
{ V9::ADDCcci, true, true, 0 },
{ V9::SUBCr, true, true, 0 },
{ V9::SUBCi, true, true, 0 },
{ V9::SUBCccr, true, true, 0 },
{ V9::SUBCcci, true, true, 0 },
//{ V9::LDSTUB, true, true, 0 },
//{ V9::SWAP, true, true, 0 },
//{ V9::SWAPA, true, true, 0 },
//{ V9::CAS, true, true, 0 },
//{ V9::CASA, true, true, 0 },
//{ V9::CASX, true, true, 0 },
//{ V9::CASXA, true, true, 0 },
//{ V9::LDFSR, true, true, 0 },
//{ V9::LDFSRA, true, true, 0 },
//{ V9::LDXFSR, true, true, 0 },
//{ V9::LDXFSRA, true, true, 0 },
//{ V9::STFSR, true, true, 0 },
//{ V9::STFSRA, true, true, 0 },
//{ V9::STXFSR, true, true, 0 },
//{ V9::STXFSRA, true, true, 0 },
//{ V9::SAVED, true, true, 0 },
//{ V9::RESTORED, true, true, 0 },
//{ V9::FLUSH, true, true, 9 },
//{ V9::FLUSHW, true, true, 9 },
//{ V9::ALIGNADDR, true, true, 0 },
//{ V9::DONE, true, true, 0 },
//{ V9::RETRY, true, true, 0 },
//{ V9::TCC, true, true, 0 },
//{ V9::SHUTDOWN, true, true, 0 },
// Special cases for breaking group *before*
// CURRENTLY NOT SUPPORTED!
{ V9::CALL, false, false, 0 },
{ V9::JMPLCALLr, false, false, 0 },
{ V9::JMPLCALLi, false, false, 0 },
{ V9::JMPLRETr, false, false, 0 },
{ V9::JMPLRETi, false, false, 0 },
// Special cases for breaking the group *after*
{ V9::MULXr, true, true, (4+34)/2 },
{ V9::MULXi, true, true, (4+34)/2 },
{ V9::FDIVS, false, true, 0 },
{ V9::FDIVD, false, true, 0 },
{ V9::FDIVQ, false, true, 0 },
{ V9::FSQRTS, false, true, 0 },
{ V9::FSQRTD, false, true, 0 },
{ V9::FSQRTQ, false, true, 0 },
//{ V9::FCMP{LE,GT,NE,EQ}, false, true, 0 },
// Instructions that introduce bubbles
//{ V9::MULScc, true, true, 2 },
//{ V9::SMULcc, true, true, (4+18)/2 },
//{ V9::UMULcc, true, true, (4+19)/2 },
{ V9::SDIVXr, true, true, 68 },
{ V9::SDIVXi, true, true, 68 },
{ V9::UDIVXr, true, true, 68 },
{ V9::UDIVXi, true, true, 68 },
//{ V9::SDIVcc, true, true, 36 },
//{ V9::UDIVcc, true, true, 37 },
{ V9::WRCCRr, true, true, 4 },
{ V9::WRCCRi, true, true, 4 },
//{ V9::WRPR, true, true, 4 },
//{ V9::RDCCR, true, true, 0 }, // no bubbles after, but see below
//{ V9::RDPR, true, true, 0 },
};
//---------------------------------------------------------------------------
// const InstrRUsageDelta SparcV9InstrUsageDeltas[]
//
// Purpose:
// Changes to resource usage information in InstrClassRUsage for
// instructions that differ from other instructions in their class.
//---------------------------------------------------------------------------
static const InstrRUsageDelta SparcV9InstrUsageDeltas[] = {
// MachineOpCode, Resource, Start cycle, Num cycles
//
// JMPL counts as a load/store instruction for issue!
//
{ V9::JMPLCALLr, LSIssueSlots.rid, 0, 1 },
{ V9::JMPLCALLi, LSIssueSlots.rid, 0, 1 },
{ V9::JMPLRETr, LSIssueSlots.rid, 0, 1 },
{ V9::JMPLRETi, LSIssueSlots.rid, 0, 1 },
//
// Many instructions cannot issue for the next 2 cycles after an FCMP
// We model that with a fake resource FCMPDelayCycle.
//
{ V9::FCMPS, FCMPDelayCycle.rid, 1, 3 },
{ V9::FCMPD, FCMPDelayCycle.rid, 1, 3 },
{ V9::FCMPQ, FCMPDelayCycle.rid, 1, 3 },
{ V9::MULXr, FCMPDelayCycle.rid, 1, 1 },
{ V9::MULXi, FCMPDelayCycle.rid, 1, 1 },
{ V9::SDIVXr, FCMPDelayCycle.rid, 1, 1 },
{ V9::SDIVXi, FCMPDelayCycle.rid, 1, 1 },
{ V9::UDIVXr, FCMPDelayCycle.rid, 1, 1 },
{ V9::UDIVXi, FCMPDelayCycle.rid, 1, 1 },
//{ V9::SMULcc, FCMPDelayCycle.rid, 1, 1 },
//{ V9::UMULcc, FCMPDelayCycle.rid, 1, 1 },
//{ V9::SDIVcc, FCMPDelayCycle.rid, 1, 1 },
//{ V9::UDIVcc, FCMPDelayCycle.rid, 1, 1 },
{ V9::STDFr, FCMPDelayCycle.rid, 1, 1 },
{ V9::STDFi, FCMPDelayCycle.rid, 1, 1 },
{ V9::FMOVRSZ, FCMPDelayCycle.rid, 1, 1 },
{ V9::FMOVRSLEZ,FCMPDelayCycle.rid, 1, 1 },
{ V9::FMOVRSLZ, FCMPDelayCycle.rid, 1, 1 },
{ V9::FMOVRSNZ, FCMPDelayCycle.rid, 1, 1 },
{ V9::FMOVRSGZ, FCMPDelayCycle.rid, 1, 1 },
{ V9::FMOVRSGEZ,FCMPDelayCycle.rid, 1, 1 },
//
// Some instructions are stalled in the GROUP stage if a CTI is in
// the E or C stage. We model that with a fake resource CTIDelayCycle.
//
{ V9::LDDFr, CTIDelayCycle.rid, 1, 1 },
{ V9::LDDFi, CTIDelayCycle.rid, 1, 1 },
//{ V9::LDDA, CTIDelayCycle.rid, 1, 1 },
//{ V9::LDDSTUB, CTIDelayCycle.rid, 1, 1 },
//{ V9::LDDSTUBA, CTIDelayCycle.rid, 1, 1 },
//{ V9::SWAP, CTIDelayCycle.rid, 1, 1 },
//{ V9::SWAPA, CTIDelayCycle.rid, 1, 1 },
//{ V9::CAS, CTIDelayCycle.rid, 1, 1 },
//{ V9::CASA, CTIDelayCycle.rid, 1, 1 },
//{ V9::CASX, CTIDelayCycle.rid, 1, 1 },
//{ V9::CASXA, CTIDelayCycle.rid, 1, 1 },
//
// Signed int loads of less than dword size return data in cycle N1 (not C)
// and put all loads in consecutive cycles into delayed load return mode.
//
{ V9::LDSBr, LdReturn.rid, 2, -1 },
{ V9::LDSBr, LdReturn.rid, 3, 1 },
{ V9::LDSBi, LdReturn.rid, 2, -1 },
{ V9::LDSBi, LdReturn.rid, 3, 1 },
{ V9::LDSHr, LdReturn.rid, 2, -1 },
{ V9::LDSHr, LdReturn.rid, 3, 1 },
{ V9::LDSHi, LdReturn.rid, 2, -1 },
{ V9::LDSHi, LdReturn.rid, 3, 1 },
{ V9::LDSWr, LdReturn.rid, 2, -1 },
{ V9::LDSWr, LdReturn.rid, 3, 1 },
{ V9::LDSWi, LdReturn.rid, 2, -1 },
{ V9::LDSWi, LdReturn.rid, 3, 1 },
//
// RDPR from certain registers and RD from any register are not dispatchable
// until four clocks after they reach the head of the instr. buffer.
// Together with their single-issue requirement, this means all four issue
// slots are effectively blocked for those cycles, plus the issue cycle.
// This does not increase the latency of the instruction itself.
//
{ V9::RDCCR, AllIssueSlots.rid, 0, 5 },
{ V9::RDCCR, AllIssueSlots.rid, 0, 5 },
{ V9::RDCCR, AllIssueSlots.rid, 0, 5 },
{ V9::RDCCR, AllIssueSlots.rid, 0, 5 },
#undef EXPLICIT_BUBBLES_NEEDED
#ifdef EXPLICIT_BUBBLES_NEEDED
//
// MULScc inserts one bubble.
// This means it breaks the current group (captured in UltraSparcV9SchedInfo)
// *and occupies all issue slots for the next cycle
//
//{ V9::MULScc, AllIssueSlots.rid, 2, 2-1 },
//{ V9::MULScc, AllIssueSlots.rid, 2, 2-1 },
//{ V9::MULScc, AllIssueSlots.rid, 2, 2-1 },
//{ V9::MULScc, AllIssueSlots.rid, 2, 2-1 },
//
// SMULcc inserts between 4 and 18 bubbles, depending on #leading 0s in rs1.
// We just model this with a simple average.
//
//{ V9::SMULcc, AllIssueSlots.rid, 2, ((4+18)/2)-1 },
//{ V9::SMULcc, AllIssueSlots.rid, 2, ((4+18)/2)-1 },
//{ V9::SMULcc, AllIssueSlots.rid, 2, ((4+18)/2)-1 },
//{ V9::SMULcc, AllIssueSlots.rid, 2, ((4+18)/2)-1 },
// SMULcc inserts between 4 and 19 bubbles, depending on #leading 0s in rs1.
//{ V9::UMULcc, AllIssueSlots.rid, 2, ((4+19)/2)-1 },
//{ V9::UMULcc, AllIssueSlots.rid, 2, ((4+19)/2)-1 },
//{ V9::UMULcc, AllIssueSlots.rid, 2, ((4+19)/2)-1 },
//{ V9::UMULcc, AllIssueSlots.rid, 2, ((4+19)/2)-1 },
//
// MULX inserts between 4 and 34 bubbles, depending on #leading 0s in rs1.
//
{ V9::MULX, AllIssueSlots.rid, 2, ((4+34)/2)-1 },
{ V9::MULX, AllIssueSlots.rid, 2, ((4+34)/2)-1 },
{ V9::MULX, AllIssueSlots.rid, 2, ((4+34)/2)-1 },
{ V9::MULX, AllIssueSlots.rid, 2, ((4+34)/2)-1 },
//
// SDIVcc inserts 36 bubbles.
//
//{ V9::SDIVcc, AllIssueSlots.rid, 2, 36-1 },
//{ V9::SDIVcc, AllIssueSlots.rid, 2, 36-1 },
//{ V9::SDIVcc, AllIssueSlots.rid, 2, 36-1 },
//{ V9::SDIVcc, AllIssueSlots.rid, 2, 36-1 },
// UDIVcc inserts 37 bubbles.
//{ V9::UDIVcc, AllIssueSlots.rid, 2, 37-1 },
//{ V9::UDIVcc, AllIssueSlots.rid, 2, 37-1 },
//{ V9::UDIVcc, AllIssueSlots.rid, 2, 37-1 },
//{ V9::UDIVcc, AllIssueSlots.rid, 2, 37-1 },
//
// SDIVX inserts 68 bubbles.
//
{ V9::SDIVX, AllIssueSlots.rid, 2, 68-1 },
{ V9::SDIVX, AllIssueSlots.rid, 2, 68-1 },
{ V9::SDIVX, AllIssueSlots.rid, 2, 68-1 },
{ V9::SDIVX, AllIssueSlots.rid, 2, 68-1 },
//
// UDIVX inserts 68 bubbles.
//
{ V9::UDIVX, AllIssueSlots.rid, 2, 68-1 },
{ V9::UDIVX, AllIssueSlots.rid, 2, 68-1 },
{ V9::UDIVX, AllIssueSlots.rid, 2, 68-1 },
{ V9::UDIVX, AllIssueSlots.rid, 2, 68-1 },
//
// WR inserts 4 bubbles.
//
//{ V9::WR, AllIssueSlots.rid, 2, 68-1 },
//{ V9::WR, AllIssueSlots.rid, 2, 68-1 },
//{ V9::WR, AllIssueSlots.rid, 2, 68-1 },
//{ V9::WR, AllIssueSlots.rid, 2, 68-1 },
//
// WRPR inserts 4 bubbles.
//
//{ V9::WRPR, AllIssueSlots.rid, 2, 68-1 },
//{ V9::WRPR, AllIssueSlots.rid, 2, 68-1 },
//{ V9::WRPR, AllIssueSlots.rid, 2, 68-1 },
//{ V9::WRPR, AllIssueSlots.rid, 2, 68-1 },
//
// DONE inserts 9 bubbles.
//
//{ V9::DONE, AllIssueSlots.rid, 2, 9-1 },
//{ V9::DONE, AllIssueSlots.rid, 2, 9-1 },
//{ V9::DONE, AllIssueSlots.rid, 2, 9-1 },
//{ V9::DONE, AllIssueSlots.rid, 2, 9-1 },
//
// RETRY inserts 9 bubbles.
//
//{ V9::RETRY, AllIssueSlots.rid, 2, 9-1 },
//{ V9::RETRY, AllIssueSlots.rid, 2, 9-1 },
//{ V9::RETRY, AllIssueSlots.rid, 2, 9-1 },
//{ V9::RETRY, AllIssueSlots.rid, 2, 9-1 },
#endif /*EXPLICIT_BUBBLES_NEEDED */
};
// Additional delays to be captured in code:
// 1. RDPR from several state registers (page 349)
// 2. RD from *any* register (page 349)
// 3. Writes to TICK, PSTATE, TL registers and FLUSH{W} instr (page 349)
// 4. Integer store can be in same group as instr producing value to store.
// 5. BICC and BPICC can be in the same group as instr producing CC (pg 350)
// 6. FMOVr cannot be in the same or next group as an IEU instr (pg 351).
// 7. The second instr. of a CTI group inserts 9 bubbles (pg 351)
// 8. WR{PR}, SVAE, SAVED, RESTORE, RESTORED, RETURN, RETRY, and DONE that
// follow an annulling branch cannot be issued in the same group or in
// the 3 groups following the branch.
// 9. A predicted annulled load does not stall dependent instructions.
// Other annulled delay slot instructions *do* stall dependents, so
// nothing special needs to be done for them during scheduling.
//10. Do not put a load use that may be annulled in the same group as the
// branch. The group will stall until the load returns.
//11. Single-prec. FP loads lock 2 registers, for dependency checking.
//
//
// Additional delays we cannot or will not capture:
// 1. If DCTI is last word of cache line, it is delayed until next line can be
// fetched. Also, other DCTI alignment-related delays (pg 352)
// 2. Load-after-store is delayed by 7 extra cycles if load hits in D-Cache.
// Also, several other store-load and load-store conflicts (pg 358)
// 3. MEMBAR, LD{X}FSR, LDD{A} and a bunch of other load stalls (pg 358)
// 4. There can be at most 8 outstanding buffered store instructions
// (including some others like MEMBAR, LDSTUB, CAS{AX}, and FLUSH)
//---------------------------------------------------------------------------
// class SparcV9SchedInfo
//
// Purpose:
// Scheduling information for the UltraSPARC.
// Primarily just initializes machine-dependent parameters in
// class TargetSchedInfo.
//---------------------------------------------------------------------------
/*ctor*/
SparcV9SchedInfo::SparcV9SchedInfo(const TargetMachine& tgt)
: TargetSchedInfo(tgt,
(unsigned int) SPARC_NUM_SCHED_CLASSES,
SparcV9RUsageDesc,
SparcV9InstrUsageDeltas,
SparcV9InstrIssueDeltas,
sizeof(SparcV9InstrUsageDeltas)/sizeof(InstrRUsageDelta),
sizeof(SparcV9InstrIssueDeltas)/sizeof(InstrIssueDelta))
{
maxNumIssueTotal = 4;
longestIssueConflict = 0; // computed from issuesGaps[]
// must be called after above parameters are initialized.
initializeResources();
}
void
SparcV9SchedInfo::initializeResources()
{
// Compute TargetSchedInfo::instrRUsages and TargetSchedInfo::issueGaps
TargetSchedInfo::initializeResources();
// Machine-dependent fixups go here. None for now.
}

View File

@ -1,52 +0,0 @@
//===- SparcV9StackSlots.cpp - Add empty stack slots to functions ---------===//
//
// 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 pass adds 2 empty slots at the top of function stack. These two slots
// are later used during code reoptimization for spilling the register values
// when rewriting branches.
//
//===----------------------------------------------------------------------===//
#include "SparcV9Internals.h"
#include "llvm/Constant.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Function.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "MachineFunctionInfo.h"
using namespace llvm;
namespace {
class StackSlots : public MachineFunctionPass {
const TargetMachine &Target;
public:
StackSlots(const TargetMachine &T) : Target(T) {}
const char *getPassName() const {
return "Stack Slot Insertion for profiling code";
}
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
AU.setPreservesCFG();
}
bool runOnMachineFunction(MachineFunction &MF) {
const Type *PtrInt = PointerType::get(Type::IntTy);
unsigned Size = Target.getTargetData().getTypeSize(PtrInt);
Value *V = Constant::getNullValue(Type::IntTy);
MF.getInfo<SparcV9FunctionInfo>()->allocateLocalVar(V, 2*Size);
return true;
}
};
}
FunctionPass *llvm::createStackSlotsPass(const TargetMachine &Target) {
return new StackSlots(Target);
}

View File

@ -1,303 +0,0 @@
//===-- SparcV9TargetMachine.cpp - SparcV9 Target Machine Implementation --===//
//
// 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.
//
//===----------------------------------------------------------------------===//
//
// Primary interface to machine description for the UltraSPARC. Primarily just
// initializes machine-dependent parameters in class TargetMachine, and creates
// machine-dependent subclasses for classes such as TargetInstrInfo.
//
//===----------------------------------------------------------------------===//
#include "llvm/Function.h"
#include "llvm/PassManager.h"
#include "llvm/Assembly/PrintModulePass.h"
#include "llvm/CodeGen/InstrScheduling.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Target/TargetMachineRegistry.h"
#include "llvm/Transforms/Scalar.h"
#include "MappingInfo.h"
#include "MachineFunctionInfo.h"
#include "MachineCodeForInstruction.h"
#include "SparcV9Internals.h"
#include "SparcV9TargetMachine.h"
#include "SparcV9BurgISel.h"
#include "llvm/Support/CommandLine.h"
using namespace llvm;
static const unsigned ImplicitRegUseList[] = { 0 }; /* not used yet */
// Build the MachineInstruction Description Array...
const TargetInstrDescriptor llvm::SparcV9MachineInstrDesc[] = {
#define I(ENUM, OPCODESTRING, NUMOPERANDS, RESULTPOS, MAXIMM, IMMSE, \
NUMDELAYSLOTS, LATENCY, SCHEDCLASS, INSTFLAGS) \
{ OPCODESTRING, NUMOPERANDS, RESULTPOS, MAXIMM, IMMSE, \
NUMDELAYSLOTS, LATENCY, SCHEDCLASS, INSTFLAGS, 0, \
ImplicitRegUseList, ImplicitRegUseList, 0 },
#include "SparcV9Instr.def"
};
//---------------------------------------------------------------------------
// Command line options to control choice of code generation passes.
//---------------------------------------------------------------------------
namespace llvm {
bool EmitMappingInfo = false;
}
namespace {
cl::opt<bool> DisableSched("disable-sched",
cl::desc("Disable sparcv9 local scheduling pass"));
cl::opt<bool> DisablePeephole("disable-peephole",
cl::desc("Disable sparcv9 peephole optimization pass"));
cl::opt<bool, true> EmitMappingInfoOpt("enable-maps", cl::ReallyHidden,
cl::location(EmitMappingInfo),
cl::init(false),
cl::desc("Emit LLVM-to-MachineCode mapping info to assembly"));
cl::opt<bool> EnableModSched("enable-modsched",
cl::desc("Enable modulo scheduling pass"), cl::Hidden);
cl::opt<bool> EnableSBModSched("enable-modschedSB",
cl::desc("Enable superblock modulo scheduling (experimental)"), cl::Hidden);
// Register the target.
RegisterTarget<SparcV9TargetMachine> X("sparcv9", " SPARC V9");
}
unsigned SparcV9TargetMachine::getJITMatchQuality() {
#if defined(__sparcv9)
return 10;
#else
return 0;
#endif
}
unsigned SparcV9TargetMachine::getModuleMatchQuality(const Module &M) {
// We strongly match "sparcv9-*".
std::string TT = M.getTargetTriple();
if (TT.size() >= 8 && std::string(TT.begin(), TT.begin()+8) == "sparcv9-")
return 20;
if (M.getEndianness() == Module::BigEndian &&
M.getPointerSize() == Module::Pointer64)
return 10; // Weak match
else if (M.getEndianness() != Module::AnyEndianness ||
M.getPointerSize() != Module::AnyPointerSize)
return 0; // Match for some other target
return getJITMatchQuality()/2;
}
//===---------------------------------------------------------------------===//
// Code generation/destruction passes
//===---------------------------------------------------------------------===//
namespace {
class ConstructMachineFunction : public FunctionPass {
TargetMachine &Target;
public:
ConstructMachineFunction(TargetMachine &T) : Target(T) {}
const char *getPassName() const {
return "ConstructMachineFunction";
}
bool runOnFunction(Function &F) {
MachineFunction::construct(&F, Target).getInfo<SparcV9FunctionInfo>()->CalculateArgSize();
return false;
}
};
struct DestroyMachineFunction : public FunctionPass {
const char *getPassName() const { return "DestroyMachineFunction"; }
static void freeMachineCode(Instruction &I) {
MachineCodeForInstruction::destroy(&I);
}
bool runOnFunction(Function &F) {
for (Function::iterator FI = F.begin(), FE = F.end(); FI != FE; ++FI)
for (BasicBlock::iterator I = FI->begin(), E = FI->end(); I != E; ++I)
MachineCodeForInstruction::get(I).dropAllReferences();
for (Function::iterator FI = F.begin(), FE = F.end(); FI != FE; ++FI)
for_each(FI->begin(), FI->end(), freeMachineCode);
MachineFunction::destruct(&F);
return false;
}
};
FunctionPass *createMachineCodeConstructionPass(TargetMachine &Target) {
return new ConstructMachineFunction(Target);
}
}
FunctionPass *llvm::createSparcV9MachineCodeDestructionPass() {
return new DestroyMachineFunction();
}
SparcV9TargetMachine::SparcV9TargetMachine(const Module &M,
const std::string &FS)
: TargetMachine("UltraSparcV9-Native", false),
schedInfo(*this),
regInfo(*this),
frameInfo(*this),
jitInfo(*this) {
}
/// addPassesToEmitFile - This method controls the entire code generation
/// process for the ultra sparc.
///
bool
SparcV9TargetMachine::addPassesToEmitFile(PassManager &PM, std::ostream &Out,
CodeGenFileType FileType,
bool Fast) {
if (FileType != TargetMachine::AssemblyFile) return true;
// FIXME: Implement efficient support for garbage collection intrinsics.
PM.add(createLowerGCPass());
// Replace malloc and free instructions with library calls.
PM.add(createLowerAllocationsPass());
// FIXME: implement the invoke/unwind instructions!
PM.add(createLowerInvokePass());
// FIXME: implement the switch instruction in the instruction selector.
PM.add(createLowerSwitchPass());
// decompose multi-dimensional array references into single-dim refs
PM.add(createDecomposeMultiDimRefsPass());
// Lower LLVM code to the form expected by the SPARCv9 instruction selector.
PM.add(createPreSelectionPass(*this));
PM.add(createLowerSelectPass());
// If the user's trying to read the generated code, they'll need to see the
// transformed input.
if (PrintMachineCode)
PM.add(new PrintModulePass());
// Construct and initialize the MachineFunction object for this fn.
PM.add(createMachineCodeConstructionPass(*this));
// Insert empty stackslots in the stack frame of each function
// so %fp+offset-8 and %fp+offset-16 are empty slots now!
PM.add(createStackSlotsPass(*this));
PM.add(createSparcV9BurgInstSelector(*this));
if(!DisableSched && PrintMachineCode)
PM.add(createMachineFunctionPrinterPass(&std::cerr, "Before local scheduling:\n"));
if (!DisableSched)
PM.add(createInstructionSchedulingWithSSAPass(*this));
if(PrintMachineCode && EnableModSched)
PM.add(createMachineFunctionPrinterPass(&std::cerr, "Before modulo scheduling:\n"));
//Use ModuloScheduling if enabled, otherwise use local scheduling if not disabled.
if(EnableModSched)
PM.add(createModuloSchedulingPass(*this));
if(EnableSBModSched)
PM.add(createModuloSchedulingSBPass(*this));
if (PrintMachineCode)
PM.add(createMachineFunctionPrinterPass(&std::cerr, "Before reg alloc:\n"));
PM.add(getRegisterAllocator(*this));
if (PrintMachineCode)
PM.add(createMachineFunctionPrinterPass(&std::cerr, "After reg alloc:\n"));
PM.add(createPrologEpilogInsertionPass());
if (!DisablePeephole)
PM.add(createPeepholeOptsPass(*this));
if (PrintMachineCode)
PM.add(createMachineFunctionPrinterPass(&std::cerr, "Final code:\n"));
if (EmitMappingInfo) {
PM.add(createInternalGlobalMapperPass());
PM.add(getMappingInfoAsmPrinterPass(Out));
}
// Output assembly language to the .s file. Assembly emission is split into
// two parts: Function output and Global value output. This is because
// function output is pipelined with all of the rest of code generation stuff,
// allowing machine code representations for functions to be free'd after the
// function has been emitted.
PM.add(createAsmPrinterPass(Out, *this));
// Free machine-code IR which is no longer needed:
PM.add(createSparcV9MachineCodeDestructionPass());
// Emit bytecode to the assembly file into its special section next
if (EmitMappingInfo)
PM.add(createBytecodeAsmPrinterPass(Out));
return false;
}
/// addPassesToJITCompile - This method controls the JIT method of code
/// generation for the UltraSparcV9.
///
void SparcV9JITInfo::addPassesToJITCompile(FunctionPassManager &PM) {
// FIXME: Implement efficient support for garbage collection intrinsics.
PM.add(createLowerGCPass());
// Replace malloc and free instructions with library calls.
PM.add(createLowerAllocationsPass());
// FIXME: implement the invoke/unwind instructions!
PM.add(createLowerInvokePass());
// FIXME: implement the switch instruction in the instruction selector.
PM.add(createLowerSwitchPass());
// decompose multi-dimensional array references into single-dim refs
PM.add(createDecomposeMultiDimRefsPass());
// Lower LLVM code to the form expected by the SPARCv9 instruction selector.
PM.add(createPreSelectionPass(TM));
PM.add(createLowerSelectPass());
// If the user's trying to read the generated code, they'll need to see the
// transformed input.
if (PrintMachineCode)
PM.add(new PrintFunctionPass());
// Construct and initialize the MachineFunction object for this fn.
PM.add(createMachineCodeConstructionPass(TM));
PM.add(createSparcV9BurgInstSelector(TM));
if (PrintMachineCode)
PM.add(createMachineFunctionPrinterPass(&std::cerr, "Before reg alloc:\n"));
PM.add(getRegisterAllocator(TM));
if (PrintMachineCode)
PM.add(createMachineFunctionPrinterPass(&std::cerr, "After reg alloc:\n"));
PM.add(createPrologEpilogInsertionPass());
if (!DisablePeephole)
PM.add(createPeepholeOptsPass(TM));
if (PrintMachineCode)
PM.add(createMachineFunctionPrinterPass(&std::cerr, "Final code:\n"));
}

View File

@ -1,57 +0,0 @@
//===-- SparcV9TargetMachine.h - Define TargetMachine for SparcV9 -*- 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 declares the top-level SparcV9 target machine.
//
//===----------------------------------------------------------------------===//
#ifndef SPARCV9TARGETMACHINE_H
#define SPARCV9TARGETMACHINE_H
#include "llvm/Target/TargetFrameInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "SparcV9InstrInfo.h"
#include "SparcV9Internals.h"
#include "SparcV9RegInfo.h"
#include "SparcV9FrameInfo.h"
#include "SparcV9JITInfo.h"
namespace llvm {
class PassManager;
class SparcV9TargetMachine : public TargetMachine {
SparcV9InstrInfo instrInfo;
SparcV9SchedInfo schedInfo;
SparcV9RegInfo regInfo;
SparcV9FrameInfo frameInfo;
SparcV9JITInfo jitInfo;
public:
SparcV9TargetMachine(const Module &M, const std::string &FS);
virtual const TargetInstrInfo *getInstrInfo() const { return &instrInfo; }
virtual const TargetSchedInfo *getSchedInfo() const { return &schedInfo; }
virtual const SparcV9RegInfo *getRegInfo() const { return &regInfo; }
virtual const TargetFrameInfo *getFrameInfo() const { return &frameInfo; }
virtual TargetJITInfo *getJITInfo() { return &jitInfo; }
virtual const MRegisterInfo *getRegisterInfo() const {
return &instrInfo.getRegisterInfo();
}
virtual bool addPassesToEmitFile(PassManager &PM, std::ostream &Out,
CodeGenFileType FileType, bool Fast);
virtual bool addPassesToEmitMachineCode(FunctionPassManager &PM,
MachineCodeEmitter &MCE);
static unsigned getModuleMatchQuality(const Module &M);
static unsigned getJITMatchQuality();
};
} // End llvm namespace
#endif

View File

@ -1,72 +0,0 @@
//===- SparcV9TmpInstr.cpp - SparcV9 Intermediate Value class -------------===//
//
// 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.
//
//===----------------------------------------------------------------------===//
//
// Methods of class for temporary intermediate values used within the current
// SparcV9 backend.
//
//===----------------------------------------------------------------------===//
#include "SparcV9TmpInstr.h"
#include "llvm/Type.h"
#include "llvm/Support/LeakDetector.h"
using namespace llvm;
TmpInstruction::TmpInstruction(const TmpInstruction &TI)
: Instruction(TI.getType(), TI.getOpcode(), Ops, TI.getNumOperands()) {
if (TI.getNumOperands()) {
Ops[0].init(TI.Ops[0], this);
if (TI.getNumOperands() == 2)
Ops[1].init(TI.Ops[1], this);
else
assert(0 && "Bad # operands to TmpInstruction!");
}
}
TmpInstruction::TmpInstruction(Value *s1, Value *s2, const std::string &name)
: Instruction(s1->getType(), Instruction::UserOp1, Ops, 1+(s2 != 0), name) {
Ops[0].init(s1, this); // s1 must be non-null
if (s2)
Ops[1].init(s2, this);
// TmpInstructions should not be garbage checked.
LeakDetector::removeGarbageObject(this);
}
TmpInstruction::TmpInstruction(MachineCodeForInstruction& mcfi,
Value *s1, Value *s2, const std::string &name)
: Instruction(s1->getType(), Instruction::UserOp1, Ops, 1+(s2 != 0), name) {
mcfi.addTemp(this);
Ops[0].init(s1, this); // s1 must be non-null
if (s2)
Ops[1].init(s2, this);
// TmpInstructions should not be garbage checked.
LeakDetector::removeGarbageObject(this);
}
// Constructor that requires the type of the temporary to be specified.
// Both S1 and S2 may be NULL.
TmpInstruction::TmpInstruction(MachineCodeForInstruction& mcfi,
const Type *Ty, Value *s1, Value* s2,
const std::string &name)
: Instruction(Ty, Instruction::UserOp1, Ops, (s1 != 0)+(s2 != 0), name) {
mcfi.addTemp(this);
assert((s1 != 0 || s2 == 0) &&
"s2 cannot be non-null if s1 is non-null!");
if (s1) {
Ops[0].init(s1, this);
if (s2)
Ops[1].init(s2, this);
}
// TmpInstructions should not be garbage checked.
LeakDetector::removeGarbageObject(this);
}

View File

@ -1,64 +0,0 @@
//===-- SparcV9TmpInstr.h ---------------------------------------*- 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.
//
//===----------------------------------------------------------------------===//
//
// Definition of class for temporary intermediate values used within the current
// SparcV9 backend.
//
//===----------------------------------------------------------------------===//
#ifndef SPARCV9TMPINSTR_H
#define SPARCV9TMPINSTR_H
#include "llvm/Instruction.h"
#include "MachineCodeForInstruction.h"
namespace llvm {
/// TmpInstruction - This class represents temporary intermediate
/// values used within the SparcV9 machine code for an LLVM instruction.
///
class TmpInstruction : public Instruction {
Use Ops[2];
TmpInstruction(const TmpInstruction &TI);
public:
// Constructor that uses the type of S1 as the type of the temporary.
// s1 must be a valid value. s2 may be NULL.
TmpInstruction(MachineCodeForInstruction &mcfi,
Value *s1, Value *s2 = 0, const std::string &name = "");
// Constructor that uses the type of S1 as the type of the temporary,
// but does not require a MachineCodeForInstruction.
// s1 must be a valid value. s2 may be NULL.
TmpInstruction(Value *s1, Value *s2 = 0, const std::string &name = "");
// Constructor that requires the type of the temporary to be specified.
// Both S1 and S2 may be NULL.
TmpInstruction(MachineCodeForInstruction& mcfi,
const Type *Ty, Value *s1 = 0, Value* s2 = 0,
const std::string &name = "");
virtual Instruction *clone() const {
assert(0 && "Cannot clone TmpInstructions!");
return 0;
}
virtual const char *getOpcodeName() const { return "TmpInstruction"; }
// Methods for support type inquiry through isa, cast, and dyn_cast:
static inline bool classof(const TmpInstruction *) { return true; }
static inline bool classof(const Instruction *I) {
return (I->getOpcode() == Instruction::UserOp1);
}
static inline bool classof(const Value *V) {
return isa<Instruction>(V) && classof(cast<Instruction>(V));
}
};
} // End llvm namespace
#endif

View File

@ -1,71 +0,0 @@
//===- SparcV9_F2.td - SparcV9 Format 2 instructions -------*- tablegen -*-===//
//
// 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.
//
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
// Format #2 classes
//
class F2 : InstV9 { // Format 2 instructions
bits<3> op2;
let op = 0; // Op = 0
let Inst{24-22} = op2;
}
// Format 2.1 instructions
class F2_1<string name> : F2 {
bits<22> imm;
bits<5> rd;
let Name = name;
let Inst{29-25} = rd;
let Inst{21-0} = imm;
}
class F2_br : F2 { // Format 2 Branch instruction
let isBranch = 1; // All instances are branch instructions
}
class F2_2<bits<4> cond, string name> : F2_br { // Format 2.2 instructions
bits<22> disp;
bit annul = 0; // currently unused by SparcV9 backend
let Name = name;
let Inst{29} = annul;
let Inst{28-25} = cond;
let Inst{21-0} = disp;
}
class F2_3<bits<4> cond, string name> : F2_br { // Format 2.3 instructions
bits<2> cc;
bits<19> disp;
bit predict = 1;
bit annul = 0; // currently unused by SparcV9 backend
let Name = name;
let Inst{29} = annul;
let Inst{28-25} = cond;
let Inst{21-20} = cc;
let Inst{19} = predict;
let Inst{18-0} = disp;
}
class F2_4<bits<3> rcond, string name> : F2_br { // Format 2.4 instructions
bits<5> rs1;
bits<16> disp;
bit predict = 1;
bit annul = 0; // currently unused by SparcV9 backend
let Name = name;
let Inst{29} = annul;
let Inst{28} = 0;
let Inst{27-25} = rcond;
let Inst{21-20} = disp{15-14};
let Inst{19} = predict;
let Inst{18-14} = rs1;
let Inst{13-0 } = disp{13-0};
}

View File

@ -1,267 +0,0 @@
//===- SparcV9_F3.td - SparcV9 Format 3 Instructions -------*- tablegen -*-===//
//
// 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.
//
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
// Format #3 classes
//
// F3 - Common superclass of all F3 instructions. All instructions have an op3
// field.
class F3 : InstV9 {
bits<6> op3;
let op{1} = 1; // Op = 2 or 3
let Inst{24-19} = op3;
}
// F3_rs1 - Common class of instructions that have an rs1 field
class F3_rs1 : F3 {
bits<5> rs1;
let Inst{18-14} = rs1;
}
// F3_rs1rs2 - Common class of instructions that only have rs1 and rs2 fields
class F3_rs1rs2 : F3_rs1 {
bits<5> rs2;
let Inst{4-0} = rs2;
}
// F3_rs1rs2 - Common class of instructions that only have rs1 and rs2 fields
class F3_rs1rs2rd : F3_rs1rs2 {
bits<5> rd;
let Inst{29-25} = rd;
}
// F3_rs1simm13 - Common class of instructions that only have rs1 and simm13
class F3_rs1simm13 : F3_rs1 {
bits<13> simm13;
let Inst{12-0} = simm13;
}
class F3_rs1simm13rd : F3_rs1simm13 {
bits<5> rd;
let Inst{29-25} = rd;
}
// F3_rs1rd - Common class of instructions that have an rs1 and rd fields
class F3_rs1rd : F3_rs1 {
bits<5> rd;
let Inst{29-25} = rd;
}
// F3_rs2 - Common class of instructions that don't use an rs1
class F3_rs2 : F3 {
bits<5> rs2;
let Inst{4-0} = rs2;
}
// F3_rs2rd - Common class of instructions that use rs2 and rd, but not rs1
class F3_rs2rd : F3_rs2 {
bits<5> rd;
let Inst{29-25} = rd;
}
// F3_rd - Common class of instructions that have an rd field
class F3_rd : F3 {
bits<5> rd;
let Inst{29-25} = rd;
}
// F3_rdrs1 - Common class of instructions that have rd and rs1 fields
class F3_rdrs1 : F3_rd {
bits<5> rs1;
let Inst{18-14} = rs1;
}
// F3_rdrs1simm13 - Common class of instructions that have rd, rs1, and simm13
class F3_rdrs1simm13 : F3_rdrs1 {
bits<13> simm13;
let Inst{12-0} = simm13;
}
// F3_rdrs1rs2 - Common class of instructions that have rd, rs1, and rs2 fields
class F3_rdrs1rs2 : F3_rdrs1 {
bits<5> rs2;
let Inst{4-0} = rs2;
}
// Specific F3 classes...
//
class F3_1<bits<2> opVal, bits<6> op3val, string name> : F3_rs1rs2rd {
let op = opVal;
let op3 = op3val;
let Name = name;
let Inst{13} = 0; // i field = 0
let Inst{12-5} = 0; // don't care
}
// The store instructions seem to like to see rd first, then rs1 and rs2
class F3_1rd<bits<2> opVal, bits<6> op3val, string name> : F3_rdrs1rs2 {
let op = opVal;
let op3 = op3val;
let Name = name;
let Inst{13} = 0; // i field = 0
let Inst{12-5} = 0; // don't care
}
class F3_2<bits<2> opVal, bits<6> op3val, string name> : F3_rs1simm13rd {
let op = opVal;
let op3 = op3val;
let Name = name;
let Inst{13} = 1; // i field = 1
}
// The store instructions seem to like to see rd first, then rs1 and imm
class F3_2rd<bits<2> opVal, bits<6> op3val, string name> : F3_rdrs1simm13 {
let op = opVal;
let op3 = op3val;
let Name = name;
let Inst{13} = 1; // i field = 1
}
class F3_3<bits<2> opVal, bits<6> op3val, string name> : F3_rs1rs2 {
let op = opVal;
let op3 = op3val;
let Name = name;
let Inst{29-25} = 0; // don't care
let Inst{13} = 0; // i field = 0
let Inst{12-5} = 0; // don't care
}
class F3_4<bits<2> opVal, bits<6> op3Val, string name> : F3_rs1simm13 {
let op = opVal;
let op3 = op3Val;
let Name = name;
let Inst{29-25} = 0; // don't care
let Inst{13} = 1; // i field = 1
let Inst{12-0} = simm13;
}
class F3_5<bits<2> opVal, bits<6> op3Val, bits<3> rcondVal,
string name> : F3_rs1rs2rd {
let op = opVal;
let op3 = op3Val;
let Name = name;
let Inst{13} = 0; // i field = 0
let Inst{12-10} = rcondVal; // rcond field
let Inst{9-5} = 0; // don't care
}
class F3_6<bits<2> opVal, bits<6> op3Val, bits<3> rcondVal,
string name> : F3_rs1 {
bits<10> simm10;
bits<5> rd;
let op = opVal;
let op3 = op3Val;
let Name = name;
let Inst{29-25} = rd;
let Inst{13} = 1; // i field = 1
let Inst{12-10} = rcondVal; // rcond field
let Inst{9-0} = simm10;
}
//FIXME: classes 7-10 not defined!!
class F3_11<bits<2> opVal, bits<6> op3Val, string name> : F3_rs1rs2rd {
bit x;
let op = opVal;
let op3 = op3Val;
let Name = name;
let Inst{13} = 0; // i field = 0
let Inst{12} = x;
let Inst{11-5} = 0; // don't care
}
class F3_12<bits<2> opVal, bits<6> op3Val, string name> : F3_rs1 {
bits<5> shcnt;
bits<5> rd;
let op = opVal;
let op3 = op3Val;
let Name = name;
let Inst{29-25} = rd;
let Inst{13} = 1; // i field = 1
let Inst{12} = 0; // x field = 0
let Inst{11-5} = 0; // don't care
let Inst{4-0} = shcnt;
}
class F3_13<bits<2> opVal, bits<6> op3Val, string name> : F3_rs1 {
bits<6> shcnt;
bits<5> rd;
let op = opVal;
let op3 = op3Val;
let Name = name;
let Inst{29-25} = rd;
let Inst{13} = 1; // i field = 1
let Inst{12} = 1; // x field = 1
let Inst{11-6} = 0; // don't care
let Inst{5-0} = shcnt;
}
class F3_14<bits<2> opVal, bits<6> op3Val,
bits<9> opfVal, string name> : F3_rs2rd {
let op = opVal;
let op3 = op3Val;
let Name = name;
let Inst{18-14} = 0; // don't care
let Inst{13-5} = opfVal;
}
class F3_15<bits<2> opVal, bits<6> op3Val,
bits<9> opfVal, string name> : F3 {
bits<2> cc;
bits<5> rs1;
bits<5> rs2;
let op = opVal;
let op3 = op3Val;
let Name = name;
let Inst{29-27} = 0; // defined to be zero
let Inst{26-25} = cc;
let Inst{18-14} = rs1;
let Inst{13-5} = opfVal;
let Inst{4-0} = rs2;
}
class F3_16<bits<2> opVal, bits<6> op3Val,
bits<9> opfval, string name> : F3_rs1rs2rd {
let op = opVal;
let op3 = op3Val;
let Name = name;
let Inst{13-5} = opfval;
}
class F3_17<bits<2> opVal, bits<6> op3Val, string name> : F3_rs1rd {
let op = opVal;
let op3 = op3Val;
let Name = name;
let Inst{13-0} = 0; // don't care
}
class F3_18<bits<5> fcn, string name> : F3 {
let op = 2;
let op3 = 0b111110;
let Name = name;
let Inst{29-25} = fcn;
let Inst{18-0 } = 0; // don't care;
}
class F3_19<bits<2> opVal, bits<6> op3Val, string name> : F3_rd {
let op = opVal;
let op3 = op3Val;
let Name = name;
let Inst{18-0} = 0; // don't care
}
// FIXME: class F3_20
// FIXME: class F3_21

View File

@ -1,141 +0,0 @@
//===- SparcV9_F4.td - SparcV9 Format 4 instructions -------*- tablegen -*-===//
//
// 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.
//
//===----------------------------------------------------------------------===//
//----------------------- F4 classes -----------------------------------------
// F4 - Common superclass of all F4 instructions. All instructions have an op3
// field.
class F4 : InstV9 {
bits<6> op3;
let Inst{24-19} = op3;
}
// F4_rs1 - Common class of instructions that use an rs1 field
class F4_rs1 : F4 {
bits<5> rs1;
let Inst{18-14} = rs1;
}
// F4_rs1rs2 - Common class of instructions that have rs1 and rs2 fields
class F4_rs1rs2 : F4_rs1 {
bits<5> rs2;
let Inst{4-0} = rs2;
}
// F4_rs1rs2rd - Common class of instructions that have 3 register operands
class F4_rs1rs2rd : F4_rs1rs2 {
bits<5> rd;
let Inst{29-25} = rd;
}
// F4_rs1rs2rd - Common class of instructions that have 2 reg and 1 imm operand
class F4_rs1simm11rd : F4_rs1 {
bits<11> simm11;
bits<5> rd;
let Inst{10-0} = simm11;
let Inst{29-25} = rd;
}
// F4_cc - Common class of instructions that have a cond field
class F4_cond : F4 {
bits<4> cond;
let Inst{17-14} = cond;
}
// F4_cc - Common class of instructions that have cc register as first operand
class F4_condcc : F4_cond {
bits<3> cc;
let Inst{18} = cc{2};
let Inst{12} = cc{1};
let Inst{11} = cc{0};
}
// Actual F4 instruction classes
//
class F4_1<bits<2> opVal, bits<6> op3Val, string name> : F4_rs1rs2rd {
bits<2> cc;
let op = opVal;
let op3 = op3Val;
let Name = name;
let Inst{13} = 0; // i bit
let Inst{12-11} = cc;
let Inst{10-5} = 0; // don't care
}
class F4_2<bits<2> opVal, bits<6> op3Val, string name> : F4_rs1simm11rd {
bits<2> cc;
let op = opVal;
let op3 = op3Val;
let Name = name;
let Inst{13} = 1; // i bit
let Inst{12-11} = cc;
}
class F4_3<bits<2> opVal, bits<6> op3Val, bits<4> condVal,
string name> : F4_condcc {
bits<5> rs2;
bits<5> rd;
let op = opVal;
let op3 = op3Val;
let cond = condVal;
let Name = name;
let Inst{29-25} = rd;
let Inst{13} = 0; // i bit
let Inst{10-5} = 0; // don't care
let Inst{4-0} = rs2;
}
class F4_4<bits<2> opVal, bits<6> op3Val, bits<4> condVal,
string name> : F4_condcc {
bits<11> simm11;
bits<5> rd;
let op = opVal;
let op3 = op3Val;
let cond = condVal;
let Name = name;
let Inst{29-25} = rd;
let Inst{13} = 1; // i bit
let Inst{10-0} = simm11;
}
// FIXME: class F4_5
class F4_6<bits<2> opVal, bits<6> op3Val, bits<3> rcondVal,
bits<5> opf_lowVal, string name> : F4_rs1rs2rd {
let op = opVal;
let op3 = op3Val;
let Name = name;
let Inst{13} = 0;
let Inst{12-10} = rcondVal;
let Inst{9-5} = opf_lowVal;
}
class F4_7<bits<2> opVal, bits<6> op3Val, bits<4> condVal,
bits<6> opf_lowVal, string name> : F4_cond {
bits<3> cc;
bits<5> rs2;
bits<5> rd;
let op = opVal;
let op3 = op3Val;
let cond = condVal;
let Name = name;
let Inst{29-25} = rd;
let Inst{18} = 0;
let Inst{13-11} = cc;
let Inst{10-5} = opf_lowVal;
let Inst{4-0} = rs2;
}
// FIXME: F4 classes 8-9