mirror of
https://github.com/RPCS3/llvm.git
synced 2025-01-07 12:30:57 +00:00
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:
parent
43c40ffa41
commit
2706983c48
@ -1,4 +0,0 @@
|
||||
*.inc
|
||||
SparcV9.burg.in1
|
||||
SparcV9.burm
|
||||
SparcV9.burm.cpp
|
@ -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;
|
||||
}
|
||||
|
@ -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
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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.
|
||||
}
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
||||
|
@ -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
|
@ -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;
|
||||
}
|
@ -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
|
@ -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
|
||||
}
|
@ -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
|
@ -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
|
@ -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
|
||||
|
@ -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
|
@ -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
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
@ -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";
|
||||
}
|
||||
|
@ -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
|
@ -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";
|
||||
}
|
||||
}
|
@ -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
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
@ -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
@ -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 ⌖
|
||||
|
||||
//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
|
File diff suppressed because it is too large
Load Diff
@ -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 ⌖
|
||||
|
||||
//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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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]);
|
||||
}
|
@ -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;
|
||||
}
|
@ -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
@ -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
|
@ -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"
|
||||
|
@ -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
|
@ -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;
|
||||
}
|
@ -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 ⌖
|
||||
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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
||||
}
|
@ -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
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
@ -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 ⌖
|
||||
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
|
@ -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);
|
||||
}
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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 ⌖
|
||||
|
||||
// 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
|
@ -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;
|
||||
}
|
@ -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
|
@ -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]>;
|
@ -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
|
@ -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.
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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"));
|
||||
}
|
||||
|
@ -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 ®Info; }
|
||||
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
|
@ -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);
|
||||
}
|
@ -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
|
@ -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};
|
||||
}
|
@ -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
|
@ -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
|
Loading…
Reference in New Issue
Block a user