+++ /dev/null
-*.inc
-SparcV9.burg.in1
-SparcV9.burm
-SparcV9.burm.cpp
+++ /dev/null
-//===- 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;
-}
-
+++ /dev/null
-//===-- 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);
-}
-
+++ /dev/null
-//===- InstrScheduling.cpp - Generic Instruction Scheduling support -------===//
-//
-// 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 llvm/CodeGen/InstrScheduling.h interface, along with
-// generic support routines for instruction scheduling.
-//
-//===----------------------------------------------------------------------===//
-
-#include "SchedPriorities.h"
-#include "llvm/BasicBlock.h"
-#include "llvm/CodeGen/MachineInstr.h"
-#include "llvm/CodeGen/MachineFunction.h"
-#include "llvm/Target/TargetMachine.h"
-#include "../MachineCodeForInstruction.h"
-#include "../LiveVar/FunctionLiveVarInfo.h"
-#include "../SparcV9InstrInfo.h"
-#include "llvm/Support/CommandLine.h"
-#include <algorithm>
-#include <iostream>
-
-namespace llvm {
-
-SchedDebugLevel_t SchedDebugLevel;
-
-static cl::opt<bool> EnableFillingDelaySlots("sched-fill-delay-slots", cl::Hidden,
- cl::desc("Fill branch delay slots during local scheduling"));
-
-static cl::opt<SchedDebugLevel_t, true>
-SDL_opt("dsched", cl::Hidden, cl::location(SchedDebugLevel),
- cl::desc("enable instruction scheduling debugging information"),
- cl::values(
- clEnumValN(Sched_NoDebugInfo, "n", "disable debug output"),
- clEnumValN(Sched_PrintMachineCode, "y", "print machine code after scheduling"),
- clEnumValN(Sched_PrintSchedTrace, "t", "print trace of scheduling actions"),
- clEnumValN(Sched_PrintSchedGraphs, "g", "print scheduling graphs"),
- clEnumValEnd));
-
-
-//************************* Internal Data Types *****************************/
-
-class InstrSchedule;
-class SchedulingManager;
-
-
-//----------------------------------------------------------------------
-// class InstrGroup:
-//
-// Represents a group of instructions scheduled to be issued
-// in a single cycle.
-//----------------------------------------------------------------------
-
-class InstrGroup {
- InstrGroup(const InstrGroup&); // DO NOT IMPLEMENT
- void operator=(const InstrGroup&); // DO NOT IMPLEMENT
-
-public:
- inline const SchedGraphNode* operator[](unsigned int slotNum) const {
- assert(slotNum < group.size());
- return group[slotNum];
- }
-
-private:
- friend class InstrSchedule;
-
- inline void addInstr(const SchedGraphNode* node, unsigned int slotNum) {
- assert(slotNum < group.size());
- group[slotNum] = node;
- }
-
- /*ctor*/ InstrGroup(unsigned int nslots)
- : group(nslots, NULL) {}
-
- /*ctor*/ InstrGroup(); // disable: DO NOT IMPLEMENT
-
-private:
- std::vector<const SchedGraphNode*> group;
-};
-
-
-//----------------------------------------------------------------------
-// class ScheduleIterator:
-//
-// Iterates over the machine instructions in the for a single basic block.
-// The schedule is represented by an InstrSchedule object.
-//----------------------------------------------------------------------
-
-template<class _NodeType>
-class ScheduleIterator : public forward_iterator<_NodeType, ptrdiff_t> {
-private:
- unsigned cycleNum;
- unsigned slotNum;
- const InstrSchedule& S;
-public:
- typedef ScheduleIterator<_NodeType> _Self;
-
- /*ctor*/ inline ScheduleIterator(const InstrSchedule& _schedule,
- unsigned _cycleNum,
- unsigned _slotNum)
- : cycleNum(_cycleNum), slotNum(_slotNum), S(_schedule) {
- skipToNextInstr();
- }
-
- /*ctor*/ inline ScheduleIterator(const _Self& x)
- : cycleNum(x.cycleNum), slotNum(x.slotNum), S(x.S) {}
-
- inline bool operator==(const _Self& x) const {
- return (slotNum == x.slotNum && cycleNum== x.cycleNum && &S==&x.S);
- }
-
- inline bool operator!=(const _Self& x) const { return !operator==(x); }
-
- inline _NodeType* operator*() const;
- inline _NodeType* operator->() const { return operator*(); }
-
- _Self& operator++(); // Preincrement
- inline _Self operator++(int) { // Postincrement
- _Self tmp(*this); ++*this; return tmp;
- }
-
- static _Self begin(const InstrSchedule& _schedule);
- static _Self end( const InstrSchedule& _schedule);
-
-private:
- inline _Self& operator=(const _Self& x); // DISABLE -- DO NOT IMPLEMENT
- void skipToNextInstr();
-};
-
-
-//----------------------------------------------------------------------
-// class InstrSchedule:
-//
-// Represents the schedule of machine instructions for a single basic block.
-//----------------------------------------------------------------------
-
-class InstrSchedule {
- const unsigned int nslots;
- unsigned int numInstr;
- std::vector<InstrGroup*> groups; // indexed by cycle number
- std::vector<CycleCount_t> startTime; // indexed by node id
-
- InstrSchedule(InstrSchedule&); // DO NOT IMPLEMENT
- void operator=(InstrSchedule&); // DO NOT IMPLEMENT
-
-public: // iterators
- typedef ScheduleIterator<SchedGraphNode> iterator;
- typedef ScheduleIterator<const SchedGraphNode> const_iterator;
-
- iterator begin() { return iterator::begin(*this); }
- const_iterator begin() const { return const_iterator::begin(*this); }
- iterator end() { return iterator::end(*this); }
- const_iterator end() const { return const_iterator::end(*this); }
-
-public: // constructors and destructor
- /*ctor*/ InstrSchedule (unsigned int _nslots,
- unsigned int _numNodes);
- /*dtor*/ ~InstrSchedule ();
-
-public: // accessor functions to query chosen schedule
- const SchedGraphNode* getInstr (unsigned int slotNum,
- CycleCount_t c) {
- const InstrGroup* igroup = this->getIGroup(c);
- return (igroup == NULL)? NULL : (*igroup)[slotNum];
- }
-
- inline InstrGroup* getIGroup (CycleCount_t c) {
- if ((unsigned)c >= groups.size())
- groups.resize(c+1);
- if (groups[c] == NULL)
- groups[c] = new InstrGroup(nslots);
- return groups[c];
- }
-
- inline const InstrGroup* getIGroup (CycleCount_t c) const {
- assert((unsigned)c < groups.size());
- return groups[c];
- }
-
- inline CycleCount_t getStartTime (unsigned int nodeId) const {
- assert(nodeId < startTime.size());
- return startTime[nodeId];
- }
-
- unsigned int getNumInstructions() const {
- return numInstr;
- }
-
- inline void scheduleInstr (const SchedGraphNode* node,
- unsigned int slotNum,
- CycleCount_t cycle) {
- InstrGroup* igroup = this->getIGroup(cycle);
- if (!((*igroup)[slotNum] == NULL)) {
- std::cerr << "Slot already filled?\n";
- abort();
- }
- igroup->addInstr(node, slotNum);
- assert(node->getNodeId() < startTime.size());
- startTime[node->getNodeId()] = cycle;
- ++numInstr;
- }
-
-private:
- friend class ScheduleIterator<SchedGraphNode>;
- friend class ScheduleIterator<const SchedGraphNode>;
- /*ctor*/ InstrSchedule (); // Disable: DO NOT IMPLEMENT.
-};
-
-template<class NodeType>
-inline NodeType *ScheduleIterator<NodeType>::operator*() const {
- assert(cycleNum < S.groups.size());
- return (*S.groups[cycleNum])[slotNum];
-}
-
-
-/*ctor*/
-InstrSchedule::InstrSchedule(unsigned int _nslots, unsigned int _numNodes)
- : nslots(_nslots),
- numInstr(0),
- groups(2 * _numNodes / _nslots), // 2 x lower-bound for #cycles
- startTime(_numNodes, (CycleCount_t) -1) // set all to -1
-{
-}
-
-
-/*dtor*/
-InstrSchedule::~InstrSchedule()
-{
- for (unsigned c=0, NC=groups.size(); c < NC; c++)
- if (groups[c] != NULL)
- delete groups[c]; // delete InstrGroup objects
-}
-
-
-template<class _NodeType>
-inline
-void
-ScheduleIterator<_NodeType>::skipToNextInstr()
-{
- while(cycleNum < S.groups.size() && S.groups[cycleNum] == NULL)
- ++cycleNum; // skip cycles with no instructions
-
- while (cycleNum < S.groups.size() &&
- (*S.groups[cycleNum])[slotNum] == NULL)
- {
- ++slotNum;
- if (slotNum == S.nslots) {
- ++cycleNum;
- slotNum = 0;
- while(cycleNum < S.groups.size() && S.groups[cycleNum] == NULL)
- ++cycleNum; // skip cycles with no instructions
- }
- }
-}
-
-template<class _NodeType>
-inline
-ScheduleIterator<_NodeType>&
-ScheduleIterator<_NodeType>::operator++() // Preincrement
-{
- ++slotNum;
- if (slotNum == S.nslots) {
- ++cycleNum;
- slotNum = 0;
- }
- skipToNextInstr();
- return *this;
-}
-
-template<class _NodeType>
-ScheduleIterator<_NodeType>
-ScheduleIterator<_NodeType>::begin(const InstrSchedule& _schedule)
-{
- return _Self(_schedule, 0, 0);
-}
-
-template<class _NodeType>
-ScheduleIterator<_NodeType>
-ScheduleIterator<_NodeType>::end(const InstrSchedule& _schedule)
-{
- return _Self(_schedule, _schedule.groups.size(), 0);
-}
-
-
-//----------------------------------------------------------------------
-// class DelaySlotInfo:
-//
-// Record information about delay slots for a single branch instruction.
-// Delay slots are simply indexed by slot number 1 ... numDelaySlots
-//----------------------------------------------------------------------
-
-class DelaySlotInfo {
- const SchedGraphNode* brNode;
- unsigned ndelays;
- std::vector<const SchedGraphNode*> delayNodeVec;
- CycleCount_t delayedNodeCycle;
- unsigned delayedNodeSlotNum;
-
- DelaySlotInfo(const DelaySlotInfo &); // DO NOT IMPLEMENT
- void operator=(const DelaySlotInfo&); // DO NOT IMPLEMENT
-public:
- /*ctor*/ DelaySlotInfo (const SchedGraphNode* _brNode,
- unsigned _ndelays)
- : brNode(_brNode), ndelays(_ndelays),
- delayedNodeCycle(0), delayedNodeSlotNum(0) {}
-
- inline unsigned getNumDelays () {
- return ndelays;
- }
-
- inline const std::vector<const SchedGraphNode*>& getDelayNodeVec() {
- return delayNodeVec;
- }
-
- inline void addDelayNode (const SchedGraphNode* node) {
- delayNodeVec.push_back(node);
- assert(delayNodeVec.size() <= ndelays && "Too many delay slot instrs!");
- }
-
- inline void recordChosenSlot (CycleCount_t cycle, unsigned slotNum) {
- delayedNodeCycle = cycle;
- delayedNodeSlotNum = slotNum;
- }
-
- unsigned scheduleDelayedNode (SchedulingManager& S);
-};
-
-
-//----------------------------------------------------------------------
-// class SchedulingManager:
-//
-// Represents the schedule of machine instructions for a single basic block.
-//----------------------------------------------------------------------
-
-class SchedulingManager {
- SchedulingManager(SchedulingManager &); // DO NOT IMPLEMENT
- void operator=(const SchedulingManager &); // DO NOT IMPLEMENT
-public: // publicly accessible data members
- const unsigned nslots;
- const TargetSchedInfo& schedInfo;
- SchedPriorities& schedPrio;
- InstrSchedule isched;
-
-private:
- unsigned totalInstrCount;
- CycleCount_t curTime;
- CycleCount_t nextEarliestIssueTime; // next cycle we can issue
- // indexed by slot#
- std::vector<hash_set<const SchedGraphNode*> > choicesForSlot;
- std::vector<const SchedGraphNode*> choiceVec; // indexed by node ptr
- std::vector<int> numInClass; // indexed by sched class
- std::vector<CycleCount_t> nextEarliestStartTime; // indexed by opCode
- hash_map<const SchedGraphNode*, DelaySlotInfo*> delaySlotInfoForBranches;
- // indexed by branch node ptr
-
-public:
- SchedulingManager(const TargetMachine& _target, const SchedGraph* graph,
- SchedPriorities& schedPrio);
- ~SchedulingManager() {
- for (hash_map<const SchedGraphNode*,
- DelaySlotInfo*>::iterator I = delaySlotInfoForBranches.begin(),
- E = delaySlotInfoForBranches.end(); I != E; ++I)
- delete I->second;
- }
-
- //----------------------------------------------------------------------
- // Simplify access to the machine instruction info
- //----------------------------------------------------------------------
-
- inline const TargetInstrInfo& getInstrInfo () const {
- return schedInfo.getInstrInfo();
- }
-
- //----------------------------------------------------------------------
- // Interface for checking and updating the current time
- //----------------------------------------------------------------------
-
- inline CycleCount_t getTime () const {
- return curTime;
- }
-
- inline CycleCount_t getEarliestIssueTime() const {
- return nextEarliestIssueTime;
- }
-
- inline CycleCount_t getEarliestStartTimeForOp(MachineOpCode opCode) const {
- assert(opCode < (int) nextEarliestStartTime.size());
- return nextEarliestStartTime[opCode];
- }
-
- // Update current time to specified cycle
- inline void updateTime (CycleCount_t c) {
- curTime = c;
- schedPrio.updateTime(c);
- }
-
- //----------------------------------------------------------------------
- // Functions to manage the choices for the current cycle including:
- // -- a vector of choices by priority (choiceVec)
- // -- vectors of the choices for each instruction slot (choicesForSlot[])
- // -- number of choices in each sched class, used to check issue conflicts
- // between choices for a single cycle
- //----------------------------------------------------------------------
-
- inline unsigned int getNumChoices () const {
- return choiceVec.size();
- }
-
- inline unsigned getNumChoicesInClass (const InstrSchedClass& sc) const {
- assert(sc < numInClass.size() && "Invalid op code or sched class!");
- return numInClass[sc];
- }
-
- inline const SchedGraphNode* getChoice(unsigned int i) const {
- // assert(i < choiceVec.size()); don't check here.
- return choiceVec[i];
- }
-
- inline hash_set<const SchedGraphNode*>& getChoicesForSlot(unsigned slotNum) {
- assert(slotNum < nslots);
- return choicesForSlot[slotNum];
- }
-
- inline void addChoice (const SchedGraphNode* node) {
- // Append the instruction to the vector of choices for current cycle.
- // Increment numInClass[c] for the sched class to which the instr belongs.
- choiceVec.push_back(node);
- const InstrSchedClass& sc = schedInfo.getSchedClass(node->getOpcode());
- assert(sc < numInClass.size());
- numInClass[sc]++;
- }
-
- inline void addChoiceToSlot (unsigned int slotNum,
- const SchedGraphNode* node) {
- // Add the instruction to the choice set for the specified slot
- assert(slotNum < nslots);
- choicesForSlot[slotNum].insert(node);
- }
-
- inline void resetChoices () {
- choiceVec.clear();
- for (unsigned int s=0; s < nslots; s++)
- choicesForSlot[s].clear();
- for (unsigned int c=0; c < numInClass.size(); c++)
- numInClass[c] = 0;
- }
-
- //----------------------------------------------------------------------
- // Code to query and manage the partial instruction schedule so far
- //----------------------------------------------------------------------
-
- inline unsigned int getNumScheduled () const {
- return isched.getNumInstructions();
- }
-
- inline unsigned int getNumUnscheduled() const {
- return totalInstrCount - isched.getNumInstructions();
- }
-
- inline bool isScheduled (const SchedGraphNode* node) const {
- return (isched.getStartTime(node->getNodeId()) >= 0);
- }
-
- inline void scheduleInstr (const SchedGraphNode* node,
- unsigned int slotNum,
- CycleCount_t cycle)
- {
- assert(! isScheduled(node) && "Instruction already scheduled?");
-
- // add the instruction to the schedule
- isched.scheduleInstr(node, slotNum, cycle);
-
- // update the earliest start times of all nodes that conflict with `node'
- // and the next-earliest time anything can issue if `node' causes bubbles
- updateEarliestStartTimes(node, cycle);
-
- // remove the instruction from the choice sets for all slots
- for (unsigned s=0; s < nslots; s++)
- choicesForSlot[s].erase(node);
-
- // and decrement the instr count for the sched class to which it belongs
- const InstrSchedClass& sc = schedInfo.getSchedClass(node->getOpcode());
- assert(sc < numInClass.size());
- numInClass[sc]--;
- }
-
- //----------------------------------------------------------------------
- // Create and retrieve delay slot info for delayed instructions
- //----------------------------------------------------------------------
-
- inline DelaySlotInfo* getDelaySlotInfoForInstr(const SchedGraphNode* bn,
- bool createIfMissing=false)
- {
- hash_map<const SchedGraphNode*, DelaySlotInfo*>::const_iterator
- I = delaySlotInfoForBranches.find(bn);
- if (I != delaySlotInfoForBranches.end())
- return I->second;
-
- if (!createIfMissing) return 0;
-
- DelaySlotInfo *dinfo =
- new DelaySlotInfo(bn, getInstrInfo().getNumDelaySlots(bn->getOpcode()));
- return delaySlotInfoForBranches[bn] = dinfo;
- }
-
-private:
- SchedulingManager(); // DISABLED: DO NOT IMPLEMENT
- void updateEarliestStartTimes(const SchedGraphNode* node, CycleCount_t schedTime);
-};
-
-
-/*ctor*/
-SchedulingManager::SchedulingManager(const TargetMachine& target,
- const SchedGraph* graph,
- SchedPriorities& _schedPrio)
- : nslots(target.getSchedInfo()->getMaxNumIssueTotal()),
- schedInfo(*target.getSchedInfo()),
- schedPrio(_schedPrio),
- isched(nslots, graph->getNumNodes()),
- totalInstrCount(graph->getNumNodes() - 2),
- nextEarliestIssueTime(0),
- choicesForSlot(nslots),
- numInClass(target.getSchedInfo()->getNumSchedClasses(), 0), // set all to 0
- nextEarliestStartTime(target.getInstrInfo()->getNumOpcodes(),
- (CycleCount_t) 0) // set all to 0
-{
- updateTime(0);
-
- // Note that an upper bound on #choices for each slot is = nslots since
- // we use this vector to hold a feasible set of instructions, and more
- // would be infeasible. Reserve that much memory since it is probably small.
- for (unsigned int i=0; i < nslots; i++)
- choicesForSlot[i].resize(nslots);
-}
-
-
-void
-SchedulingManager::updateEarliestStartTimes(const SchedGraphNode* node,
- CycleCount_t schedTime)
-{
- if (schedInfo.numBubblesAfter(node->getOpcode()) > 0)
- { // Update next earliest time before which *nothing* can issue.
- nextEarliestIssueTime = std::max(nextEarliestIssueTime,
- curTime + 1 + schedInfo.numBubblesAfter(node->getOpcode()));
- }
-
- const std::vector<MachineOpCode>&
- conflictVec = schedInfo.getConflictList(node->getOpcode());
-
- for (unsigned i=0; i < conflictVec.size(); i++)
- {
- MachineOpCode toOp = conflictVec[i];
- CycleCount_t est=schedTime + schedInfo.getMinIssueGap(node->getOpcode(),toOp);
- assert(toOp < (int) nextEarliestStartTime.size());
- if (nextEarliestStartTime[toOp] < est)
- nextEarliestStartTime[toOp] = est;
- }
-}
-
-//************************* Internal Functions *****************************/
-
-
-static void
-AssignInstructionsToSlots(class SchedulingManager& S, unsigned maxIssue)
-{
- // find the slot to start from, in the current cycle
- unsigned int startSlot = 0;
- CycleCount_t curTime = S.getTime();
-
- assert(maxIssue > 0 && maxIssue <= S.nslots - startSlot);
-
- // If only one instruction can be issued, do so.
- if (maxIssue == 1)
- for (unsigned s=startSlot; s < S.nslots; s++)
- if (S.getChoicesForSlot(s).size() > 0) {
- // found the one instruction
- S.scheduleInstr(*S.getChoicesForSlot(s).begin(), s, curTime);
- return;
- }
-
- // Otherwise, choose from the choices for each slot
- //
- InstrGroup* igroup = S.isched.getIGroup(S.getTime());
- assert(igroup != NULL && "Group creation failed?");
-
- // Find a slot that has only a single choice, and take it.
- // If all slots have 0 or multiple choices, pick the first slot with
- // choices and use its last instruction (just to avoid shifting the vector).
- unsigned numIssued;
- for (numIssued = 0; numIssued < maxIssue; numIssued++) {
- int chosenSlot = -1;
- for (unsigned s=startSlot; s < S.nslots; s++)
- if ((*igroup)[s] == NULL && S.getChoicesForSlot(s).size() == 1) {
- chosenSlot = (int) s;
- break;
- }
-
- if (chosenSlot == -1)
- for (unsigned s=startSlot; s < S.nslots; s++)
- if ((*igroup)[s] == NULL && S.getChoicesForSlot(s).size() > 0) {
- chosenSlot = (int) s;
- break;
- }
-
- if (chosenSlot != -1) {
- // Insert the chosen instr in the chosen slot and
- // erase it from all slots.
- const SchedGraphNode* node= *S.getChoicesForSlot(chosenSlot).begin();
- S.scheduleInstr(node, chosenSlot, curTime);
- }
- }
-
- assert(numIssued > 0 && "Should not happen when maxIssue > 0!");
-}
-
-
-//
-// For now, just assume we are scheduling within a single basic block.
-// Get the machine instruction vector for the basic block and clear it,
-// then append instructions in scheduled order.
-// Also, re-insert the dummy PHI instructions that were at the beginning
-// of the basic block, since they are not part of the schedule.
-//
-static void
-RecordSchedule(MachineBasicBlock &MBB, const SchedulingManager& S)
-{
- const TargetInstrInfo& mii = S.schedInfo.getInstrInfo();
-
- // Lets make sure we didn't lose any instructions, except possibly
- // some NOPs from delay slots. Also, PHIs are not included in the schedule.
- unsigned numInstr = 0;
- for (MachineBasicBlock::iterator I=MBB.begin(); I != MBB.end(); ++I)
- if (!(I->getOpcode() == V9::NOP || I->getOpcode() == V9::PHI))
- ++numInstr;
- assert(S.isched.getNumInstructions() >= numInstr &&
- "Lost some non-NOP instructions during scheduling!");
-
- if (S.isched.getNumInstructions() == 0)
- return; // empty basic block!
-
- // First find the dummy instructions at the start of the basic block
- MachineBasicBlock::iterator I = MBB.begin();
- for ( ; I != MBB.end(); ++I)
- if (I->getOpcode() != V9::PHI)
- break;
-
- // Remove all except the dummy PHI instructions from MBB, and
- // pre-allocate create space for the ones we will put back in.
- while (I != MBB.end())
- MBB.remove(I++);
-
- InstrSchedule::const_iterator NIend = S.isched.end();
- for (InstrSchedule::const_iterator NI = S.isched.begin(); NI != NIend; ++NI)
- MBB.push_back(const_cast<MachineInstr*>((*NI)->getMachineInstr()));
-}
-
-
-
-static void
-MarkSuccessorsReady(SchedulingManager& S, const SchedGraphNode* node)
-{
- // Check if any successors are now ready that were not already marked
- // ready before, and that have not yet been scheduled.
- //
- for (sg_succ_const_iterator SI = succ_begin(node); SI !=succ_end(node); ++SI)
- if (! (*SI)->isDummyNode()
- && ! S.isScheduled(*SI)
- && ! S.schedPrio.nodeIsReady(*SI))
- {
- // successor not scheduled and not marked ready; check *its* preds.
-
- bool succIsReady = true;
- for (sg_pred_const_iterator P=pred_begin(*SI); P != pred_end(*SI); ++P)
- if (! (*P)->isDummyNode() && ! S.isScheduled(*P)) {
- succIsReady = false;
- break;
- }
-
- if (succIsReady) // add the successor to the ready list
- S.schedPrio.insertReady(*SI);
- }
-}
-
-
-// Choose up to `nslots' FEASIBLE instructions and assign each
-// instruction to all possible slots that do not violate feasibility.
-// FEASIBLE means it should be guaranteed that the set
-// of chosen instructions can be issued in a single group.
-//
-// Return value:
-// maxIssue : total number of feasible instructions
-// S.choicesForSlot[i=0..nslots] : set of instructions feasible in slot i
-//
-static unsigned
-FindSlotChoices(SchedulingManager& S,
- DelaySlotInfo*& getDelaySlotInfo)
-{
- // initialize result vectors to empty
- S.resetChoices();
-
- // find the slot to start from, in the current cycle
- unsigned int startSlot = 0;
- InstrGroup* igroup = S.isched.getIGroup(S.getTime());
- for (int s = S.nslots - 1; s >= 0; s--)
- if ((*igroup)[s] != NULL) {
- startSlot = s+1;
- break;
- }
-
- // Make sure we pick at most one instruction that would break the group.
- // Also, if we do pick one, remember which it was.
- unsigned int indexForBreakingNode = S.nslots;
- unsigned int indexForDelayedInstr = S.nslots;
- DelaySlotInfo* delaySlotInfo = NULL;
-
- getDelaySlotInfo = NULL;
-
- // Choose instructions in order of priority.
- // Add choices to the choice vector in the SchedulingManager class as
- // we choose them so that subsequent choices will be correctly tested
- // for feasibility, w.r.t. higher priority choices for the same cycle.
- //
- while (S.getNumChoices() < S.nslots - startSlot) {
- const SchedGraphNode* nextNode=S.schedPrio.getNextHighest(S,S.getTime());
- if (nextNode == NULL)
- break; // no more instructions for this cycle
-
- if (S.getInstrInfo().getNumDelaySlots(nextNode->getOpcode()) > 0) {
- delaySlotInfo = S.getDelaySlotInfoForInstr(nextNode);
- if (delaySlotInfo != NULL) {
- if (indexForBreakingNode < S.nslots)
- // cannot issue a delayed instr in the same cycle as one
- // that breaks the issue group or as another delayed instr
- nextNode = NULL;
- else
- indexForDelayedInstr = S.getNumChoices();
- }
- } else if (S.schedInfo.breaksIssueGroup(nextNode->getOpcode())) {
- if (indexForBreakingNode < S.nslots)
- // have a breaking instruction already so throw this one away
- nextNode = NULL;
- else
- indexForBreakingNode = S.getNumChoices();
- }
-
- if (nextNode != NULL) {
- S.addChoice(nextNode);
-
- if (S.schedInfo.isSingleIssue(nextNode->getOpcode())) {
- assert(S.getNumChoices() == 1 &&
- "Prioritizer returned invalid instr for this cycle!");
- break;
- }
- }
-
- if (indexForDelayedInstr < S.nslots)
- break; // leave the rest for delay slots
- }
-
- assert(S.getNumChoices() <= S.nslots);
- assert(! (indexForDelayedInstr < S.nslots &&
- indexForBreakingNode < S.nslots) && "Cannot have both in a cycle");
-
- // Assign each chosen instruction to all possible slots for that instr.
- // But if only one instruction was chosen, put it only in the first
- // feasible slot; no more analysis will be needed.
- //
- if (indexForDelayedInstr >= S.nslots &&
- indexForBreakingNode >= S.nslots)
- { // No instructions that break the issue group or that have delay slots.
- // This is the common case, so handle it separately for efficiency.
-
- if (S.getNumChoices() == 1) {
- MachineOpCode opCode = S.getChoice(0)->getOpcode();
- unsigned int s;
- for (s=startSlot; s < S.nslots; s++)
- if (S.schedInfo.instrCanUseSlot(opCode, s))
- break;
- assert(s < S.nslots && "No feasible slot for this opCode?");
- S.addChoiceToSlot(s, S.getChoice(0));
- } else {
- for (unsigned i=0; i < S.getNumChoices(); i++) {
- MachineOpCode opCode = S.getChoice(i)->getOpcode();
- for (unsigned int s=startSlot; s < S.nslots; s++)
- if (S.schedInfo.instrCanUseSlot(opCode, s))
- S.addChoiceToSlot(s, S.getChoice(i));
- }
- }
- } else if (indexForDelayedInstr < S.nslots) {
- // There is an instruction that needs delay slots.
- // Try to assign that instruction to a higher slot than any other
- // instructions in the group, so that its delay slots can go
- // right after it.
- //
-
- assert(indexForDelayedInstr == S.getNumChoices() - 1 &&
- "Instruction with delay slots should be last choice!");
- assert(delaySlotInfo != NULL && "No delay slot info for instr?");
-
- const SchedGraphNode* delayedNode = S.getChoice(indexForDelayedInstr);
- MachineOpCode delayOpCode = delayedNode->getOpcode();
- unsigned ndelays= S.getInstrInfo().getNumDelaySlots(delayOpCode);
-
- unsigned delayedNodeSlot = S.nslots;
- int highestSlotUsed;
-
- // Find the last possible slot for the delayed instruction that leaves
- // at least `d' slots vacant after it (d = #delay slots)
- for (int s = S.nslots-ndelays-1; s >= (int) startSlot; s--)
- if (S.schedInfo.instrCanUseSlot(delayOpCode, s)) {
- delayedNodeSlot = s;
- break;
- }
-
- highestSlotUsed = -1;
- for (unsigned i=0; i < S.getNumChoices() - 1; i++) {
- // Try to assign every other instruction to a lower numbered
- // slot than delayedNodeSlot.
- MachineOpCode opCode =S.getChoice(i)->getOpcode();
- bool noSlotFound = true;
- unsigned int s;
- for (s=startSlot; s < delayedNodeSlot; s++)
- if (S.schedInfo.instrCanUseSlot(opCode, s)) {
- S.addChoiceToSlot(s, S.getChoice(i));
- noSlotFound = false;
- }
-
- // No slot before `delayedNodeSlot' was found for this opCode
- // Use a later slot, and allow some delay slots to fall in
- // the next cycle.
- if (noSlotFound)
- for ( ; s < S.nslots; s++)
- if (S.schedInfo.instrCanUseSlot(opCode, s)) {
- S.addChoiceToSlot(s, S.getChoice(i));
- break;
- }
-
- assert(s < S.nslots && "No feasible slot for instruction?");
-
- highestSlotUsed = std::max(highestSlotUsed, (int) s);
- }
-
- assert(highestSlotUsed <= (int) S.nslots-1 && "Invalid slot used?");
-
- // We will put the delayed node in the first slot after the
- // highest slot used. But we just mark that for now, and
- // schedule it separately because we want to schedule the delay
- // slots for the node at the same time.
- CycleCount_t dcycle = S.getTime();
- unsigned int dslot = highestSlotUsed + 1;
- if (dslot == S.nslots) {
- dslot = 0;
- ++dcycle;
- }
- delaySlotInfo->recordChosenSlot(dcycle, dslot);
- getDelaySlotInfo = delaySlotInfo;
- } else {
- // There is an instruction that breaks the issue group.
- // For such an instruction, assign to the last possible slot in
- // the current group, and then don't assign any other instructions
- // to later slots.
- assert(indexForBreakingNode < S.nslots);
- const SchedGraphNode* breakingNode=S.getChoice(indexForBreakingNode);
- unsigned breakingSlot = INT_MAX;
- unsigned int nslotsToUse = S.nslots;
-
- // Find the last possible slot for this instruction.
- for (int s = S.nslots-1; s >= (int) startSlot; s--)
- if (S.schedInfo.instrCanUseSlot(breakingNode->getOpcode(), s)) {
- breakingSlot = s;
- break;
- }
- assert(breakingSlot < S.nslots &&
- "No feasible slot for `breakingNode'?");
-
- // Higher priority instructions than the one that breaks the group:
- // These can be assigned to all slots, but will be assigned only
- // to earlier slots if possible.
- for (unsigned i=0;
- i < S.getNumChoices() && i < indexForBreakingNode; i++)
- {
- MachineOpCode opCode =S.getChoice(i)->getOpcode();
-
- // If a higher priority instruction cannot be assigned to
- // any earlier slots, don't schedule the breaking instruction.
- //
- bool foundLowerSlot = false;
- nslotsToUse = S.nslots; // May be modified in the loop
- for (unsigned int s=startSlot; s < nslotsToUse; s++)
- if (S.schedInfo.instrCanUseSlot(opCode, s)) {
- if (breakingSlot < S.nslots && s < breakingSlot) {
- foundLowerSlot = true;
- nslotsToUse = breakingSlot; // RESETS LOOP UPPER BOUND!
- }
-
- S.addChoiceToSlot(s, S.getChoice(i));
- }
-
- if (!foundLowerSlot)
- breakingSlot = INT_MAX; // disable breaking instr
- }
-
- // Assign the breaking instruction (if any) to a single slot
- // Otherwise, just ignore the instruction. It will simply be
- // scheduled in a later cycle.
- if (breakingSlot < S.nslots) {
- S.addChoiceToSlot(breakingSlot, breakingNode);
- nslotsToUse = breakingSlot;
- } else
- nslotsToUse = S.nslots;
-
- // For lower priority instructions than the one that breaks the
- // group, only assign them to slots lower than the breaking slot.
- // Otherwise, just ignore the instruction.
- for (unsigned i=indexForBreakingNode+1; i < S.getNumChoices(); i++) {
- MachineOpCode opCode = S.getChoice(i)->getOpcode();
- for (unsigned int s=startSlot; s < nslotsToUse; s++)
- if (S.schedInfo.instrCanUseSlot(opCode, s))
- S.addChoiceToSlot(s, S.getChoice(i));
- }
- } // endif (no delay slots and no breaking slots)
-
- return S.getNumChoices();
-}
-
-
-static unsigned
-ChooseOneGroup(SchedulingManager& S)
-{
- assert(S.schedPrio.getNumReady() > 0
- && "Don't get here without ready instructions.");
-
- CycleCount_t firstCycle = S.getTime();
- DelaySlotInfo* getDelaySlotInfo = NULL;
-
- // Choose up to `nslots' feasible instructions and their possible slots.
- unsigned numIssued = FindSlotChoices(S, getDelaySlotInfo);
-
- while (numIssued == 0) {
- S.updateTime(S.getTime()+1);
- numIssued = FindSlotChoices(S, getDelaySlotInfo);
- }
-
- AssignInstructionsToSlots(S, numIssued);
-
- if (getDelaySlotInfo != NULL)
- numIssued += getDelaySlotInfo->scheduleDelayedNode(S);
-
- // Print trace of scheduled instructions before newly ready ones
- if (SchedDebugLevel >= Sched_PrintSchedTrace) {
- for (CycleCount_t c = firstCycle; c <= S.getTime(); c++) {
- std::cerr << " Cycle " << (long)c <<" : Scheduled instructions:\n";
- const InstrGroup* igroup = S.isched.getIGroup(c);
- for (unsigned int s=0; s < S.nslots; s++) {
- std::cerr << " ";
- if ((*igroup)[s] != NULL)
- std::cerr << * ((*igroup)[s])->getMachineInstr() << "\n";
- else
- std::cerr << "<none>\n";
- }
- }
- }
-
- return numIssued;
-}
-
-
-static void
-ForwardListSchedule(SchedulingManager& S)
-{
- unsigned N;
- const SchedGraphNode* node;
-
- S.schedPrio.initialize();
-
- while ((N = S.schedPrio.getNumReady()) > 0) {
- CycleCount_t nextCycle = S.getTime();
-
- // Choose one group of instructions for a cycle, plus any delay slot
- // instructions (which may overflow into successive cycles).
- // This will advance S.getTime() to the last cycle in which
- // instructions are actually issued.
- //
- unsigned numIssued = ChooseOneGroup(S);
- assert(numIssued > 0 && "Deadlock in list scheduling algorithm?");
-
- // Notify the priority manager of scheduled instructions and mark
- // any successors that may now be ready
- //
- for (CycleCount_t c = nextCycle; c <= S.getTime(); c++) {
- const InstrGroup* igroup = S.isched.getIGroup(c);
- for (unsigned int s=0; s < S.nslots; s++)
- if ((node = (*igroup)[s]) != NULL) {
- S.schedPrio.issuedReadyNodeAt(S.getTime(), node);
- MarkSuccessorsReady(S, node);
- }
- }
-
- // Move to the next the next earliest cycle for which
- // an instruction can be issued, or the next earliest in which
- // one will be ready, or to the next cycle, whichever is latest.
- //
- S.updateTime(std::max(S.getTime() + 1,
- std::max(S.getEarliestIssueTime(),
- S.schedPrio.getEarliestReadyTime())));
- }
-}
-
-
-//---------------------------------------------------------------------
-// Code for filling delay slots for delayed terminator instructions
-// (e.g., BRANCH and RETURN). Delay slots for non-terminator
-// instructions (e.g., CALL) are not handled here because they almost
-// always can be filled with instructions from the call sequence code
-// before a call. That's preferable because we incur many tradeoffs here
-// when we cannot find single-cycle instructions that can be reordered.
-//----------------------------------------------------------------------
-
-static bool
-NodeCanFillDelaySlot(const SchedulingManager& S,
- const SchedGraphNode* node,
- const SchedGraphNode* brNode,
- bool nodeIsPredecessor)
-{
- assert(! node->isDummyNode());
-
- // don't put a branch in the delay slot of another branch
- if (S.getInstrInfo().isBranch(node->getOpcode()))
- return false;
-
- // don't put a single-issue instruction in the delay slot of a branch
- if (S.schedInfo.isSingleIssue(node->getOpcode()))
- return false;
-
- // don't put a load-use dependence in the delay slot of a branch
- const TargetInstrInfo& mii = S.getInstrInfo();
-
- for (SchedGraphNode::const_iterator EI = node->beginInEdges();
- EI != node->endInEdges(); ++EI)
- if (! ((SchedGraphNode*)(*EI)->getSrc())->isDummyNode()
- && mii.isLoad(((SchedGraphNode*)(*EI)->getSrc())->getOpcode())
- && (*EI)->getDepType() == SchedGraphEdge::CtrlDep)
- return false;
-
- // Finally, if the instruction precedes the branch, we make sure the
- // instruction can be reordered relative to the branch. We simply check
- // if the instr. has only 1 outgoing edge, viz., a CD edge to the branch.
- //
- if (nodeIsPredecessor) {
- bool onlyCDEdgeToBranch = true;
- for (SchedGraphNode::const_iterator OEI = node->beginOutEdges();
- OEI != node->endOutEdges(); ++OEI)
- if (! ((SchedGraphNode*)(*OEI)->getSink())->isDummyNode()
- && ((*OEI)->getSink() != brNode
- || (*OEI)->getDepType() != SchedGraphEdge::CtrlDep))
- {
- onlyCDEdgeToBranch = false;
- break;
- }
-
- if (!onlyCDEdgeToBranch)
- return false;
- }
-
- return true;
-}
-
-
-static void
-MarkNodeForDelaySlot(SchedulingManager& S,
- SchedGraph* graph,
- SchedGraphNode* node,
- const SchedGraphNode* brNode,
- bool nodeIsPredecessor)
-{
- if (nodeIsPredecessor) {
- // If node is in the same basic block (i.e., precedes brNode),
- // remove it and all its incident edges from the graph. Make sure we
- // add dummy edges for pred/succ nodes that become entry/exit nodes.
- graph->eraseIncidentEdges(node, /*addDummyEdges*/ true);
- } else {
- // If the node was from a target block, add the node to the graph
- // and add a CD edge from brNode to node.
- assert(0 && "NOT IMPLEMENTED YET");
- }
-
- DelaySlotInfo* dinfo = S.getDelaySlotInfoForInstr(brNode, /*create*/ true);
- dinfo->addDelayNode(node);
-}
-
-
-void
-FindUsefulInstructionsForDelaySlots(SchedulingManager& S,
- SchedGraphNode* brNode,
- std::vector<SchedGraphNode*>& sdelayNodeVec)
-{
- const TargetInstrInfo& mii = S.getInstrInfo();
- unsigned ndelays =
- mii.getNumDelaySlots(brNode->getOpcode());
-
- if (ndelays == 0)
- return;
-
- sdelayNodeVec.reserve(ndelays);
-
- // Use a separate vector to hold the feasible multi-cycle nodes.
- // These will be used if not enough single-cycle nodes are found.
- //
- std::vector<SchedGraphNode*> mdelayNodeVec;
-
- for (sg_pred_iterator P = pred_begin(brNode);
- P != pred_end(brNode) && sdelayNodeVec.size() < ndelays; ++P)
- if (! (*P)->isDummyNode() &&
- ! mii.isNop((*P)->getOpcode()) &&
- NodeCanFillDelaySlot(S, *P, brNode, /*pred*/ true))
- {
- if (mii.maxLatency((*P)->getOpcode()) > 1)
- mdelayNodeVec.push_back(*P);
- else
- sdelayNodeVec.push_back(*P);
- }
-
- // If not enough single-cycle instructions were found, select the
- // lowest-latency multi-cycle instructions and use them.
- // Note that this is the most efficient code when only 1 (or even 2)
- // values need to be selected.
- //
- while (sdelayNodeVec.size() < ndelays && mdelayNodeVec.size() > 0) {
- unsigned lmin =
- mii.maxLatency(mdelayNodeVec[0]->getOpcode());
- unsigned minIndex = 0;
- for (unsigned i=1; i < mdelayNodeVec.size(); i++)
- {
- unsigned li =
- mii.maxLatency(mdelayNodeVec[i]->getOpcode());
- if (lmin >= li)
- {
- lmin = li;
- minIndex = i;
- }
- }
- sdelayNodeVec.push_back(mdelayNodeVec[minIndex]);
- if (sdelayNodeVec.size() < ndelays) // avoid the last erase!
- mdelayNodeVec.erase(mdelayNodeVec.begin() + minIndex);
- }
-}
-
-
-// Remove the NOPs currently in delay slots from the graph.
-// Mark instructions specified in sdelayNodeVec to replace them.
-// If not enough useful instructions were found, mark the NOPs to be used
-// for filling delay slots, otherwise, otherwise just discard them.
-//
-static void ReplaceNopsWithUsefulInstr(SchedulingManager& S,
- SchedGraphNode* node,
- // FIXME: passing vector BY VALUE!!!
- std::vector<SchedGraphNode*> sdelayNodeVec,
- SchedGraph* graph)
-{
- std::vector<SchedGraphNode*> nopNodeVec; // this will hold unused NOPs
- const TargetInstrInfo& mii = S.getInstrInfo();
- const MachineInstr* brInstr = node->getMachineInstr();
- unsigned ndelays= mii.getNumDelaySlots(brInstr->getOpcode());
- assert(ndelays > 0 && "Unnecessary call to replace NOPs");
-
- // Remove the NOPs currently in delay slots from the graph.
- // If not enough useful instructions were found, use the NOPs to
- // fill delay slots, otherwise, just discard them.
- //
- unsigned int firstDelaySlotIdx = node->getOrigIndexInBB() + 1;
- MachineBasicBlock& MBB = node->getMachineBasicBlock();
- MachineBasicBlock::iterator MBBI = MBB.begin();
- std::advance(MBBI, firstDelaySlotIdx - 1);
- if (!(&*MBBI++ == brInstr)) {
- std::cerr << "Incorrect instr. index in basic block for brInstr";
- abort();
- }
-
- // First find all useful instructions already in the delay slots
- // and USE THEM. We'll throw away the unused alternatives below
- //
- MachineBasicBlock::iterator Tmp = MBBI;
- for (unsigned i = 0; i != ndelays; ++i, ++MBBI)
- if (!mii.isNop(MBBI->getOpcode()))
- sdelayNodeVec.insert(sdelayNodeVec.begin(),
- graph->getGraphNodeForInstr(MBBI));
- MBBI = Tmp;
-
- // Then find the NOPs and keep only as many as are needed.
- // Put the rest in nopNodeVec to be deleted.
- for (unsigned i=firstDelaySlotIdx; i < firstDelaySlotIdx+ndelays; ++i, ++MBBI)
- if (mii.isNop(MBBI->getOpcode()))
- if (sdelayNodeVec.size() < ndelays)
- sdelayNodeVec.push_back(graph->getGraphNodeForInstr(MBBI));
- else {
- nopNodeVec.push_back(graph->getGraphNodeForInstr(MBBI));
-
- //remove the MI from the Machine Code For Instruction
- const TerminatorInst *TI = MBB.getBasicBlock()->getTerminator();
- MachineCodeForInstruction& llvmMvec =
- MachineCodeForInstruction::get((const Instruction *)TI);
-
- for(MachineCodeForInstruction::iterator mciI=llvmMvec.begin(),
- mciE=llvmMvec.end(); mciI!=mciE; ++mciI){
- if (*mciI == MBBI)
- llvmMvec.erase(mciI);
- }
- }
-
- assert(sdelayNodeVec.size() >= ndelays);
-
- // If some delay slots were already filled, throw away that many new choices
- if (sdelayNodeVec.size() > ndelays)
- sdelayNodeVec.resize(ndelays);
-
- // Mark the nodes chosen for delay slots. This removes them from the graph.
- for (unsigned i=0; i < sdelayNodeVec.size(); i++)
- MarkNodeForDelaySlot(S, graph, sdelayNodeVec[i], node, true);
-
- // And remove the unused NOPs from the graph.
- for (unsigned i=0; i < nopNodeVec.size(); i++)
- graph->eraseIncidentEdges(nopNodeVec[i], /*addDummyEdges*/ true);
-}
-
-
-// For all delayed instructions, choose instructions to put in the delay
-// slots and pull those out of the graph. Mark them for the delay slots
-// in the DelaySlotInfo object for that graph node. If no useful work
-// is found for a delay slot, use the NOP that is currently in that slot.
-//
-// We try to fill the delay slots with useful work for all instructions
-// EXCEPT CALLS AND RETURNS.
-// For CALLs and RETURNs, it is nearly always possible to use one of the
-// call sequence instrs and putting anything else in the delay slot could be
-// suboptimal. Also, it complicates generating the calling sequence code in
-// regalloc.
-//
-static void
-ChooseInstructionsForDelaySlots(SchedulingManager& S, MachineBasicBlock &MBB,
- SchedGraph *graph)
-{
- const TargetInstrInfo& mii = S.getInstrInfo();
-
- Instruction *termInstr = (Instruction*)MBB.getBasicBlock()->getTerminator();
- MachineCodeForInstruction &termMvec=MachineCodeForInstruction::get(termInstr);
- std::vector<SchedGraphNode*> delayNodeVec;
- const MachineInstr* brInstr = NULL;
-
- if (EnableFillingDelaySlots &&
- termInstr->getOpcode() != Instruction::Ret)
- {
- // To find instructions that need delay slots without searching the full
- // machine code, we assume that the only delayed instructions are CALLs
- // or instructions generated for the terminator inst.
- // Find the first branch instr in the sequence of machine instrs for term
- //
- unsigned first = 0;
- while (first < termMvec.size() &&
- ! mii.isBranch(termMvec[first]->getOpcode()))
- {
- ++first;
- }
- assert(first < termMvec.size() &&
- "No branch instructions for BR? Ok, but weird! Delete assertion.");
-
- brInstr = (first < termMvec.size())? termMvec[first] : NULL;
-
- // Compute a vector of the nodes chosen for delay slots and then
- // mark delay slots to replace NOPs with these useful instructions.
- //
- if (brInstr != NULL) {
- SchedGraphNode* brNode = graph->getGraphNodeForInstr(brInstr);
- FindUsefulInstructionsForDelaySlots(S, brNode, delayNodeVec);
- ReplaceNopsWithUsefulInstr(S, brNode, delayNodeVec, graph);
- }
- }
-
- // Also mark delay slots for other delayed instructions to hold NOPs.
- // Simply passing in an empty delayNodeVec will have this effect.
- // If brInstr is not handled above (EnableFillingDelaySlots == false),
- // brInstr will be NULL so this will handle the branch instrs. as well.
- //
- delayNodeVec.clear();
- for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); I != E; ++I)
- if (I != brInstr && mii.getNumDelaySlots(I->getOpcode()) > 0) {
- SchedGraphNode* node = graph->getGraphNodeForInstr(I);
- ReplaceNopsWithUsefulInstr(S, node, delayNodeVec, graph);
- }
-}
-
-
-//
-// Schedule the delayed branch and its delay slots
-//
-unsigned
-DelaySlotInfo::scheduleDelayedNode(SchedulingManager& S)
-{
- assert(delayedNodeSlotNum < S.nslots && "Illegal slot for branch");
- assert(S.isched.getInstr(delayedNodeSlotNum, delayedNodeCycle) == NULL
- && "Slot for branch should be empty");
-
- unsigned int nextSlot = delayedNodeSlotNum;
- CycleCount_t nextTime = delayedNodeCycle;
-
- S.scheduleInstr(brNode, nextSlot, nextTime);
-
- for (unsigned d=0; d < ndelays; d++) {
- ++nextSlot;
- if (nextSlot == S.nslots) {
- nextSlot = 0;
- nextTime++;
- }
-
- // Find the first feasible instruction for this delay slot
- // Note that we only check for issue restrictions here.
- // We do *not* check for flow dependences but rely on pipeline
- // interlocks to resolve them. Machines without interlocks
- // will require this code to be modified.
- for (unsigned i=0; i < delayNodeVec.size(); i++) {
- const SchedGraphNode* dnode = delayNodeVec[i];
- if ( ! S.isScheduled(dnode)
- && S.schedInfo.instrCanUseSlot(dnode->getOpcode(), nextSlot)
- && instrIsFeasible(S, dnode->getOpcode())) {
- S.scheduleInstr(dnode, nextSlot, nextTime);
- break;
- }
- }
- }
-
- // Update current time if delay slots overflowed into later cycles.
- // Do this here because we know exactly which cycle is the last cycle
- // that contains delay slots. The next loop doesn't compute that.
- if (nextTime > S.getTime())
- S.updateTime(nextTime);
-
- // Now put any remaining instructions in the unfilled delay slots.
- // This could lead to suboptimal performance but needed for correctness.
- nextSlot = delayedNodeSlotNum;
- nextTime = delayedNodeCycle;
- for (unsigned i=0; i < delayNodeVec.size(); i++)
- if (! S.isScheduled(delayNodeVec[i])) {
- do { // find the next empty slot
- ++nextSlot;
- if (nextSlot == S.nslots) {
- nextSlot = 0;
- nextTime++;
- }
- } while (S.isched.getInstr(nextSlot, nextTime) != NULL);
-
- S.scheduleInstr(delayNodeVec[i], nextSlot, nextTime);
- break;
- }
-
- return 1 + ndelays;
-}
-
-
-// Check if the instruction would conflict with instructions already
-// chosen for the current cycle
-//
-static inline bool
-ConflictsWithChoices(const SchedulingManager& S,
- MachineOpCode opCode)
-{
- // Check if the instruction must issue by itself, and some feasible
- // choices have already been made for this cycle
- if (S.getNumChoices() > 0 && S.schedInfo.isSingleIssue(opCode))
- return true;
-
- // For each class that opCode belongs to, check if there are too many
- // instructions of that class.
- //
- const InstrSchedClass sc = S.schedInfo.getSchedClass(opCode);
- return (S.getNumChoicesInClass(sc) == S.schedInfo.getMaxIssueForClass(sc));
-}
-
-
-//************************* External Functions *****************************/
-
-
-//---------------------------------------------------------------------------
-// Function: ViolatesMinimumGap
-//
-// Purpose:
-// Check minimum gap requirements relative to instructions scheduled in
-// previous cycles.
-// Note that we do not need to consider `nextEarliestIssueTime' here because
-// that is also captured in the earliest start times for each opcode.
-//---------------------------------------------------------------------------
-
-static inline bool
-ViolatesMinimumGap(const SchedulingManager& S,
- MachineOpCode opCode,
- const CycleCount_t inCycle)
-{
- return (inCycle < S.getEarliestStartTimeForOp(opCode));
-}
-
-
-//---------------------------------------------------------------------------
-// Function: instrIsFeasible
-//
-// Purpose:
-// Check if any issue restrictions would prevent the instruction from
-// being issued in the current cycle
-//---------------------------------------------------------------------------
-
-bool
-instrIsFeasible(const SchedulingManager& S,
- MachineOpCode opCode)
-{
- // skip the instruction if it cannot be issued due to issue restrictions
- // caused by previously issued instructions
- if (ViolatesMinimumGap(S, opCode, S.getTime()))
- return false;
-
- // skip the instruction if it cannot be issued due to issue restrictions
- // caused by previously chosen instructions for the current cycle
- if (ConflictsWithChoices(S, opCode))
- return false;
-
- return true;
-}
-
-//---------------------------------------------------------------------------
-// Function: ScheduleInstructionsWithSSA
-//
-// Purpose:
-// Entry point for instruction scheduling on SSA form.
-// Schedules the machine instructions generated by instruction selection.
-// Assumes that register allocation has not been done, i.e., operands
-// are still in SSA form.
-//---------------------------------------------------------------------------
-
-namespace {
- class InstructionSchedulingWithSSA : public FunctionPass {
- const TargetMachine ⌖
- public:
- inline InstructionSchedulingWithSSA(const TargetMachine &T) : target(T) {}
-
- const char *getPassName() const { return "Instruction Scheduling"; }
-
- // getAnalysisUsage - We use LiveVarInfo...
- virtual void getAnalysisUsage(AnalysisUsage &AU) const {
- AU.addRequired<FunctionLiveVarInfo>();
- AU.setPreservesCFG();
- }
-
- bool runOnFunction(Function &F);
- };
-} // end anonymous namespace
-
-
-bool InstructionSchedulingWithSSA::runOnFunction(Function &F)
-{
- SchedGraphSet graphSet(&F, target);
-
- if (SchedDebugLevel >= Sched_PrintSchedGraphs) {
- std::cerr << "\n*** SCHEDULING GRAPHS FOR INSTRUCTION SCHEDULING\n";
- graphSet.dump();
- }
-
- for (SchedGraphSet::const_iterator GI=graphSet.begin(), GE=graphSet.end();
- GI != GE; ++GI)
- {
- SchedGraph* graph = (*GI);
- MachineBasicBlock &MBB = graph->getBasicBlock();
-
- if (SchedDebugLevel >= Sched_PrintSchedTrace)
- std::cerr << "\n*** TRACE OF INSTRUCTION SCHEDULING OPERATIONS\n\n";
-
- // expensive!
- SchedPriorities schedPrio(&F, graph, getAnalysis<FunctionLiveVarInfo>());
- SchedulingManager S(target, graph, schedPrio);
-
- ChooseInstructionsForDelaySlots(S, MBB, graph); // modifies graph
- ForwardListSchedule(S); // computes schedule in S
- RecordSchedule(MBB, S); // records schedule in BB
- }
-
- if (SchedDebugLevel >= Sched_PrintMachineCode) {
- std::cerr << "\n*** Machine instructions after INSTRUCTION SCHEDULING\n";
- MachineFunction::get(&F).dump();
- }
-
- return false;
-}
-
-
-FunctionPass *createInstructionSchedulingWithSSAPass(const TargetMachine &tgt) {
- return new InstructionSchedulingWithSSA(tgt);
-}
-
-} // End llvm namespace
-
+++ /dev/null
-##===- 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
+++ /dev/null
-//===- 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
+++ /dev/null
-//===-- 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
+++ /dev/null
-//===- 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
+++ /dev/null
-//===-- 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
+++ /dev/null
-//===-- 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
+++ /dev/null
-//===-- 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.
-}
+++ /dev/null
-//===-- 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
+++ /dev/null
-//===-- 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
+++ /dev/null
-//===-- 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
+++ /dev/null
-//===-- 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
+++ /dev/null
-##===- 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
-
+++ /dev/null
-//
-// 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
+++ /dev/null
-//===-- 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;
-}
+++ /dev/null
-//===-- 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
+++ /dev/null
-//===-- 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
-}
+++ /dev/null
-//===-- 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
+++ /dev/null
-//===-- 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
+++ /dev/null
-##===- 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
-
+++ /dev/null
-//===- 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
+++ /dev/null
-//===- 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
+++ /dev/null
-//===-- 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;
-}
-
+++ /dev/null
-//===-- 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
+++ /dev/null
-//===-- 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";
-}
-
+++ /dev/null
-//===-- 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
+++ /dev/null
-//===-- 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";
- }
-}
+++ /dev/null
-//===-- 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
+++ /dev/null
-//===-- 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);
- }
- }
- }
- }
-}
+++ /dev/null
-//===-- 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
+++ /dev/null
-//===-- 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);
- }
- }
- }
- }
-}
+++ /dev/null
-//===-- 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
+++ /dev/null
-##===- 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
+++ /dev/null
-//===-- ModuloScheduling.cpp - ModuloScheduling ----------------*- 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 ModuloScheduling pass is based on the Swing Modulo Scheduling
-// algorithm.
-//
-//===----------------------------------------------------------------------===//
-
-#define DEBUG_TYPE "ModuloSched"
-
-#include "ModuloScheduling.h"
-#include "llvm/Constants.h"
-#include "llvm/Instructions.h"
-#include "llvm/Function.h"
-#include "llvm/CodeGen/MachineFunction.h"
-#include "llvm/CodeGen/Passes.h"
-#include "llvm/Support/CFG.h"
-#include "llvm/Target/TargetSchedInfo.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/GraphWriter.h"
-#include "llvm/ADT/SCCIterator.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/ADT/Statistic.h"
-#include "llvm/Support/Timer.h"
-#include <cmath>
-#include <algorithm>
-#include <fstream>
-#include <sstream>
-#include <utility>
-#include <vector>
-#include "../MachineCodeForInstruction.h"
-#include "../SparcV9TmpInstr.h"
-#include "../SparcV9Internals.h"
-#include "../SparcV9RegisterInfo.h"
-using namespace llvm;
-
-/// Create ModuloSchedulingPass
-///
-FunctionPass *llvm::createModuloSchedulingPass(TargetMachine & targ) {
- DEBUG(std::cerr << "Created ModuloSchedulingPass\n");
- return new ModuloSchedulingPass(targ);
-}
-
-
-//Graph Traits for printing out the dependence graph
-template<typename GraphType>
-static void WriteGraphToFile(std::ostream &O, const std::string &GraphName,
- const GraphType >) {
- std::string Filename = GraphName + ".dot";
- O << "Writing '" << Filename << "'...";
- std::ofstream F(Filename.c_str());
-
- if (F.good())
- WriteGraph(F, GT);
- else
- O << " error opening file for writing!";
- O << "\n";
-};
-
-
-#if 1
-#define TIME_REGION(VARNAME, DESC) \
- NamedRegionTimer VARNAME(DESC)
-#else
-#define TIME_REGION(VARNAME, DESC)
-#endif
-
-
-//Graph Traits for printing out the dependence graph
-namespace llvm {
-
- //Loop statistics
- Statistic<> ValidLoops("modulosched-validLoops", "Number of candidate loops modulo-scheduled");
- Statistic<> JumboBB("modulosched-jumboBB", "Basic Blocks with more then 100 instructions");
- Statistic<> LoopsWithCalls("modulosched-loopCalls", "Loops with calls");
- Statistic<> LoopsWithCondMov("modulosched-loopCondMov", "Loops with conditional moves");
- Statistic<> InvalidLoops("modulosched-invalidLoops", "Loops with unknown trip counts or loop invariant trip counts");
- Statistic<> SingleBBLoops("modulosched-singeBBLoops", "Number of single basic block loops");
-
- //Scheduling Statistics
- Statistic<> MSLoops("modulosched-schedLoops", "Number of loops successfully modulo-scheduled");
- Statistic<> NoSched("modulosched-noSched", "No schedule");
- Statistic<> SameStage("modulosched-sameStage", "Max stage is 0");
- Statistic<> ResourceConstraint("modulosched-resourceConstraint", "Loops constrained by resources");
- Statistic<> RecurrenceConstraint("modulosched-recurrenceConstraint", "Loops constrained by recurrences");
- Statistic<> FinalIISum("modulosched-finalIISum", "Sum of all final II");
- Statistic<> IISum("modulosched-IISum", "Sum of all theoretical II");
-
- template<>
- struct DOTGraphTraits<MSchedGraph*> : public DefaultDOTGraphTraits {
- static std::string getGraphName(MSchedGraph *F) {
- return "Dependence Graph";
- }
-
- static std::string getNodeLabel(MSchedGraphNode *Node, MSchedGraph *Graph) {
- if (Node->getInst()) {
- std::stringstream ss;
- ss << *(Node->getInst());
- return ss.str(); //((MachineInstr*)Node->getInst());
- }
- else
- return "No Inst";
- }
- static std::string getEdgeSourceLabel(MSchedGraphNode *Node,
- MSchedGraphNode::succ_iterator I) {
- //Label each edge with the type of dependence
- std::string edgelabel = "";
- switch (I.getEdge().getDepOrderType()) {
-
- case MSchedGraphEdge::TrueDep:
- edgelabel = "True";
- break;
-
- case MSchedGraphEdge::AntiDep:
- edgelabel = "Anti";
- break;
-
- case MSchedGraphEdge::OutputDep:
- edgelabel = "Output";
- break;
-
- default:
- edgelabel = "Unknown";
- break;
- }
-
- //FIXME
- int iteDiff = I.getEdge().getIteDiff();
- std::string intStr = "(IteDiff: ";
- intStr += itostr(iteDiff);
-
- intStr += ")";
- edgelabel += intStr;
-
- return edgelabel;
- }
- };
-}
-
-
-#include <unistd.h>
-
-/// ModuloScheduling::runOnFunction - main transformation entry point
-/// The Swing Modulo Schedule algorithm has three basic steps:
-/// 1) Computation and Analysis of the dependence graph
-/// 2) Ordering of the nodes
-/// 3) Scheduling
-///
-bool ModuloSchedulingPass::runOnFunction(Function &F) {
- alarm(100);
-
- bool Changed = false;
- int numMS = 0;
-
- DEBUG(std::cerr << "Creating ModuloSchedGraph for each valid BasicBlock in " + F.getName() + "\n");
-
- //Get MachineFunction
- MachineFunction &MF = MachineFunction::get(&F);
-
- DependenceAnalyzer &DA = getAnalysis<DependenceAnalyzer>();
-
-
- //Worklist
- std::vector<MachineBasicBlock*> Worklist;
-
- //Iterate over BasicBlocks and put them into our worklist if they are valid
- for (MachineFunction::iterator BI = MF.begin(); BI != MF.end(); ++BI)
- if(MachineBBisValid(BI)) {
- if(BI->size() < 100) {
- Worklist.push_back(&*BI);
- ++ValidLoops;
- }
- else
- ++JumboBB;
-
- }
-
- defaultInst = 0;
-
- DEBUG(if(Worklist.size() == 0) std::cerr << "No single basic block loops in function to ModuloSchedule\n");
-
- //Iterate over the worklist and perform scheduling
- for(std::vector<MachineBasicBlock*>::iterator BI = Worklist.begin(),
- BE = Worklist.end(); BI != BE; ++BI) {
-
- //Print out BB for debugging
- DEBUG(std::cerr << "BB Size: " << (*BI)->size() << "\n");
- DEBUG(std::cerr << "ModuloScheduling BB: \n"; (*BI)->print(std::cerr));
-
- //Print out LLVM BB
- DEBUG(std::cerr << "ModuloScheduling LLVMBB: \n"; (*BI)->getBasicBlock()->print(std::cerr));
-
- //Catch the odd case where we only have TmpInstructions and no real Value*s
- if(!CreateDefMap(*BI)) {
- //Clear out our maps for the next basic block that is processed
- nodeToAttributesMap.clear();
- partialOrder.clear();
- recurrenceList.clear();
- FinalNodeOrder.clear();
- schedule.clear();
- defMap.clear();
- continue;
- }
-
- MSchedGraph *MSG = new MSchedGraph(*BI, target, indVarInstrs[*BI], DA, machineTollvm[*BI]);
-
- //Write Graph out to file
- DEBUG(WriteGraphToFile(std::cerr, F.getName(), MSG));
- DEBUG(MSG->print(std::cerr));
-
- //Calculate Resource II
- int ResMII = calculateResMII(*BI);
-
- //Calculate Recurrence II
- int RecMII = calculateRecMII(MSG, ResMII);
-
- DEBUG(std::cerr << "Number of reccurrences found: " << recurrenceList.size() << "\n");
-
- //Our starting initiation interval is the maximum of RecMII and ResMII
- if(RecMII < ResMII)
- ++RecurrenceConstraint;
- else
- ++ResourceConstraint;
-
- II = std::max(RecMII, ResMII);
- int mII = II;
-
- //Print out II, RecMII, and ResMII
- DEBUG(std::cerr << "II starts out as " << II << " ( RecMII=" << RecMII << " and ResMII=" << ResMII << ")\n");
-
- //Dump node properties if in debug mode
- DEBUG(for(std::map<MSchedGraphNode*, MSNodeAttributes>::iterator I = nodeToAttributesMap.begin(),
- E = nodeToAttributesMap.end(); I !=E; ++I) {
- std::cerr << "Node: " << *(I->first) << " ASAP: " << I->second.ASAP << " ALAP: "
- << I->second.ALAP << " MOB: " << I->second.MOB << " Depth: " << I->second.depth
- << " Height: " << I->second.height << "\n";
- });
-
- //Calculate Node Properties
- calculateNodeAttributes(MSG, ResMII);
-
- //Dump node properties if in debug mode
- DEBUG(for(std::map<MSchedGraphNode*, MSNodeAttributes>::iterator I = nodeToAttributesMap.begin(),
- E = nodeToAttributesMap.end(); I !=E; ++I) {
- std::cerr << "Node: " << *(I->first) << " ASAP: " << I->second.ASAP << " ALAP: "
- << I->second.ALAP << " MOB: " << I->second.MOB << " Depth: " << I->second.depth
- << " Height: " << I->second.height << "\n";
- });
-
- //Put nodes in order to schedule them
- computePartialOrder();
-
- //Dump out partial order
- DEBUG(for(std::vector<std::set<MSchedGraphNode*> >::iterator I = partialOrder.begin(),
- E = partialOrder.end(); I !=E; ++I) {
- std::cerr << "Start set in PO\n";
- for(std::set<MSchedGraphNode*>::iterator J = I->begin(), JE = I->end(); J != JE; ++J)
- std::cerr << "PO:" << **J << "\n";
- });
-
- //Place nodes in final order
- orderNodes();
-
- //Dump out order of nodes
- DEBUG(for(std::vector<MSchedGraphNode*>::iterator I = FinalNodeOrder.begin(), E = FinalNodeOrder.end(); I != E; ++I) {
- std::cerr << "FO:" << **I << "\n";
- });
-
- //Finally schedule nodes
- bool haveSched = computeSchedule(*BI, MSG);
-
- //Print out final schedule
- DEBUG(schedule.print(std::cerr));
-
- //Final scheduling step is to reconstruct the loop only if we actual have
- //stage > 0
- if(haveSched) {
- reconstructLoop(*BI);
- ++MSLoops;
- Changed = true;
- FinalIISum += II;
- IISum += mII;
-
- if(schedule.getMaxStage() == 0)
- ++SameStage;
- }
- else {
- ++NoSched;
- }
-
- //Clear out our maps for the next basic block that is processed
- nodeToAttributesMap.clear();
- partialOrder.clear();
- recurrenceList.clear();
- FinalNodeOrder.clear();
- schedule.clear();
- defMap.clear();
- //Clean up. Nuke old MachineBB and llvmBB
- //BasicBlock *llvmBB = (BasicBlock*) (*BI)->getBasicBlock();
- //Function *parent = (Function*) llvmBB->getParent();
- //Should't std::find work??
- //parent->getBasicBlockList().erase(std::find(parent->getBasicBlockList().begin(), parent->getBasicBlockList().end(), *llvmBB));
- //parent->getBasicBlockList().erase(llvmBB);
-
- //delete(llvmBB);
- //delete(*BI);
- }
-
- alarm(0);
- return Changed;
-}
-
-bool ModuloSchedulingPass::CreateDefMap(MachineBasicBlock *BI) {
- defaultInst = 0;
-
- for(MachineBasicBlock::iterator I = BI->begin(), E = BI->end(); I != E; ++I) {
- for(unsigned opNum = 0; opNum < I->getNumOperands(); ++opNum) {
- const MachineOperand &mOp = I->getOperand(opNum);
- if(mOp.getType() == MachineOperand::MO_VirtualRegister && mOp.isDef()) {
- //assert if this is the second def we have seen
- //DEBUG(std::cerr << "Putting " << *(mOp.getVRegValue()) << " into map\n");
- //assert(!defMap.count(mOp.getVRegValue()) && "Def already in the map");
- if(defMap.count(mOp.getVRegValue()))
- return false;
-
- defMap[mOp.getVRegValue()] = &*I;
- }
-
- //See if we can use this Value* as our defaultInst
- if(!defaultInst && mOp.getType() == MachineOperand::MO_VirtualRegister) {
- Value *V = mOp.getVRegValue();
- if(!isa<TmpInstruction>(V) && !isa<Argument>(V) && !isa<Constant>(V) && !isa<PHINode>(V))
- defaultInst = (Instruction*) V;
- }
- }
- }
-
- if(!defaultInst)
- return false;
-
- return true;
-
-}
-/// This function checks if a Machine Basic Block is valid for modulo
-/// scheduling. This means that it has no control flow (if/else or
-/// calls) in the block. Currently ModuloScheduling only works on
-/// single basic block loops.
-bool ModuloSchedulingPass::MachineBBisValid(const MachineBasicBlock *BI) {
-
- bool isLoop = false;
-
- //Check first if its a valid loop
- for(succ_const_iterator I = succ_begin(BI->getBasicBlock()),
- E = succ_end(BI->getBasicBlock()); I != E; ++I) {
- if (*I == BI->getBasicBlock()) // has single block loop
- isLoop = true;
- }
-
- if(!isLoop)
- return false;
-
- //Check that we have a conditional branch (avoiding MS infinite loops)
- if(BranchInst *b = dyn_cast<BranchInst>(((BasicBlock*) BI->getBasicBlock())->getTerminator()))
- if(b->isUnconditional())
- return false;
-
- //Check size of our basic block.. make sure we have more then just the terminator in it
- if(BI->getBasicBlock()->size() == 1)
- return false;
-
- //Increase number of single basic block loops for stats
- ++SingleBBLoops;
-
- //Get Target machine instruction info
- const TargetInstrInfo *TMI = target.getInstrInfo();
-
- //Check each instruction and look for calls, keep map to get index later
- std::map<const MachineInstr*, unsigned> indexMap;
-
- unsigned count = 0;
- for(MachineBasicBlock::const_iterator I = BI->begin(), E = BI->end(); I != E; ++I) {
- //Get opcode to check instruction type
- MachineOpCode OC = I->getOpcode();
-
- //Look for calls
- if(TMI->isCall(OC)) {
- ++LoopsWithCalls;
- return false;
- }
-
- //Look for conditional move
- if(OC == V9::MOVRZr || OC == V9::MOVRZi || OC == V9::MOVRLEZr || OC == V9::MOVRLEZi
- || OC == V9::MOVRLZr || OC == V9::MOVRLZi || OC == V9::MOVRNZr || OC == V9::MOVRNZi
- || OC == V9::MOVRGZr || OC == V9::MOVRGZi || OC == V9::MOVRGEZr
- || OC == V9::MOVRGEZi || OC == V9::MOVLEr || OC == V9::MOVLEi || OC == V9::MOVLEUr
- || OC == V9::MOVLEUi || OC == V9::MOVFLEr || OC == V9::MOVFLEi
- || OC == V9::MOVNEr || OC == V9::MOVNEi || OC == V9::MOVNEGr || OC == V9::MOVNEGi
- || OC == V9::MOVFNEr || OC == V9::MOVFNEi || OC == V9::MOVGr || OC == V9::MOVGi) {
- ++LoopsWithCondMov;
- return false;
- }
-
- indexMap[I] = count;
-
- if(TMI->isNop(OC))
- continue;
-
- ++count;
- }
-
- //Apply a simple pattern match to make sure this loop can be modulo scheduled
- //This means only loops with a branch associated to the iteration count
-
- //Get the branch
- BranchInst *b = dyn_cast<BranchInst>(((BasicBlock*) BI->getBasicBlock())->getTerminator());
-
- //Get the condition for the branch (we already checked if it was conditional)
- Value *cond = b->getCondition();
-
- DEBUG(std::cerr << "Condition: " << *cond << "\n");
-
- //List of instructions associated with induction variable
- std::set<Instruction*> indVar;
- std::vector<Instruction*> stack;
-
- BasicBlock *BB = (BasicBlock*) BI->getBasicBlock();
-
- //Add branch
- indVar.insert(b);
-
- if(Instruction *I = dyn_cast<Instruction>(cond))
- if(I->getParent() == BB) {
- if (!assocIndVar(I, indVar, stack, BB)) {
- ++InvalidLoops;
- return false;
- }
- }
- else {
- ++InvalidLoops;
- return false;
- }
- else {
- ++InvalidLoops;
- return false;
- }
- //The indVar set must be >= 3 instructions for this loop to match (FIX ME!)
- if(indVar.size() < 3 )
- return false;
-
- //Dump out instructions associate with indvar for debug reasons
- DEBUG(for(std::set<Instruction*>::iterator N = indVar.begin(), NE = indVar.end(); N != NE; ++N) {
- std::cerr << **N << "\n";
- });
-
- //Create map of machine instr to llvm instr
- std::map<MachineInstr*, Instruction*> mllvm;
- for(BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I) {
- MachineCodeForInstruction & tempMvec = MachineCodeForInstruction::get(I);
- for (unsigned j = 0; j < tempMvec.size(); j++) {
- mllvm[tempMvec[j]] = I;
- }
- }
-
- //Convert list of LLVM Instructions to list of Machine instructions
- std::map<const MachineInstr*, unsigned> mIndVar;
- for(std::set<Instruction*>::iterator N = indVar.begin(), NE = indVar.end(); N != NE; ++N) {
-
- //If we have a load, we can't handle this loop because there is no way to preserve dependences
- //between loads and stores
- if(isa<LoadInst>(*N))
- return false;
-
- MachineCodeForInstruction & tempMvec = MachineCodeForInstruction::get(*N);
- for (unsigned j = 0; j < tempMvec.size(); j++) {
- MachineOpCode OC = (tempMvec[j])->getOpcode();
- if(TMI->isNop(OC))
- continue;
- if(!indexMap.count(tempMvec[j]))
- continue;
- mIndVar[(MachineInstr*) tempMvec[j]] = indexMap[(MachineInstr*) tempMvec[j]];
- DEBUG(std::cerr << *(tempMvec[j]) << " at index " << indexMap[(MachineInstr*) tempMvec[j]] << "\n");
- }
- }
-
- //Must have some guts to the loop body (more then 1 instr, dont count nops in size)
- if(mIndVar.size() >= (BI->size()-3))
- return false;
-
- //Put into a map for future access
- indVarInstrs[BI] = mIndVar;
- machineTollvm[BI] = mllvm;
- return true;
-}
-
-bool ModuloSchedulingPass::assocIndVar(Instruction *I, std::set<Instruction*> &indVar,
- std::vector<Instruction*> &stack, BasicBlock *BB) {
-
- stack.push_back(I);
-
- //If this is a phi node, check if its the canonical indvar
- if(PHINode *PN = dyn_cast<PHINode>(I)) {
- if (Instruction *Inc =
- dyn_cast<Instruction>(PN->getIncomingValueForBlock(BB)))
- if (Inc->getOpcode() == Instruction::Add && Inc->getOperand(0) == PN)
- if (ConstantInt *CI = dyn_cast<ConstantInt>(Inc->getOperand(1)))
- if (CI->equalsInt(1)) {
- //We have found the indvar, so add the stack, and inc instruction to the set
- indVar.insert(stack.begin(), stack.end());
- indVar.insert(Inc);
- stack.pop_back();
- return true;
- }
- return false;
- }
- else {
- //Loop over each of the instructions operands, check if they are an instruction and in this BB
- for(unsigned i = 0; i < I->getNumOperands(); ++i) {
- if(Instruction *N = dyn_cast<Instruction>(I->getOperand(i))) {
- if(N->getParent() == BB)
- if(!assocIndVar(N, indVar, stack, BB))
- return false;
- }
- }
- }
-
- stack.pop_back();
- return true;
-}
-
-//ResMII is calculated by determining the usage count for each resource
-//and using the maximum.
-//FIXME: In future there should be a way to get alternative resources
-//for each instruction
-int ModuloSchedulingPass::calculateResMII(const MachineBasicBlock *BI) {
-
- TIME_REGION(X, "calculateResMII");
-
- const TargetInstrInfo *mii = target.getInstrInfo();
- const TargetSchedInfo *msi = target.getSchedInfo();
-
- int ResMII = 0;
-
- //Map to keep track of usage count of each resource
- std::map<unsigned, unsigned> resourceUsageCount;
-
- for(MachineBasicBlock::const_iterator I = BI->begin(), E = BI->end(); I != E; ++I) {
-
- //Get resource usage for this instruction
- InstrRUsage rUsage = msi->getInstrRUsage(I->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) {
- if(!resourceUsageCount.count(resources[i][j])) {
- resourceUsageCount[resources[i][j]] = 1;
- }
- else {
- resourceUsageCount[resources[i][j]] = resourceUsageCount[resources[i][j]] + 1;
- }
- }
- }
-
- //Find maximum usage count
-
- //Get max number of instructions that can be issued at once. (FIXME)
- int issueSlots = msi->maxNumIssueTotal;
-
- for(std::map<unsigned,unsigned>::iterator RB = resourceUsageCount.begin(), RE = resourceUsageCount.end(); RB != RE; ++RB) {
-
- //Get the total number of the resources in our cpu
- int resourceNum = CPUResource::getCPUResource(RB->first)->maxNumUsers;
-
- //Get total usage count for this resources
- unsigned usageCount = RB->second;
-
- //Divide the usage count by either the max number we can issue or the number of
- //resources (whichever is its upper bound)
- double finalUsageCount;
- DEBUG(std::cerr << "Resource Num: " << RB->first << " Usage: " << usageCount << " TotalNum: " << resourceNum << "\n");
-
- if( resourceNum <= issueSlots)
- finalUsageCount = ceil(1.0 * usageCount / resourceNum);
- else
- finalUsageCount = ceil(1.0 * usageCount / issueSlots);
-
-
- //Only keep track of the max
- ResMII = std::max( (int) finalUsageCount, ResMII);
-
- }
-
- return ResMII;
-
-}
-
-/// calculateRecMII - Calculates the value of the highest recurrence
-/// By value we mean the total latency
-int ModuloSchedulingPass::calculateRecMII(MSchedGraph *graph, int MII) {
- /*std::vector<MSchedGraphNode*> vNodes;
- //Loop over all nodes in the graph
- for(MSchedGraph::iterator I = graph->begin(), E = graph->end(); I != E; ++I) {
- findAllReccurrences(I->second, vNodes, MII);
- vNodes.clear();
- }*/
-
- TIME_REGION(X, "calculateRecMII");
-
- findAllCircuits(graph, MII);
- int RecMII = 0;
-
- for(std::set<std::pair<int, std::vector<MSchedGraphNode*> > >::iterator I = recurrenceList.begin(), E=recurrenceList.end(); I !=E; ++I) {
- RecMII = std::max(RecMII, I->first);
- }
-
- return MII;
-}
-
-/// calculateNodeAttributes - The following properties are calculated for
-/// each node in the dependence graph: ASAP, ALAP, Depth, Height, and
-/// MOB.
-void ModuloSchedulingPass::calculateNodeAttributes(MSchedGraph *graph, int MII) {
-
- TIME_REGION(X, "calculateNodeAttributes");
-
- assert(nodeToAttributesMap.empty() && "Node attribute map was not cleared");
-
- //Loop over the nodes and add them to the map
- for(MSchedGraph::iterator I = graph->begin(), E = graph->end(); I != E; ++I) {
-
- DEBUG(std::cerr << "Inserting node into attribute map: " << *I->second << "\n");
-
- //Assert if its already in the map
- assert(nodeToAttributesMap.count(I->second) == 0 &&
- "Node attributes are already in the map");
-
- //Put into the map with default attribute values
- nodeToAttributesMap[I->second] = MSNodeAttributes();
- }
-
- //Create set to deal with reccurrences
- std::set<MSchedGraphNode*> visitedNodes;
-
- //Now Loop over map and calculate the node attributes
- for(std::map<MSchedGraphNode*, MSNodeAttributes>::iterator I = nodeToAttributesMap.begin(), E = nodeToAttributesMap.end(); I != E; ++I) {
- calculateASAP(I->first, MII, (MSchedGraphNode*) 0);
- visitedNodes.clear();
- }
-
- int maxASAP = findMaxASAP();
- //Calculate ALAP which depends on ASAP being totally calculated
- for(std::map<MSchedGraphNode*, MSNodeAttributes>::iterator I = nodeToAttributesMap.begin(), E = nodeToAttributesMap.end(); I != E; ++I) {
- calculateALAP(I->first, MII, maxASAP, (MSchedGraphNode*) 0);
- visitedNodes.clear();
- }
-
- //Calculate MOB which depends on ASAP being totally calculated, also do depth and height
- for(std::map<MSchedGraphNode*, MSNodeAttributes>::iterator I = nodeToAttributesMap.begin(), E = nodeToAttributesMap.end(); I != E; ++I) {
- (I->second).MOB = std::max(0,(I->second).ALAP - (I->second).ASAP);
-
- DEBUG(std::cerr << "MOB: " << (I->second).MOB << " (" << *(I->first) << ")\n");
- calculateDepth(I->first, (MSchedGraphNode*) 0);
- calculateHeight(I->first, (MSchedGraphNode*) 0);
- }
-
-
-}
-
-/// ignoreEdge - Checks to see if this edge of a recurrence should be ignored or not
-bool ModuloSchedulingPass::ignoreEdge(MSchedGraphNode *srcNode, MSchedGraphNode *destNode) {
- if(destNode == 0 || srcNode ==0)
- return false;
-
- bool findEdge = edgesToIgnore.count(std::make_pair(srcNode, destNode->getInEdgeNum(srcNode)));
-
- DEBUG(std::cerr << "Ignoring edge? from: " << *srcNode << " to " << *destNode << "\n");
-
- return findEdge;
-}
-
-
-/// calculateASAP - Calculates the
-int ModuloSchedulingPass::calculateASAP(MSchedGraphNode *node, int MII, MSchedGraphNode *destNode) {
-
- DEBUG(std::cerr << "Calculating ASAP for " << *node << "\n");
-
- //Get current node attributes
- MSNodeAttributes &attributes = nodeToAttributesMap.find(node)->second;
-
- if(attributes.ASAP != -1)
- return attributes.ASAP;
-
- int maxPredValue = 0;
-
- //Iterate over all of the predecessors and find max
- for(MSchedGraphNode::pred_iterator P = node->pred_begin(), E = node->pred_end(); P != E; ++P) {
-
- //Only process if we are not ignoring the edge
- if(!ignoreEdge(*P, node)) {
- int predASAP = -1;
- predASAP = calculateASAP(*P, MII, node);
-
- assert(predASAP != -1 && "ASAP has not been calculated");
- int iteDiff = node->getInEdge(*P).getIteDiff();
-
- int currentPredValue = predASAP + (*P)->getLatency() - (iteDiff * MII);
- DEBUG(std::cerr << "pred ASAP: " << predASAP << ", iteDiff: " << iteDiff << ", PredLatency: " << (*P)->getLatency() << ", Current ASAP pred: " << currentPredValue << "\n");
- maxPredValue = std::max(maxPredValue, currentPredValue);
- }
- }
-
- attributes.ASAP = maxPredValue;
-
- DEBUG(std::cerr << "ASAP: " << attributes.ASAP << " (" << *node << ")\n");
-
- return maxPredValue;
-}
-
-
-int ModuloSchedulingPass::calculateALAP(MSchedGraphNode *node, int MII,
- int maxASAP, MSchedGraphNode *srcNode) {
-
- DEBUG(std::cerr << "Calculating ALAP for " << *node << "\n");
-
- MSNodeAttributes &attributes = nodeToAttributesMap.find(node)->second;
-
- if(attributes.ALAP != -1)
- return attributes.ALAP;
-
- if(node->hasSuccessors()) {
-
- //Trying to deal with the issue where the node has successors, but
- //we are ignoring all of the edges to them. So this is my hack for
- //now.. there is probably a more elegant way of doing this (FIXME)
- bool processedOneEdge = false;
-
- //FIXME, set to something high to start
- int minSuccValue = 9999999;
-
- //Iterate over all of the predecessors and fine max
- for(MSchedGraphNode::succ_iterator P = node->succ_begin(),
- E = node->succ_end(); P != E; ++P) {
-
- //Only process if we are not ignoring the edge
- if(!ignoreEdge(node, *P)) {
- processedOneEdge = true;
- int succALAP = -1;
- succALAP = calculateALAP(*P, MII, maxASAP, node);
-
- assert(succALAP != -1 && "Successors ALAP should have been caclulated");
-
- int iteDiff = P.getEdge().getIteDiff();
-
- int currentSuccValue = succALAP - node->getLatency() + iteDiff * MII;
-
- DEBUG(std::cerr << "succ ALAP: " << succALAP << ", iteDiff: " << iteDiff << ", SuccLatency: " << (*P)->getLatency() << ", Current ALAP succ: " << currentSuccValue << "\n");
-
- minSuccValue = std::min(minSuccValue, currentSuccValue);
- }
- }
-
- if(processedOneEdge)
- attributes.ALAP = minSuccValue;
-
- else
- attributes.ALAP = maxASAP;
- }
- else
- attributes.ALAP = maxASAP;
-
- DEBUG(std::cerr << "ALAP: " << attributes.ALAP << " (" << *node << ")\n");
-
- if(attributes.ALAP < 0)
- attributes.ALAP = 0;
-
- return attributes.ALAP;
-}
-
-int ModuloSchedulingPass::findMaxASAP() {
- int maxASAP = 0;
-
- for(std::map<MSchedGraphNode*, MSNodeAttributes>::iterator I = nodeToAttributesMap.begin(),
- E = nodeToAttributesMap.end(); I != E; ++I)
- maxASAP = std::max(maxASAP, I->second.ASAP);
- return maxASAP;
-}
-
-
-int ModuloSchedulingPass::calculateHeight(MSchedGraphNode *node,MSchedGraphNode *srcNode) {
-
- MSNodeAttributes &attributes = nodeToAttributesMap.find(node)->second;
-
- if(attributes.height != -1)
- return attributes.height;
-
- int maxHeight = 0;
-
- //Iterate over all of the predecessors and find max
- for(MSchedGraphNode::succ_iterator P = node->succ_begin(),
- E = node->succ_end(); P != E; ++P) {
-
-
- if(!ignoreEdge(node, *P)) {
- int succHeight = calculateHeight(*P, node);
-
- assert(succHeight != -1 && "Successors Height should have been caclulated");
-
- int currentHeight = succHeight + node->getLatency();
- maxHeight = std::max(maxHeight, currentHeight);
- }
- }
- attributes.height = maxHeight;
- DEBUG(std::cerr << "Height: " << attributes.height << " (" << *node << ")\n");
- return maxHeight;
-}
-
-
-int ModuloSchedulingPass::calculateDepth(MSchedGraphNode *node,
- MSchedGraphNode *destNode) {
-
- MSNodeAttributes &attributes = nodeToAttributesMap.find(node)->second;
-
- if(attributes.depth != -1)
- return attributes.depth;
-
- int maxDepth = 0;
-
- //Iterate over all of the predecessors and fine max
- for(MSchedGraphNode::pred_iterator P = node->pred_begin(), E = node->pred_end(); P != E; ++P) {
-
- if(!ignoreEdge(*P, node)) {
- int predDepth = -1;
- predDepth = calculateDepth(*P, node);
-
- assert(predDepth != -1 && "Predecessors ASAP should have been caclulated");
-
- int currentDepth = predDepth + (*P)->getLatency();
- maxDepth = std::max(maxDepth, currentDepth);
- }
- }
- attributes.depth = maxDepth;
-
- DEBUG(std::cerr << "Depth: " << attributes.depth << " (" << *node << "*)\n");
- return maxDepth;
-}
-
-
-
-void ModuloSchedulingPass::addReccurrence(std::vector<MSchedGraphNode*> &recurrence, int II, MSchedGraphNode *srcBENode, MSchedGraphNode *destBENode) {
- //Check to make sure that this recurrence is unique
- bool same = false;
-
-
- //Loop over all recurrences already in our list
- for(std::set<std::pair<int, std::vector<MSchedGraphNode*> > >::iterator R = recurrenceList.begin(), RE = recurrenceList.end(); R != RE; ++R) {
-
- bool all_same = true;
- //First compare size
- if(R->second.size() == recurrence.size()) {
-
- for(std::vector<MSchedGraphNode*>::const_iterator node = R->second.begin(), end = R->second.end(); node != end; ++node) {
- if(std::find(recurrence.begin(), recurrence.end(), *node) == recurrence.end()) {
- all_same = all_same && false;
- break;
- }
- else
- all_same = all_same && true;
- }
- if(all_same) {
- same = true;
- break;
- }
- }
- }
-
- if(!same) {
- srcBENode = recurrence.back();
- destBENode = recurrence.front();
-
- //FIXME
- if(destBENode->getInEdge(srcBENode).getIteDiff() == 0) {
- //DEBUG(std::cerr << "NOT A BACKEDGE\n");
- //find actual backedge HACK HACK
- for(unsigned i=0; i< recurrence.size()-1; ++i) {
- if(recurrence[i+1]->getInEdge(recurrence[i]).getIteDiff() == 1) {
- srcBENode = recurrence[i];
- destBENode = recurrence[i+1];
- break;
- }
-
- }
-
- }
- DEBUG(std::cerr << "Back Edge to Remove: " << *srcBENode << " to " << *destBENode << "\n");
- edgesToIgnore.insert(std::make_pair(srcBENode, destBENode->getInEdgeNum(srcBENode)));
- recurrenceList.insert(std::make_pair(II, recurrence));
- }
-
-}
-
-int CircCount;
-
-void ModuloSchedulingPass::unblock(MSchedGraphNode *u, std::set<MSchedGraphNode*> &blocked,
- std::map<MSchedGraphNode*, std::set<MSchedGraphNode*> > &B) {
-
- //Unblock u
- DEBUG(std::cerr << "Unblocking: " << *u << "\n");
- blocked.erase(u);
-
- //std::set<MSchedGraphNode*> toErase;
- while (!B[u].empty()) {
- MSchedGraphNode *W = *B[u].begin();
- B[u].erase(W);
- //toErase.insert(*W);
- DEBUG(std::cerr << "Removed: " << *W << "from B-List\n");
- if(blocked.count(W))
- unblock(W, blocked, B);
- }
-
-}
-
-bool ModuloSchedulingPass::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) {
- bool f = false;
-
- DEBUG(std::cerr << "Finding Circuits Starting with: ( " << v << ")"<< *v << "\n");
-
- //Push node onto the stack
- stack.push_back(v);
-
- //block this node
- blocked.insert(v);
-
- //Loop over all successors of node v that are in the scc, create Adjaceny list
- std::set<MSchedGraphNode*> AkV;
- for(MSchedGraphNode::succ_iterator I = v->succ_begin(), E = v->succ_end(); I != E; ++I) {
- if((std::find(SCC.begin(), SCC.end(), *I) != SCC.end())) {
- AkV.insert(*I);
- }
- }
-
- for(std::set<MSchedGraphNode*>::iterator I = AkV.begin(), E = AkV.end(); I != E; ++I) {
- if(*I == s) {
- //We have a circuit, so add it to our list
- addRecc(stack, newNodes);
- f = true;
- }
- else if(!blocked.count(*I)) {
- if(circuit(*I, stack, blocked, SCC, s, B, II, newNodes))
- f = true;
- }
- else
- DEBUG(std::cerr << "Blocked: " << **I << "\n");
- }
-
-
- if(f) {
- unblock(v, blocked, B);
- }
- else {
- for(std::set<MSchedGraphNode*>::iterator I = AkV.begin(), E = AkV.end(); I != E; ++I)
- B[*I].insert(v);
-
- }
-
- //Pop v
- stack.pop_back();
-
- return f;
-
-}
-
-void ModuloSchedulingPass::addRecc(std::vector<MSchedGraphNode*> &stack, std::map<MSchedGraphNode*, MSchedGraphNode*> &newNodes) {
- std::vector<MSchedGraphNode*> recc;
- //Dump recurrence for now
- DEBUG(std::cerr << "Starting Recc\n");
-
- int totalDelay = 0;
- int totalDistance = 0;
- MSchedGraphNode *lastN = 0;
- MSchedGraphNode *start = 0;
- MSchedGraphNode *end = 0;
-
- //Loop over recurrence, get delay and distance
- for(std::vector<MSchedGraphNode*>::iterator N = stack.begin(), NE = stack.end(); N != NE; ++N) {
- DEBUG(std::cerr << **N << "\n");
- totalDelay += (*N)->getLatency();
- if(lastN) {
- int iteDiff = (*N)->getInEdge(lastN).getIteDiff();
- totalDistance += iteDiff;
-
- if(iteDiff > 0) {
- start = lastN;
- end = *N;
- }
- }
- //Get the original node
- lastN = *N;
- recc.push_back(newNodes[*N]);
-
-
- }
-
- //Get the loop edge
- totalDistance += lastN->getIteDiff(*stack.begin());
-
- DEBUG(std::cerr << "End Recc\n");
- CircCount++;
-
- if(start && end) {
- //Insert reccurrence into the list
- DEBUG(std::cerr << "Ignore Edge from!!: " << *start << " to " << *end << "\n");
- edgesToIgnore.insert(std::make_pair(newNodes[start], (newNodes[end])->getInEdgeNum(newNodes[start])));
- }
- else {
- //Insert reccurrence into the list
- DEBUG(std::cerr << "Ignore Edge from: " << *lastN << " to " << **stack.begin() << "\n");
- edgesToIgnore.insert(std::make_pair(newNodes[lastN], newNodes[(*stack.begin())]->getInEdgeNum(newNodes[lastN])));
-
- }
- //Adjust II until we get close to the inequality delay - II*distance <= 0
- int RecMII = II; //Starting value
- int value = totalDelay-(RecMII * totalDistance);
- int lastII = II;
- while(value < 0) {
-
- lastII = RecMII;
- RecMII--;
- value = totalDelay-(RecMII * totalDistance);
- }
-
- recurrenceList.insert(std::make_pair(lastII, recc));
-
-}
-
-void ModuloSchedulingPass::addSCC(std::vector<MSchedGraphNode*> &SCC, std::map<MSchedGraphNode*, MSchedGraphNode*> &newNodes) {
-
- int totalDelay = 0;
- int totalDistance = 0;
- std::vector<MSchedGraphNode*> recc;
- MSchedGraphNode *start = 0;
- MSchedGraphNode *end = 0;
-
- //Loop over recurrence, get delay and distance
- for(std::vector<MSchedGraphNode*>::iterator N = SCC.begin(), NE = SCC.end(); N != NE; ++N) {
- DEBUG(std::cerr << **N << "\n");
- totalDelay += (*N)->getLatency();
-
- for(unsigned i = 0; i < (*N)->succ_size(); ++i) {
- MSchedGraphEdge *edge = (*N)->getSuccessor(i);
- if(find(SCC.begin(), SCC.end(), edge->getDest()) != SCC.end()) {
- totalDistance += edge->getIteDiff();
- if(edge->getIteDiff() > 0)
- if(!start && !end) {
- start = *N;
- end = edge->getDest();
- }
-
- }
- }
-
-
- //Get the original node
- recc.push_back(newNodes[*N]);
-
-
- }
-
- DEBUG(std::cerr << "End Recc\n");
- CircCount++;
-
- assert( (start && end) && "Must have start and end node to ignore edge for SCC");
-
- if(start && end) {
- //Insert reccurrence into the list
- DEBUG(std::cerr << "Ignore Edge from!!: " << *start << " to " << *end << "\n");
- edgesToIgnore.insert(std::make_pair(newNodes[start], (newNodes[end])->getInEdgeNum(newNodes[start])));
- }
-
- int lastII = totalDelay / totalDistance;
-
-
- recurrenceList.insert(std::make_pair(lastII, recc));
-
-}
-
-void ModuloSchedulingPass::findAllCircuits(MSchedGraph *g, int II) {
-
- CircCount = 0;
-
- //Keep old to new node mapping information
- std::map<MSchedGraphNode*, MSchedGraphNode*> newNodes;
-
- //copy the graph
- MSchedGraph *MSG = new MSchedGraph(*g, newNodes);
-
- DEBUG(std::cerr << "Finding All Circuits\n");
-
- //Set of blocked nodes
- std::set<MSchedGraphNode*> blocked;
-
- //Stack holding current circuit
- std::vector<MSchedGraphNode*> stack;
-
- //Map for B Lists
- std::map<MSchedGraphNode*, std::set<MSchedGraphNode*> > B;
-
- //current node
- MSchedGraphNode *s;
-
-
- //Iterate over the graph until its down to one node or empty
- while(MSG->size() > 1) {
-
- //Write Graph out to file
- //WriteGraphToFile(std::cerr, "Graph" + utostr(MSG->size()), MSG);
-
- DEBUG(std::cerr << "Graph Size: " << MSG->size() << "\n");
- DEBUG(std::cerr << "Finding strong component Vk with least vertex\n");
-
- //Iterate over all the SCCs in the graph
- std::set<MSchedGraphNode*> Visited;
- std::vector<MSchedGraphNode*> Vk;
- MSchedGraphNode* s = 0;
- int numEdges = 0;
-
- //Find scc with the least vertex
- for (MSchedGraph::iterator GI = MSG->begin(), E = MSG->end(); GI != E; ++GI)
- if (Visited.insert(GI->second).second) {
- for (scc_iterator<MSchedGraphNode*> SCCI = scc_begin(GI->second),
- E = scc_end(GI->second); SCCI != E; ++SCCI) {
- std::vector<MSchedGraphNode*> &nextSCC = *SCCI;
-
- if (Visited.insert(nextSCC[0]).second) {
- Visited.insert(nextSCC.begin()+1, nextSCC.end());
-
- if(nextSCC.size() > 1) {
- std::cerr << "SCC size: " << nextSCC.size() << "\n";
-
- for(unsigned i = 0; i < nextSCC.size(); ++i) {
- //Loop over successor and see if in scc, then count edge
- MSchedGraphNode *node = nextSCC[i];
- for(MSchedGraphNode::succ_iterator S = node->succ_begin(), SE = node->succ_end(); S != SE; ++S) {
- if(find(nextSCC.begin(), nextSCC.end(), *S) != nextSCC.end())
- numEdges++;
- }
- }
- std::cerr << "Num Edges: " << numEdges << "\n";
- }
-
- //Ignore self loops
- if(nextSCC.size() > 1) {
-
- //Get least vertex in Vk
- if(!s) {
- s = nextSCC[0];
- Vk = nextSCC;
- }
-
- for(unsigned i = 0; i < nextSCC.size(); ++i) {
- if(nextSCC[i] < s) {
- s = nextSCC[i];
- Vk = nextSCC;
- }
- }
- }
- }
- }
- }
-
-
-
- //Process SCC
- DEBUG(for(std::vector<MSchedGraphNode*>::iterator N = Vk.begin(), NE = Vk.end();
- N != NE; ++N) { std::cerr << *((*N)->getInst()); });
-
- //Iterate over all nodes in this scc
- for(std::vector<MSchedGraphNode*>::iterator N = Vk.begin(), NE = Vk.end();
- N != NE; ++N) {
- blocked.erase(*N);
- B[*N].clear();
- }
- if(Vk.size() > 1) {
- if(numEdges < 98)
- circuit(s, stack, blocked, Vk, s, B, II, newNodes);
- else
- addSCC(Vk, newNodes);
-
- //Delete nodes from the graph
- //Find all nodes up to s and delete them
- std::vector<MSchedGraphNode*> nodesToRemove;
- nodesToRemove.push_back(s);
- for(MSchedGraph::iterator N = MSG->begin(), NE = MSG->end(); N != NE; ++N) {
- if(N->second < s )
- nodesToRemove.push_back(N->second);
- }
- for(std::vector<MSchedGraphNode*>::iterator N = nodesToRemove.begin(), NE = nodesToRemove.end(); N != NE; ++N) {
- DEBUG(std::cerr << "Deleting Node: " << **N << "\n");
- MSG->deleteNode(*N);
- }
- }
- else
- break;
- }
- DEBUG(std::cerr << "Num Circuits found: " << CircCount << "\n");
-}
-
-
-void ModuloSchedulingPass::findAllReccurrences(MSchedGraphNode *node,
- std::vector<MSchedGraphNode*> &visitedNodes,
- int II) {
-
-
- if(std::find(visitedNodes.begin(), visitedNodes.end(), node) != visitedNodes.end()) {
- std::vector<MSchedGraphNode*> recurrence;
- bool first = true;
- int delay = 0;
- int distance = 0;
- int RecMII = II; //Starting value
- MSchedGraphNode *last = node;
- MSchedGraphNode *srcBackEdge = 0;
- MSchedGraphNode *destBackEdge = 0;
-
-
-
- for(std::vector<MSchedGraphNode*>::iterator I = visitedNodes.begin(), E = visitedNodes.end();
- I !=E; ++I) {
-
- if(*I == node)
- first = false;
- if(first)
- continue;
-
- delay = delay + (*I)->getLatency();
-
- if(*I != node) {
- int diff = (*I)->getInEdge(last).getIteDiff();
- distance += diff;
- if(diff > 0) {
- srcBackEdge = last;
- destBackEdge = *I;
- }
- }
-
- recurrence.push_back(*I);
- last = *I;
- }
-
-
-
- //Get final distance calc
- distance += node->getInEdge(last).getIteDiff();
- DEBUG(std::cerr << "Reccurrence Distance: " << distance << "\n");
-
- //Adjust II until we get close to the inequality delay - II*distance <= 0
-
- int value = delay-(RecMII * distance);
- int lastII = II;
- while(value <= 0) {
-
- lastII = RecMII;
- RecMII--;
- value = delay-(RecMII * distance);
- }
-
-
- DEBUG(std::cerr << "Final II for this recurrence: " << lastII << "\n");
- addReccurrence(recurrence, lastII, srcBackEdge, destBackEdge);
- assert(distance != 0 && "Recurrence distance should not be zero");
- return;
- }
-
- unsigned count = 0;
- for(MSchedGraphNode::succ_iterator I = node->succ_begin(), E = node->succ_end(); I != E; ++I) {
- visitedNodes.push_back(node);
- //if(!edgesToIgnore.count(std::make_pair(node, count)))
- findAllReccurrences(*I, visitedNodes, II);
- visitedNodes.pop_back();
- count++;
- }
-}
-
-void ModuloSchedulingPass::searchPath(MSchedGraphNode *node,
- std::vector<MSchedGraphNode*> &path,
- std::set<MSchedGraphNode*> &nodesToAdd,
- std::set<MSchedGraphNode*> &new_reccurrence) {
- //Push node onto the path
- path.push_back(node);
-
- //Loop over all successors and see if there is a path from this node to
- //a recurrence in the partial order, if so.. add all nodes to be added to recc
- for(MSchedGraphNode::succ_iterator S = node->succ_begin(), SE = node->succ_end(); S != SE;
- ++S) {
-
- //Check if we should ignore this edge first
- if(ignoreEdge(node,*S))
- continue;
-
- //check if successor is in this recurrence, we will get to it eventually
- if(new_reccurrence.count(*S))
- continue;
-
- //If this node exists in a recurrence already in the partial
- //order, then add all nodes in the path to the set of nodes to add
- //Check if its already in our partial order, if not add it to the
- //final vector
- bool found = false;
- for(std::vector<std::set<MSchedGraphNode*> >::iterator PO = partialOrder.begin(),
- PE = partialOrder.end(); PO != PE; ++PO) {
-
- if(PO->count(*S)) {
- found = true;
- break;
- }
- }
-
- if(!found) {
- nodesToAdd.insert(*S);
- searchPath(*S, path, nodesToAdd, new_reccurrence);
- }
- }
-
- //Pop Node off the path
- path.pop_back();
-}
-
-void ModuloSchedulingPass::pathToRecc(MSchedGraphNode *node,
- std::vector<MSchedGraphNode*> &path,
- std::set<MSchedGraphNode*> &poSet,
- std::set<MSchedGraphNode*> &lastNodes) {
- //Push node onto the path
- path.push_back(node);
-
- DEBUG(std::cerr << "Current node: " << *node << "\n");
-
- //Loop over all successors and see if there is a path from this node to
- //a recurrence in the partial order, if so.. add all nodes to be added to recc
- for(MSchedGraphNode::succ_iterator S = node->succ_begin(), SE = node->succ_end(); S != SE;
- ++S) {
- DEBUG(std::cerr << "Succ:" << **S << "\n");
- //Check if we should ignore this edge first
- if(ignoreEdge(node,*S))
- continue;
-
- if(poSet.count(*S)) {
- DEBUG(std::cerr << "Found path to recc from no pred\n");
- //Loop over path, if it exists in lastNodes, then add to poset, and remove from lastNodes
- for(std::vector<MSchedGraphNode*>::iterator I = path.begin(), IE = path.end(); I != IE; ++I) {
- if(lastNodes.count(*I)) {
- DEBUG(std::cerr << "Inserting node into recc: " << **I << "\n");
- poSet.insert(*I);
- lastNodes.erase(*I);
- }
- }
- }
- else
- pathToRecc(*S, path, poSet, lastNodes);
- }
-
- //Pop Node off the path
- path.pop_back();
-}
-
-void ModuloSchedulingPass::computePartialOrder() {
-
- TIME_REGION(X, "calculatePartialOrder");
-
- DEBUG(std::cerr << "Computing Partial Order\n");
-
- //Only push BA branches onto the final node order, we put other
- //branches after it FIXME: Should we really be pushing branches on
- //it a specific order instead of relying on BA being there?
-
- std::vector<MSchedGraphNode*> branches;
-
- //Steps to add a recurrence to the partial order 1) Find reccurrence
- //with the highest RecMII. Add it to the partial order. 2) For each
- //recurrence with decreasing RecMII, add it to the partial order
- //along with any nodes that connect this recurrence to recurrences
- //already in the partial order
- for(std::set<std::pair<int, std::vector<MSchedGraphNode*> > >::reverse_iterator
- I = recurrenceList.rbegin(), E=recurrenceList.rend(); I !=E; ++I) {
-
- std::set<MSchedGraphNode*> new_recurrence;
-
- //Loop through recurrence and remove any nodes already in the partial order
- for(std::vector<MSchedGraphNode*>::const_iterator N = I->second.begin(),
- NE = I->second.end(); N != NE; ++N) {
-
- bool found = false;
- for(std::vector<std::set<MSchedGraphNode*> >::iterator PO = partialOrder.begin(),
- PE = partialOrder.end(); PO != PE; ++PO) {
- if(PO->count(*N))
- found = true;
- }
-
- //Check if its a branch, and remove to handle special
- if(!found) {
- if((*N)->isBranch() && !(*N)->hasPredecessors()) {
- branches.push_back(*N);
- }
- else
- new_recurrence.insert(*N);
- }
-
- }
-
-
- if(new_recurrence.size() > 0) {
-
- std::vector<MSchedGraphNode*> path;
- std::set<MSchedGraphNode*> nodesToAdd;
-
- //Dump recc we are dealing with (minus nodes already in PO)
- DEBUG(std::cerr << "Recc: ");
- DEBUG(for(std::set<MSchedGraphNode*>::iterator R = new_recurrence.begin(), RE = new_recurrence.end(); R != RE; ++R) { std::cerr << **R ; });
-
- //Add nodes that connect this recurrence to recurrences in the partial path
- for(std::set<MSchedGraphNode*>::iterator N = new_recurrence.begin(),
- NE = new_recurrence.end(); N != NE; ++N)
- searchPath(*N, path, nodesToAdd, new_recurrence);
-
- //Add nodes to this recurrence if they are not already in the partial order
- for(std::set<MSchedGraphNode*>::iterator N = nodesToAdd.begin(), NE = nodesToAdd.end();
- N != NE; ++N) {
- bool found = false;
- for(std::vector<std::set<MSchedGraphNode*> >::iterator PO = partialOrder.begin(),
- PE = partialOrder.end(); PO != PE; ++PO) {
- if(PO->count(*N))
- found = true;
- }
- if(!found) {
- assert("FOUND CONNECTOR");
- new_recurrence.insert(*N);
- }
- }
-
- partialOrder.push_back(new_recurrence);
-
-
- //Dump out partial order
- DEBUG(for(std::vector<std::set<MSchedGraphNode*> >::iterator I = partialOrder.begin(),
- E = partialOrder.end(); I !=E; ++I) {
- std::cerr << "Start set in PO\n";
- for(std::set<MSchedGraphNode*>::iterator J = I->begin(), JE = I->end(); J != JE; ++J)
- std::cerr << "PO:" << **J << "\n";
- });
-
- }
- }
-
- //Add any nodes that are not already in the partial order
- //Add them in a set, one set per connected component
- std::set<MSchedGraphNode*> lastNodes;
- std::set<MSchedGraphNode*> noPredNodes;
- for(std::map<MSchedGraphNode*, MSNodeAttributes>::iterator I = nodeToAttributesMap.begin(),
- E = nodeToAttributesMap.end(); I != E; ++I) {
-
- bool found = false;
-
- //Check if its already in our partial order, if not add it to the final vector
- for(std::vector<std::set<MSchedGraphNode*> >::iterator PO = partialOrder.begin(),
- PE = partialOrder.end(); PO != PE; ++PO) {
- if(PO->count(I->first))
- found = true;
- }
- if(!found)
- lastNodes.insert(I->first);
- }
-
- //For each node w/out preds, see if there is a path to one of the
- //recurrences, and if so add them to that current recc
- /*for(std::set<MSchedGraphNode*>::iterator N = noPredNodes.begin(), NE = noPredNodes.end();
- N != NE; ++N) {
- DEBUG(std::cerr << "No Pred Path from: " << **N << "\n");
- for(std::vector<std::set<MSchedGraphNode*> >::iterator PO = partialOrder.begin(),
- PE = partialOrder.end(); PO != PE; ++PO) {
- std::vector<MSchedGraphNode*> path;
- pathToRecc(*N, path, *PO, lastNodes);
- }
- }*/
-
-
- //Break up remaining nodes that are not in the partial order
- ///into their connected compoenents
- while(lastNodes.size() > 0) {
- std::set<MSchedGraphNode*> ccSet;
- connectedComponentSet(*(lastNodes.begin()),ccSet, lastNodes);
- if(ccSet.size() > 0)
- partialOrder.push_back(ccSet);
- }
-
-
- //Clean up branches by putting them in final order
- assert(branches.size() == 0 && "We should not have any branches in our graph");
-}
-
-
-void ModuloSchedulingPass::connectedComponentSet(MSchedGraphNode *node, std::set<MSchedGraphNode*> &ccSet, std::set<MSchedGraphNode*> &lastNodes) {
-
-//Add to final set
- if( !ccSet.count(node) && lastNodes.count(node)) {
- lastNodes.erase(node);
- ccSet.insert(node);
- }
- else
- return;
-
- //Loop over successors and recurse if we have not seen this node before
- for(MSchedGraphNode::succ_iterator node_succ = node->succ_begin(), end=node->succ_end(); node_succ != end; ++node_succ) {
- connectedComponentSet(*node_succ, ccSet, lastNodes);
- }
-
-}
-
-void ModuloSchedulingPass::predIntersect(std::set<MSchedGraphNode*> &CurrentSet, std::set<MSchedGraphNode*> &IntersectResult) {
-
- for(unsigned j=0; j < FinalNodeOrder.size(); ++j) {
- for(MSchedGraphNode::pred_iterator P = FinalNodeOrder[j]->pred_begin(),
- E = FinalNodeOrder[j]->pred_end(); P != E; ++P) {
-
- //Check if we are supposed to ignore this edge or not
- if(ignoreEdge(*P,FinalNodeOrder[j]))
- continue;
-
- if(CurrentSet.count(*P))
- if(std::find(FinalNodeOrder.begin(), FinalNodeOrder.end(), *P) == FinalNodeOrder.end())
- IntersectResult.insert(*P);
- }
- }
-}
-
-
-
-
-
-void ModuloSchedulingPass::succIntersect(std::set<MSchedGraphNode*> &CurrentSet, std::set<MSchedGraphNode*> &IntersectResult) {
-
- for(unsigned j=0; j < FinalNodeOrder.size(); ++j) {
- for(MSchedGraphNode::succ_iterator P = FinalNodeOrder[j]->succ_begin(),
- E = FinalNodeOrder[j]->succ_end(); P != E; ++P) {
-
- //Check if we are supposed to ignore this edge or not
- if(ignoreEdge(FinalNodeOrder[j],*P))
- continue;
-
- if(CurrentSet.count(*P))
- if(std::find(FinalNodeOrder.begin(), FinalNodeOrder.end(), *P) == FinalNodeOrder.end())
- IntersectResult.insert(*P);
- }
- }
-}
-
-void dumpIntersection(std::set<MSchedGraphNode*> &IntersectCurrent) {
- std::cerr << "Intersection (";
- for(std::set<MSchedGraphNode*>::iterator I = IntersectCurrent.begin(), E = IntersectCurrent.end(); I != E; ++I)
- std::cerr << **I << ", ";
- std::cerr << ")\n";
-}
-
-
-
-void ModuloSchedulingPass::orderNodes() {
-
- TIME_REGION(X, "orderNodes");
-
- int BOTTOM_UP = 0;
- int TOP_DOWN = 1;
-
- //Set default order
- int order = BOTTOM_UP;
-
-
- //Loop over all the sets and place them in the final node order
- for(std::vector<std::set<MSchedGraphNode*> >::iterator CurrentSet = partialOrder.begin(), E= partialOrder.end(); CurrentSet != E; ++CurrentSet) {
-
- DEBUG(std::cerr << "Processing set in S\n");
- DEBUG(dumpIntersection(*CurrentSet));
-
- //Result of intersection
- std::set<MSchedGraphNode*> IntersectCurrent;
-
- predIntersect(*CurrentSet, IntersectCurrent);
-
- //If the intersection of predecessor and current set is not empty
- //sort nodes bottom up
- if(IntersectCurrent.size() != 0) {
- DEBUG(std::cerr << "Final Node Order Predecessors and Current Set interesection is NOT empty\n");
- order = BOTTOM_UP;
- }
- //If empty, use successors
- else {
- DEBUG(std::cerr << "Final Node Order Predecessors and Current Set interesection is empty\n");
-
- succIntersect(*CurrentSet, IntersectCurrent);
-
- //sort top-down
- if(IntersectCurrent.size() != 0) {
- DEBUG(std::cerr << "Final Node Order Successors and Current Set interesection is NOT empty\n");
- order = TOP_DOWN;
- }
- else {
- DEBUG(std::cerr << "Final Node Order Successors and Current Set interesection is empty\n");
- //Find node with max ASAP in current Set
- MSchedGraphNode *node;
- int maxASAP = 0;
- DEBUG(std::cerr << "Using current set of size " << CurrentSet->size() << "to find max ASAP\n");
- for(std::set<MSchedGraphNode*>::iterator J = CurrentSet->begin(), JE = CurrentSet->end(); J != JE; ++J) {
- //Get node attributes
- MSNodeAttributes nodeAttr= nodeToAttributesMap.find(*J)->second;
- //assert(nodeAttr != nodeToAttributesMap.end() && "Node not in attributes map!");
-
- if(maxASAP <= nodeAttr.ASAP) {
- maxASAP = nodeAttr.ASAP;
- node = *J;
- }
- }
- assert(node != 0 && "In node ordering node should not be null");
- IntersectCurrent.insert(node);
- order = BOTTOM_UP;
- }
- }
-
- //Repeat until all nodes are put into the final order from current set
- while(IntersectCurrent.size() > 0) {
-
- if(order == TOP_DOWN) {
- DEBUG(std::cerr << "Order is TOP DOWN\n");
-
- while(IntersectCurrent.size() > 0) {
- DEBUG(std::cerr << "Intersection is not empty, so find heighest height\n");
-
- int MOB = 0;
- int height = 0;
- MSchedGraphNode *highestHeightNode = *(IntersectCurrent.begin());
-
- //Find node in intersection with highest heigh and lowest MOB
- for(std::set<MSchedGraphNode*>::iterator I = IntersectCurrent.begin(),
- E = IntersectCurrent.end(); I != E; ++I) {
-
- //Get current nodes properties
- MSNodeAttributes nodeAttr= nodeToAttributesMap.find(*I)->second;
-
- if(height < nodeAttr.height) {
- highestHeightNode = *I;
- height = nodeAttr.height;
- MOB = nodeAttr.MOB;
- }
- else if(height == nodeAttr.height) {
- if(MOB > nodeAttr.height) {
- highestHeightNode = *I;
- height = nodeAttr.height;
- MOB = nodeAttr.MOB;
- }
- }
- }
-
- //Append our node with greatest height to the NodeOrder
- if(std::find(FinalNodeOrder.begin(), FinalNodeOrder.end(), highestHeightNode) == FinalNodeOrder.end()) {
- DEBUG(std::cerr << "Adding node to Final Order: " << *highestHeightNode << "\n");
- FinalNodeOrder.push_back(highestHeightNode);
- }
-
- //Remove V from IntersectOrder
- IntersectCurrent.erase(std::find(IntersectCurrent.begin(),
- IntersectCurrent.end(), highestHeightNode));
-
-
- //Intersect V's successors with CurrentSet
- for(MSchedGraphNode::succ_iterator P = highestHeightNode->succ_begin(),
- E = highestHeightNode->succ_end(); P != E; ++P) {
- //if(lower_bound(CurrentSet->begin(),
- // CurrentSet->end(), *P) != CurrentSet->end()) {
- if(std::find(CurrentSet->begin(), CurrentSet->end(), *P) != CurrentSet->end()) {
- if(ignoreEdge(highestHeightNode, *P))
- continue;
- //If not already in Intersect, add
- if(!IntersectCurrent.count(*P))
- IntersectCurrent.insert(*P);
- }
- }
- } //End while loop over Intersect Size
-
- //Change direction
- order = BOTTOM_UP;
-
- //Reset Intersect to reflect changes in OrderNodes
- IntersectCurrent.clear();
- predIntersect(*CurrentSet, IntersectCurrent);
-
- } //End If TOP_DOWN
-
- //Begin if BOTTOM_UP
- else {
- DEBUG(std::cerr << "Order is BOTTOM UP\n");
- while(IntersectCurrent.size() > 0) {
- DEBUG(std::cerr << "Intersection of size " << IntersectCurrent.size() << ", finding highest depth\n");
-
- //dump intersection
- DEBUG(dumpIntersection(IntersectCurrent));
- //Get node with highest depth, if a tie, use one with lowest
- //MOB
- int MOB = 0;
- int depth = 0;
- MSchedGraphNode *highestDepthNode = *(IntersectCurrent.begin());
-
- for(std::set<MSchedGraphNode*>::iterator I = IntersectCurrent.begin(),
- E = IntersectCurrent.end(); I != E; ++I) {
- //Find node attribute in graph
- MSNodeAttributes nodeAttr= nodeToAttributesMap.find(*I)->second;
-
- if(depth < nodeAttr.depth) {
- highestDepthNode = *I;
- depth = nodeAttr.depth;
- MOB = nodeAttr.MOB;
- }
- else if(depth == nodeAttr.depth) {
- if(MOB > nodeAttr.MOB) {
- highestDepthNode = *I;
- depth = nodeAttr.depth;
- MOB = nodeAttr.MOB;
- }
- }
- }
-
-
-
- //Append highest depth node to the NodeOrder
- if(std::find(FinalNodeOrder.begin(), FinalNodeOrder.end(), highestDepthNode) == FinalNodeOrder.end()) {
- DEBUG(std::cerr << "Adding node to Final Order: " << *highestDepthNode << "\n");
- FinalNodeOrder.push_back(highestDepthNode);
- }
- //Remove heightestDepthNode from IntersectOrder
- IntersectCurrent.erase(highestDepthNode);
-
-
- //Intersect heightDepthNode's pred with CurrentSet
- for(MSchedGraphNode::pred_iterator P = highestDepthNode->pred_begin(),
- E = highestDepthNode->pred_end(); P != E; ++P) {
- if(CurrentSet->count(*P)) {
- if(ignoreEdge(*P, highestDepthNode))
- continue;
-
- //If not already in Intersect, add
- if(!IntersectCurrent.count(*P))
- IntersectCurrent.insert(*P);
- }
- }
-
- } //End while loop over Intersect Size
-
- //Change order
- order = TOP_DOWN;
-
- //Reset IntersectCurrent to reflect changes in OrderNodes
- IntersectCurrent.clear();
- succIntersect(*CurrentSet, IntersectCurrent);
- } //End if BOTTOM_DOWN
-
- DEBUG(std::cerr << "Current Intersection Size: " << IntersectCurrent.size() << "\n");
- }
- //End Wrapping while loop
- DEBUG(std::cerr << "Ending Size of Current Set: " << CurrentSet->size() << "\n");
- }//End for over all sets of nodes
-
- //FIXME: As the algorithm stands it will NEVER add an instruction such as ba (with no
- //data dependencies) to the final order. We add this manually. It will always be
- //in the last set of S since its not part of a recurrence
- //Loop over all the sets and place them in the final node order
- std::vector<std::set<MSchedGraphNode*> > ::reverse_iterator LastSet = partialOrder.rbegin();
- for(std::set<MSchedGraphNode*>::iterator CurrentNode = LastSet->begin(), LastNode = LastSet->end();
- CurrentNode != LastNode; ++CurrentNode) {
- if((*CurrentNode)->getInst()->getOpcode() == V9::BA)
- FinalNodeOrder.push_back(*CurrentNode);
- }
- //Return final Order
- //return FinalNodeOrder;
-}
-
-bool ModuloSchedulingPass::computeSchedule(const MachineBasicBlock *BB, MSchedGraph *MSG) {
-
- TIME_REGION(X, "computeSchedule");
-
- bool success = false;
-
- //FIXME: Should be set to max II of the original loop
- //Cap II in order to prevent infinite loop
- int capII = MSG->totalDelay();
-
- while(!success) {
-
- //Keep track of branches, but do not insert into the schedule
- std::vector<MSchedGraphNode*> branches;
-
- //Loop over the final node order and process each node
- for(std::vector<MSchedGraphNode*>::iterator I = FinalNodeOrder.begin(),
- E = FinalNodeOrder.end(); I != E; ++I) {
-
- //CalculateEarly and Late start
- bool initialLSVal = false;
- bool initialESVal = false;
- int EarlyStart = 0;
- int LateStart = 0;
- bool hasSucc = false;
- bool hasPred = false;
- bool sched;
-
- if((*I)->isBranch())
- if((*I)->hasPredecessors())
- sched = true;
- else
- sched = false;
- else
- sched = true;
-
- if(sched) {
- //Loop over nodes in the schedule and determine if they are predecessors
- //or successors of the node we are trying to schedule
- for(MSSchedule::schedule_iterator nodesByCycle = schedule.begin(), nodesByCycleEnd = schedule.end();
- nodesByCycle != nodesByCycleEnd; ++nodesByCycle) {
-
- //For this cycle, get the vector of nodes schedule and loop over it
- for(std::vector<MSchedGraphNode*>::iterator schedNode = nodesByCycle->second.begin(), SNE = nodesByCycle->second.end(); schedNode != SNE; ++schedNode) {
-
- if((*I)->isPredecessor(*schedNode)) {
- int diff = (*I)->getInEdge(*schedNode).getIteDiff();
- int ES_Temp = nodesByCycle->first + (*schedNode)->getLatency() - diff * II;
- DEBUG(std::cerr << "Diff: " << diff << " Cycle: " << nodesByCycle->first << "\n");
- DEBUG(std::cerr << "Temp EarlyStart: " << ES_Temp << " Prev EarlyStart: " << EarlyStart << "\n");
- if(initialESVal)
- EarlyStart = std::max(EarlyStart, ES_Temp);
- else {
- EarlyStart = ES_Temp;
- initialESVal = true;
- }
- hasPred = true;
- }
- if((*I)->isSuccessor(*schedNode)) {
- int diff = (*schedNode)->getInEdge(*I).getIteDiff();
- int LS_Temp = nodesByCycle->first - (*I)->getLatency() + diff * II;
- DEBUG(std::cerr << "Diff: " << diff << " Cycle: " << nodesByCycle->first << "\n");
- DEBUG(std::cerr << "Temp LateStart: " << LS_Temp << " Prev LateStart: " << LateStart << "\n");
- if(initialLSVal)
- LateStart = std::min(LateStart, LS_Temp);
- else {
- LateStart = LS_Temp;
- initialLSVal = true;
- }
- hasSucc = true;
- }
- }
- }
- }
- else {
- branches.push_back(*I);
- continue;
- }
-
- //Check if this node is a pred or succ to a branch, and restrict its placement
- //even though the branch is not in the schedule
- /*int count = branches.size();
- for(std::vector<MSchedGraphNode*>::iterator B = branches.begin(), BE = branches.end();
- B != BE; ++B) {
- if((*I)->isPredecessor(*B)) {
- int diff = (*I)->getInEdge(*B).getIteDiff();
- int ES_Temp = (II+count-1) + (*B)->getLatency() - diff * II;
- DEBUG(std::cerr << "Diff: " << diff << " Cycle: " << (II+count)-1 << "\n");
- DEBUG(std::cerr << "Temp EarlyStart: " << ES_Temp << " Prev EarlyStart: " << EarlyStart << "\n");
- EarlyStart = std::max(EarlyStart, ES_Temp);
- hasPred = true;
- }
-
- if((*I)->isSuccessor(*B)) {
- int diff = (*B)->getInEdge(*I).getIteDiff();
- int LS_Temp = (II+count-1) - (*I)->getLatency() + diff * II;
- DEBUG(std::cerr << "Diff: " << diff << " Cycle: " << (II+count-1) << "\n");
- DEBUG(std::cerr << "Temp LateStart: " << LS_Temp << " Prev LateStart: " << LateStart << "\n");
- LateStart = std::min(LateStart, LS_Temp);
- hasSucc = true;
- }
-
- count--;
- }*/
-
- //Check if the node has no pred or successors and set Early Start to its ASAP
- if(!hasSucc && !hasPred)
- EarlyStart = nodeToAttributesMap.find(*I)->second.ASAP;
-
- DEBUG(std::cerr << "Has Successors: " << hasSucc << ", Has Pred: " << hasPred << "\n");
- DEBUG(std::cerr << "EarlyStart: " << EarlyStart << ", LateStart: " << LateStart << "\n");
-
- //Now, try to schedule this node depending upon its pred and successor in the schedule
- //already
- if(!hasSucc && hasPred)
- success = scheduleNode(*I, EarlyStart, (EarlyStart + II -1));
- else if(!hasPred && hasSucc)
- success = scheduleNode(*I, LateStart, (LateStart - II +1));
- else if(hasPred && hasSucc) {
- if(EarlyStart > LateStart) {
- success = false;
- //LateStart = EarlyStart;
- DEBUG(std::cerr << "Early Start can not be later then the late start cycle, schedule fails\n");
- }
- else
- success = scheduleNode(*I, EarlyStart, std::min(LateStart, (EarlyStart + II -1)));
- }
- else
- success = scheduleNode(*I, EarlyStart, EarlyStart + II - 1);
-
- if(!success) {
- ++II;
- schedule.clear();
- break;
- }
-
- }
-
- if(success) {
- DEBUG(std::cerr << "Constructing Schedule Kernel\n");
- success = schedule.constructKernel(II, branches, indVarInstrs[BB]);
- DEBUG(std::cerr << "Done Constructing Schedule Kernel\n");
- if(!success) {
- ++II;
- schedule.clear();
- }
- DEBUG(std::cerr << "Final II: " << II << "\n");
- }
-
-
- if(II >= capII) {
- DEBUG(std::cerr << "Maximum II reached, giving up\n");
- return false;
- }
-
- assert(II < capII && "The II should not exceed the original loop number of cycles");
- }
- return true;
-}
-
-
-bool ModuloSchedulingPass::scheduleNode(MSchedGraphNode *node,
- int start, int end) {
- bool success = false;
-
- DEBUG(std::cerr << *node << " (Start Cycle: " << start << ", End Cycle: " << end << ")\n");
-
- //Make sure start and end are not negative
- //if(start < 0) {
- //start = 0;
-
- //}
- //if(end < 0)
- //end = 0;
-
- bool forward = true;
- if(start > end)
- forward = false;
-
- bool increaseSC = true;
- int cycle = start ;
-
-
- while(increaseSC) {
-
- increaseSC = false;
-
- increaseSC = schedule.insert(node, cycle, II);
-
- if(!increaseSC)
- return true;
-
- //Increment cycle to try again
- if(forward) {
- ++cycle;
- DEBUG(std::cerr << "Increase cycle: " << cycle << "\n");
- if(cycle > end)
- return false;
- }
- else {
- --cycle;
- DEBUG(std::cerr << "Decrease cycle: " << cycle << "\n");
- if(cycle < end)
- return false;
- }
- }
-
- return success;
-}
-
-void ModuloSchedulingPass::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) {
-
- //Keep a map to easily know whats in the kernel
- std::map<int, std::set<const MachineInstr*> > inKernel;
- int maxStageCount = 0;
-
- //Keep a map of new values we consumed in case they need to be added back
- std::map<Value*, std::map<int, Value*> > consumedValues;
-
- MSchedGraphNode *branch = 0;
- MSchedGraphNode *BAbranch = 0;
-
- DEBUG(schedule.print(std::cerr));
-
- std::vector<MSchedGraphNode*> branches;
-
- for(MSSchedule::kernel_iterator I = schedule.kernel_begin(), E = schedule.kernel_end(); I != E; ++I) {
- maxStageCount = std::max(maxStageCount, I->second);
-
- //Put int the map so we know what instructions in each stage are in the kernel
- DEBUG(std::cerr << "Inserting instruction " << *(I->first) << " into map at stage " << I->second << "\n");
- inKernel[I->second].insert(I->first);
- }
-
- //Get target information to look at machine operands
- const TargetInstrInfo *mii = target.getInstrInfo();
-
- //Now write the prologues
- for(int i = 0; i < maxStageCount; ++i) {
- BasicBlock *llvmBB = new BasicBlock("PROLOGUE", (Function*) (origBB->getBasicBlock()->getParent()));
- MachineBasicBlock *machineBB = new MachineBasicBlock(llvmBB);
-
- DEBUG(std::cerr << "i=" << i << "\n");
- for(int j = i; j >= 0; --j) {
- for(MachineBasicBlock::const_iterator MI = origBB->begin(), ME = origBB->end(); ME != MI; ++MI) {
- if(inKernel[j].count(&*MI)) {
- MachineInstr *instClone = MI->clone();
- machineBB->push_back(instClone);
-
- //If its a branch, insert a nop
- if(mii->isBranch(instClone->getOpcode()))
- BuildMI(machineBB, V9::NOP, 0);
-
-
- DEBUG(std::cerr << "Cloning: " << *MI << "\n");
-
- //After cloning, we may need to save the value that this instruction defines
- for(unsigned opNum=0; opNum < MI->getNumOperands(); ++opNum) {
- Instruction *tmp;
-
- //get machine operand
- MachineOperand &mOp = instClone->getOperand(opNum);
- if(mOp.getType() == MachineOperand::MO_VirtualRegister && mOp.isDef()) {
-
- //Check if this is a value we should save
- if(valuesToSave.count(mOp.getVRegValue())) {
- //Save copy in tmpInstruction
- tmp = new TmpInstruction(mOp.getVRegValue());
-
- //Add TmpInstruction to safe LLVM Instruction MCFI
- MachineCodeForInstruction & tempMvec = MachineCodeForInstruction::get(defaultInst);
- tempMvec.addTemp((Value*) tmp);
-
- DEBUG(std::cerr << "Value: " << *(mOp.getVRegValue()) << " New Value: " << *tmp << " Stage: " << i << "\n");
-
- newValues[mOp.getVRegValue()][i]= tmp;
- newValLocation[tmp] = machineBB;
-
- DEBUG(std::cerr << "Machine Instr Operands: " << *(mOp.getVRegValue()) << ", 0, " << *tmp << "\n");
-
- //Create machine instruction and put int machineBB
- MachineInstr *saveValue;
- if(mOp.getVRegValue()->getType() == Type::FloatTy)
- saveValue = BuildMI(machineBB, V9::FMOVS, 3).addReg(mOp.getVRegValue()).addRegDef(tmp);
- else if(mOp.getVRegValue()->getType() == Type::DoubleTy)
- saveValue = BuildMI(machineBB, V9::FMOVD, 3).addReg(mOp.getVRegValue()).addRegDef(tmp);
- else
- saveValue = BuildMI(machineBB, V9::ORr, 3).addReg(mOp.getVRegValue()).addImm(0).addRegDef(tmp);
-
-
- DEBUG(std::cerr << "Created new machine instr: " << *saveValue << "\n");
- }
- }
-
- //We may also need to update the value that we use if its from an earlier prologue
- if(j != 0) {
- if(mOp.getType() == MachineOperand::MO_VirtualRegister && mOp.isUse()) {
- if(newValues.count(mOp.getVRegValue())) {
- if(newValues[mOp.getVRegValue()].count(i-1)) {
- Value *oldV = mOp.getVRegValue();
- DEBUG(std::cerr << "Replaced this value: " << mOp.getVRegValue() << " With:" << (newValues[mOp.getVRegValue()][i-1]) << "\n");
- //Update the operand with the right value
- mOp.setValueReg(newValues[mOp.getVRegValue()][i-1]);
-
- //Remove this value since we have consumed it
- //NOTE: Should this only be done if j != maxStage?
- consumedValues[oldV][i-1] = (newValues[oldV][i-1]);
- DEBUG(std::cerr << "Deleted value: " << consumedValues[oldV][i-1] << "\n");
- newValues[oldV].erase(i-1);
- }
- }
- else
- if(consumedValues.count(mOp.getVRegValue()))
- assert(!consumedValues[mOp.getVRegValue()].count(i-1) && "Found a case where we need the value");
- }
- }
- }
- }
- }
- }
-
- MachineFunction *F = (((MachineBasicBlock*)origBB)->getParent());
- MachineFunction::BasicBlockListType &BL = F->getBasicBlockList();
- MachineFunction::BasicBlockListType::iterator BLI = origBB;
- assert(BLI != BL.end() && "Must find original BB in machine function\n");
- BL.insert(BLI,machineBB);
- prologues.push_back(machineBB);
- llvm_prologues.push_back(llvmBB);
- }
-}
-
-void ModuloSchedulingPass::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 ) {
-
- std::map<int, std::set<const MachineInstr*> > inKernel;
-
- for(MSSchedule::kernel_iterator I = schedule.kernel_begin(), E = schedule.kernel_end(); I != E; ++I) {
-
- //Ignore the branch, we will handle this separately
- //if(I->first->isBranch())
- //continue;
-
- //Put int the map so we know what instructions in each stage are in the kernel
- inKernel[I->second].insert(I->first);
- }
-
- std::map<Value*, Value*> valPHIs;
-
- //some debug stuff, will remove later
- DEBUG(for(std::map<Value*, std::map<int, Value*> >::iterator V = newValues.begin(), E = newValues.end(); V !=E; ++V) {
- std::cerr << "Old Value: " << *(V->first) << "\n";
- for(std::map<int, Value*>::iterator I = V->second.begin(), IE = V->second.end(); I != IE; ++I)
- std::cerr << "Stage: " << I->first << " Value: " << *(I->second) << "\n";
- });
-
- //some debug stuff, will remove later
- DEBUG(for(std::map<Value*, std::map<int, Value*> >::iterator V = kernelPHIs.begin(), E = kernelPHIs.end(); V !=E; ++V) {
- std::cerr << "Old Value: " << *(V->first) << "\n";
- for(std::map<int, Value*>::iterator I = V->second.begin(), IE = V->second.end(); I != IE; ++I)
- std::cerr << "Stage: " << I->first << " Value: " << *(I->second) << "\n";
- });
-
- //Now write the epilogues
- for(int i = schedule.getMaxStage()-1; i >= 0; --i) {
- BasicBlock *llvmBB = new BasicBlock("EPILOGUE", (Function*) (origBB->getBasicBlock()->getParent()));
- MachineBasicBlock *machineBB = new MachineBasicBlock(llvmBB);
-
- DEBUG(std::cerr << " Epilogue #: " << i << "\n");
-
-
- std::map<Value*, int> inEpilogue;
-
- for(MachineBasicBlock::const_iterator MI = origBB->begin(), ME = origBB->end(); ME != MI; ++MI) {
- for(int j=schedule.getMaxStage(); j > i; --j) {
- if(inKernel[j].count(&*MI)) {
- DEBUG(std::cerr << "Cloning instruction " << *MI << "\n");
- MachineInstr *clone = MI->clone();
-
- //Update operands that need to use the result from the phi
- for(unsigned opNum=0; opNum < clone->getNumOperands(); ++opNum) {
- //get machine operand
- const MachineOperand &mOp = clone->getOperand(opNum);
-
- if((mOp.getType() == MachineOperand::MO_VirtualRegister && mOp.isUse())) {
-
- DEBUG(std::cerr << "Writing PHI for " << (mOp.getVRegValue()) << "\n");
-
- //If this is the last instructions for the max iterations ago, don't update operands
- if(inEpilogue.count(mOp.getVRegValue()))
- if(inEpilogue[mOp.getVRegValue()] == i)
- continue;
-
- //Quickly write appropriate phis for this operand
- if(newValues.count(mOp.getVRegValue())) {
- if(newValues[mOp.getVRegValue()].count(i)) {
- Instruction *tmp = new TmpInstruction(newValues[mOp.getVRegValue()][i]);
-
- //Get machine code for this instruction
- MachineCodeForInstruction & tempMvec = MachineCodeForInstruction::get(defaultInst);
- tempMvec.addTemp((Value*) tmp);
-
- //assert of no kernelPHI for this value
- assert(kernelPHIs[mOp.getVRegValue()][i] !=0 && "Must have final kernel phi to construct epilogue phi");
-
- MachineInstr *saveValue = BuildMI(machineBB, V9::PHI, 3).addReg(newValues[mOp.getVRegValue()][i]).addReg(kernelPHIs[mOp.getVRegValue()][i]).addRegDef(tmp);
- DEBUG(std::cerr << "Resulting PHI: " << *saveValue << "\n");
- valPHIs[mOp.getVRegValue()] = tmp;
- }
- }
-
- if(valPHIs.count(mOp.getVRegValue())) {
- //Update the operand in the cloned instruction
- clone->getOperand(opNum).setValueReg(valPHIs[mOp.getVRegValue()]);
- }
- }
- else if((mOp.getType() == MachineOperand::MO_VirtualRegister && mOp.isDef())) {
- inEpilogue[mOp.getVRegValue()] = i;
- }
- }
- machineBB->push_back(clone);
- }
- }
- }
-
- MachineFunction *F = (((MachineBasicBlock*)origBB)->getParent());
- MachineFunction::BasicBlockListType &BL = F->getBasicBlockList();
- MachineFunction::BasicBlockListType::iterator BLI = (MachineBasicBlock*) origBB;
- assert(BLI != BL.end() && "Must find original BB in machine function\n");
- BL.insert(BLI,machineBB);
- epilogues.push_back(machineBB);
- llvm_epilogues.push_back(llvmBB);
-
- DEBUG(std::cerr << "EPILOGUE #" << i << "\n");
- DEBUG(machineBB->print(std::cerr));
- }
-}
-
-void ModuloSchedulingPass::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) {
-
- //Keep track of operands that are read and saved from a previous iteration. The new clone
- //instruction will use the result of the phi instead.
- std::map<Value*, Value*> finalPHIValue;
- std::map<Value*, Value*> kernelValue;
-
- //Branches are a special case
- std::vector<MachineInstr*> branches;
-
- //Get target information to look at machine operands
- const TargetInstrInfo *mii = target.getInstrInfo();
-
- //Create TmpInstructions for the final phis
- for(MSSchedule::kernel_iterator I = schedule.kernel_begin(), E = schedule.kernel_end(); I != E; ++I) {
-
- DEBUG(std::cerr << "Stage: " << I->second << " Inst: " << *(I->first) << "\n";);
-
- //Clone instruction
- const MachineInstr *inst = I->first;
- MachineInstr *instClone = inst->clone();
-
- //Insert into machine basic block
- machineBB->push_back(instClone);
-
- if(mii->isBranch(instClone->getOpcode()))
- BuildMI(machineBB, V9::NOP, 0);
-
- DEBUG(std::cerr << "Cloned Inst: " << *instClone << "\n");
-
- //Loop over Machine Operands
- for(unsigned i=0; i < inst->getNumOperands(); ++i) {
- //get machine operand
- const MachineOperand &mOp = inst->getOperand(i);
-
- if(I->second != 0) {
- if(mOp.getType() == MachineOperand::MO_VirtualRegister && mOp.isUse()) {
-
- //Check to see where this operand is defined if this instruction is from max stage
- if(I->second == schedule.getMaxStage()) {
- DEBUG(std::cerr << "VREG: " << *(mOp.getVRegValue()) << "\n");
- }
-
- //If its in the value saved, we need to create a temp instruction and use that instead
- if(valuesToSave.count(mOp.getVRegValue())) {
-
- //Check if we already have a final PHI value for this
- if(!finalPHIValue.count(mOp.getVRegValue())) {
- //Only create phi if the operand def is from a stage before this one
- if(schedule.defPreviousStage(mOp.getVRegValue(), I->second)) {
- TmpInstruction *tmp = new TmpInstruction(mOp.getVRegValue());
-
- //Get machine code for this instruction
- MachineCodeForInstruction & tempMvec = MachineCodeForInstruction::get(defaultInst);
- tempMvec.addTemp((Value*) tmp);
-
- //Update the operand in the cloned instruction
- instClone->getOperand(i).setValueReg(tmp);
-
- //save this as our final phi
- finalPHIValue[mOp.getVRegValue()] = tmp;
- newValLocation[tmp] = machineBB;
- }
- }
- else {
- //Use the previous final phi value
- instClone->getOperand(i).setValueReg(finalPHIValue[mOp.getVRegValue()]);
- }
- }
- }
- }
- if(I->second != schedule.getMaxStage()) {
- if(mOp.getType() == MachineOperand::MO_VirtualRegister && mOp.isDef()) {
- if(valuesToSave.count(mOp.getVRegValue())) {
-
- TmpInstruction *tmp = new TmpInstruction(mOp.getVRegValue());
-
- //Get machine code for this instruction
- MachineCodeForInstruction & tempVec = MachineCodeForInstruction::get(defaultInst);
- tempVec.addTemp((Value*) tmp);
-
- //Create new machine instr and put in MBB
- MachineInstr *saveValue;
- if(mOp.getVRegValue()->getType() == Type::FloatTy)
- saveValue = BuildMI(machineBB, V9::FMOVS, 3).addReg(mOp.getVRegValue()).addRegDef(tmp);
- else if(mOp.getVRegValue()->getType() == Type::DoubleTy)
- saveValue = BuildMI(machineBB, V9::FMOVD, 3).addReg(mOp.getVRegValue()).addRegDef(tmp);
- else
- saveValue = BuildMI(machineBB, V9::ORr, 3).addReg(mOp.getVRegValue()).addImm(0).addRegDef(tmp);
-
-
- //Save for future cleanup
- kernelValue[mOp.getVRegValue()] = tmp;
- newValLocation[tmp] = machineBB;
- kernelPHIs[mOp.getVRegValue()][schedule.getMaxStage()-1] = tmp;
- }
- }
- }
- }
-
- }
-
- //Add branches
- for(std::vector<MachineInstr*>::iterator I = branches.begin(), E = branches.end(); I != E; ++I) {
- machineBB->push_back(*I);
- BuildMI(machineBB, V9::NOP, 0);
- }
-
-
- DEBUG(std::cerr << "KERNEL before PHIs\n");
- DEBUG(machineBB->print(std::cerr));
-
-
- //Loop over each value we need to generate phis for
- for(std::map<Value*, std::map<int, Value*> >::iterator V = newValues.begin(),
- E = newValues.end(); V != E; ++V) {
-
-
- DEBUG(std::cerr << "Writing phi for" << *(V->first));
- DEBUG(std::cerr << "\nMap of Value* for this phi\n");
- DEBUG(for(std::map<int, Value*>::iterator I = V->second.begin(),
- IE = V->second.end(); I != IE; ++I) {
- std::cerr << "Stage: " << I->first;
- std::cerr << " Value: " << *(I->second) << "\n";
- });
-
- //If we only have one current iteration live, its safe to set lastPhi = to kernel value
- if(V->second.size() == 1) {
- assert(kernelValue[V->first] != 0 && "Kernel value* must exist to create phi");
- MachineInstr *saveValue = BuildMI(*machineBB, machineBB->begin(),V9::PHI, 3).addReg(V->second.begin()->second).addReg(kernelValue[V->first]).addRegDef(finalPHIValue[V->first]);
- DEBUG(std::cerr << "Resulting PHI (one live): " << *saveValue << "\n");
- kernelPHIs[V->first][V->second.begin()->first] = kernelValue[V->first];
- DEBUG(std::cerr << "Put kernel phi in at stage: " << schedule.getMaxStage()-1 << " (map stage = " << V->second.begin()->first << ")\n");
- }
- else {
-
- //Keep track of last phi created.
- Instruction *lastPhi = 0;
-
- unsigned count = 1;
- //Loop over the the map backwards to generate phis
- for(std::map<int, Value*>::reverse_iterator I = V->second.rbegin(), IE = V->second.rend();
- I != IE; ++I) {
-
- if(count < (V->second).size()) {
- if(lastPhi == 0) {
- lastPhi = new TmpInstruction(I->second);
-
- //Get machine code for this instruction
- MachineCodeForInstruction & tempMvec = MachineCodeForInstruction::get(defaultInst);
- tempMvec.addTemp((Value*) lastPhi);
-
- MachineInstr *saveValue = BuildMI(*machineBB, machineBB->begin(), V9::PHI, 3).addReg(kernelValue[V->first]).addReg(I->second).addRegDef(lastPhi);
- DEBUG(std::cerr << "Resulting PHI: " << *saveValue << "\n");
- newValLocation[lastPhi] = machineBB;
- }
- else {
- Instruction *tmp = new TmpInstruction(I->second);
-
- //Get machine code for this instruction
- MachineCodeForInstruction & tempMvec = MachineCodeForInstruction::get(defaultInst);
- tempMvec.addTemp((Value*) tmp);
-
-
- MachineInstr *saveValue = BuildMI(*machineBB, machineBB->begin(), V9::PHI, 3).addReg(lastPhi).addReg(I->second).addRegDef(tmp);
- DEBUG(std::cerr << "Resulting PHI: " << *saveValue << "\n");
- lastPhi = tmp;
- kernelPHIs[V->first][I->first] = lastPhi;
- newValLocation[lastPhi] = machineBB;
- }
- }
- //Final phi value
- else {
- //The resulting value must be the Value* we created earlier
- assert(lastPhi != 0 && "Last phi is NULL!\n");
- MachineInstr *saveValue = BuildMI(*machineBB, machineBB->begin(), V9::PHI, 3).addReg(lastPhi).addReg(I->second).addRegDef(finalPHIValue[V->first]);
- DEBUG(std::cerr << "Resulting PHI: " << *saveValue << "\n");
- kernelPHIs[V->first][I->first] = finalPHIValue[V->first];
- }
-
- ++count;
- }
-
- }
- }
-
- DEBUG(std::cerr << "KERNEL after PHIs\n");
- DEBUG(machineBB->print(std::cerr));
-}
-
-
-void ModuloSchedulingPass::removePHIs(const MachineBasicBlock *origBB, std::vector<MachineBasicBlock *> &prologues, std::vector<MachineBasicBlock *> &epilogues, MachineBasicBlock *kernelBB, std::map<Value*, MachineBasicBlock*> &newValLocation) {
-
- //Worklist to delete things
- std::vector<std::pair<MachineBasicBlock*, MachineBasicBlock::iterator> > worklist;
-
- //Worklist of TmpInstructions that need to be added to a MCFI
- std::vector<Instruction*> addToMCFI;
-
- //Worklist to add OR instructions to end of kernel so not to invalidate the iterator
- //std::vector<std::pair<Instruction*, Value*> > newORs;
-
- const TargetInstrInfo *TMI = target.getInstrInfo();
-
- //Start with the kernel and for each phi insert a copy for the phi def and for each arg
- for(MachineBasicBlock::iterator I = kernelBB->begin(), E = kernelBB->end(); I != E; ++I) {
-
- DEBUG(std::cerr << "Looking at Instr: " << *I << "\n");
- //Get op code and check if its a phi
- if(I->getOpcode() == V9::PHI) {
-
- DEBUG(std::cerr << "Replacing PHI: " << *I << "\n");
- Instruction *tmp = 0;
-
- for(unsigned i = 0; i < I->getNumOperands(); ++i) {
- //Get Operand
- const MachineOperand &mOp = I->getOperand(i);
- assert(mOp.getType() == MachineOperand::MO_VirtualRegister && "Should be a Value*\n");
-
- if(!tmp) {
- tmp = new TmpInstruction(mOp.getVRegValue());
- addToMCFI.push_back(tmp);
- }
-
- //Now for all our arguments we read, OR to the new TmpInstruction that we created
- if(mOp.isUse()) {
- DEBUG(std::cerr << "Use: " << mOp << "\n");
- //Place a copy at the end of its BB but before the branches
- assert(newValLocation.count(mOp.getVRegValue()) && "We must know where this value is located\n");
- //Reverse iterate to find the branches, we can safely assume no instructions have been
- //put in the nop positions
- for(MachineBasicBlock::iterator inst = --(newValLocation[mOp.getVRegValue()])->end(), endBB = (newValLocation[mOp.getVRegValue()])->begin(); inst != endBB; --inst) {
- MachineOpCode opc = inst->getOpcode();
- if(TMI->isBranch(opc) || TMI->isNop(opc))
- continue;
- else {
- if(mOp.getVRegValue()->getType() == Type::FloatTy)
- BuildMI(*(newValLocation[mOp.getVRegValue()]), ++inst, V9::FMOVS, 3).addReg(mOp.getVRegValue()).addRegDef(tmp);
- else if(mOp.getVRegValue()->getType() == Type::DoubleTy)
- BuildMI(*(newValLocation[mOp.getVRegValue()]), ++inst, V9::FMOVD, 3).addReg(mOp.getVRegValue()).addRegDef(tmp);
- else
- BuildMI(*(newValLocation[mOp.getVRegValue()]), ++inst, V9::ORr, 3).addReg(mOp.getVRegValue()).addImm(0).addRegDef(tmp);
-
- break;
- }
-
- }
-
- }
- else {
- //Remove the phi and replace it with an OR
- DEBUG(std::cerr << "Def: " << mOp << "\n");
- //newORs.push_back(std::make_pair(tmp, mOp.getVRegValue()));
- if(tmp->getType() == Type::FloatTy)
- BuildMI(*kernelBB, I, V9::FMOVS, 3).addReg(tmp).addRegDef(mOp.getVRegValue());
- else if(tmp->getType() == Type::DoubleTy)
- BuildMI(*kernelBB, I, V9::FMOVD, 3).addReg(tmp).addRegDef(mOp.getVRegValue());
- else
- BuildMI(*kernelBB, I, V9::ORr, 3).addReg(tmp).addImm(0).addRegDef(mOp.getVRegValue());
-
-
- worklist.push_back(std::make_pair(kernelBB, I));
- }
-
- }
-
- }
-
-
- }
-
- //Add TmpInstructions to some MCFI
- if(addToMCFI.size() > 0) {
- MachineCodeForInstruction & tempMvec = MachineCodeForInstruction::get(defaultInst);
- for(unsigned x = 0; x < addToMCFI.size(); ++x) {
- tempMvec.addTemp(addToMCFI[x]);
- }
- addToMCFI.clear();
- }
-
-
- //Remove phis from epilogue
- for(std::vector<MachineBasicBlock*>::iterator MB = epilogues.begin(), ME = epilogues.end(); MB != ME; ++MB) {
- for(MachineBasicBlock::iterator I = (*MB)->begin(), E = (*MB)->end(); I != E; ++I) {
-
- DEBUG(std::cerr << "Looking at Instr: " << *I << "\n");
- //Get op code and check if its a phi
- if(I->getOpcode() == V9::PHI) {
- Instruction *tmp = 0;
-
- for(unsigned i = 0; i < I->getNumOperands(); ++i) {
- //Get Operand
- const MachineOperand &mOp = I->getOperand(i);
- assert(mOp.getType() == MachineOperand::MO_VirtualRegister && "Should be a Value*\n");
-
- if(!tmp) {
- tmp = new TmpInstruction(mOp.getVRegValue());
- addToMCFI.push_back(tmp);
- }
-
- //Now for all our arguments we read, OR to the new TmpInstruction that we created
- if(mOp.isUse()) {
- DEBUG(std::cerr << "Use: " << mOp << "\n");
- //Place a copy at the end of its BB but before the branches
- assert(newValLocation.count(mOp.getVRegValue()) && "We must know where this value is located\n");
- //Reverse iterate to find the branches, we can safely assume no instructions have been
- //put in the nop positions
- for(MachineBasicBlock::iterator inst = --(newValLocation[mOp.getVRegValue()])->end(), endBB = (newValLocation[mOp.getVRegValue()])->begin(); inst != endBB; --inst) {
- MachineOpCode opc = inst->getOpcode();
- if(TMI->isBranch(opc) || TMI->isNop(opc))
- continue;
- else {
- if(mOp.getVRegValue()->getType() == Type::FloatTy)
- BuildMI(*(newValLocation[mOp.getVRegValue()]), ++inst, V9::FMOVS, 3).addReg(mOp.getVRegValue()).addRegDef(tmp);
- else if(mOp.getVRegValue()->getType() == Type::DoubleTy)
- BuildMI(*(newValLocation[mOp.getVRegValue()]), ++inst, V9::FMOVD, 3).addReg(mOp.getVRegValue()).addRegDef(tmp);
- else
- BuildMI(*(newValLocation[mOp.getVRegValue()]), ++inst, V9::ORr, 3).addReg(mOp.getVRegValue()).addImm(0).addRegDef(tmp);
-
-
- break;
- }
-
- }
-
- }
- else {
- //Remove the phi and replace it with an OR
- DEBUG(std::cerr << "Def: " << mOp << "\n");
- if(tmp->getType() == Type::FloatTy)
- BuildMI(**MB, I, V9::FMOVS, 3).addReg(tmp).addRegDef(mOp.getVRegValue());
- else if(tmp->getType() == Type::DoubleTy)
- BuildMI(**MB, I, V9::FMOVD, 3).addReg(tmp).addRegDef(mOp.getVRegValue());
- else
- BuildMI(**MB, I, V9::ORr, 3).addReg(tmp).addImm(0).addRegDef(mOp.getVRegValue());
-
- worklist.push_back(std::make_pair(*MB,I));
- }
-
- }
- }
-
-
- }
- }
-
-
- if(addToMCFI.size() > 0) {
- MachineCodeForInstruction & tempMvec = MachineCodeForInstruction::get(defaultInst);
- for(unsigned x = 0; x < addToMCFI.size(); ++x) {
- tempMvec.addTemp(addToMCFI[x]);
- }
- addToMCFI.clear();
- }
-
- //Delete the phis
- for(std::vector<std::pair<MachineBasicBlock*, MachineBasicBlock::iterator> >::iterator I = worklist.begin(), E = worklist.end(); I != E; ++I) {
-
- DEBUG(std::cerr << "Deleting PHI " << *I->second << "\n");
- I->first->erase(I->second);
-
- }
-
-
- assert((addToMCFI.size() == 0) && "We should have added all TmpInstructions to some MachineCodeForInstruction");
-}
-
-
-void ModuloSchedulingPass::reconstructLoop(MachineBasicBlock *BB) {
-
- TIME_REGION(X, "reconstructLoop");
-
-
- DEBUG(std::cerr << "Reconstructing Loop\n");
-
- //First find the value *'s that we need to "save"
- std::map<const Value*, std::pair<const MachineInstr*, int> > valuesToSave;
-
- //Keep track of instructions we have already seen and their stage because
- //we don't want to "save" values if they are used in the kernel immediately
- std::map<const MachineInstr*, int> lastInstrs;
- std::map<const Value*, int> phiUses;
-
- //Loop over kernel and only look at instructions from a stage > 0
- //Look at its operands and save values *'s that are read
- for(MSSchedule::kernel_iterator I = schedule.kernel_begin(), E = schedule.kernel_end(); I != E; ++I) {
-
- if(I->second !=0) {
- //For this instruction, get the Value*'s that it reads and put them into the set.
- //Assert if there is an operand of another type that we need to save
- const MachineInstr *inst = I->first;
- lastInstrs[inst] = I->second;
-
- for(unsigned i=0; i < inst->getNumOperands(); ++i) {
- //get machine operand
- const MachineOperand &mOp = inst->getOperand(i);
-
- if(mOp.getType() == MachineOperand::MO_VirtualRegister && mOp.isUse()) {
- //find the value in the map
- if (const Value* srcI = mOp.getVRegValue()) {
-
- if(isa<Constant>(srcI) || isa<Argument>(srcI))
- continue;
-
- //Before we declare this Value* one that we should save
- //make sure its def is not of the same stage as this instruction
- //because it will be consumed before its used
- Instruction *defInst = (Instruction*) srcI;
-
- //Should we save this value?
- bool save = true;
-
- //Continue if not in the def map, loop invariant code does not need to be saved
- if(!defMap.count(srcI))
- continue;
-
- MachineInstr *defInstr = defMap[srcI];
-
-
- if(lastInstrs.count(defInstr)) {
- if(lastInstrs[defInstr] == I->second) {
- save = false;
-
- }
- }
-
- if(save) {
- assert(!phiUses.count(srcI) && "Did not expect to see phi use twice");
- if(isa<PHINode>(srcI))
- phiUses[srcI] = I->second;
-
- valuesToSave[srcI] = std::make_pair(I->first, i);
-
- }
- }
- }
- else if(mOp.getType() == MachineOperand::MO_VirtualRegister && mOp.isDef()) {
- if (const Value* destI = mOp.getVRegValue()) {
- if(!isa<PHINode>(destI))
- continue;
- if(phiUses.count(destI)) {
- if(phiUses[destI] == I->second) {
- //remove from save list
- valuesToSave.erase(destI);
- }
- }
- }
- }
-
- if(mOp.getType() != MachineOperand::MO_VirtualRegister && mOp.isUse()) {
- assert("Our assumption is wrong. We have another type of register that needs to be saved\n");
- }
- }
- }
- }
-
- //The new loop will consist of one or more prologues, the kernel, and one or more epilogues.
-
- //Map to keep track of old to new values
- std::map<Value*, std::map<int, Value*> > newValues;
-
- //Map to keep track of old to new values in kernel
- std::map<Value*, std::map<int, Value*> > kernelPHIs;
-
- //Another map to keep track of what machine basic blocks these new value*s are in since
- //they have no llvm instruction equivalent
- std::map<Value*, MachineBasicBlock*> newValLocation;
-
- std::vector<MachineBasicBlock*> prologues;
- std::vector<BasicBlock*> llvm_prologues;
-
-
- //Write prologue
- if(schedule.getMaxStage() != 0)
- writePrologues(prologues, BB, llvm_prologues, valuesToSave, newValues, newValLocation);
-
- //Print out epilogues and prologue
- DEBUG(for(std::vector<MachineBasicBlock*>::iterator I = prologues.begin(), E = prologues.end();
- I != E; ++I) {
- std::cerr << "PROLOGUE\n";
- (*I)->print(std::cerr);
- });
-
- BasicBlock *llvmKernelBB = new BasicBlock("Kernel", (Function*) (BB->getBasicBlock()->getParent()));
- MachineBasicBlock *machineKernelBB = new MachineBasicBlock(llvmKernelBB);
-
- MachineFunction *F = (((MachineBasicBlock*)BB)->getParent());
- MachineFunction::BasicBlockListType &BL = F->getBasicBlockList();
- MachineFunction::BasicBlockListType::iterator BLI = BB;
- assert(BLI != BL.end() && "Must find original BB in machine function\n");
- BL.insert(BLI,machineKernelBB);
-
- //(((MachineBasicBlock*)BB)->getParent())->getBasicBlockList().push_back(machineKernelBB);
- writeKernel(llvmKernelBB, machineKernelBB, valuesToSave, newValues, newValLocation, kernelPHIs);
-
-
- std::vector<MachineBasicBlock*> epilogues;
- std::vector<BasicBlock*> llvm_epilogues;
-
- //Write epilogues
- if(schedule.getMaxStage() != 0)
- writeEpilogues(epilogues, BB, llvm_epilogues, valuesToSave, newValues, newValLocation, kernelPHIs);
-
-
- //Fix our branches
- fixBranches(prologues, llvm_prologues, machineKernelBB, llvmKernelBB, epilogues, llvm_epilogues, BB);
-
- //Remove phis
- removePHIs(BB, prologues, epilogues, machineKernelBB, newValLocation);
-
- //Print out epilogues and prologue
- DEBUG(for(std::vector<MachineBasicBlock*>::iterator I = prologues.begin(), E = prologues.end();
- I != E; ++I) {
- std::cerr << "PROLOGUE\n";
- (*I)->print(std::cerr);
- });
-
- DEBUG(std::cerr << "KERNEL\n");
- DEBUG(machineKernelBB->print(std::cerr));
-
- DEBUG(for(std::vector<MachineBasicBlock*>::iterator I = epilogues.begin(), E = epilogues.end();
- I != E; ++I) {
- std::cerr << "EPILOGUE\n";
- (*I)->print(std::cerr);
- });
-
-
- DEBUG(std::cerr << "New Machine Function" << "\n");
- DEBUG(std::cerr << BB->getParent() << "\n");
-
-
-}
-
-void ModuloSchedulingPass::fixBranches(std::vector<MachineBasicBlock *> &prologues, std::vector<BasicBlock*> &llvm_prologues, MachineBasicBlock *machineKernelBB, BasicBlock *llvmKernelBB, std::vector<MachineBasicBlock *> &epilogues, std::vector<BasicBlock*> &llvm_epilogues, MachineBasicBlock *BB) {
-
- const TargetInstrInfo *TMI = target.getInstrInfo();
-
- if(schedule.getMaxStage() != 0) {
- //Fix prologue branches
- for(unsigned I = 0; I < prologues.size(); ++I) {
-
- //Find terminator since getFirstTerminator does not work!
- for(MachineBasicBlock::reverse_iterator mInst = prologues[I]->rbegin(), mInstEnd = prologues[I]->rend(); mInst != mInstEnd; ++mInst) {
- MachineOpCode OC = mInst->getOpcode();
- //If its a branch update its branchto
- if(TMI->isBranch(OC)) {
- for(unsigned opNum = 0; opNum < mInst->getNumOperands(); ++opNum) {
- MachineOperand &mOp = mInst->getOperand(opNum);
- if (mOp.getType() == MachineOperand::MO_PCRelativeDisp) {
- //Check if we are branching to the kernel, if not branch to epilogue
- if(mOp.getVRegValue() == BB->getBasicBlock()) {
- if(I == prologues.size()-1)
- mOp.setValueReg(llvmKernelBB);
- else
- mOp.setValueReg(llvm_prologues[I+1]);
- }
- else {
- mOp.setValueReg(llvm_epilogues[(llvm_epilogues.size()-1-I)]);
- }
- }
- }
-
- DEBUG(std::cerr << "New Prologue Branch: " << *mInst << "\n");
- }
- }
-
-
- //Update llvm basic block with our new branch instr
- DEBUG(std::cerr << BB->getBasicBlock()->getTerminator() << "\n");
- const BranchInst *branchVal = dyn_cast<BranchInst>(BB->getBasicBlock()->getTerminator());
-
- if(I == prologues.size()-1) {
- TerminatorInst *newBranch = new BranchInst(llvmKernelBB,
- llvm_epilogues[(llvm_epilogues.size()-1-I)],
- branchVal->getCondition(),
- llvm_prologues[I]);
- }
- else
- TerminatorInst *newBranch = new BranchInst(llvm_prologues[I+1],
- llvm_epilogues[(llvm_epilogues.size()-1-I)],
- branchVal->getCondition(),
- llvm_prologues[I]);
-
- }
- }
-
- Value *origBranchExit = 0;
-
- //Fix up kernel machine branches
- for(MachineBasicBlock::reverse_iterator mInst = machineKernelBB->rbegin(), mInstEnd = machineKernelBB->rend(); mInst != mInstEnd; ++mInst) {
- MachineOpCode OC = mInst->getOpcode();
- if(TMI->isBranch(OC)) {
- for(unsigned opNum = 0; opNum < mInst->getNumOperands(); ++opNum) {
- MachineOperand &mOp = mInst->getOperand(opNum);
-
- if(mOp.getType() == MachineOperand::MO_PCRelativeDisp) {
- if(mOp.getVRegValue() == BB->getBasicBlock())
- mOp.setValueReg(llvmKernelBB);
- else
- if(llvm_epilogues.size() > 0) {
- assert(origBranchExit == 0 && "There should only be one branch out of the loop");
-
- origBranchExit = mOp.getVRegValue();
- mOp.setValueReg(llvm_epilogues[0]);
- }
- else
- origBranchExit = mOp.getVRegValue();
- }
- }
- }
- }
-
- //Update kernelLLVM branches
- const BranchInst *branchVal = dyn_cast<BranchInst>(BB->getBasicBlock()->getTerminator());
-
- assert(origBranchExit != 0 && "We must have the original bb the kernel exits to!");
-
- if(epilogues.size() > 0) {
- TerminatorInst *newBranch = new BranchInst(llvmKernelBB,
- llvm_epilogues[0],
- branchVal->getCondition(),
- llvmKernelBB);
- }
- else {
- BasicBlock *origBBExit = dyn_cast<BasicBlock>(origBranchExit);
- assert(origBBExit !=0 && "Original exit basic block must be set");
- TerminatorInst *newBranch = new BranchInst(llvmKernelBB,
- origBBExit,
- branchVal->getCondition(),
- llvmKernelBB);
- }
-
- if(schedule.getMaxStage() != 0) {
- //Lastly add unconditional branches for the epilogues
- for(unsigned I = 0; I < epilogues.size(); ++I) {
-
- //Now since we don't have fall throughs, add a unconditional branch to the next prologue
- if(I != epilogues.size()-1) {
- BuildMI(epilogues[I], V9::BA, 1).addPCDisp(llvm_epilogues[I+1]);
- //Add unconditional branch to end of epilogue
- TerminatorInst *newBranch = new BranchInst(llvm_epilogues[I+1],
- llvm_epilogues[I]);
-
- }
- else {
- BuildMI(epilogues[I], V9::BA, 1).addPCDisp(origBranchExit);
-
-
- //Update last epilogue exit branch
- BranchInst *branchVal = (BranchInst*) dyn_cast<BranchInst>(BB->getBasicBlock()->getTerminator());
- //Find where we are supposed to branch to
- BasicBlock *nextBlock = 0;
- for(unsigned j=0; j <branchVal->getNumSuccessors(); ++j) {
- if(branchVal->getSuccessor(j) != BB->getBasicBlock())
- nextBlock = branchVal->getSuccessor(j);
- }
-
- assert((nextBlock != 0) && "Next block should not be null!");
- TerminatorInst *newBranch = new BranchInst(nextBlock, llvm_epilogues[I]);
- }
- //Add one more nop!
- BuildMI(epilogues[I], V9::NOP, 0);
-
- }
- }
-
- //FIX UP Machine BB entry!!
- //We are looking at the predecesor of our loop basic block and we want to change its ba instruction
-
-
- //Find all llvm basic blocks that branch to the loop entry and change to our first prologue.
- const BasicBlock *llvmBB = BB->getBasicBlock();
-
- std::vector<const BasicBlock*>Preds (pred_begin(llvmBB), pred_end(llvmBB));
-
- //for(pred_const_iterator P = pred_begin(llvmBB), PE = pred_end(llvmBB); P != PE; ++PE) {
- for(std::vector<const BasicBlock*>::iterator P = Preds.begin(), PE = Preds.end(); P != PE; ++P) {
- if(*P == llvmBB)
- continue;
- else {
- DEBUG(std::cerr << "Found our entry BB\n");
- //Get the Terminator instruction for this basic block and print it out
- DEBUG(std::cerr << *((*P)->getTerminator()) << "\n");
- //Update the terminator
- TerminatorInst *term = ((BasicBlock*)*P)->getTerminator();
- for(unsigned i=0; i < term->getNumSuccessors(); ++i) {
- if(term->getSuccessor(i) == llvmBB) {
- DEBUG(std::cerr << "Replacing successor bb\n");
- if(llvm_prologues.size() > 0) {
- term->setSuccessor(i, llvm_prologues[0]);
- //Also update its corresponding machine instruction
- MachineCodeForInstruction & tempMvec =
- MachineCodeForInstruction::get(term);
- for (unsigned j = 0; j < tempMvec.size(); j++) {
- MachineInstr *temp = tempMvec[j];
- MachineOpCode opc = temp->getOpcode();
- if(TMI->isBranch(opc)) {
- DEBUG(std::cerr << *temp << "\n");
- //Update branch
- for(unsigned opNum = 0; opNum < temp->getNumOperands(); ++opNum) {
- MachineOperand &mOp = temp->getOperand(opNum);
- if (mOp.getType() == MachineOperand::MO_PCRelativeDisp) {
- if(mOp.getVRegValue() == llvmBB)
- mOp.setValueReg(llvm_prologues[0]);
- }
- }
- }
- }
- }
- else {
- term->setSuccessor(i, llvmKernelBB);
- //Also update its corresponding machine instruction
- MachineCodeForInstruction & tempMvec =
- MachineCodeForInstruction::get(term);
- for (unsigned j = 0; j < tempMvec.size(); j++) {
- MachineInstr *temp = tempMvec[j];
- MachineOpCode opc = temp->getOpcode();
- if(TMI->isBranch(opc)) {
- DEBUG(std::cerr << *temp << "\n");
- //Update branch
- for(unsigned opNum = 0; opNum < temp->getNumOperands(); ++opNum) {
- MachineOperand &mOp = temp->getOperand(opNum);
- if (mOp.getType() == MachineOperand::MO_PCRelativeDisp) {
- if(mOp.getVRegValue() == llvmBB)
- mOp.setValueReg(llvmKernelBB);
- }
- }
- }
- }
- }
- }
- }
- break;
- }
- }
-
-
- //BB->getParent()->getBasicBlockList().erase(BB);
-
-}
-
+++ /dev/null
-//===-- 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
+++ /dev/null
-//===-- ModuloSchedulingSuperBlock.cpp - ModuloScheduling--------*- 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 ModuloScheduling pass is based on the Swing Modulo Scheduling
-// algorithm, but has been extended to support SuperBlocks (multiple
-// basic block, single entry, multipl exit loops).
-//
-//===----------------------------------------------------------------------===//
-
-#define DEBUG_TYPE "ModuloSchedSB"
-
-#include "DependenceAnalyzer.h"
-#include "ModuloSchedulingSuperBlock.h"
-#include "llvm/Constants.h"
-#include "llvm/ADT/Statistic.h"
-#include "llvm/CodeGen/MachineFunction.h"
-#include "llvm/CodeGen/Passes.h"
-#include "llvm/Support/CFG.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/GraphWriter.h"
-#include "llvm/Support/Timer.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/ADT/SCCIterator.h"
-#include "llvm/Instructions.h"
-#include "../MachineCodeForInstruction.h"
-#include "../SparcV9RegisterInfo.h"
-#include "../SparcV9Internals.h"
-#include "../SparcV9TmpInstr.h"
-#include <fstream>
-#include <sstream>
-#include <cmath>
-#include <utility>
-
-using namespace llvm;
-/// Create ModuloSchedulingSBPass
-///
-FunctionPass *llvm::createModuloSchedulingSBPass(TargetMachine & targ) {
- DEBUG(std::cerr << "Created ModuloSchedulingSBPass\n");
- return new ModuloSchedulingSBPass(targ);
-}
-
-
-#if 1
-#define TIME_REGION(VARNAME, DESC) \
- NamedRegionTimer VARNAME(DESC)
-#else
-#define TIME_REGION(VARNAME, DESC)
-#endif
-
-
-//Graph Traits for printing out the dependence graph
-template<typename GraphType>
-static void WriteGraphToFileSB(std::ostream &O, const std::string &GraphName,
- const GraphType >) {
- std::string Filename = GraphName + ".dot";
- O << "Writing '" << Filename << "'...";
- std::ofstream F(Filename.c_str());
-
- if (F.good())
- WriteGraph(F, GT);
- else
- O << " error opening file for writing!";
- O << "\n";
-};
-
-namespace llvm {
- Statistic<> NumLoops("moduloschedSB-numLoops", "Total Number of Loops");
- Statistic<> NumSB("moduloschedSB-numSuperBlocks", "Total Number of SuperBlocks");
- Statistic<> BBWithCalls("modulosched-BBCalls", "Basic Blocks rejected due to calls");
- Statistic<> BBWithCondMov("modulosched-loopCondMov",
- "Basic Blocks rejected due to conditional moves");
- Statistic<> SBResourceConstraint("modulosched-resourceConstraint",
- "Loops constrained by resources");
- Statistic<> SBRecurrenceConstraint("modulosched-recurrenceConstraint",
- "Loops constrained by recurrences");
- Statistic<> SBFinalIISum("modulosched-finalIISum", "Sum of all final II");
- Statistic<> SBIISum("modulosched-IISum", "Sum of all theoretical II");
- Statistic<> SBMSLoops("modulosched-schedLoops", "Number of loops successfully modulo-scheduled");
- Statistic<> SBNoSched("modulosched-noSched", "No schedule");
- Statistic<> SBSameStage("modulosched-sameStage", "Max stage is 0");
- Statistic<> SBBLoops("modulosched-SBBLoops", "Number single basic block loops");
- Statistic<> SBInvalid("modulosched-SBInvalid", "Number invalid superblock loops");
- Statistic<> SBValid("modulosched-SBValid", "Number valid superblock loops");
- Statistic<> SBSize("modulosched-SBSize", "Total size of all valid superblocks");
-
- template<>
- struct DOTGraphTraits<MSchedGraphSB*> : public DefaultDOTGraphTraits {
- static std::string getGraphName(MSchedGraphSB *F) {
- return "Dependence Graph";
- }
-
- static std::string getNodeLabel(MSchedGraphSBNode *Node, MSchedGraphSB *Graph) {
- if(!Node->isPredicate()) {
- if (Node->getInst()) {
- std::stringstream ss;
- ss << *(Node->getInst());
- return ss.str(); //((MachineInstr*)Node->getInst());
- }
- else
- return "No Inst";
- }
- else
- return "Pred Node";
- }
- static std::string getEdgeSourceLabel(MSchedGraphSBNode *Node,
- MSchedGraphSBNode::succ_iterator I) {
- //Label each edge with the type of dependence
- std::string edgelabel = "";
- switch (I.getEdge().getDepOrderType()) {
-
- case MSchedGraphSBEdge::TrueDep:
- edgelabel = "True";
- break;
-
- case MSchedGraphSBEdge::AntiDep:
- edgelabel = "Anti";
- break;
-
- case MSchedGraphSBEdge::OutputDep:
- edgelabel = "Output";
- break;
-
- case MSchedGraphSBEdge::NonDataDep:
- edgelabel = "Pred";
- break;
-
- default:
- edgelabel = "Unknown";
- break;
- }
-
- //FIXME
- int iteDiff = I.getEdge().getIteDiff();
- std::string intStr = "(IteDiff: ";
- intStr += itostr(iteDiff);
-
- intStr += ")";
- edgelabel += intStr;
-
- return edgelabel;
- }
- };
-
- bool ModuloSchedulingSBPass::runOnFunction(Function &F) {
- bool Changed = false;
-
- //Get MachineFunction
- MachineFunction &MF = MachineFunction::get(&F);
-
- //Get Loop Info & Dependence Anaysis info
- LoopInfo &LI = getAnalysis<LoopInfo>();
- DependenceAnalyzer &DA = getAnalysis<DependenceAnalyzer>();
-
- //Worklist of superblocks
- std::vector<std::vector<const MachineBasicBlock*> > Worklist;
- FindSuperBlocks(F, LI, Worklist);
-
- DEBUG(if(Worklist.size() == 0) std::cerr << "No superblocks in function to ModuloSchedule\n");
-
- //Loop over worklist and ModuloSchedule each SuperBlock
- for(std::vector<std::vector<const MachineBasicBlock*> >::iterator SB = Worklist.begin(),
- SBE = Worklist.end(); SB != SBE; ++SB) {
-
- //Print out Superblock
- DEBUG(std::cerr << "ModuloScheduling SB: \n";
- for(std::vector<const MachineBasicBlock*>::const_iterator BI = SB->begin(),
- BE = SB->end(); BI != BE; ++BI) {
- (*BI)->print(std::cerr);});
-
- if(!CreateDefMap(*SB)) {
- defaultInst = 0;
- defMap.clear();
- continue;
- }
-
- MSchedGraphSB *MSG = new MSchedGraphSB(*SB, target, indVarInstrs[*SB], DA,
- machineTollvm[*SB]);
-
- //Write Graph out to file
- DEBUG(WriteGraphToFileSB(std::cerr, F.getName(), MSG));
-
- //Calculate Resource II
- int ResMII = calculateResMII(*SB);
-
- //Calculate Recurrence II
- int RecMII = calculateRecMII(MSG, ResMII);
-
- DEBUG(std::cerr << "Number of reccurrences found: " << recurrenceList.size() << "\n");
-
- //Our starting initiation interval is the maximum of RecMII and ResMII
- if(RecMII < ResMII)
- ++SBRecurrenceConstraint;
- else
- ++SBResourceConstraint;
-
- II = std::max(RecMII, ResMII);
- int mII = II;
-
-
- //Print out II, RecMII, and ResMII
- DEBUG(std::cerr << "II starts out as " << II << " ( RecMII=" << RecMII << " and ResMII=" << ResMII << ")\n");
-
- //Calculate Node Properties
- calculateNodeAttributes(MSG, ResMII);
-
- //Dump node properties if in debug mode
- DEBUG(for(std::map<MSchedGraphSBNode*, MSNodeSBAttributes>::iterator I = nodeToAttributesMap.begin(),
- E = nodeToAttributesMap.end(); I !=E; ++I) {
- std::cerr << "Node: " << *(I->first) << " ASAP: " << I->second.ASAP << " ALAP: "
- << I->second.ALAP << " MOB: " << I->second.MOB << " Depth: " << I->second.depth
- << " Height: " << I->second.height << "\n";
- });
-
-
- //Put nodes in order to schedule them
- computePartialOrder();
-
- //Dump out partial order
- DEBUG(for(std::vector<std::set<MSchedGraphSBNode*> >::iterator I = partialOrder.begin(),
- E = partialOrder.end(); I !=E; ++I) {
- std::cerr << "Start set in PO\n";
- for(std::set<MSchedGraphSBNode*>::iterator J = I->begin(), JE = I->end(); J != JE; ++J)
- std::cerr << "PO:" << **J << "\n";
- });
-
- //Place nodes in final order
- orderNodes();
-
- //Dump out order of nodes
- DEBUG(for(std::vector<MSchedGraphSBNode*>::iterator I = FinalNodeOrder.begin(), E = FinalNodeOrder.end(); I != E; ++I) {
- std::cerr << "FO:" << **I << "\n";
- });
-
-
- //Finally schedule nodes
- bool haveSched = computeSchedule(*SB, MSG);
-
- //Print out final schedule
- DEBUG(schedule.print(std::cerr));
-
- //Final scheduling step is to reconstruct the loop only if we actual have
- //stage > 0
- if(haveSched) {
- //schedule.printSchedule(std::cerr);
- reconstructLoop(*SB);
- ++SBMSLoops;
- //Changed = true;
- SBIISum += mII;
- SBFinalIISum += II;
-
- if(schedule.getMaxStage() == 0)
- ++SBSameStage;
- }
- else
- ++SBNoSched;
-
- //Clear out our maps for the next basic block that is processed
- nodeToAttributesMap.clear();
- partialOrder.clear();
- recurrenceList.clear();
- FinalNodeOrder.clear();
- schedule.clear();
- defMap.clear();
-
- }
- return Changed;
- }
-
- void ModuloSchedulingSBPass::FindSuperBlocks(Function &F, LoopInfo &LI,
- std::vector<std::vector<const MachineBasicBlock*> > &Worklist) {
-
- //Get MachineFunction
- MachineFunction &MF = MachineFunction::get(&F);
-
- //Map of LLVM BB to machine BB
- std::map<BasicBlock*, MachineBasicBlock*> bbMap;
-
- for (MachineFunction::iterator BI = MF.begin(); BI != MF.end(); ++BI) {
- BasicBlock *llvmBB = (BasicBlock*) BI->getBasicBlock();
- assert(!bbMap.count(llvmBB) && "LLVM BB already in map!");
- bbMap[llvmBB] = &*BI;
- }
-
- //Iterate over the loops, and find super blocks
- for(LoopInfo::iterator LB = LI.begin(), LE = LI.end(); LB != LE; ++LB) {
- Loop *L = *LB;
- ++NumLoops;
-
- //If loop is not single entry, try the next one
- if(!L->getLoopPreheader())
- continue;
-
- //Check size of this loop, we don't want SBB loops
- if(L->getBlocks().size() == 1)
- continue;
-
- //Check if this loop contains no sub loops
- if(L->getSubLoops().size() == 0) {
-
- std::vector<const MachineBasicBlock*> superBlock;
-
- //Get Loop Headers
- BasicBlock *header = L->getHeader();
-
- //Follow the header and make sure each BB only has one entry and is valid
- BasicBlock *current = header;
- assert(bbMap.count(current) && "LLVM BB must have corresponding Machine BB\n");
- MachineBasicBlock *currentMBB = bbMap[header];
- bool done = false;
- bool success = true;
- unsigned offset = 0;
- std::map<const MachineInstr*, unsigned> indexMap;
-
- while(!done) {
- //Loop over successors of this BB, they should be in the
- //loop block and be valid
- BasicBlock *next = 0;
- for(succ_iterator I = succ_begin(current), E = succ_end(current);
- I != E; ++I) {
- if(L->contains(*I)) {
- if(!next)
- next = *I;
- else {
- done = true;
- success = false;
- break;
- }
- }
- }
-
- if(success) {
- superBlock.push_back(currentMBB);
- if(next == header)
- done = true;
- else if(!next->getSinglePredecessor()) {
- done = true;
- success = false;
- }
- else {
- //Check that the next BB only has one entry
- current = next;
- assert(bbMap.count(current) && "LLVM BB must have corresponding Machine BB");
- currentMBB = bbMap[current];
- }
- }
- }
-
-
-
-
-
- if(success) {
- ++NumSB;
-
- //Loop over all the blocks in the superblock
- for(std::vector<const MachineBasicBlock*>::iterator currentMBB = superBlock.begin(), MBBEnd = superBlock.end(); currentMBB != MBBEnd; ++currentMBB) {
- if(!MachineBBisValid(*currentMBB, indexMap, offset)) {
- success = false;
- break;
- }
- }
- }
-
- if(success) {
- if(getIndVar(superBlock, bbMap, indexMap)) {
- ++SBValid;
- Worklist.push_back(superBlock);
- SBSize += superBlock.size();
- }
- else
- ++SBInvalid;
- }
- }
- }
- }
-
-
- bool ModuloSchedulingSBPass::getIndVar(std::vector<const MachineBasicBlock*> &superBlock, std::map<BasicBlock*, MachineBasicBlock*> &bbMap,
- std::map<const MachineInstr*, unsigned> &indexMap) {
- //See if we can get induction var instructions
- std::set<const BasicBlock*> llvmSuperBlock;
-
- for(unsigned i =0; i < superBlock.size(); ++i)
- llvmSuperBlock.insert(superBlock[i]->getBasicBlock());
-
- //Get Target machine instruction info
- const TargetInstrInfo *TMI = target.getInstrInfo();
-
- //Get the loop back branch
- BranchInst *b = dyn_cast<BranchInst>(((BasicBlock*) (superBlock[superBlock.size()-1])->getBasicBlock())->getTerminator());
- std::set<Instruction*> indVar;
-
- if(b->isConditional()) {
- //Get the condition for the branch
- Value *cond = b->getCondition();
-
- DEBUG(std::cerr << "Condition: " << *cond << "\n");
-
- //List of instructions associated with induction variable
- std::vector<Instruction*> stack;
-
- //Add branch
- indVar.insert(b);
-
- if(Instruction *I = dyn_cast<Instruction>(cond))
- if(bbMap.count(I->getParent())) {
- if (!assocIndVar(I, indVar, stack, bbMap, superBlock[(superBlock.size()-1)]->getBasicBlock(), llvmSuperBlock))
- return false;
- }
- else
- return false;
- else
- return false;
- }
- else {
- indVar.insert(b);
- }
-
- //Dump out instructions associate with indvar for debug reasons
- DEBUG(for(std::set<Instruction*>::iterator N = indVar.begin(), NE = indVar.end();
- N != NE; ++N) {
- std::cerr << **N << "\n";
- });
-
- //Create map of machine instr to llvm instr
- std::map<MachineInstr*, Instruction*> mllvm;
- for(std::vector<const MachineBasicBlock*>::iterator MBB = superBlock.begin(), MBE = superBlock.end(); MBB != MBE; ++MBB) {
- BasicBlock *BB = (BasicBlock*) (*MBB)->getBasicBlock();
- for(BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I) {
- MachineCodeForInstruction & tempMvec = MachineCodeForInstruction::get(I);
- for (unsigned j = 0; j < tempMvec.size(); j++) {
- mllvm[tempMvec[j]] = I;
- }
- }
- }
-
- //Convert list of LLVM Instructions to list of Machine instructions
- std::map<const MachineInstr*, unsigned> mIndVar;
- for(std::set<Instruction*>::iterator N = indVar.begin(),
- NE = indVar.end(); N != NE; ++N) {
-
- //If we have a load, we can't handle this loop because
- //there is no way to preserve dependences between loads
- //and stores
- if(isa<LoadInst>(*N))
- return false;
-
- MachineCodeForInstruction & tempMvec = MachineCodeForInstruction::get(*N);
- for (unsigned j = 0; j < tempMvec.size(); j++) {
- MachineOpCode OC = (tempMvec[j])->getOpcode();
- if(TMI->isNop(OC))
- continue;
- if(!indexMap.count(tempMvec[j]))
- continue;
- mIndVar[(MachineInstr*) tempMvec[j]] = indexMap[(MachineInstr*) tempMvec[j]];
- DEBUG(std::cerr << *(tempMvec[j]) << " at index " << indexMap[(MachineInstr*) tempMvec[j]] << "\n");
- }
- }
-
- //Put into a map for future access
- indVarInstrs[superBlock] = mIndVar;
- machineTollvm[superBlock] = mllvm;
-
- return true;
-
- }
-
- bool ModuloSchedulingSBPass::assocIndVar(Instruction *I,
- std::set<Instruction*> &indVar,
- std::vector<Instruction*> &stack,
- std::map<BasicBlock*, MachineBasicBlock*> &bbMap,
- const BasicBlock *last, std::set<const BasicBlock*> &llvmSuperBlock) {
-
- stack.push_back(I);
-
- //If this is a phi node, check if its the canonical indvar
- if(PHINode *PN = dyn_cast<PHINode>(I)) {
- if(llvmSuperBlock.count(PN->getParent())) {
- if (Instruction *Inc =
- dyn_cast<Instruction>(PN->getIncomingValueForBlock(last)))
- if (Inc->getOpcode() == Instruction::Add && Inc->getOperand(0) == PN)
- if (ConstantInt *CI = dyn_cast<ConstantInt>(Inc->getOperand(1)))
- if (CI->equalsInt(1)) {
- //We have found the indvar, so add the stack, and inc instruction to the set
- indVar.insert(stack.begin(), stack.end());
- indVar.insert(Inc);
- stack.pop_back();
- return true;
- }
- return false;
- }
- }
- else {
- //Loop over each of the instructions operands, check if they are an instruction and in this BB
- for(unsigned i = 0; i < I->getNumOperands(); ++i) {
- if(Instruction *N = dyn_cast<Instruction>(I->getOperand(i))) {
- if(bbMap.count(N->getParent()))
- if(!assocIndVar(N, indVar, stack, bbMap, last, llvmSuperBlock))
- return false;
- }
- }
- }
-
- stack.pop_back();
- return true;
- }
-
-
- /// This function checks if a Machine Basic Block is valid for modulo
- /// scheduling. This means that it has no control flow (if/else or
- /// calls) in the block. Currently ModuloScheduling only works on
- /// single basic block loops.
- bool ModuloSchedulingSBPass::MachineBBisValid(const MachineBasicBlock *BI,
- std::map<const MachineInstr*, unsigned> &indexMap,
- unsigned &offset) {
-
- //Check size of our basic block.. make sure we have more then just the terminator in it
- if(BI->getBasicBlock()->size() == 1)
- return false;
-
- //Get Target machine instruction info
- const TargetInstrInfo *TMI = target.getInstrInfo();
-
- unsigned count = 0;
- for(MachineBasicBlock::const_iterator I = BI->begin(), E = BI->end(); I != E; ++I) {
- //Get opcode to check instruction type
- MachineOpCode OC = I->getOpcode();
-
- //Look for calls
- if(TMI->isCall(OC)) {
- ++BBWithCalls;
- return false;
- }
-
- //Look for conditional move
- if(OC == V9::MOVRZr || OC == V9::MOVRZi || OC == V9::MOVRLEZr || OC == V9::MOVRLEZi
- || OC == V9::MOVRLZr || OC == V9::MOVRLZi || OC == V9::MOVRNZr || OC == V9::MOVRNZi
- || OC == V9::MOVRGZr || OC == V9::MOVRGZi || OC == V9::MOVRGEZr
- || OC == V9::MOVRGEZi || OC == V9::MOVLEr || OC == V9::MOVLEi || OC == V9::MOVLEUr
- || OC == V9::MOVLEUi || OC == V9::MOVFLEr || OC == V9::MOVFLEi
- || OC == V9::MOVNEr || OC == V9::MOVNEi || OC == V9::MOVNEGr || OC == V9::MOVNEGi
- || OC == V9::MOVFNEr || OC == V9::MOVFNEi) {
- ++BBWithCondMov;
- return false;
- }
-
- indexMap[I] = count + offset;
-
- if(TMI->isNop(OC))
- continue;
-
- ++count;
- }
-
- offset += count;
-
- return true;
- }
-}
-
-bool ModuloSchedulingSBPass::CreateDefMap(std::vector<const MachineBasicBlock*> &SB) {
- defaultInst = 0;
-
- for(std::vector<const MachineBasicBlock*>::iterator BI = SB.begin(),
- BE = SB.end(); BI != BE; ++BI) {
-
- for(MachineBasicBlock::const_iterator I = (*BI)->begin(), E = (*BI)->end(); I != E; ++I) {
- for(unsigned opNum = 0; opNum < I->getNumOperands(); ++opNum) {
- const MachineOperand &mOp = I->getOperand(opNum);
- if(mOp.getType() == MachineOperand::MO_VirtualRegister && mOp.isDef()) {
- Value *V = mOp.getVRegValue();
- //assert if this is the second def we have seen
- if(defMap.count(V) && isa<PHINode>(V))
- DEBUG(std::cerr << "FIXME: Dup def for phi!\n");
- else {
- //assert(!defMap.count(V) && "Def already in the map");
- if(defMap.count(V))
- return false;
- defMap[V] = (MachineInstr*) &*I;
- }
- }
-
- //See if we can use this Value* as our defaultInst
- if(!defaultInst && mOp.getType() == MachineOperand::MO_VirtualRegister) {
- Value *V = mOp.getVRegValue();
- if(!isa<TmpInstruction>(V) && !isa<Argument>(V) && !isa<Constant>(V) && !isa<PHINode>(V))
- defaultInst = (Instruction*) V;
- }
- }
- }
- }
-
- if(!defaultInst)
- return false;
-
- return true;
-
-}
-
-
-//ResMII is calculated by determining the usage count for each resource
-//and using the maximum.
-//FIXME: In future there should be a way to get alternative resources
-//for each instruction
-int ModuloSchedulingSBPass::calculateResMII(std::vector<const MachineBasicBlock*> &superBlock) {
-
- TIME_REGION(X, "calculateResMII");
-
- const TargetInstrInfo *mii = target.getInstrInfo();
- const TargetSchedInfo *msi = target.getSchedInfo();
-
- int ResMII = 0;
-
- //Map to keep track of usage count of each resource
- std::map<unsigned, unsigned> resourceUsageCount;
-
- for(std::vector<const MachineBasicBlock*>::iterator BI = superBlock.begin(), BE = superBlock.end(); BI != BE; ++BI) {
- for(MachineBasicBlock::const_iterator I = (*BI)->begin(), E = (*BI)->end(); I != E; ++I) {
-
- //Get resource usage for this instruction
- InstrRUsage rUsage = msi->getInstrRUsage(I->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) {
- if(!resourceUsageCount.count(resources[i][j])) {
- resourceUsageCount[resources[i][j]] = 1;
- }
- else {
- resourceUsageCount[resources[i][j]] = resourceUsageCount[resources[i][j]] + 1;
- }
- }
- }
- }
-
- //Find maximum usage count
-
- //Get max number of instructions that can be issued at once. (FIXME)
- int issueSlots = msi->maxNumIssueTotal;
-
- for(std::map<unsigned,unsigned>::iterator RB = resourceUsageCount.begin(), RE = resourceUsageCount.end(); RB != RE; ++RB) {
-
- //Get the total number of the resources in our cpu
- int resourceNum = CPUResource::getCPUResource(RB->first)->maxNumUsers;
-
- //Get total usage count for this resources
- unsigned usageCount = RB->second;
-
- //Divide the usage count by either the max number we can issue or the number of
- //resources (whichever is its upper bound)
- double finalUsageCount;
- DEBUG(std::cerr << "Resource Num: " << RB->first << " Usage: " << usageCount << " TotalNum: " << resourceNum << "\n");
-
- if( resourceNum <= issueSlots)
- finalUsageCount = ceil(1.0 * usageCount / resourceNum);
- else
- finalUsageCount = ceil(1.0 * usageCount / issueSlots);
-
-
- //Only keep track of the max
- ResMII = std::max( (int) finalUsageCount, ResMII);
-
- }
-
- return ResMII;
-
-}
-
-/// calculateRecMII - Calculates the value of the highest recurrence
-/// By value we mean the total latency/distance
-int ModuloSchedulingSBPass::calculateRecMII(MSchedGraphSB *graph, int MII) {
-
- TIME_REGION(X, "calculateRecMII");
-
- findAllCircuits(graph, MII);
- int RecMII = 0;
-
- for(std::set<std::pair<int, std::vector<MSchedGraphSBNode*> > >::iterator I = recurrenceList.begin(), E=recurrenceList.end(); I !=E; ++I) {
- RecMII = std::max(RecMII, I->first);
- }
-
- return MII;
-}
-
-int CircCountSB;
-
-void ModuloSchedulingSBPass::unblock(MSchedGraphSBNode *u, std::set<MSchedGraphSBNode*> &blocked,
- std::map<MSchedGraphSBNode*, std::set<MSchedGraphSBNode*> > &B) {
-
- //Unblock u
- DEBUG(std::cerr << "Unblocking: " << *u << "\n");
- blocked.erase(u);
-
- //std::set<MSchedGraphSBNode*> toErase;
- while (!B[u].empty()) {
- MSchedGraphSBNode *W = *B[u].begin();
- B[u].erase(W);
- //toErase.insert(*W);
- DEBUG(std::cerr << "Removed: " << *W << "from B-List\n");
- if(blocked.count(W))
- unblock(W, blocked, B);
- }
-
-}
-
-void ModuloSchedulingSBPass::addSCC(std::vector<MSchedGraphSBNode*> &SCC, std::map<MSchedGraphSBNode*, MSchedGraphSBNode*> &newNodes) {
-
- int totalDelay = 0;
- int totalDistance = 0;
- std::vector<MSchedGraphSBNode*> recc;
- MSchedGraphSBNode *start = 0;
- MSchedGraphSBNode *end = 0;
-
- //Loop over recurrence, get delay and distance
- for(std::vector<MSchedGraphSBNode*>::iterator N = SCC.begin(), NE = SCC.end(); N != NE; ++N) {
- DEBUG(std::cerr << **N << "\n");
- totalDelay += (*N)->getLatency();
-
- for(unsigned i = 0; i < (*N)->succ_size(); ++i) {
- MSchedGraphSBEdge *edge = (*N)->getSuccessor(i);
- if(find(SCC.begin(), SCC.end(), edge->getDest()) != SCC.end()) {
- totalDistance += edge->getIteDiff();
- if(edge->getIteDiff() > 0)
- if(!start && !end) {
- start = *N;
- end = edge->getDest();
- }
-
- }
- }
-
-
- //Get the original node
- recc.push_back(newNodes[*N]);
-
-
- }
-
- DEBUG(std::cerr << "End Recc\n");
-
-
- assert( (start && end) && "Must have start and end node to ignore edge for SCC");
-
- if(start && end) {
- //Insert reccurrence into the list
- DEBUG(std::cerr << "Ignore Edge from!!: " << *start << " to " << *end << "\n");
- edgesToIgnore.insert(std::make_pair(newNodes[start], (newNodes[end])->getInEdgeNum(newNodes[start])));
- }
-
- int lastII = totalDelay / totalDistance;
-
-
- recurrenceList.insert(std::make_pair(lastII, recc));
-
-}
-
-bool ModuloSchedulingSBPass::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) {
- bool f = false;
-
- DEBUG(std::cerr << "Finding Circuits Starting with: ( " << v << ")"<< *v << "\n");
-
- //Push node onto the stack
- stack.push_back(v);
-
- //block this node
- blocked.insert(v);
-
- //Loop over all successors of node v that are in the scc, create Adjaceny list
- std::set<MSchedGraphSBNode*> AkV;
- for(MSchedGraphSBNode::succ_iterator I = v->succ_begin(), E = v->succ_end(); I != E; ++I) {
- if((std::find(SCC.begin(), SCC.end(), *I) != SCC.end())) {
- AkV.insert(*I);
- }
- }
-
- for(std::set<MSchedGraphSBNode*>::iterator I = AkV.begin(), E = AkV.end(); I != E; ++I) {
- if(*I == s) {
- //We have a circuit, so add it to our list
- addRecc(stack, newNodes);
- f = true;
- }
- else if(!blocked.count(*I)) {
- if(circuit(*I, stack, blocked, SCC, s, B, II, newNodes))
- f = true;
- }
- else
- DEBUG(std::cerr << "Blocked: " << **I << "\n");
- }
-
-
- if(f) {
- unblock(v, blocked, B);
- }
- else {
- for(std::set<MSchedGraphSBNode*>::iterator I = AkV.begin(), E = AkV.end(); I != E; ++I)
- B[*I].insert(v);
-
- }
-
- //Pop v
- stack.pop_back();
-
- return f;
-
-}
-
-void ModuloSchedulingSBPass::addRecc(std::vector<MSchedGraphSBNode*> &stack, std::map<MSchedGraphSBNode*, MSchedGraphSBNode*> &newNodes) {
- std::vector<MSchedGraphSBNode*> recc;
- //Dump recurrence for now
- DEBUG(std::cerr << "Starting Recc\n");
-
- int totalDelay = 0;
- int totalDistance = 0;
- MSchedGraphSBNode *lastN = 0;
- MSchedGraphSBNode *start = 0;
- MSchedGraphSBNode *end = 0;
-
- //Loop over recurrence, get delay and distance
- for(std::vector<MSchedGraphSBNode*>::iterator N = stack.begin(), NE = stack.end(); N != NE; ++N) {
- DEBUG(std::cerr << **N << "\n");
- totalDelay += (*N)->getLatency();
- if(lastN) {
- int iteDiff = (*N)->getInEdge(lastN).getIteDiff();
- totalDistance += iteDiff;
-
- if(iteDiff > 0) {
- start = lastN;
- end = *N;
- }
- }
- //Get the original node
- lastN = *N;
- recc.push_back(newNodes[*N]);
-
-
- }
-
- //Get the loop edge
- totalDistance += lastN->getIteDiff(*stack.begin());
-
- DEBUG(std::cerr << "End Recc\n");
- CircCountSB++;
-
- if(start && end) {
- //Insert reccurrence into the list
- DEBUG(std::cerr << "Ignore Edge from!!: " << *start << " to " << *end << "\n");
- edgesToIgnore.insert(std::make_pair(newNodes[start], (newNodes[end])->getInEdgeNum(newNodes[start])));
- }
- else {
- //Insert reccurrence into the list
- DEBUG(std::cerr << "Ignore Edge from: " << *lastN << " to " << **stack.begin() << "\n");
- edgesToIgnore.insert(std::make_pair(newNodes[lastN], newNodes[(*stack.begin())]->getInEdgeNum(newNodes[lastN])));
-
- }
- //Adjust II until we get close to the inequality delay - II*distance <= 0
- int RecMII = II; //Starting value
- int value = totalDelay-(RecMII * totalDistance);
- int lastII = II;
- while(value < 0) {
-
- lastII = RecMII;
- RecMII--;
- value = totalDelay-(RecMII * totalDistance);
- }
-
- recurrenceList.insert(std::make_pair(lastII, recc));
-
-}
-
-
-void ModuloSchedulingSBPass::findAllCircuits(MSchedGraphSB *g, int II) {
-
- CircCountSB = 0;
-
- //Keep old to new node mapping information
- std::map<MSchedGraphSBNode*, MSchedGraphSBNode*> newNodes;
-
- //copy the graph
- MSchedGraphSB *MSG = new MSchedGraphSB(*g, newNodes);
-
- DEBUG(std::cerr << "Finding All Circuits\n");
-
- //Set of blocked nodes
- std::set<MSchedGraphSBNode*> blocked;
-
- //Stack holding current circuit
- std::vector<MSchedGraphSBNode*> stack;
-
- //Map for B Lists
- std::map<MSchedGraphSBNode*, std::set<MSchedGraphSBNode*> > B;
-
- //current node
- MSchedGraphSBNode *s;
-
-
- //Iterate over the graph until its down to one node or empty
- while(MSG->size() > 1) {
-
- //Write Graph out to file
- //WriteGraphToFile(std::cerr, "Graph" + utostr(MSG->size()), MSG);
-
- DEBUG(std::cerr << "Graph Size: " << MSG->size() << "\n");
- DEBUG(std::cerr << "Finding strong component Vk with least vertex\n");
-
- //Iterate over all the SCCs in the graph
- std::set<MSchedGraphSBNode*> Visited;
- std::vector<MSchedGraphSBNode*> Vk;
- MSchedGraphSBNode* s = 0;
- int numEdges = 0;
-
- //Find scc with the least vertex
- for (MSchedGraphSB::iterator GI = MSG->begin(), E = MSG->end(); GI != E; ++GI)
- if (Visited.insert(GI->second).second) {
- for (scc_iterator<MSchedGraphSBNode*> SCCI = scc_begin(GI->second),
- E = scc_end(GI->second); SCCI != E; ++SCCI) {
- std::vector<MSchedGraphSBNode*> &nextSCC = *SCCI;
-
- if (Visited.insert(nextSCC[0]).second) {
- Visited.insert(nextSCC.begin()+1, nextSCC.end());
-
- if(nextSCC.size() > 1) {
- DEBUG(std::cerr << "SCC size: " << nextSCC.size() << "\n");
-
- for(unsigned i = 0; i < nextSCC.size(); ++i) {
- //Loop over successor and see if in scc, then count edge
- MSchedGraphSBNode *node = nextSCC[i];
- for(MSchedGraphSBNode::succ_iterator S = node->succ_begin(), SE = node->succ_end(); S != SE; ++S) {
- if(find(nextSCC.begin(), nextSCC.end(), *S) != nextSCC.end())
- numEdges++;
- }
- }
- DEBUG(std::cerr << "Num Edges: " << numEdges << "\n");
- }
-
- //Ignore self loops
- if(nextSCC.size() > 1) {
-
- //Get least vertex in Vk
- if(!s) {
- s = nextSCC[0];
- Vk = nextSCC;
- }
-
- for(unsigned i = 0; i < nextSCC.size(); ++i) {
- if(nextSCC[i] < s) {
- s = nextSCC[i];
- Vk = nextSCC;
- }
- }
- }
- }
- }
- }
-
-
-
- //Process SCC
- DEBUG(for(std::vector<MSchedGraphSBNode*>::iterator N = Vk.begin(), NE = Vk.end();
- N != NE; ++N) { std::cerr << *((*N)->getInst()); });
-
- //Iterate over all nodes in this scc
- for(std::vector<MSchedGraphSBNode*>::iterator N = Vk.begin(), NE = Vk.end();
- N != NE; ++N) {
- blocked.erase(*N);
- B[*N].clear();
- }
- if(Vk.size() > 1) {
- if(numEdges < 98)
- circuit(s, stack, blocked, Vk, s, B, II, newNodes);
- else
- addSCC(Vk, newNodes);
-
-
- //Delete nodes from the graph
- //Find all nodes up to s and delete them
- std::vector<MSchedGraphSBNode*> nodesToRemove;
- nodesToRemove.push_back(s);
- for(MSchedGraphSB::iterator N = MSG->begin(), NE = MSG->end(); N != NE; ++N) {
- if(N->second < s )
- nodesToRemove.push_back(N->second);
- }
- for(std::vector<MSchedGraphSBNode*>::iterator N = nodesToRemove.begin(), NE = nodesToRemove.end(); N != NE; ++N) {
- DEBUG(std::cerr << "Deleting Node: " << **N << "\n");
- MSG->deleteNode(*N);
- }
- }
- else
- break;
- }
- DEBUG(std::cerr << "Num Circuits found: " << CircCountSB << "\n");
-}
-/// calculateNodeAttributes - The following properties are calculated for
-/// each node in the dependence graph: ASAP, ALAP, Depth, Height, and
-/// MOB.
-void ModuloSchedulingSBPass::calculateNodeAttributes(MSchedGraphSB *graph, int MII) {
-
- TIME_REGION(X, "calculateNodeAttributes");
-
- assert(nodeToAttributesMap.empty() && "Node attribute map was not cleared");
-
- //Loop over the nodes and add them to the map
- for(MSchedGraphSB::iterator I = graph->begin(), E = graph->end(); I != E; ++I) {
-
- DEBUG(std::cerr << "Inserting node into attribute map: " << *I->second << "\n");
-
- //Assert if its already in the map
- assert(nodeToAttributesMap.count(I->second) == 0 &&
- "Node attributes are already in the map");
-
- //Put into the map with default attribute values
- nodeToAttributesMap[I->second] = MSNodeSBAttributes();
- }
-
- //Create set to deal with reccurrences
- std::set<MSchedGraphSBNode*> visitedNodes;
-
- //Now Loop over map and calculate the node attributes
- for(std::map<MSchedGraphSBNode*, MSNodeSBAttributes>::iterator I = nodeToAttributesMap.begin(), E = nodeToAttributesMap.end(); I != E; ++I) {
- calculateASAP(I->first, MII, (MSchedGraphSBNode*) 0);
- visitedNodes.clear();
- }
-
- int maxASAP = findMaxASAP();
- //Calculate ALAP which depends on ASAP being totally calculated
- for(std::map<MSchedGraphSBNode*, MSNodeSBAttributes>::iterator I = nodeToAttributesMap.begin(), E = nodeToAttributesMap.end(); I != E; ++I) {
- calculateALAP(I->first, MII, maxASAP, (MSchedGraphSBNode*) 0);
- visitedNodes.clear();
- }
-
- //Calculate MOB which depends on ASAP being totally calculated, also do depth and height
- for(std::map<MSchedGraphSBNode*, MSNodeSBAttributes>::iterator I = nodeToAttributesMap.begin(), E = nodeToAttributesMap.end(); I != E; ++I) {
- (I->second).MOB = std::max(0,(I->second).ALAP - (I->second).ASAP);
-
- DEBUG(std::cerr << "MOB: " << (I->second).MOB << " (" << *(I->first) << ")\n");
- calculateDepth(I->first, (MSchedGraphSBNode*) 0);
- calculateHeight(I->first, (MSchedGraphSBNode*) 0);
- }
-
-
-}
-
-/// ignoreEdge - Checks to see if this edge of a recurrence should be ignored or not
-bool ModuloSchedulingSBPass::ignoreEdge(MSchedGraphSBNode *srcNode, MSchedGraphSBNode *destNode) {
- if(destNode == 0 || srcNode ==0)
- return false;
-
- bool findEdge = edgesToIgnore.count(std::make_pair(srcNode, destNode->getInEdgeNum(srcNode)));
-
- DEBUG(std::cerr << "Ignoring edge? from: " << *srcNode << " to " << *destNode << "\n");
-
- return findEdge;
-}
-
-
-/// calculateASAP - Calculates the
-int ModuloSchedulingSBPass::calculateASAP(MSchedGraphSBNode *node, int MII, MSchedGraphSBNode *destNode) {
-
- DEBUG(std::cerr << "Calculating ASAP for " << *node << "\n");
-
- //Get current node attributes
- MSNodeSBAttributes &attributes = nodeToAttributesMap.find(node)->second;
-
- if(attributes.ASAP != -1)
- return attributes.ASAP;
-
- int maxPredValue = 0;
-
- //Iterate over all of the predecessors and find max
- for(MSchedGraphSBNode::pred_iterator P = node->pred_begin(), E = node->pred_end(); P != E; ++P) {
-
- //Only process if we are not ignoring the edge
- if(!ignoreEdge(*P, node)) {
- int predASAP = -1;
- predASAP = calculateASAP(*P, MII, node);
-
- assert(predASAP != -1 && "ASAP has not been calculated");
- int iteDiff = node->getInEdge(*P).getIteDiff();
-
- int currentPredValue = predASAP + (*P)->getLatency() - (iteDiff * MII);
- DEBUG(std::cerr << "pred ASAP: " << predASAP << ", iteDiff: " << iteDiff << ", PredLatency: " << (*P)->getLatency() << ", Current ASAP pred: " << currentPredValue << "\n");
- maxPredValue = std::max(maxPredValue, currentPredValue);
- }
- }
-
- attributes.ASAP = maxPredValue;
-
- DEBUG(std::cerr << "ASAP: " << attributes.ASAP << " (" << *node << ")\n");
-
- return maxPredValue;
-}
-
-
-int ModuloSchedulingSBPass::calculateALAP(MSchedGraphSBNode *node, int MII,
- int maxASAP, MSchedGraphSBNode *srcNode) {
-
- DEBUG(std::cerr << "Calculating ALAP for " << *node << "\n");
-
- MSNodeSBAttributes &attributes = nodeToAttributesMap.find(node)->second;
-
- if(attributes.ALAP != -1)
- return attributes.ALAP;
-
- if(node->hasSuccessors()) {
-
- //Trying to deal with the issue where the node has successors, but
- //we are ignoring all of the edges to them. So this is my hack for
- //now.. there is probably a more elegant way of doing this (FIXME)
- bool processedOneEdge = false;
-
- //FIXME, set to something high to start
- int minSuccValue = 9999999;
-
- //Iterate over all of the predecessors and fine max
- for(MSchedGraphSBNode::succ_iterator P = node->succ_begin(),
- E = node->succ_end(); P != E; ++P) {
-
- //Only process if we are not ignoring the edge
- if(!ignoreEdge(node, *P)) {
- processedOneEdge = true;
- int succALAP = -1;
- succALAP = calculateALAP(*P, MII, maxASAP, node);
-
- assert(succALAP != -1 && "Successors ALAP should have been caclulated");
-
- int iteDiff = P.getEdge().getIteDiff();
-
- int currentSuccValue = succALAP - node->getLatency() + iteDiff * MII;
-
- DEBUG(std::cerr << "succ ALAP: " << succALAP << ", iteDiff: " << iteDiff << ", SuccLatency: " << (*P)->getLatency() << ", Current ALAP succ: " << currentSuccValue << "\n");
-
- minSuccValue = std::min(minSuccValue, currentSuccValue);
- }
- }
-
- if(processedOneEdge)
- attributes.ALAP = minSuccValue;
-
- else
- attributes.ALAP = maxASAP;
- }
- else
- attributes.ALAP = maxASAP;
-
- DEBUG(std::cerr << "ALAP: " << attributes.ALAP << " (" << *node << ")\n");
-
- if(attributes.ALAP < 0)
- attributes.ALAP = 0;
-
- return attributes.ALAP;
-}
-
-int ModuloSchedulingSBPass::findMaxASAP() {
- int maxASAP = 0;
-
- for(std::map<MSchedGraphSBNode*, MSNodeSBAttributes>::iterator I = nodeToAttributesMap.begin(),
- E = nodeToAttributesMap.end(); I != E; ++I)
- maxASAP = std::max(maxASAP, I->second.ASAP);
- return maxASAP;
-}
-
-
-int ModuloSchedulingSBPass::calculateHeight(MSchedGraphSBNode *node,MSchedGraphSBNode *srcNode) {
-
- MSNodeSBAttributes &attributes = nodeToAttributesMap.find(node)->second;
-
- if(attributes.height != -1)
- return attributes.height;
-
- int maxHeight = 0;
-
- //Iterate over all of the predecessors and find max
- for(MSchedGraphSBNode::succ_iterator P = node->succ_begin(),
- E = node->succ_end(); P != E; ++P) {
-
-
- if(!ignoreEdge(node, *P)) {
- int succHeight = calculateHeight(*P, node);
-
- assert(succHeight != -1 && "Successors Height should have been caclulated");
-
- int currentHeight = succHeight + node->getLatency();
- maxHeight = std::max(maxHeight, currentHeight);
- }
- }
- attributes.height = maxHeight;
- DEBUG(std::cerr << "Height: " << attributes.height << " (" << *node << ")\n");
- return maxHeight;
-}
-
-
-int ModuloSchedulingSBPass::calculateDepth(MSchedGraphSBNode *node,
- MSchedGraphSBNode *destNode) {
-
- MSNodeSBAttributes &attributes = nodeToAttributesMap.find(node)->second;
-
- if(attributes.depth != -1)
- return attributes.depth;
-
- int maxDepth = 0;
-
- //Iterate over all of the predecessors and fine max
- for(MSchedGraphSBNode::pred_iterator P = node->pred_begin(), E = node->pred_end(); P != E; ++P) {
-
- if(!ignoreEdge(*P, node)) {
- int predDepth = -1;
- predDepth = calculateDepth(*P, node);
-
- assert(predDepth != -1 && "Predecessors ASAP should have been caclulated");
-
- int currentDepth = predDepth + (*P)->getLatency();
- maxDepth = std::max(maxDepth, currentDepth);
- }
- }
- attributes.depth = maxDepth;
-
- DEBUG(std::cerr << "Depth: " << attributes.depth << " (" << *node << "*)\n");
- return maxDepth;
-}
-
-void ModuloSchedulingSBPass::computePartialOrder() {
-
- TIME_REGION(X, "calculatePartialOrder");
-
- DEBUG(std::cerr << "Computing Partial Order\n");
-
- //Steps to add a recurrence to the partial order 1) Find reccurrence
- //with the highest RecMII. Add it to the partial order. 2) For each
- //recurrence with decreasing RecMII, add it to the partial order
- //along with any nodes that connect this recurrence to recurrences
- //already in the partial order
- for(std::set<std::pair<int, std::vector<MSchedGraphSBNode*> > >::reverse_iterator
- I = recurrenceList.rbegin(), E=recurrenceList.rend(); I !=E; ++I) {
-
- std::set<MSchedGraphSBNode*> new_recurrence;
-
- //Loop through recurrence and remove any nodes already in the partial order
- for(std::vector<MSchedGraphSBNode*>::const_iterator N = I->second.begin(),
- NE = I->second.end(); N != NE; ++N) {
-
- bool found = false;
- for(std::vector<std::set<MSchedGraphSBNode*> >::iterator PO = partialOrder.begin(),
- PE = partialOrder.end(); PO != PE; ++PO) {
- if(PO->count(*N))
- found = true;
- }
-
- //Check if its a branch, and remove to handle special
- if(!found) {
- new_recurrence.insert(*N);
- }
-
- }
-
-
- if(new_recurrence.size() > 0) {
-
- std::vector<MSchedGraphSBNode*> path;
- std::set<MSchedGraphSBNode*> nodesToAdd;
-
- //Dump recc we are dealing with (minus nodes already in PO)
- DEBUG(std::cerr << "Recc: ");
- DEBUG(for(std::set<MSchedGraphSBNode*>::iterator R = new_recurrence.begin(), RE = new_recurrence.end(); R != RE; ++R) { std::cerr << **R ; });
-
- //Add nodes that connect this recurrence to recurrences in the partial path
- for(std::set<MSchedGraphSBNode*>::iterator N = new_recurrence.begin(),
- NE = new_recurrence.end(); N != NE; ++N)
- searchPath(*N, path, nodesToAdd, new_recurrence);
-
- //Add nodes to this recurrence if they are not already in the partial order
- for(std::set<MSchedGraphSBNode*>::iterator N = nodesToAdd.begin(), NE = nodesToAdd.end();
- N != NE; ++N) {
- bool found = false;
- for(std::vector<std::set<MSchedGraphSBNode*> >::iterator PO = partialOrder.begin(),
- PE = partialOrder.end(); PO != PE; ++PO) {
- if(PO->count(*N))
- found = true;
- }
- if(!found) {
- assert("FOUND CONNECTOR");
- new_recurrence.insert(*N);
- }
- }
-
- partialOrder.push_back(new_recurrence);
- }
- }
-
- //Add any nodes that are not already in the partial order
- //Add them in a set, one set per connected component
- std::set<MSchedGraphSBNode*> lastNodes;
- std::set<MSchedGraphSBNode*> noPredNodes;
- for(std::map<MSchedGraphSBNode*, MSNodeSBAttributes>::iterator I = nodeToAttributesMap.begin(),
- E = nodeToAttributesMap.end(); I != E; ++I) {
-
- bool found = false;
-
- //Check if its already in our partial order, if not add it to the final vector
- for(std::vector<std::set<MSchedGraphSBNode*> >::iterator PO = partialOrder.begin(),
- PE = partialOrder.end(); PO != PE; ++PO) {
- if(PO->count(I->first))
- found = true;
- }
- if(!found)
- lastNodes.insert(I->first);
- }
-
- //For each node w/out preds, see if there is a path to one of the
- //recurrences, and if so add them to that current recc
- /*for(std::set<MSchedGraphSBNode*>::iterator N = noPredNodes.begin(), NE = noPredNodes.end();
- N != NE; ++N) {
- DEBUG(std::cerr << "No Pred Path from: " << **N << "\n");
- for(std::vector<std::set<MSchedGraphSBNode*> >::iterator PO = partialOrder.begin(),
- PE = partialOrder.end(); PO != PE; ++PO) {
- std::vector<MSchedGraphSBNode*> path;
- pathToRecc(*N, path, *PO, lastNodes);
- }
- }*/
-
-
- //Break up remaining nodes that are not in the partial order
- ///into their connected compoenents
- while(lastNodes.size() > 0) {
- std::set<MSchedGraphSBNode*> ccSet;
- connectedComponentSet(*(lastNodes.begin()),ccSet, lastNodes);
- if(ccSet.size() > 0)
- partialOrder.push_back(ccSet);
- }
-
-}
-
-void ModuloSchedulingSBPass::connectedComponentSet(MSchedGraphSBNode *node, std::set<MSchedGraphSBNode*> &ccSet, std::set<MSchedGraphSBNode*> &lastNodes) {
-
- //Add to final set
- if( !ccSet.count(node) && lastNodes.count(node)) {
- lastNodes.erase(node);
- ccSet.insert(node);
- }
- else
- return;
-
- //Loop over successors and recurse if we have not seen this node before
- for(MSchedGraphSBNode::succ_iterator node_succ = node->succ_begin(), end=node->succ_end(); node_succ != end; ++node_succ) {
- connectedComponentSet(*node_succ, ccSet, lastNodes);
- }
-
-}
-
-void ModuloSchedulingSBPass::searchPath(MSchedGraphSBNode *node,
- std::vector<MSchedGraphSBNode*> &path,
- std::set<MSchedGraphSBNode*> &nodesToAdd,
- std::set<MSchedGraphSBNode*> &new_reccurrence) {
- //Push node onto the path
- path.push_back(node);
-
- //Loop over all successors and see if there is a path from this node to
- //a recurrence in the partial order, if so.. add all nodes to be added to recc
- for(MSchedGraphSBNode::succ_iterator S = node->succ_begin(), SE = node->succ_end(); S != SE;
- ++S) {
-
- //Check if we should ignore this edge first
- if(ignoreEdge(node,*S))
- continue;
-
- //check if successor is in this recurrence, we will get to it eventually
- if(new_reccurrence.count(*S))
- continue;
-
- //If this node exists in a recurrence already in the partial
- //order, then add all nodes in the path to the set of nodes to add
- //Check if its already in our partial order, if not add it to the
- //final vector
- bool found = false;
- for(std::vector<std::set<MSchedGraphSBNode*> >::iterator PO = partialOrder.begin(),
- PE = partialOrder.end(); PO != PE; ++PO) {
-
- if(PO->count(*S)) {
- found = true;
- break;
- }
- }
-
- if(!found) {
- nodesToAdd.insert(*S);
- searchPath(*S, path, nodesToAdd, new_reccurrence);
- }
- }
-
- //Pop Node off the path
- path.pop_back();
-}
-
-void dumpIntersection(std::set<MSchedGraphSBNode*> &IntersectCurrent) {
- std::cerr << "Intersection (";
- for(std::set<MSchedGraphSBNode*>::iterator I = IntersectCurrent.begin(), E = IntersectCurrent.end(); I != E; ++I)
- std::cerr << **I << ", ";
- std::cerr << ")\n";
-}
-
-void ModuloSchedulingSBPass::orderNodes() {
-
- TIME_REGION(X, "orderNodes");
-
- int BOTTOM_UP = 0;
- int TOP_DOWN = 1;
-
- //Set default order
- int order = BOTTOM_UP;
-
- //Loop over and find all pred nodes and schedule them first
- /*for(std::vector<std::set<MSchedGraphSBNode*> >::iterator CurrentSet = partialOrder.begin(), E= partialOrder.end(); CurrentSet != E; ++CurrentSet) {
- for(std::set<MSchedGraphSBNode*>::iterator N = CurrentSet->begin(), NE = CurrentSet->end(); N != NE; ++N)
- if((*N)->isPredicate()) {
- FinalNodeOrder.push_back(*N);
- CurrentSet->erase(*N);
- }
- }*/
-
-
-
- //Loop over all the sets and place them in the final node order
- for(std::vector<std::set<MSchedGraphSBNode*> >::iterator CurrentSet = partialOrder.begin(), E= partialOrder.end(); CurrentSet != E; ++CurrentSet) {
-
- DEBUG(std::cerr << "Processing set in S\n");
- DEBUG(dumpIntersection(*CurrentSet));
-
- //Result of intersection
- std::set<MSchedGraphSBNode*> IntersectCurrent;
-
- predIntersect(*CurrentSet, IntersectCurrent);
-
- //If the intersection of predecessor and current set is not empty
- //sort nodes bottom up
- if(IntersectCurrent.size() != 0) {
- DEBUG(std::cerr << "Final Node Order Predecessors and Current Set interesection is NOT empty\n");
- order = BOTTOM_UP;
- }
- //If empty, use successors
- else {
- DEBUG(std::cerr << "Final Node Order Predecessors and Current Set interesection is empty\n");
-
- succIntersect(*CurrentSet, IntersectCurrent);
-
- //sort top-down
- if(IntersectCurrent.size() != 0) {
- DEBUG(std::cerr << "Final Node Order Successors and Current Set interesection is NOT empty\n");
- order = TOP_DOWN;
- }
- else {
- DEBUG(std::cerr << "Final Node Order Successors and Current Set interesection is empty\n");
- //Find node with max ASAP in current Set
- MSchedGraphSBNode *node;
- int maxASAP = 0;
- DEBUG(std::cerr << "Using current set of size " << CurrentSet->size() << "to find max ASAP\n");
- for(std::set<MSchedGraphSBNode*>::iterator J = CurrentSet->begin(), JE = CurrentSet->end(); J != JE; ++J) {
- //Get node attributes
- MSNodeSBAttributes nodeAttr= nodeToAttributesMap.find(*J)->second;
- //assert(nodeAttr != nodeToAttributesMap.end() && "Node not in attributes map!");
-
- if(maxASAP <= nodeAttr.ASAP) {
- maxASAP = nodeAttr.ASAP;
- node = *J;
- }
- }
- assert(node != 0 && "In node ordering node should not be null");
- IntersectCurrent.insert(node);
- order = BOTTOM_UP;
- }
- }
-
- //Repeat until all nodes are put into the final order from current set
- while(IntersectCurrent.size() > 0) {
-
- if(order == TOP_DOWN) {
- DEBUG(std::cerr << "Order is TOP DOWN\n");
-
- while(IntersectCurrent.size() > 0) {
- DEBUG(std::cerr << "Intersection is not empty, so find heighest height\n");
-
- int MOB = 0;
- int height = 0;
- MSchedGraphSBNode *highestHeightNode = *(IntersectCurrent.begin());
-
- //Find node in intersection with highest heigh and lowest MOB
- for(std::set<MSchedGraphSBNode*>::iterator I = IntersectCurrent.begin(),
- E = IntersectCurrent.end(); I != E; ++I) {
-
- //Get current nodes properties
- MSNodeSBAttributes nodeAttr= nodeToAttributesMap.find(*I)->second;
-
- if(height < nodeAttr.height) {
- highestHeightNode = *I;
- height = nodeAttr.height;
- MOB = nodeAttr.MOB;
- }
- else if(height == nodeAttr.height) {
- if(MOB > nodeAttr.height) {
- highestHeightNode = *I;
- height = nodeAttr.height;
- MOB = nodeAttr.MOB;
- }
- }
- }
-
- //Append our node with greatest height to the NodeOrder
- if(std::find(FinalNodeOrder.begin(), FinalNodeOrder.end(), highestHeightNode) == FinalNodeOrder.end()) {
- DEBUG(std::cerr << "Adding node to Final Order: " << *highestHeightNode << "\n");
- FinalNodeOrder.push_back(highestHeightNode);
- }
-
- //Remove V from IntersectOrder
- IntersectCurrent.erase(std::find(IntersectCurrent.begin(),
- IntersectCurrent.end(), highestHeightNode));
-
-
- //Intersect V's successors with CurrentSet
- for(MSchedGraphSBNode::succ_iterator P = highestHeightNode->succ_begin(),
- E = highestHeightNode->succ_end(); P != E; ++P) {
- //if(lower_bound(CurrentSet->begin(),
- // CurrentSet->end(), *P) != CurrentSet->end()) {
- if(std::find(CurrentSet->begin(), CurrentSet->end(), *P) != CurrentSet->end()) {
- if(ignoreEdge(highestHeightNode, *P))
- continue;
- //If not already in Intersect, add
- if(!IntersectCurrent.count(*P))
- IntersectCurrent.insert(*P);
- }
- }
- } //End while loop over Intersect Size
-
- //Change direction
- order = BOTTOM_UP;
-
- //Reset Intersect to reflect changes in OrderNodes
- IntersectCurrent.clear();
- predIntersect(*CurrentSet, IntersectCurrent);
-
- } //End If TOP_DOWN
-
- //Begin if BOTTOM_UP
- else {
- DEBUG(std::cerr << "Order is BOTTOM UP\n");
- while(IntersectCurrent.size() > 0) {
- DEBUG(std::cerr << "Intersection of size " << IntersectCurrent.size() << ", finding highest depth\n");
-
- //dump intersection
- DEBUG(dumpIntersection(IntersectCurrent));
- //Get node with highest depth, if a tie, use one with lowest
- //MOB
- int MOB = 0;
- int depth = 0;
- MSchedGraphSBNode *highestDepthNode = *(IntersectCurrent.begin());
-
- for(std::set<MSchedGraphSBNode*>::iterator I = IntersectCurrent.begin(),
- E = IntersectCurrent.end(); I != E; ++I) {
- //Find node attribute in graph
- MSNodeSBAttributes nodeAttr= nodeToAttributesMap.find(*I)->second;
-
- if(depth < nodeAttr.depth) {
- highestDepthNode = *I;
- depth = nodeAttr.depth;
- MOB = nodeAttr.MOB;
- }
- else if(depth == nodeAttr.depth) {
- if(MOB > nodeAttr.MOB) {
- highestDepthNode = *I;
- depth = nodeAttr.depth;
- MOB = nodeAttr.MOB;
- }
- }
- }
-
-
-
- //Append highest depth node to the NodeOrder
- if(std::find(FinalNodeOrder.begin(), FinalNodeOrder.end(), highestDepthNode) == FinalNodeOrder.end()) {
- DEBUG(std::cerr << "Adding node to Final Order: " << *highestDepthNode << "\n");
- FinalNodeOrder.push_back(highestDepthNode);
- }
- //Remove heightestDepthNode from IntersectOrder
- IntersectCurrent.erase(highestDepthNode);
-
-
- //Intersect heightDepthNode's pred with CurrentSet
- for(MSchedGraphSBNode::pred_iterator P = highestDepthNode->pred_begin(),
- E = highestDepthNode->pred_end(); P != E; ++P) {
- if(CurrentSet->count(*P)) {
- if(ignoreEdge(*P, highestDepthNode))
- continue;
-
- //If not already in Intersect, add
- if(!IntersectCurrent.count(*P))
- IntersectCurrent.insert(*P);
- }
- }
-
- } //End while loop over Intersect Size
-
- //Change order
- order = TOP_DOWN;
-
- //Reset IntersectCurrent to reflect changes in OrderNodes
- IntersectCurrent.clear();
- succIntersect(*CurrentSet, IntersectCurrent);
- } //End if BOTTOM_DOWN
-
- DEBUG(std::cerr << "Current Intersection Size: " << IntersectCurrent.size() << "\n");
- }
- //End Wrapping while loop
- DEBUG(std::cerr << "Ending Size of Current Set: " << CurrentSet->size() << "\n");
- }//End for over all sets of nodes
-
- //FIXME: As the algorithm stands it will NEVER add an instruction such as ba (with no
- //data dependencies) to the final order. We add this manually. It will always be
- //in the last set of S since its not part of a recurrence
- //Loop over all the sets and place them in the final node order
- std::vector<std::set<MSchedGraphSBNode*> > ::reverse_iterator LastSet = partialOrder.rbegin();
- for(std::set<MSchedGraphSBNode*>::iterator CurrentNode = LastSet->begin(), LastNode = LastSet->end();
- CurrentNode != LastNode; ++CurrentNode) {
- if((*CurrentNode)->getInst()->getOpcode() == V9::BA)
- FinalNodeOrder.push_back(*CurrentNode);
- }
- //Return final Order
- //return FinalNodeOrder;
-}
-
-
-void ModuloSchedulingSBPass::predIntersect(std::set<MSchedGraphSBNode*> &CurrentSet, std::set<MSchedGraphSBNode*> &IntersectResult) {
-
- for(unsigned j=0; j < FinalNodeOrder.size(); ++j) {
- for(MSchedGraphSBNode::pred_iterator P = FinalNodeOrder[j]->pred_begin(),
- E = FinalNodeOrder[j]->pred_end(); P != E; ++P) {
-
- //Check if we are supposed to ignore this edge or not
- if(ignoreEdge(*P,FinalNodeOrder[j]))
- continue;
-
- if(CurrentSet.count(*P))
- if(std::find(FinalNodeOrder.begin(), FinalNodeOrder.end(), *P) == FinalNodeOrder.end())
- IntersectResult.insert(*P);
- }
- }
-}
-
-void ModuloSchedulingSBPass::succIntersect(std::set<MSchedGraphSBNode*> &CurrentSet, std::set<MSchedGraphSBNode*> &IntersectResult) {
-
- for(unsigned j=0; j < FinalNodeOrder.size(); ++j) {
- for(MSchedGraphSBNode::succ_iterator P = FinalNodeOrder[j]->succ_begin(),
- E = FinalNodeOrder[j]->succ_end(); P != E; ++P) {
-
- //Check if we are supposed to ignore this edge or not
- if(ignoreEdge(FinalNodeOrder[j],*P))
- continue;
-
- if(CurrentSet.count(*P))
- if(std::find(FinalNodeOrder.begin(), FinalNodeOrder.end(), *P) == FinalNodeOrder.end())
- IntersectResult.insert(*P);
- }
- }
-}
-
-
-
-bool ModuloSchedulingSBPass::computeSchedule(std::vector<const MachineBasicBlock*> &SB, MSchedGraphSB *MSG) {
-
- TIME_REGION(X, "computeSchedule");
-
- bool success = false;
-
- //FIXME: Should be set to max II of the original loop
- //Cap II in order to prevent infinite loop
- int capII = MSG->totalDelay();
-
- while(!success) {
-
- //Keep track of branches, but do not insert into the schedule
- std::vector<MSchedGraphSBNode*> branches;
-
- //Loop over the final node order and process each node
- for(std::vector<MSchedGraphSBNode*>::iterator I = FinalNodeOrder.begin(),
- E = FinalNodeOrder.end(); I != E; ++I) {
-
- //CalculateEarly and Late start
- bool initialLSVal = false;
- bool initialESVal = false;
- int EarlyStart = 0;
- int LateStart = 0;
- bool hasSucc = false;
- bool hasPred = false;
- bool sched;
-
- if((*I)->isBranch())
- if((*I)->hasPredecessors())
- sched = true;
- else
- sched = false;
- else
- sched = true;
-
- if(sched) {
- //Loop over nodes in the schedule and determine if they are predecessors
- //or successors of the node we are trying to schedule
- for(MSScheduleSB::schedule_iterator nodesByCycle = schedule.begin(), nodesByCycleEnd = schedule.end();
- nodesByCycle != nodesByCycleEnd; ++nodesByCycle) {
-
- //For this cycle, get the vector of nodes schedule and loop over it
- for(std::vector<MSchedGraphSBNode*>::iterator schedNode = nodesByCycle->second.begin(), SNE = nodesByCycle->second.end(); schedNode != SNE; ++schedNode) {
-
- if((*I)->isPredecessor(*schedNode)) {
- int diff = (*I)->getInEdge(*schedNode).getIteDiff();
- int ES_Temp = nodesByCycle->first + (*schedNode)->getLatency() - diff * II;
- DEBUG(std::cerr << "Diff: " << diff << " Cycle: " << nodesByCycle->first << "\n");
- DEBUG(std::cerr << "Temp EarlyStart: " << ES_Temp << " Prev EarlyStart: " << EarlyStart << "\n");
- if(initialESVal)
- EarlyStart = std::max(EarlyStart, ES_Temp);
- else {
- EarlyStart = ES_Temp;
- initialESVal = true;
- }
- hasPred = true;
- }
- if((*I)->isSuccessor(*schedNode)) {
- int diff = (*schedNode)->getInEdge(*I).getIteDiff();
- int LS_Temp = nodesByCycle->first - (*I)->getLatency() + diff * II;
- DEBUG(std::cerr << "Diff: " << diff << " Cycle: " << nodesByCycle->first << "\n");
- DEBUG(std::cerr << "Temp LateStart: " << LS_Temp << " Prev LateStart: " << LateStart << "\n");
- if(initialLSVal)
- LateStart = std::min(LateStart, LS_Temp);
- else {
- LateStart = LS_Temp;
- initialLSVal = true;
- }
- hasSucc = true;
- }
- }
- }
- }
- else {
- branches.push_back(*I);
- continue;
- }
-
- //Check if the node has no pred or successors and set Early Start to its ASAP
- if(!hasSucc && !hasPred)
- EarlyStart = nodeToAttributesMap.find(*I)->second.ASAP;
-
- DEBUG(std::cerr << "Has Successors: " << hasSucc << ", Has Pred: " << hasPred << "\n");
- DEBUG(std::cerr << "EarlyStart: " << EarlyStart << ", LateStart: " << LateStart << "\n");
-
- //Now, try to schedule this node depending upon its pred and successor in the schedule
- //already
- if(!hasSucc && hasPred)
- success = scheduleNode(*I, EarlyStart, (EarlyStart + II -1));
- else if(!hasPred && hasSucc)
- success = scheduleNode(*I, LateStart, (LateStart - II +1));
- else if(hasPred && hasSucc) {
- if(EarlyStart > LateStart) {
- success = false;
- //LateStart = EarlyStart;
- DEBUG(std::cerr << "Early Start can not be later then the late start cycle, schedule fails\n");
- }
- else
- success = scheduleNode(*I, EarlyStart, std::min(LateStart, (EarlyStart + II -1)));
- }
- else
- success = scheduleNode(*I, EarlyStart, EarlyStart + II - 1);
-
- if(!success) {
- ++II;
- schedule.clear();
- break;
- }
-
- }
-
- if(success) {
- DEBUG(std::cerr << "Constructing Schedule Kernel\n");
- success = schedule.constructKernel(II, branches, indVarInstrs[SB]);
- DEBUG(std::cerr << "Done Constructing Schedule Kernel\n");
- if(!success) {
- ++II;
- schedule.clear();
- }
- DEBUG(std::cerr << "Final II: " << II << "\n");
-
- }
-
- if(II >= capII) {
- DEBUG(std::cerr << "Maximum II reached, giving up\n");
- return false;
- }
-
- assert(II < capII && "The II should not exceed the original loop number of cycles");
- }
- return true;
-}
-
-
-bool ModuloSchedulingSBPass::scheduleNode(MSchedGraphSBNode *node,
- int start, int end) {
- bool success = false;
-
- DEBUG(std::cerr << *node << " (Start Cycle: " << start << ", End Cycle: " << end << ")\n");
-
- //Make sure start and end are not negative
- //if(start < 0) {
- //start = 0;
-
- //}
- //if(end < 0)
- //end = 0;
-
- bool forward = true;
- if(start > end)
- forward = false;
-
- bool increaseSC = true;
- int cycle = start ;
-
-
- while(increaseSC) {
-
- increaseSC = false;
-
- increaseSC = schedule.insert(node, cycle, II);
-
- if(!increaseSC)
- return true;
-
- //Increment cycle to try again
- if(forward) {
- ++cycle;
- DEBUG(std::cerr << "Increase cycle: " << cycle << "\n");
- if(cycle > end)
- return false;
- }
- else {
- --cycle;
- DEBUG(std::cerr << "Decrease cycle: " << cycle << "\n");
- if(cycle < end)
- return false;
- }
- }
-
- return success;
-}
-
-void ModuloSchedulingSBPass::reconstructLoop(std::vector<const MachineBasicBlock*> &SB) {
-
- TIME_REGION(X, "reconstructLoop");
-
-
- DEBUG(std::cerr << "Reconstructing Loop\n");
-
- //First find the value *'s that we need to "save"
- std::map<const Value*, std::pair<const MachineInstr*, int> > valuesToSave;
-
- //Keep track of instructions we have already seen and their stage because
- //we don't want to "save" values if they are used in the kernel immediately
- std::map<const MachineInstr*, int> lastInstrs;
-
-
- std::set<MachineBasicBlock*> seenBranchesBB;
- const TargetInstrInfo *MTI = target.getInstrInfo();
- std::map<MachineBasicBlock*, std::vector<std::pair<MachineInstr*, int> > > instrsMovedDown;
- std::map<MachineBasicBlock*, int> branchStage;
-
- //Loop over kernel and only look at instructions from a stage > 0
- //Look at its operands and save values *'s that are read
- for(MSScheduleSB::kernel_iterator I = schedule.kernel_begin(), E = schedule.kernel_end(); I != E; ++I) {
-
- if(I->second !=0) {
- //For this instruction, get the Value*'s that it reads and put them into the set.
- //Assert if there is an operand of another type that we need to save
- const MachineInstr *inst = I->first;
- lastInstrs[inst] = I->second;
-
- for(unsigned i=0; i < inst->getNumOperands(); ++i) {
- //get machine operand
- const MachineOperand &mOp = inst->getOperand(i);
-
- if(mOp.getType() == MachineOperand::MO_VirtualRegister && mOp.isUse()) {
- //find the value in the map
- if (const Value* srcI = mOp.getVRegValue()) {
-
- if(isa<Constant>(srcI) || isa<Argument>(srcI))
- continue;
-
- //Before we declare this Value* one that we should save
- //make sure its def is not of the same stage as this instruction
- //because it will be consumed before its used
- Instruction *defInst = (Instruction*) srcI;
-
- //Should we save this value?
- bool save = true;
-
- //Continue if not in the def map, loop invariant code does not need to be saved
- if(!defMap.count(srcI))
- continue;
-
- MachineInstr *defInstr = defMap[srcI];
-
-
- if(lastInstrs.count(defInstr)) {
- if(lastInstrs[defInstr] == I->second) {
- save = false;
-
- }
- }
-
- if(save)
- valuesToSave[srcI] = std::make_pair(I->first, i);
- }
- }
-
- if(mOp.getType() != MachineOperand::MO_VirtualRegister && mOp.isUse()) {
- assert("Our assumption is wrong. We have another type of register that needs to be saved\n");
- }
- }
- }
-
-
- //Do a check to see if instruction was moved below its original branch
- if(MTI->isBranch(I->first->getOpcode())) {
- seenBranchesBB.insert(I->first->getParent());
- branchStage[I->first->getParent()] = I->second;
- }
- else {
- instrsMovedDown[I->first->getParent()].push_back(std::make_pair(I->first, I->second));
- //assert(seenBranchesBB.count(I->first->getParent()) && "Instruction moved below branch\n");
- }
-
- }
-
- //The new loop will consist of one or more prologues, the kernel, and one or more epilogues.
-
- //Map to keep track of old to new values
- std::map<Value*, std::map<int, Value*> > newValues;
-
- //Map to keep track of old to new values in kernel
- std::map<Value*, std::map<int, Value*> > kernelPHIs;
-
- //Another map to keep track of what machine basic blocks these new value*s are in since
- //they have no llvm instruction equivalent
- std::map<Value*, MachineBasicBlock*> newValLocation;
-
- std::vector<std::vector<MachineBasicBlock*> > prologues;
- std::vector<std::vector<BasicBlock*> > llvm_prologues;
-
- //Map to keep track of where the inner branches go
- std::map<const MachineBasicBlock*, Value*> sideExits;
-
-
- //Write prologue
- if(schedule.getMaxStage() != 0)
- writePrologues(prologues, SB, llvm_prologues, valuesToSave, newValues, newValLocation);
-
- std::vector<BasicBlock*> llvmKernelBBs;
- std::vector<MachineBasicBlock*> machineKernelBBs;
- Function *parent = (Function*) SB[0]->getBasicBlock()->getParent();
-
- for(unsigned i = 0; i < SB.size(); ++i) {
- llvmKernelBBs.push_back(new BasicBlock("Kernel", parent));
-
- machineKernelBBs.push_back(new MachineBasicBlock(llvmKernelBBs[i]));
- (((MachineBasicBlock*)SB[0])->getParent())->getBasicBlockList().push_back(machineKernelBBs[i]);
- }
-
- writeKernel(llvmKernelBBs, machineKernelBBs, valuesToSave, newValues, newValLocation, kernelPHIs);
-
-
- std::vector<std::vector<MachineBasicBlock*> > epilogues;
- std::vector<std::vector<BasicBlock*> > llvm_epilogues;
-
- //Write epilogues
- if(schedule.getMaxStage() != 0)
- writeEpilogues(epilogues, SB, llvm_epilogues, valuesToSave, newValues, newValLocation, kernelPHIs);
-
-
- //Fix our branches
- fixBranches(prologues, llvm_prologues, machineKernelBBs, llvmKernelBBs, epilogues, llvm_epilogues, SB, sideExits);
-
- //Print out epilogues and prologue
- DEBUG(for(std::vector<std::vector<MachineBasicBlock*> >::iterator PI = prologues.begin(), PE = prologues.end();
- PI != PE; ++PI) {
- std::cerr << "PROLOGUE\n";
- for(std::vector<MachineBasicBlock*>::iterator I = PI->begin(), E = PI->end(); I != E; ++I)
- (*I)->print(std::cerr);
- });
-
- DEBUG(std::cerr << "KERNEL\n");
- DEBUG(for(std::vector<MachineBasicBlock*>::iterator I = machineKernelBBs.begin(), E = machineKernelBBs.end(); I != E; ++I) { (*I)->print(std::cerr);});
-
- DEBUG(for(std::vector<std::vector<MachineBasicBlock*> >::iterator EI = epilogues.begin(), EE = epilogues.end();
- EI != EE; ++EI) {
- std::cerr << "EPILOGUE\n";
- for(std::vector<MachineBasicBlock*>::iterator I = EI->begin(), E = EI->end(); I != E; ++I)
- (*I)->print(std::cerr);
- });
-
-
- //Remove phis
- removePHIs(SB, prologues, epilogues, machineKernelBBs, newValLocation);
-
- //Print out epilogues and prologue
- DEBUG(for(std::vector<std::vector<MachineBasicBlock*> >::iterator PI = prologues.begin(), PE = prologues.end();
- PI != PE; ++PI) {
- std::cerr << "PROLOGUE\n";
- for(std::vector<MachineBasicBlock*>::iterator I = PI->begin(), E = PI->end(); I != E; ++I)
- (*I)->print(std::cerr);
- });
-
- DEBUG(std::cerr << "KERNEL\n");
- DEBUG(for(std::vector<MachineBasicBlock*>::iterator I = machineKernelBBs.begin(), E = machineKernelBBs.end(); I != E; ++I) { (*I)->print(std::cerr);});
-
- DEBUG(for(std::vector<std::vector<MachineBasicBlock*> >::iterator EI = epilogues.begin(), EE = epilogues.end();
- EI != EE; ++EI) {
- std::cerr << "EPILOGUE\n";
- for(std::vector<MachineBasicBlock*>::iterator I = EI->begin(), E = EI->end(); I != E; ++I)
- (*I)->print(std::cerr);
- });
-
- writeSideExits(prologues, llvm_prologues, epilogues, llvm_epilogues, sideExits, instrsMovedDown, SB, machineKernelBBs, branchStage);
-
-
- DEBUG(std::cerr << "New Machine Function" << "\n");
-}
-
-
-void ModuloSchedulingSBPass::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) {
-
- const TargetInstrInfo *TMI = target.getInstrInfo();
-
- //Get exit BB
- BasicBlock *last = (BasicBlock*) SB[SB.size()-1]->getBasicBlock();
- BasicBlock *kernel_exit = 0;
- bool sawFirst = false;
-
- for(succ_iterator I = succ_begin(last),
- E = succ_end(last); I != E; ++I) {
- if (*I != SB[0]->getBasicBlock()) {
- kernel_exit = *I;
- break;
- }
- else
- sawFirst = true;
- }
- if(!kernel_exit && sawFirst) {
- kernel_exit = (BasicBlock*) SB[0]->getBasicBlock();
- }
-
- assert(kernel_exit && "Kernel Exit can not be null");
-
- if(schedule.getMaxStage() != 0) {
- //Fix prologue branches
- for(unsigned i = 0; i < prologues.size(); ++i) {
-
- for(unsigned j = 0; j < prologues[i].size(); ++j) {
-
- MachineBasicBlock *currentMBB = prologues[i][j];
-
- //Find terminator since getFirstTerminator does not work!
- for(MachineBasicBlock::reverse_iterator mInst = currentMBB->rbegin(), mInstEnd = currentMBB->rend(); mInst != mInstEnd; ++mInst) {
- MachineOpCode OC = mInst->getOpcode();
- //If its a branch update its branchto
- if(TMI->isBranch(OC)) {
- for(unsigned opNum = 0; opNum < mInst->getNumOperands(); ++opNum) {
- MachineOperand &mOp = mInst->getOperand(opNum);
- if (mOp.getType() == MachineOperand::MO_PCRelativeDisp) {
- //Check if we are branching to the kernel, if not branch to epilogue
- if(mOp.getVRegValue() == SB[0]->getBasicBlock()) {
- if(i >= prologues.size()-1)
- mOp.setValueReg(llvmKernelBB[0]);
- else
- mOp.setValueReg(llvm_prologues[i+1][0]);
- }
- else if( (mOp.getVRegValue() == kernel_exit) && (j == prologues[i].size()-1)) {
- mOp.setValueReg(llvm_epilogues[i][0]);
- }
- else if(mOp.getVRegValue() == SB[j+1]->getBasicBlock()) {
- mOp.setValueReg(llvm_prologues[i][j+1]);
- }
-
- }
- }
-
- DEBUG(std::cerr << "New Prologue Branch: " << *mInst << "\n");
- }
- }
-
- //Update llvm basic block with our new branch instr
- DEBUG(std::cerr << SB[i]->getBasicBlock()->getTerminator() << "\n");
-
- const BranchInst *branchVal = dyn_cast<BranchInst>(SB[i]->getBasicBlock()->getTerminator());
-
- //Check for inner branch
- if(j < prologues[i].size()-1) {
- //Find our side exit LLVM basic block
- BasicBlock *sideExit = 0;
- for(unsigned s = 0; s < branchVal->getNumSuccessors(); ++s) {
- if(branchVal->getSuccessor(s) != SB[i+1]->getBasicBlock())
- sideExit = branchVal->getSuccessor(s);
- }
- assert(sideExit && "Must have side exit llvm basic block");
- TerminatorInst *newBranch = new BranchInst(sideExit,
- llvm_prologues[i][j+1],
- branchVal->getCondition(),
- llvm_prologues[i][j]);
- }
- else {
- //If last prologue
- if(i == prologues.size()-1) {
- TerminatorInst *newBranch = new BranchInst(llvmKernelBB[0],
- llvm_epilogues[i][0],
- branchVal->getCondition(),
- llvm_prologues[i][j]);
- }
- else {
- TerminatorInst *newBranch = new BranchInst(llvm_prologues[i+1][0],
- llvm_epilogues[i][0],
- branchVal->getCondition(),
- llvm_prologues[i][j]);
- }
- }
- }
- }
- }
-
- //Fix up kernel machine branches
- for(unsigned i = 0; i < machineKernelBB.size(); ++i) {
- MachineBasicBlock *currentMBB = machineKernelBB[i];
-
- for(MachineBasicBlock::reverse_iterator mInst = currentMBB->rbegin(), mInstEnd = currentMBB->rend(); mInst != mInstEnd; ++mInst) {
- MachineOpCode OC = mInst->getOpcode();
- if(TMI->isBranch(OC)) {
- for(unsigned opNum = 0; opNum < mInst->getNumOperands(); ++opNum) {
- MachineOperand &mOp = mInst->getOperand(opNum);
-
- if(mOp.getType() == MachineOperand::MO_PCRelativeDisp) {
- //Deal with inner kernel branches
- if(i < machineKernelBB.size()-1) {
- if(mOp.getVRegValue() == SB[i+1]->getBasicBlock())
- mOp.setValueReg(llvmKernelBB[i+1]);
- //Side exit!
- else {
- sideExits[SB[i]] = mOp.getVRegValue();
- }
- }
- else {
- if(mOp.getVRegValue() == SB[0]->getBasicBlock())
- mOp.setValueReg(llvmKernelBB[0]);
- else {
- if(llvm_epilogues.size() > 0)
- mOp.setValueReg(llvm_epilogues[0][0]);
- }
- }
- }
- }
- }
- }
-
- //Update kernelLLVM branches
- const BranchInst *branchVal = dyn_cast<BranchInst>(SB[0]->getBasicBlock()->getTerminator());
-
- //deal with inner branch
- if(i < machineKernelBB.size()-1) {
-
- //Find our side exit LLVM basic block
- BasicBlock *sideExit = 0;
- for(unsigned s = 0; s < branchVal->getNumSuccessors(); ++s) {
- if(branchVal->getSuccessor(s) != SB[i+1]->getBasicBlock())
- sideExit = branchVal->getSuccessor(s);
- }
- assert(sideExit && "Must have side exit llvm basic block");
- TerminatorInst *newBranch = new BranchInst(sideExit,
- llvmKernelBB[i+1],
- branchVal->getCondition(),
- llvmKernelBB[i]);
- }
- else {
- //Deal with outter branches
- if(epilogues.size() > 0) {
- TerminatorInst *newBranch = new BranchInst(llvmKernelBB[0],
- llvm_epilogues[0][0],
- branchVal->getCondition(),
- llvmKernelBB[i]);
- }
- else {
- TerminatorInst *newBranch = new BranchInst(llvmKernelBB[0],
- kernel_exit,
- branchVal->getCondition(),
- llvmKernelBB[i]);
- }
- }
- }
-
- if(schedule.getMaxStage() != 0) {
-
- //Lastly add unconditional branches for the epilogues
- for(unsigned i = 0; i < epilogues.size(); ++i) {
-
- for(unsigned j=0; j < epilogues[i].size(); ++j) {
- //Now since we don't have fall throughs, add a unconditional
- //branch to the next prologue
-
- //Before adding these, we need to check if the epilogue already has
- //a branch in it
- bool hasBranch = false;
- /*if(j < epilogues[i].size()-1) {
- MachineBasicBlock *currentMBB = epilogues[i][j];
- for(MachineBasicBlock::reverse_iterator mInst = currentMBB->rbegin(), mInstEnd = currentMBB->rend(); mInst != mInstEnd; ++mInst) {
-
- MachineOpCode OC = mInst->getOpcode();
-
- //If its a branch update its branchto
- if(TMI->isBranch(OC)) {
- hasBranch = true;
- for(unsigned opNum = 0; opNum < mInst->getNumOperands(); ++opNum) {
- MachineOperand &mOp = mInst->getOperand(opNum);
- if (mOp.getType() == MachineOperand::MO_PCRelativeDisp) {
-
- if(mOp.getVRegValue() != sideExits[SB[j]]) {
- mOp.setValueReg(llvm_epilogues[i][j+1]);
- }
-
- }
- }
-
-
- DEBUG(std::cerr << "New Epilogue Branch: " << *mInst << "\n");
- }
- }
- if(hasBranch) {
- const BranchInst *branchVal = dyn_cast<BranchInst>(SB[j]->getBasicBlock()->getTerminator());
- TerminatorInst *newBranch = new BranchInst((BasicBlock*)sideExits[SB[j]],
- llvm_epilogues[i][j+1],
- branchVal->getCondition(),
- llvm_epilogues[i][j]);
- }
- }*/
-
- if(!hasBranch) {
-
- //Handle inner branches
- if(j < epilogues[i].size()-1) {
- BuildMI(epilogues[i][j], V9::BA, 1).addPCDisp(llvm_epilogues[i][j+1]);
- TerminatorInst *newBranch = new BranchInst(llvm_epilogues[i][j+1],
- llvm_epilogues[i][j]);
- }
- else {
-
- //Check if this is the last epilogue
- if(i != epilogues.size()-1) {
- BuildMI(epilogues[i][j], V9::BA, 1).addPCDisp(llvm_epilogues[i+1][0]);
- //Add unconditional branch to end of epilogue
- TerminatorInst *newBranch = new BranchInst(llvm_epilogues[i+1][0],
- llvm_epilogues[i][j]);
-
- }
- else {
- BuildMI(epilogues[i][j], V9::BA, 1).addPCDisp(kernel_exit);
- TerminatorInst *newBranch = new BranchInst(kernel_exit, llvm_epilogues[i][j]);
- }
- }
-
- //Add one more nop!
- BuildMI(epilogues[i][j], V9::NOP, 0);
-
- }
- }
- }
- }
-
- //Find all llvm basic blocks that branch to the loop entry and
- //change to our first prologue.
- const BasicBlock *llvmBB = SB[0]->getBasicBlock();
-
- std::vector<const BasicBlock*>Preds (pred_begin(llvmBB), pred_end(llvmBB));
-
- for(std::vector<const BasicBlock*>::iterator P = Preds.begin(),
- PE = Preds.end(); P != PE; ++P) {
- if(*P == SB[SB.size()-1]->getBasicBlock())
- continue;
- else {
- DEBUG(std::cerr << "Found our entry BB\n");
- DEBUG((*P)->print(std::cerr));
- //Get the Terminator instruction for this basic block and print it out
- //DEBUG(std::cerr << *((*P)->getTerminator()) << "\n");
-
- //Update the terminator
- TerminatorInst *term = ((BasicBlock*)*P)->getTerminator();
- for(unsigned i=0; i < term->getNumSuccessors(); ++i) {
- if(term->getSuccessor(i) == llvmBB) {
- DEBUG(std::cerr << "Replacing successor bb\n");
- if(llvm_prologues.size() > 0) {
- term->setSuccessor(i, llvm_prologues[0][0]);
-
- DEBUG(std::cerr << "New Term" << *((*P)->getTerminator()) << "\n");
-
- //Also update its corresponding machine instruction
- MachineCodeForInstruction & tempMvec =
- MachineCodeForInstruction::get(term);
- for (unsigned j = 0; j < tempMvec.size(); j++) {
- MachineInstr *temp = tempMvec[j];
- MachineOpCode opc = temp->getOpcode();
- if(TMI->isBranch(opc)) {
- DEBUG(std::cerr << *temp << "\n");
- //Update branch
- for(unsigned opNum = 0; opNum < temp->getNumOperands(); ++opNum) {
- MachineOperand &mOp = temp->getOperand(opNum);
- if (mOp.getType() == MachineOperand::MO_PCRelativeDisp) {
- if(mOp.getVRegValue() == llvmBB)
- mOp.setValueReg(llvm_prologues[0][0]);
- }
- }
- }
- }
- }
- else {
- term->setSuccessor(i, llvmKernelBB[0]);
-
- //Also update its corresponding machine instruction
- MachineCodeForInstruction & tempMvec =
- MachineCodeForInstruction::get(term);
- for(unsigned j = 0; j < tempMvec.size(); j++) {
- MachineInstr *temp = tempMvec[j];
- MachineOpCode opc = temp->getOpcode();
- if(TMI->isBranch(opc)) {
- DEBUG(std::cerr << *temp << "\n");
- //Update branch
- for(unsigned opNum = 0; opNum < temp->getNumOperands(); ++opNum) {
- MachineOperand &mOp = temp->getOperand(opNum);
- if(mOp.getType() == MachineOperand::MO_PCRelativeDisp) {
- if(mOp.getVRegValue() == llvmBB)
- mOp.setValueReg(llvmKernelBB[0]);
- }
- }
- }
- }
- }
- }
- }
- break;
- }
- }
-
-}
-
-
-void ModuloSchedulingSBPass::writePrologues(std::vector<std::vector<MachineBasicBlock *> > &prologues, std::vector<const MachineBasicBlock*> &origSB, 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) {
-
- //Keep a map to easily know whats in the kernel
- std::map<int, std::set<const MachineInstr*> > inKernel;
- int maxStageCount = 0;
-
- //Keep a map of new values we consumed in case they need to be added back
- std::map<Value*, std::map<int, Value*> > consumedValues;
-
- DEBUG(schedule.print(std::cerr));
-
- for(MSScheduleSB::kernel_iterator I = schedule.kernel_begin(), E = schedule.kernel_end(); I != E; ++I) {
- maxStageCount = std::max(maxStageCount, I->second);
-
- //Put int the map so we know what instructions in each stage are in the kernel
- DEBUG(std::cerr << "Inserting instruction " << *(I->first) << " into map at stage " << I->second << "\n");
- inKernel[I->second].insert(I->first);
- }
-
- //Get target information to look at machine operands
- const TargetInstrInfo *mii = target.getInstrInfo();
-
- //Now write the prologues
- for(int i = 0; i < maxStageCount; ++i) {
- std::vector<MachineBasicBlock*> current_prologue;
- std::vector<BasicBlock*> current_llvm_prologue;
-
- for(std::vector<const MachineBasicBlock*>::iterator MB = origSB.begin(),
- MBE = origSB.end(); MB != MBE; ++MB) {
- const MachineBasicBlock *MBB = *MB;
- //Create new llvm and machine bb
- BasicBlock *llvmBB = new BasicBlock("PROLOGUE", (Function*) (MBB->getBasicBlock()->getParent()));
- MachineBasicBlock *machineBB = new MachineBasicBlock(llvmBB);
-
- DEBUG(std::cerr << "i=" << i << "\n");
-
- for(int j = i; j >= 0; --j) {
- //iterate over instructions in original bb
- for(MachineBasicBlock::const_iterator MI = MBB->begin(),
- ME = MBB->end(); ME != MI; ++MI) {
- if(inKernel[j].count(&*MI)) {
- MachineInstr *instClone = MI->clone();
- machineBB->push_back(instClone);
-
- //If its a branch, insert a nop
- if(mii->isBranch(instClone->getOpcode()))
- BuildMI(machineBB, V9::NOP, 0);
-
-
- DEBUG(std::cerr << "Cloning: " << *MI << "\n");
-
- //After cloning, we may need to save the value that this instruction defines
- for(unsigned opNum=0; opNum < MI->getNumOperands(); ++opNum) {
- Instruction *tmp;
-
- //get machine operand
- MachineOperand &mOp = instClone->getOperand(opNum);
- if(mOp.getType() == MachineOperand::MO_VirtualRegister
- && mOp.isDef()) {
-
- //Check if this is a value we should save
- if(valuesToSave.count(mOp.getVRegValue())) {
- //Save copy in tmpInstruction
- tmp = new TmpInstruction(mOp.getVRegValue());
-
- //Add TmpInstruction to safe LLVM Instruction MCFI
- MachineCodeForInstruction & tempMvec = MachineCodeForInstruction::get(defaultInst);
- tempMvec.addTemp((Value*) tmp);
-
- DEBUG(std::cerr << "Value: " << *(mOp.getVRegValue())
- << " New Value: " << *tmp << " Stage: " << i << "\n");
-
- newValues[mOp.getVRegValue()][i]= tmp;
- newValLocation[tmp] = machineBB;
-
- DEBUG(std::cerr << "Machine Instr Operands: "
- << *(mOp.getVRegValue()) << ", 0, " << *tmp << "\n");
-
- //Create machine instruction and put int machineBB
- MachineInstr *saveValue;
- if(mOp.getVRegValue()->getType() == Type::FloatTy)
- saveValue = BuildMI(machineBB, V9::FMOVS, 3).addReg(mOp.getVRegValue()).addRegDef(tmp);
- else if(mOp.getVRegValue()->getType() == Type::DoubleTy)
- saveValue = BuildMI(machineBB, V9::FMOVD, 3).addReg(mOp.getVRegValue()).addRegDef(tmp);
- else
- saveValue = BuildMI(machineBB, V9::ORr, 3).addReg(mOp.getVRegValue()).addImm(0).addRegDef(tmp);
-
-
- DEBUG(std::cerr << "Created new machine instr: " << *saveValue << "\n");
- }
- }
-
- //We may also need to update the value that we use if
- //its from an earlier prologue
- if(j != 0) {
- if(mOp.getType() == MachineOperand::MO_VirtualRegister && mOp.isUse()) {
- if(newValues.count(mOp.getVRegValue())) {
- if(newValues[mOp.getVRegValue()].count(i-1)) {
- Value *oldV = mOp.getVRegValue();
- DEBUG(std::cerr << "Replaced this value: " << mOp.getVRegValue() << " With:" << (newValues[mOp.getVRegValue()][i-1]) << "\n");
- //Update the operand with the right value
- mOp.setValueReg(newValues[mOp.getVRegValue()][i-1]);
-
- //Remove this value since we have consumed it
- //NOTE: Should this only be done if j != maxStage?
- consumedValues[oldV][i-1] = (newValues[oldV][i-1]);
- DEBUG(std::cerr << "Deleted value: " << consumedValues[oldV][i-1] << "\n");
- newValues[oldV].erase(i-1);
- }
- }
- else
- if(consumedValues.count(mOp.getVRegValue()))
- assert(!consumedValues[mOp.getVRegValue()].count(i-1) && "Found a case where we need the value");
- }
- }
- }
- }
- }
- }
- (((MachineBasicBlock*)MBB)->getParent())->getBasicBlockList().push_back(machineBB);
- current_prologue.push_back(machineBB);
- current_llvm_prologue.push_back(llvmBB);
- }
- prologues.push_back(current_prologue);
- llvm_prologues.push_back(current_llvm_prologue);
-
- }
-}
-
-
-void ModuloSchedulingSBPass::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 ) {
-
- std::map<int, std::set<const MachineInstr*> > inKernel;
- const TargetInstrInfo *MTI = target.getInstrInfo();
-
- for(MSScheduleSB::kernel_iterator I = schedule.kernel_begin(), E = schedule.kernel_end(); I != E; ++I) {
-
- //Put int the map so we know what instructions in each stage are in the kernel
- inKernel[I->second].insert(I->first);
- }
-
- std::map<Value*, Value*> valPHIs;
-
- //some debug stuff, will remove later
- DEBUG(for(std::map<Value*, std::map<int, Value*> >::iterator V = newValues.begin(), E = newValues.end(); V !=E; ++V) {
- std::cerr << "Old Value: " << *(V->first) << "\n";
- for(std::map<int, Value*>::iterator I = V->second.begin(), IE = V->second.end(); I != IE; ++I)
- std::cerr << "Stage: " << I->first << " Value: " << *(I->second) << "\n";
- });
-
-
- //Now write the epilogues
- for(int i = schedule.getMaxStage()-1; i >= 0; --i) {
- std::vector<MachineBasicBlock*> current_epilogue;
- std::vector<BasicBlock*> current_llvm_epilogue;
-
- for(std::vector<const MachineBasicBlock*>::iterator MB = origSB.begin(), MBE = origSB.end(); MB != MBE; ++MB) {
- const MachineBasicBlock *MBB = *MB;
-
- BasicBlock *llvmBB = new BasicBlock("EPILOGUE", (Function*) (MBB->getBasicBlock()->getParent()));
- MachineBasicBlock *machineBB = new MachineBasicBlock(llvmBB);
-
- DEBUG(std::cerr << " Epilogue #: " << i << "\n");
-
- std::map<Value*, int> inEpilogue;
-
- for(MachineBasicBlock::const_iterator MI = MBB->begin(), ME = MBB->end(); ME != MI; ++MI) {
- for(int j=schedule.getMaxStage(); j > i; --j) {
- if(inKernel[j].count(&*MI)) {
- DEBUG(std::cerr << "Cloning instruction " << *MI << "\n");
- MachineInstr *clone = MI->clone();
-
- //Update operands that need to use the result from the phi
- for(unsigned opNum=0; opNum < clone->getNumOperands(); ++opNum) {
- //get machine operand
- const MachineOperand &mOp = clone->getOperand(opNum);
-
- if((mOp.getType() == MachineOperand::MO_VirtualRegister && mOp.isUse())) {
-
- DEBUG(std::cerr << "Writing PHI for " << (mOp.getVRegValue()) << "\n");
-
- //If this is the last instructions for the max iterations ago, don't update operands
- if(inEpilogue.count(mOp.getVRegValue()))
- if(inEpilogue[mOp.getVRegValue()] == i)
- continue;
-
- //Quickly write appropriate phis for this operand
- if(newValues.count(mOp.getVRegValue())) {
- if(newValues[mOp.getVRegValue()].count(i)) {
- Instruction *tmp = new TmpInstruction(newValues[mOp.getVRegValue()][i]);
-
- //Get machine code for this instruction
- MachineCodeForInstruction & tempMvec = MachineCodeForInstruction::get(defaultInst);
- tempMvec.addTemp((Value*) tmp);
-
- //assert of no kernelPHI for this value
- assert(kernelPHIs[mOp.getVRegValue()][i] !=0 && "Must have final kernel phi to construct epilogue phi");
-
- MachineInstr *saveValue = BuildMI(machineBB, V9::PHI, 3).addReg(newValues[mOp.getVRegValue()][i]).addReg(kernelPHIs[mOp.getVRegValue()][i]).addRegDef(tmp);
- DEBUG(std::cerr << "Resulting PHI: " << *saveValue << "\n");
- valPHIs[mOp.getVRegValue()] = tmp;
- }
- }
-
- if(valPHIs.count(mOp.getVRegValue())) {
- //Update the operand in the cloned instruction
- clone->getOperand(opNum).setValueReg(valPHIs[mOp.getVRegValue()]);
- }
- }
- else if((mOp.getType() == MachineOperand::MO_VirtualRegister && mOp.isDef())) {
- inEpilogue[mOp.getVRegValue()] = i;
- }
-
- }
- machineBB->push_back(clone);
- //if(MTI->isBranch(clone->getOpcode()))
- //BuildMI(machineBB, V9::NOP, 0);
- }
- }
- }
- (((MachineBasicBlock*)MBB)->getParent())->getBasicBlockList().push_back(machineBB);
- current_epilogue.push_back(machineBB);
- current_llvm_epilogue.push_back(llvmBB);
- }
-
- DEBUG(std::cerr << "EPILOGUE #" << i << "\n");
- DEBUG(for(std::vector<MachineBasicBlock*>::iterator B = current_epilogue.begin(), BE = current_epilogue.end(); B != BE; ++B) {
- (*B)->print(std::cerr);});
-
- epilogues.push_back(current_epilogue);
- llvm_epilogues.push_back(current_llvm_epilogue);
- }
-}
-
-void ModuloSchedulingSBPass::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) {
-
- //Keep track of operands that are read and saved from a previous iteration. The new clone
- //instruction will use the result of the phi instead.
- std::map<Value*, Value*> finalPHIValue;
- std::map<Value*, Value*> kernelValue;
-
- //Branches are a special case
- std::vector<MachineInstr*> branches;
-
- //Get target information to look at machine operands
- const TargetInstrInfo *mii = target.getInstrInfo();
- unsigned index = 0;
- int numBr = 0;
- bool seenBranch = false;
-
- //Create TmpInstructions for the final phis
- for(MSScheduleSB::kernel_iterator I = schedule.kernel_begin(), E = schedule.kernel_end(); I != E; ++I) {
-
- DEBUG(std::cerr << "Stage: " << I->second << " Inst: " << *(I->first) << "\n";);
-
- //Clone instruction
- const MachineInstr *inst = I->first;
- MachineInstr *instClone = inst->clone();
-
- if(seenBranch && !mii->isBranch(instClone->getOpcode())) {
- index++;
- seenBranch = false;
- numBr = 0;
- }
- else if(seenBranch && (numBr == 2)) {
- index++;
- numBr = 0;
- }
-
- //Insert into machine basic block
- assert(index < machineBB.size() && "Must have a valid index into kernel MBBs");
- machineBB[index]->push_back(instClone);
-
- if(mii->isBranch(instClone->getOpcode())) {
- BuildMI(machineBB[index], V9::NOP, 0);
-
- seenBranch = true;
- numBr++;
- }
-
- DEBUG(std::cerr << "Cloned Inst: " << *instClone << "\n");
-
- //Loop over Machine Operands
- for(unsigned i=0; i < inst->getNumOperands(); ++i) {
- //get machine operand
- const MachineOperand &mOp = inst->getOperand(i);
-
- if(I->second != 0) {
- if(mOp.getType() == MachineOperand::MO_VirtualRegister && mOp.isUse()) {
-
- //Check to see where this operand is defined if this instruction is from max stage
- if(I->second == schedule.getMaxStage()) {
- DEBUG(std::cerr << "VREG: " << *(mOp.getVRegValue()) << "\n");
- }
-
- //If its in the value saved, we need to create a temp instruction and use that instead
- if(valuesToSave.count(mOp.getVRegValue())) {
-
- //Check if we already have a final PHI value for this
- if(!finalPHIValue.count(mOp.getVRegValue())) {
- //Only create phi if the operand def is from a stage before this one
- if(schedule.defPreviousStage(mOp.getVRegValue(), I->second)) {
- TmpInstruction *tmp = new TmpInstruction(mOp.getVRegValue());
-
- //Get machine code for this instruction
- MachineCodeForInstruction & tempMvec = MachineCodeForInstruction::get(defaultInst);
- tempMvec.addTemp((Value*) tmp);
-
- //Update the operand in the cloned instruction
- instClone->getOperand(i).setValueReg(tmp);
-
- //save this as our final phi
- finalPHIValue[mOp.getVRegValue()] = tmp;
- newValLocation[tmp] = machineBB[index];
- }
- }
- else {
- //Use the previous final phi value
- instClone->getOperand(i).setValueReg(finalPHIValue[mOp.getVRegValue()]);
- }
- }
- }
- }
- if(I->second != schedule.getMaxStage()) {
- if(mOp.getType() == MachineOperand::MO_VirtualRegister && mOp.isDef()) {
- if(valuesToSave.count(mOp.getVRegValue())) {
-
- TmpInstruction *tmp = new TmpInstruction(mOp.getVRegValue());
-
- //Get machine code for this instruction
- MachineCodeForInstruction & tempVec = MachineCodeForInstruction::get(defaultInst);
- tempVec.addTemp((Value*) tmp);
-
- //Create new machine instr and put in MBB
- MachineInstr *saveValue;
- if(mOp.getVRegValue()->getType() == Type::FloatTy)
- saveValue = BuildMI(machineBB[index], V9::FMOVS, 3).addReg(mOp.getVRegValue()).addRegDef(tmp);
- else if(mOp.getVRegValue()->getType() == Type::DoubleTy)
- saveValue = BuildMI(machineBB[index], V9::FMOVD, 3).addReg(mOp.getVRegValue()).addRegDef(tmp);
- else
- saveValue = BuildMI(machineBB[index], V9::ORr, 3).addReg(mOp.getVRegValue()).addImm(0).addRegDef(tmp);
-
-
- //Save for future cleanup
- kernelValue[mOp.getVRegValue()] = tmp;
- newValLocation[tmp] = machineBB[index];
- kernelPHIs[mOp.getVRegValue()][schedule.getMaxStage()-1] = tmp;
- }
- }
- }
- }
-
- }
-
- //Loop over each value we need to generate phis for
- for(std::map<Value*, std::map<int, Value*> >::iterator V = newValues.begin(),
- E = newValues.end(); V != E; ++V) {
-
-
- DEBUG(std::cerr << "Writing phi for" << *(V->first));
- DEBUG(std::cerr << "\nMap of Value* for this phi\n");
- DEBUG(for(std::map<int, Value*>::iterator I = V->second.begin(),
- IE = V->second.end(); I != IE; ++I) {
- std::cerr << "Stage: " << I->first;
- std::cerr << " Value: " << *(I->second) << "\n";
- });
-
- //If we only have one current iteration live, its safe to set
- //lastPhi = to kernel value
- if(V->second.size() == 1) {
- assert(kernelValue[V->first] != 0 && "Kernel value* must exist to create phi");
- MachineInstr *saveValue = BuildMI(*machineBB[0], machineBB[0]->begin(),V9::PHI, 3).addReg(V->second.begin()->second).addReg(kernelValue[V->first]).addRegDef(finalPHIValue[V->first]);
- DEBUG(std::cerr << "Resulting PHI (one live): " << *saveValue << "\n");
- kernelPHIs[V->first][V->second.begin()->first] = kernelValue[V->first];
- DEBUG(std::cerr << "Put kernel phi in at stage: " << schedule.getMaxStage()-1 << " (map stage = " << V->second.begin()->first << ")\n");
- }
- else {
-
- //Keep track of last phi created.
- Instruction *lastPhi = 0;
-
- unsigned count = 1;
- //Loop over the the map backwards to generate phis
- for(std::map<int, Value*>::reverse_iterator I = V->second.rbegin(), IE = V->second.rend();
- I != IE; ++I) {
-
- if(count < (V->second).size()) {
- if(lastPhi == 0) {
- lastPhi = new TmpInstruction(I->second);
-
- //Get machine code for this instruction
- MachineCodeForInstruction & tempMvec = MachineCodeForInstruction::get(defaultInst);
- tempMvec.addTemp((Value*) lastPhi);
-
- MachineInstr *saveValue = BuildMI(*machineBB[0], machineBB[0]->begin(), V9::PHI, 3).addReg(kernelValue[V->first]).addReg(I->second).addRegDef(lastPhi);
- DEBUG(std::cerr << "Resulting PHI: " << *saveValue << "\n");
- newValLocation[lastPhi] = machineBB[0];
- }
- else {
- Instruction *tmp = new TmpInstruction(I->second);
-
- //Get machine code for this instruction
- MachineCodeForInstruction & tempMvec = MachineCodeForInstruction::get(defaultInst);
- tempMvec.addTemp((Value*) tmp);
-
-
- MachineInstr *saveValue = BuildMI(*machineBB[0], machineBB[0]->begin(), V9::PHI, 3).addReg(lastPhi).addReg(I->second).addRegDef(tmp);
- DEBUG(std::cerr << "Resulting PHI: " << *saveValue << "\n");
- lastPhi = tmp;
- kernelPHIs[V->first][I->first] = lastPhi;
- newValLocation[lastPhi] = machineBB[0];
- }
- }
- //Final phi value
- else {
- //The resulting value must be the Value* we created earlier
- assert(lastPhi != 0 && "Last phi is NULL!\n");
- MachineInstr *saveValue = BuildMI(*machineBB[0], machineBB[0]->begin(), V9::PHI, 3).addReg(lastPhi).addReg(I->second).addRegDef(finalPHIValue[V->first]);
- DEBUG(std::cerr << "Resulting PHI: " << *saveValue << "\n");
- kernelPHIs[V->first][I->first] = finalPHIValue[V->first];
- }
-
- ++count;
- }
-
- }
- }
-}
-
-
-void ModuloSchedulingSBPass::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) {
-
- //Worklist to delete things
- std::vector<std::pair<MachineBasicBlock*, MachineBasicBlock::iterator> > worklist;
-
- //Worklist of TmpInstructions that need to be added to a MCFI
- std::vector<Instruction*> addToMCFI;
-
- //Worklist to add OR instructions to end of kernel so not to invalidate the iterator
- //std::vector<std::pair<Instruction*, Value*> > newORs;
-
- const TargetInstrInfo *TMI = target.getInstrInfo();
-
- //Start with the kernel and for each phi insert a copy for the phi
- //def and for each arg
- //phis are only in the first BB in the kernel
- for(MachineBasicBlock::iterator I = kernelBB[0]->begin(), E = kernelBB[0]->end();
- I != E; ++I) {
-
- DEBUG(std::cerr << "Looking at Instr: " << *I << "\n");
-
- //Get op code and check if its a phi
- if(I->getOpcode() == V9::PHI) {
-
- DEBUG(std::cerr << "Replacing PHI: " << *I << "\n");
- Instruction *tmp = 0;
-
- for(unsigned i = 0; i < I->getNumOperands(); ++i) {
-
- //Get Operand
- const MachineOperand &mOp = I->getOperand(i);
- assert(mOp.getType() == MachineOperand::MO_VirtualRegister
- && "Should be a Value*\n");
-
- if(!tmp) {
- tmp = new TmpInstruction(mOp.getVRegValue());
- addToMCFI.push_back(tmp);
- }
-
- //Now for all our arguments we read, OR to the new
- //TmpInstruction that we created
- if(mOp.isUse()) {
- DEBUG(std::cerr << "Use: " << mOp << "\n");
- //Place a copy at the end of its BB but before the branches
- assert(newValLocation.count(mOp.getVRegValue()) && "We must know where this value is located\n");
- //Reverse iterate to find the branches, we can safely assume no instructions have been
- //put in the nop positions
- for(MachineBasicBlock::iterator inst = --(newValLocation[mOp.getVRegValue()])->end(), endBB = (newValLocation[mOp.getVRegValue()])->begin(); inst != endBB; --inst) {
- MachineOpCode opc = inst->getOpcode();
- if(TMI->isBranch(opc) || TMI->isNop(opc))
- continue;
- else {
- if(mOp.getVRegValue()->getType() == Type::FloatTy)
- BuildMI(*(newValLocation[mOp.getVRegValue()]), ++inst, V9::FMOVS, 3).addReg(mOp.getVRegValue()).addRegDef(tmp);
- else if(mOp.getVRegValue()->getType() == Type::DoubleTy)
- BuildMI(*(newValLocation[mOp.getVRegValue()]), ++inst, V9::FMOVD, 3).addReg(mOp.getVRegValue()).addRegDef(tmp);
- else
- BuildMI(*(newValLocation[mOp.getVRegValue()]), ++inst, V9::ORr, 3).addReg(mOp.getVRegValue()).addImm(0).addRegDef(tmp);
-
- break;
- }
-
- }
-
- }
- else {
- //Remove the phi and replace it with an OR
- DEBUG(std::cerr << "Def: " << mOp << "\n");
- //newORs.push_back(std::make_pair(tmp, mOp.getVRegValue()));
- if(tmp->getType() == Type::FloatTy)
- BuildMI(*kernelBB[0], I, V9::FMOVS, 3).addReg(tmp).addRegDef(mOp.getVRegValue());
- else if(tmp->getType() == Type::DoubleTy)
- BuildMI(*kernelBB[0], I, V9::FMOVD, 3).addReg(tmp).addRegDef(mOp.getVRegValue());
- else
- BuildMI(*kernelBB[0], I, V9::ORr, 3).addReg(tmp).addImm(0).addRegDef(mOp.getVRegValue());
-
-
- worklist.push_back(std::make_pair(kernelBB[0], I));
- }
-
- }
-
- }
-
-
- }
-
- //Add TmpInstructions to some MCFI
- if(addToMCFI.size() > 0) {
- MachineCodeForInstruction & tempMvec = MachineCodeForInstruction::get(defaultInst);
- for(unsigned x = 0; x < addToMCFI.size(); ++x) {
- tempMvec.addTemp(addToMCFI[x]);
- }
- addToMCFI.clear();
- }
-
-
- //Remove phis from epilogue
- for(std::vector<std::vector<MachineBasicBlock*> >::iterator MB = epilogues.begin(),
- ME = epilogues.end(); MB != ME; ++MB) {
-
- for(std::vector<MachineBasicBlock*>::iterator currentMBB = MB->begin(), currentME = MB->end(); currentMBB != currentME; ++currentMBB) {
-
- for(MachineBasicBlock::iterator I = (*currentMBB)->begin(),
- E = (*currentMBB)->end(); I != E; ++I) {
-
- DEBUG(std::cerr << "Looking at Instr: " << *I << "\n");
- //Get op code and check if its a phi
- if(I->getOpcode() == V9::PHI) {
- Instruction *tmp = 0;
-
- for(unsigned i = 0; i < I->getNumOperands(); ++i) {
- //Get Operand
- const MachineOperand &mOp = I->getOperand(i);
- assert(mOp.getType() == MachineOperand::MO_VirtualRegister && "Should be a Value*\n");
-
- if(!tmp) {
- tmp = new TmpInstruction(mOp.getVRegValue());
- addToMCFI.push_back(tmp);
- }
-
- //Now for all our arguments we read, OR to the new TmpInstruction that we created
- if(mOp.isUse()) {
- DEBUG(std::cerr << "Use: " << mOp << "\n");
- //Place a copy at the end of its BB but before the branches
- assert(newValLocation.count(mOp.getVRegValue()) && "We must know where this value is located\n");
- //Reverse iterate to find the branches, we can safely assume no instructions have been
- //put in the nop positions
- for(MachineBasicBlock::iterator inst = --(newValLocation[mOp.getVRegValue()])->end(), endBB = (newValLocation[mOp.getVRegValue()])->begin(); inst != endBB; --inst) {
- MachineOpCode opc = inst->getOpcode();
- if(TMI->isBranch(opc) || TMI->isNop(opc))
- continue;
- else {
- if(mOp.getVRegValue()->getType() == Type::FloatTy)
- BuildMI(*(newValLocation[mOp.getVRegValue()]), ++inst, V9::FMOVS, 3).addReg(mOp.getVRegValue()).addRegDef(tmp);
- else if(mOp.getVRegValue()->getType() == Type::DoubleTy)
- BuildMI(*(newValLocation[mOp.getVRegValue()]), ++inst, V9::FMOVD, 3).addReg(mOp.getVRegValue()).addRegDef(tmp);
- else
- BuildMI(*(newValLocation[mOp.getVRegValue()]), ++inst, V9::ORr, 3).addReg(mOp.getVRegValue()).addImm(0).addRegDef(tmp);
-
-
- break;
- }
-
- }
-
- }
- else {
- //Remove the phi and replace it with an OR
- DEBUG(std::cerr << "Def: " << mOp << "\n");
- if(tmp->getType() == Type::FloatTy)
- BuildMI(**currentMBB, I, V9::FMOVS, 3).addReg(tmp).addRegDef(mOp.getVRegValue());
- else if(tmp->getType() == Type::DoubleTy)
- BuildMI(**currentMBB, I, V9::FMOVD, 3).addReg(tmp).addRegDef(mOp.getVRegValue());
- else
- BuildMI(**currentMBB, I, V9::ORr, 3).addReg(tmp).addImm(0).addRegDef(mOp.getVRegValue());
-
- worklist.push_back(std::make_pair(*currentMBB,I));
- }
- }
- }
- }
- }
- }
-
-
- if(addToMCFI.size() > 0) {
- MachineCodeForInstruction & tempMvec = MachineCodeForInstruction::get(defaultInst);
- for(unsigned x = 0; x < addToMCFI.size(); ++x) {
- tempMvec.addTemp(addToMCFI[x]);
- }
- addToMCFI.clear();
- }
-
- //Delete the phis
- for(std::vector<std::pair<MachineBasicBlock*, MachineBasicBlock::iterator> >::iterator I = worklist.begin(), E = worklist.end(); I != E; ++I) {
- DEBUG(std::cerr << "Deleting PHI " << *I->second << "\n");
- I->first->erase(I->second);
-
- }
-
-
- assert((addToMCFI.size() == 0) && "We should have added all TmpInstructions to some MachineCodeForInstruction");
-}
-
-
-
-
-void ModuloSchedulingSBPass::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) {
-
- const TargetInstrInfo *TMI = target.getInstrInfo();
-
- //Repeat for each side exit
- for(unsigned sideExitNum = 0; sideExitNum < SB.size()-1; ++sideExitNum) {
-
- std::vector<std::vector<BasicBlock*> > side_llvm_epilogues;
- std::vector<std::vector<MachineBasicBlock*> > side_epilogues;
- MachineBasicBlock* sideMBB;
- BasicBlock* sideBB;
-
- //Create side exit blocks
- //Get the LLVM basic block
- BasicBlock *bb = (BasicBlock*) SB[sideExitNum]->getBasicBlock();
- MachineBasicBlock *mbb = (MachineBasicBlock*) SB[sideExitNum];
-
- int stage = branchStage[mbb];
-
- //Create new basic blocks for our side exit instructios that were moved below the branch
- sideBB = new BasicBlock("SideExit", (Function*) bb->getParent());
- sideMBB = new MachineBasicBlock(sideBB);
- (((MachineBasicBlock*)SB[0])->getParent())->getBasicBlockList().push_back(sideMBB);
-
-
- if(instrsMovedDown.count(mbb)) {
- for(std::vector<std::pair<MachineInstr*, int> >::iterator I = instrsMovedDown[mbb].begin(), E = instrsMovedDown[mbb].end(); I != E; ++I) {
- if(branchStage[mbb] == I->second)
- sideMBB->push_back((I->first)->clone());
- }
-
- //Add unconditional branches to original exits
- BuildMI(sideMBB, V9::BA, 1).addPCDisp(sideExits[mbb]);
- BuildMI(sideMBB, V9::NOP, 0);
-
- //Add unconditioal branch to llvm BB
- BasicBlock *extBB = dyn_cast<BasicBlock>(sideExits[mbb]);
- assert(extBB && "Side exit basicblock can not be null");
- TerminatorInst *newBranch = new BranchInst(extBB, sideBB);
- }
-
- //Clone epilogues and update their branches, one cloned epilogue set per side exit
- //only clone epilogues that are from a greater stage!
- for(unsigned i = 0; i < epilogues.size()-stage; ++i) {
- std::vector<MachineBasicBlock*> MB = epilogues[i];
-
- std::vector<MachineBasicBlock*> newEp;
- std::vector<BasicBlock*> newLLVMEp;
-
- for(std::vector<MachineBasicBlock*>::iterator currentMBB = MB.begin(),
- lastMBB = MB.end(); currentMBB != lastMBB; ++currentMBB) {
- BasicBlock *tmpBB = new BasicBlock("SideEpilogue", (Function*) (*currentMBB)->getBasicBlock()->getParent());
- MachineBasicBlock *tmp = new MachineBasicBlock(tmpBB);
-
- //Clone instructions and insert into new MBB
- for(MachineBasicBlock::iterator I = (*currentMBB)->begin(),
- E = (*currentMBB)->end(); I != E; ++I) {
-
- MachineInstr *clone = I->clone();
- if(clone->getOpcode() == V9::BA && (currentMBB+1 == lastMBB)) {
- //update branch to side exit
- for(unsigned i = 0; i < clone->getNumOperands(); ++i) {
- MachineOperand &mOp = clone->getOperand(i);
- if (mOp.getType() == MachineOperand::MO_PCRelativeDisp) {
- mOp.setValueReg(sideBB);
- }
- }
- }
-
- tmp->push_back(clone);
-
- }
-
- //Add llvm branch
- TerminatorInst *newBranch = new BranchInst(sideBB, tmpBB);
-
- newEp.push_back(tmp);
- (((MachineBasicBlock*)SB[0])->getParent())->getBasicBlockList().push_back(tmp);
-
- newLLVMEp.push_back(tmpBB);
-
- }
- side_llvm_epilogues.push_back(newLLVMEp);
- side_epilogues.push_back(newEp);
- }
-
- //Now stich up all the branches
-
- //Loop over prologues, and if its an inner branch and branches to our original side exit
- //then have it branch to the appropriate epilogue first (if it exists)
- for(unsigned P = 0; P < prologues.size(); ++P) {
-
- //Get BB side exit we are dealing with
- MachineBasicBlock *currentMBB = prologues[P][sideExitNum];
- if(P >= (unsigned) stage) {
- //Iterate backwards of machine instructions to find the branch we need to update
- for(MachineBasicBlock::reverse_iterator mInst = currentMBB->rbegin(), mInstEnd = currentMBB->rend(); mInst != mInstEnd; ++mInst) {
- MachineOpCode OC = mInst->getOpcode();
-
- //If its a branch update its branchto
- if(TMI->isBranch(OC)) {
- for(unsigned opNum = 0; opNum < mInst->getNumOperands(); ++opNum) {
- MachineOperand &mOp = mInst->getOperand(opNum);
- if (mOp.getType() == MachineOperand::MO_PCRelativeDisp) {
- //Check if we branch to side exit
- if(mOp.getVRegValue() == sideExits[mbb]) {
- mOp.setValueReg(side_llvm_epilogues[P][0]);
- }
- }
- }
- DEBUG(std::cerr << "New Prologue Branch: " << *mInst << "\n");
- }
- }
-
- //Update llvm branch
- TerminatorInst *branchVal = ((BasicBlock*) currentMBB->getBasicBlock())->getTerminator();
- DEBUG(std::cerr << *branchVal << "\n");
-
- for(unsigned i=0; i < branchVal->getNumSuccessors(); ++i) {
- if(branchVal->getSuccessor(i) == sideExits[mbb]) {
- DEBUG(std::cerr << "Replacing successor bb\n");
- branchVal->setSuccessor(i, side_llvm_epilogues[P][0]);
- }
- }
- }
- else {
- //must add BA branch because another prologue or kernel has the actual side exit branch
- //Add unconditional branches to original exits
- assert( (sideExitNum+1) < prologues[P].size() && "must have valid prologue to branch to");
- BuildMI(prologues[P][sideExitNum], V9::BA, 1).addPCDisp((BasicBlock*)(prologues[P][sideExitNum+1])->getBasicBlock());
- BuildMI(prologues[P][sideExitNum], V9::NOP, 0);
-
- TerminatorInst *newBranch = new BranchInst((BasicBlock*) (prologues[P][sideExitNum+1])->getBasicBlock(), (BasicBlock*) (prologues[P][sideExitNum])->getBasicBlock());
-
- }
- }
-
-
- //Update side exits in kernel
- MachineBasicBlock *currentMBB = kernelMBBs[sideExitNum];
- //Iterate backwards of machine instructions to find the branch we need to update
- for(MachineBasicBlock::reverse_iterator mInst = currentMBB->rbegin(), mInstEnd = currentMBB->rend(); mInst != mInstEnd; ++mInst) {
- MachineOpCode OC = mInst->getOpcode();
-
- //If its a branch update its branchto
- if(TMI->isBranch(OC)) {
- for(unsigned opNum = 0; opNum < mInst->getNumOperands(); ++opNum) {
- MachineOperand &mOp = mInst->getOperand(opNum);
- if (mOp.getType() == MachineOperand::MO_PCRelativeDisp) {
- //Check if we branch to side exit
- if(mOp.getVRegValue() == sideExits[mbb]) {
- if(side_llvm_epilogues.size() > 0)
- mOp.setValueReg(side_llvm_epilogues[0][0]);
- else
- mOp.setValueReg(sideBB);
- }
- }
- }
- DEBUG(std::cerr << "New Prologue Branch: " << *mInst << "\n");
- }
- }
-
- //Update llvm branch
- //Update llvm branch
- TerminatorInst *branchVal = ((BasicBlock*)currentMBB->getBasicBlock())->getTerminator();
- DEBUG(std::cerr << *branchVal << "\n");
-
- for(unsigned i=0; i < branchVal->getNumSuccessors(); ++i) {
- if(branchVal->getSuccessor(i) == sideExits[mbb]) {
- DEBUG(std::cerr << "Replacing successor bb\n");
- if(side_llvm_epilogues.size() > 0)
- branchVal->setSuccessor(i, side_llvm_epilogues[0][0]);
- else
- branchVal->setSuccessor(i, sideBB);
- }
- }
- }
-}
-
+++ /dev/null
-//===-- 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
+++ /dev/null
-//===-- 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
+++ /dev/null
-//===-- 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
+++ /dev/null
-//===-- 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
+++ /dev/null
-//===-- 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
+++ /dev/null
-//===-- 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
+++ /dev/null
-//===-- 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
+++ /dev/null
-//===-- 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
+++ /dev/null
-//===-- 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
+++ /dev/null
-##===- 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
+++ /dev/null
-//===-- PhyRegAlloc.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.
-//
-//===----------------------------------------------------------------------===//
-//
-// Traditional graph-coloring global register allocator currently used
-// by the SPARC back-end.
-//
-// NOTE: This register allocator has some special support
-// for the Reoptimizer, such as not saving some registers on calls to
-// the first-level instrumentation function.
-//
-// NOTE 2: This register allocator can save its state in a global
-// variable in the module it's working on. This feature is not
-// thread-safe; if you have doubts, leave it turned off.
-//
-//===----------------------------------------------------------------------===//
-
-#include "AllocInfo.h"
-#include "IGNode.h"
-#include "PhyRegAlloc.h"
-#include "RegAllocCommon.h"
-#include "RegClass.h"
-#include "../LiveVar/FunctionLiveVarInfo.h"
-#include "../MachineCodeForInstruction.h"
-#include "../MachineFunctionInfo.h"
-#include "../SparcV9InstrInfo.h"
-#include "../SparcV9TmpInstr.h"
-#include "llvm/Constants.h"
-#include "llvm/DerivedTypes.h"
-#include "llvm/Instructions.h"
-#include "llvm/Module.h"
-#include "llvm/Type.h"
-#include "llvm/Analysis/LoopInfo.h"
-#include "llvm/CodeGen/MachineFunction.h"
-#include "llvm/CodeGen/MachineInstr.h"
-#include "llvm/CodeGen/MachineInstrBuilder.h"
-#include "../MachineInstrAnnot.h"
-#include "llvm/CodeGen/Passes.h"
-#include "llvm/Support/InstIterator.h"
-#include "llvm/Target/TargetInstrInfo.h"
-#include "llvm/Support/CommandLine.h"
-#include "llvm/ADT/SetOperations.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/Statistic.h"
-#include <cmath>
-#include <iostream>
-
-namespace llvm {
- Statistic<> RASpills("regalloc-spills", "Number of registers spilled");
-
-RegAllocDebugLevel_t DEBUG_RA;
-
-static cl::opt<RegAllocDebugLevel_t, true>
-DRA_opt("dregalloc", cl::Hidden, cl::location(DEBUG_RA),
- cl::desc("enable register allocation debugging information"),
- cl::values(
- clEnumValN(RA_DEBUG_None , "n", "disable debug output"),
- clEnumValN(RA_DEBUG_Results, "y", "debug output for allocation results"),
- clEnumValN(RA_DEBUG_Coloring, "c", "debug output for graph coloring step"),
- clEnumValN(RA_DEBUG_Interference,"ig","debug output for interference graphs"),
- clEnumValN(RA_DEBUG_LiveRanges , "lr","debug output for live ranges"),
- clEnumValN(RA_DEBUG_Verbose, "v", "extra debug output"),
- clEnumValEnd));
-
-/// The reoptimizer wants to be able to grovel through the register
-/// allocator's state after it has done its job. This is a hack.
-///
-PhyRegAlloc::SavedStateMapTy ExportedFnAllocState;
-bool SaveRegAllocState = false;
-bool SaveStateToModule = true;
-static cl::opt<bool, true>
-SaveRegAllocStateOpt("save-ra-state", cl::Hidden,
- cl::location (SaveRegAllocState),
- cl::init(false),
- cl::desc("write reg. allocator state into module"));
-
-FunctionPass *getRegisterAllocator(TargetMachine &T) {
- return new PhyRegAlloc (T);
-}
-
-void PhyRegAlloc::getAnalysisUsage(AnalysisUsage &AU) const {
- AU.addRequired<LoopInfo> ();
- AU.addRequired<FunctionLiveVarInfo> ();
-}
-
-
-/// Initialize interference graphs (one in each reg class) and IGNodeLists
-/// (one in each IG). The actual nodes will be pushed later.
-///
-void PhyRegAlloc::createIGNodeListsAndIGs() {
- if (DEBUG_RA >= RA_DEBUG_LiveRanges) std::cerr << "Creating LR lists ...\n";
-
- LiveRangeMapType::const_iterator HMI = LRI->getLiveRangeMap()->begin();
- LiveRangeMapType::const_iterator HMIEnd = LRI->getLiveRangeMap()->end();
-
- for (; HMI != HMIEnd ; ++HMI ) {
- if (HMI->first) {
- V9LiveRange *L = HMI->second; // get the V9LiveRange
- if (!L) {
- if (DEBUG_RA && !isa<ConstantIntegral> (HMI->first))
- std::cerr << "\n**** ?!?WARNING: NULL LIVE RANGE FOUND FOR: "
- << RAV(HMI->first) << "****\n";
- continue;
- }
-
- // if the Value * is not null, and LR is not yet written to the IGNodeList
- if (!(L->getUserIGNode()) ) {
- RegClass *const RC = // RegClass of first value in the LR
- RegClassList[ L->getRegClassID() ];
- RC->addLRToIG(L); // add this LR to an IG
- }
- }
- }
-
- // init RegClassList
- for ( unsigned rc=0; rc < NumOfRegClasses ; rc++)
- RegClassList[rc]->createInterferenceGraph();
-
- if (DEBUG_RA >= RA_DEBUG_LiveRanges) std::cerr << "LRLists Created!\n";
-}
-
-
-/// Add all interferences for a given instruction. Interference occurs only
-/// if the LR of Def (Inst or Arg) is of the same reg class as that of live
-/// var. The live var passed to this function is the LVset AFTER the
-/// instruction.
-///
-void PhyRegAlloc::addInterference(const Value *Def, const ValueSet *LVSet,
- bool isCallInst) {
- ValueSet::const_iterator LIt = LVSet->begin();
-
- // get the live range of instruction
- const V9LiveRange *const LROfDef = LRI->getLiveRangeForValue( Def );
-
- IGNode *const IGNodeOfDef = LROfDef->getUserIGNode();
- assert( IGNodeOfDef );
-
- RegClass *const RCOfDef = LROfDef->getRegClass();
-
- // for each live var in live variable set
- for ( ; LIt != LVSet->end(); ++LIt) {
-
- if (DEBUG_RA >= RA_DEBUG_Verbose)
- std::cerr << "< Def=" << RAV(Def) << ", Lvar=" << RAV(*LIt) << "> ";
-
- // get the live range corresponding to live var
- V9LiveRange *LROfVar = LRI->getLiveRangeForValue(*LIt);
-
- // LROfVar can be null if it is a const since a const
- // doesn't have a dominating def - see Assumptions above
- if (LROfVar)
- if (LROfDef != LROfVar) // do not set interf for same LR
- if (RCOfDef == LROfVar->getRegClass()) // 2 reg classes are the same
- RCOfDef->setInterference( LROfDef, LROfVar);
- }
-}
-
-
-/// For a call instruction, this method sets the CallInterference flag in
-/// the LR of each variable live in the Live Variable Set live after the
-/// call instruction (except the return value of the call instruction - since
-/// the return value does not interfere with that call itself).
-///
-void PhyRegAlloc::setCallInterferences(const MachineInstr *MInst,
- const ValueSet *LVSetAft) {
- if (DEBUG_RA >= RA_DEBUG_Interference)
- std::cerr << "\n For call inst: " << *MInst;
-
- // for each live var in live variable set after machine inst
- for (ValueSet::const_iterator LIt = LVSetAft->begin(), LEnd = LVSetAft->end();
- LIt != LEnd; ++LIt) {
-
- // get the live range corresponding to live var
- V9LiveRange *const LR = LRI->getLiveRangeForValue(*LIt);
-
- // LR can be null if it is a const since a const
- // doesn't have a dominating def - see Assumptions above
- if (LR) {
- if (DEBUG_RA >= RA_DEBUG_Interference)
- std::cerr << "\n\tLR after Call: " << *LR << "\n";
- LR->setCallInterference();
- if (DEBUG_RA >= RA_DEBUG_Interference)
- std::cerr << "\n ++After adding call interference for LR: " << *LR << "\n";
- }
- }
-
- // Now find the LR of the return value of the call
- // We do this because, we look at the LV set *after* the instruction
- // to determine, which LRs must be saved across calls. The return value
- // of the call is live in this set - but it does not interfere with call
- // (i.e., we can allocate a volatile register to the return value)
- CallArgsDescriptor* argDesc = CallArgsDescriptor::get(MInst);
-
- if (const Value *RetVal = argDesc->getReturnValue()) {
- V9LiveRange *RetValLR = LRI->getLiveRangeForValue( RetVal );
- assert( RetValLR && "No LR for RetValue of call");
- RetValLR->clearCallInterference();
- }
-
- // If the CALL is an indirect call, find the LR of the function pointer.
- // That has a call interference because it conflicts with outgoing args.
- if (const Value *AddrVal = argDesc->getIndirectFuncPtr()) {
- V9LiveRange *AddrValLR = LRI->getLiveRangeForValue( AddrVal );
- // LR can be null if the function pointer is a constant.
- if (AddrValLR)
- AddrValLR->setCallInterference();
- }
-}
-
-
-/// Create interferences in the IG of each RegClass, and calculate the spill
-/// cost of each Live Range (it is done in this method to save another pass
-/// over the code).
-///
-void PhyRegAlloc::buildInterferenceGraphs() {
- if (DEBUG_RA >= RA_DEBUG_Interference)
- std::cerr << "Creating interference graphs ...\n";
-
- unsigned BBLoopDepthCost;
- for (MachineFunction::iterator BBI = MF->begin(), BBE = MF->end();
- BBI != BBE; ++BBI) {
- const MachineBasicBlock &MBB = *BBI;
- const BasicBlock *BB = MBB.getBasicBlock();
-
- // find the 10^(loop_depth) of this BB
- BBLoopDepthCost = (unsigned)pow(10.0, LoopDepthCalc->getLoopDepth(BB));
-
- // get the iterator for machine instructions
- MachineBasicBlock::const_iterator MII = MBB.begin();
-
- // iterate over all the machine instructions in BB
- for ( ; MII != MBB.end(); ++MII) {
- const MachineInstr *MInst = MII;
-
- // get the LV set after the instruction
- const ValueSet &LVSetAI = LVI->getLiveVarSetAfterMInst(MInst, BB);
- bool isCallInst = TM.getInstrInfo()->isCall(MInst->getOpcode());
-
- if (isCallInst) {
- // set the isCallInterference flag of each live range which extends
- // across this call instruction. This information is used by graph
- // coloring algorithm to avoid allocating volatile colors to live ranges
- // that span across calls (since they have to be saved/restored)
- setCallInterferences(MInst, &LVSetAI);
- }
-
- // iterate over all MI operands to find defs
- for (MachineInstr::const_val_op_iterator OpI = MInst->begin(),
- OpE = MInst->end(); OpI != OpE; ++OpI) {
- if (OpI.isDef()) // create a new LR since def
- addInterference(*OpI, &LVSetAI, isCallInst);
-
- // Calculate the spill cost of each live range
- V9LiveRange *LR = LRI->getLiveRangeForValue(*OpI);
- if (LR) LR->addSpillCost(BBLoopDepthCost);
- }
- // Also add interference for any implicit definitions in a machine
- // instr (currently, only calls have this).
- unsigned NumOfImpRefs = MInst->getNumImplicitRefs();
- for (unsigned z=0; z < NumOfImpRefs; z++)
- if (MInst->getImplicitOp(z).isDef())
- addInterference( MInst->getImplicitRef(z), &LVSetAI, isCallInst );
- } // for all machine instructions in BB
- } // for all BBs in function
-
- // add interferences for function arguments. Since there are no explicit
- // defs in the function for args, we have to add them manually
- addInterferencesForArgs();
-
- if (DEBUG_RA >= RA_DEBUG_Interference)
- std::cerr << "Interference graphs calculated!\n";
-}
-
-
-/// Mark all operands of the given MachineInstr as interfering with one
-/// another.
-///
-void PhyRegAlloc::addInterf4PseudoInstr(const MachineInstr *MInst) {
- bool setInterf = false;
-
- // iterate over MI operands to find defs
- for (MachineInstr::const_val_op_iterator It1 = MInst->begin(),
- ItE = MInst->end(); It1 != ItE; ++It1) {
- const V9LiveRange *LROfOp1 = LRI->getLiveRangeForValue(*It1);
- assert((LROfOp1 || It1.isDef()) && "No LR for Def in PSEUDO insruction");
-
- MachineInstr::const_val_op_iterator It2 = It1;
- for (++It2; It2 != ItE; ++It2) {
- const V9LiveRange *LROfOp2 = LRI->getLiveRangeForValue(*It2);
-
- if (LROfOp2) {
- RegClass *RCOfOp1 = LROfOp1->getRegClass();
- RegClass *RCOfOp2 = LROfOp2->getRegClass();
-
- if (RCOfOp1 == RCOfOp2 ){
- RCOfOp1->setInterference( LROfOp1, LROfOp2 );
- setInterf = true;
- }
- } // if Op2 has a LR
- } // for all other defs in machine instr
- } // for all operands in an instruction
-
- if (!setInterf && MInst->getNumOperands() > 2) {
- std::cerr << "\nInterf not set for any operand in pseudo instr:\n";
- std::cerr << *MInst;
- assert(0 && "Interf not set for pseudo instr with > 2 operands" );
- }
-}
-
-
-/// Add interferences for incoming arguments to a function.
-///
-void PhyRegAlloc::addInterferencesForArgs() {
- // get the InSet of root BB
- const ValueSet &InSet = LVI->getInSetOfBB(&Fn->front());
-
- for (Function::const_arg_iterator AI = Fn->arg_begin(); AI != Fn->arg_end(); ++AI) {
- // add interferences between args and LVars at start
- addInterference(AI, &InSet, false);
-
- if (DEBUG_RA >= RA_DEBUG_Interference)
- std::cerr << " - %% adding interference for argument " << RAV(AI) << "\n";
- }
-}
-
-
-/// The following are utility functions used solely by updateMachineCode and
-/// the functions that it calls. They should probably be folded back into
-/// updateMachineCode at some point.
-///
-
-// used by: updateMachineCode (1 time), PrependInstructions (1 time)
-inline void InsertBefore(MachineInstr* newMI, MachineBasicBlock& MBB,
- MachineBasicBlock::iterator& MII) {
- MII = MBB.insert(MII, newMI);
- ++MII;
-}
-
-// used by: AppendInstructions (1 time)
-inline void InsertAfter(MachineInstr* newMI, MachineBasicBlock& MBB,
- MachineBasicBlock::iterator& MII) {
- ++MII; // insert before the next instruction
- MII = MBB.insert(MII, newMI);
-}
-
-// used by: updateMachineCode (2 times)
-inline void PrependInstructions(std::vector<MachineInstr *> &IBef,
- MachineBasicBlock& MBB,
- MachineBasicBlock::iterator& MII,
- const std::string& msg) {
- if (!IBef.empty()) {
- MachineInstr* OrigMI = MII;
- std::vector<MachineInstr *>::iterator AdIt;
- for (AdIt = IBef.begin(); AdIt != IBef.end() ; ++AdIt) {
- if (DEBUG_RA) {
- if (OrigMI) std::cerr << "For MInst:\n " << *OrigMI;
- std::cerr << msg << "PREPENDed instr:\n " << **AdIt << "\n";
- }
- InsertBefore(*AdIt, MBB, MII);
- }
- }
-}
-
-// used by: updateMachineCode (1 time)
-inline void AppendInstructions(std::vector<MachineInstr *> &IAft,
- MachineBasicBlock& MBB,
- MachineBasicBlock::iterator& MII,
- const std::string& msg) {
- if (!IAft.empty()) {
- MachineInstr* OrigMI = MII;
- std::vector<MachineInstr *>::iterator AdIt;
- for ( AdIt = IAft.begin(); AdIt != IAft.end() ; ++AdIt ) {
- if (DEBUG_RA) {
- if (OrigMI) std::cerr << "For MInst:\n " << *OrigMI;
- std::cerr << msg << "APPENDed instr:\n " << **AdIt << "\n";
- }
- InsertAfter(*AdIt, MBB, MII);
- }
- }
-}
-
-/// Set the registers for operands in the given MachineInstr, if a register was
-/// successfully allocated. Return true if any of its operands has been marked
-/// for spill.
-///
-bool PhyRegAlloc::markAllocatedRegs(MachineInstr* MInst)
-{
- bool instrNeedsSpills = false;
-
- // First, set the registers for operands in the machine instruction
- // if a register was successfully allocated. Do this first because we
- // will need to know which registers are already used by this instr'n.
- for (unsigned OpNum=0; OpNum < MInst->getNumOperands(); ++OpNum) {
- MachineOperand& Op = MInst->getOperand(OpNum);
- if (Op.getType() == MachineOperand::MO_VirtualRegister ||
- Op.getType() == MachineOperand::MO_CCRegister) {
- const Value *const Val = Op.getVRegValue();
- if (const V9LiveRange* LR = LRI->getLiveRangeForValue(Val)) {
- // Remember if any operand needs spilling
- instrNeedsSpills |= LR->isMarkedForSpill();
-
- // An operand may have a color whether or not it needs spilling
- if (LR->hasColor())
- MInst->SetRegForOperand(OpNum,
- MRI.getUnifiedRegNum(LR->getRegClassID(),
- LR->getColor()));
- }
- }
- } // for each operand
-
- return instrNeedsSpills;
-}
-
-/// Mark allocated registers (using markAllocatedRegs()) on the instruction
-/// that MII points to. Then, if it's a call instruction, insert caller-saving
-/// code before and after it. Finally, insert spill code before and after it,
-/// using insertCode4SpilledLR().
-///
-void PhyRegAlloc::updateInstruction(MachineBasicBlock::iterator& MII,
- MachineBasicBlock &MBB) {
- MachineInstr* MInst = MII;
- unsigned Opcode = MInst->getOpcode();
-
- // Reset tmp stack positions so they can be reused for each machine instr.
- MF->getInfo<SparcV9FunctionInfo>()->popAllTempValues();
-
- // Mark the operands for which regs have been allocated.
- bool instrNeedsSpills = markAllocatedRegs(MII);
-
-#ifndef NDEBUG
- // Mark that the operands have been updated. Later,
- // setRelRegsUsedByThisInst() is called to find registers used by each
- // MachineInst, and it should not be used for an instruction until
- // this is done. This flag just serves as a sanity check.
- OperandsColoredMap[MInst] = true;
-#endif
-
- // Now insert caller-saving code before/after the call.
- // Do this before inserting spill code since some registers must be
- // used by save/restore and spill code should not use those registers.
- if (TM.getInstrInfo()->isCall(Opcode)) {
- AddedInstrns &AI = AddedInstrMap[MInst];
- insertCallerSavingCode(AI.InstrnsBefore, AI.InstrnsAfter, MInst,
- MBB.getBasicBlock());
- }
-
- // Now insert spill code for remaining operands not allocated to
- // registers. This must be done even for call return instructions
- // since those are not handled by the special code above.
- if (instrNeedsSpills)
- for (unsigned OpNum=0; OpNum < MInst->getNumOperands(); ++OpNum) {
- MachineOperand& Op = MInst->getOperand(OpNum);
- if (Op.getType() == MachineOperand::MO_VirtualRegister ||
- Op.getType() == MachineOperand::MO_CCRegister) {
- const Value* Val = Op.getVRegValue();
- if (const V9LiveRange *LR = LRI->getLiveRangeForValue(Val))
- if (LR->isMarkedForSpill())
- insertCode4SpilledLR(LR, MII, MBB, OpNum);
- }
- } // for each operand
-}
-
-/// Iterate over all the MachineBasicBlocks in the current function and set
-/// the allocated registers for each instruction (using updateInstruction()),
-/// after register allocation is complete. Then move code out of delay slots.
-///
-void PhyRegAlloc::updateMachineCode()
-{
- // Insert any instructions needed at method entry
- MachineBasicBlock::iterator MII = MF->front().begin();
- PrependInstructions(AddedInstrAtEntry.InstrnsBefore, MF->front(), MII,
- "At function entry: \n");
- assert(AddedInstrAtEntry.InstrnsAfter.empty() &&
- "InstrsAfter should be unnecessary since we are just inserting at "
- "the function entry point here.");
-
- for (MachineFunction::iterator BBI = MF->begin(), BBE = MF->end();
- BBI != BBE; ++BBI) {
- MachineBasicBlock &MBB = *BBI;
-
- // Iterate over all machine instructions in BB and mark operands with
- // their assigned registers or insert spill code, as appropriate.
- // Also, fix operands of call/return instructions.
- for (MachineBasicBlock::iterator MII = MBB.begin(); MII != MBB.end(); ++MII)
- if (MII->getOpcode() != V9::PHI)
- updateInstruction(MII, MBB);
-
- // Now, move code out of delay slots of branches and returns if needed.
- // (Also, move "after" code from calls to the last delay slot instruction.)
- // Moving code out of delay slots is needed in 2 situations:
- // (1) If this is a branch and it needs instructions inserted after it,
- // move any existing instructions out of the delay slot so that the
- // instructions can go into the delay slot. This only supports the
- // case that #instrsAfter <= #delay slots.
- //
- // (2) If any instruction in the delay slot needs
- // instructions inserted, move it out of the delay slot and before the
- // branch because putting code before or after it would be VERY BAD!
- //
- // If the annul bit of the branch is set, neither of these is legal!
- // If so, we need to handle spill differently but annulling is not yet used.
- for (MachineBasicBlock::iterator MII = MBB.begin(); MII != MBB.end(); ++MII)
- if (unsigned delaySlots =
- TM.getInstrInfo()->getNumDelaySlots(MII->getOpcode())) {
- MachineBasicBlock::iterator DelaySlotMI = next(MII);
- assert(DelaySlotMI != MBB.end() && "no instruction for delay slot");
-
- // Check the 2 conditions above:
- // (1) Does a branch need instructions added after it?
- // (2) O/w does delay slot instr. need instrns before or after?
- bool isBranch = (TM.getInstrInfo()->isBranch(MII->getOpcode()) ||
- TM.getInstrInfo()->isReturn(MII->getOpcode()));
- bool cond1 = (isBranch &&
- AddedInstrMap.count(MII) &&
- AddedInstrMap[MII].InstrnsAfter.size() > 0);
- bool cond2 = (AddedInstrMap.count(DelaySlotMI) &&
- (AddedInstrMap[DelaySlotMI].InstrnsBefore.size() > 0 ||
- AddedInstrMap[DelaySlotMI].InstrnsAfter.size() > 0));
-
- if (cond1 || cond2) {
- assert(delaySlots==1 &&
- "InsertBefore does not yet handle >1 delay slots!");
-
- if (DEBUG_RA) {
- std::cerr << "\nRegAlloc: Moved instr. with added code: "
- << *DelaySlotMI
- << " out of delay slots of instr: " << *MII;
- }
-
- // move instruction before branch
- MBB.insert(MII, MBB.remove(DelaySlotMI++));
-
- // On cond1 we are done (we already moved the
- // instruction out of the delay slot). On cond2 we need
- // to insert a nop in place of the moved instruction
- if (cond2) {
- MBB.insert(MII, BuildMI(V9::NOP, 1));
- }
- }
- else {
- // For non-branch instr with delay slots (probably a call), move
- // InstrAfter to the instr. in the last delay slot.
- MachineBasicBlock::iterator tmp = next(MII, delaySlots);
- move2DelayedInstr(MII, tmp);
- }
- }
-
- // Finally iterate over all instructions in BB and insert before/after
- for (MachineBasicBlock::iterator MII=MBB.begin(); MII != MBB.end(); ++MII) {
- MachineInstr *MInst = MII;
-
- // do not process Phis
- if (MInst->getOpcode() == V9::PHI)
- continue;
-
- // if there are any added instructions...
- if (AddedInstrMap.count(MInst)) {
- AddedInstrns &CallAI = AddedInstrMap[MInst];
-
-#ifndef NDEBUG
- bool isBranch = (TM.getInstrInfo()->isBranch(MInst->getOpcode()) ||
- TM.getInstrInfo()->isReturn(MInst->getOpcode()));
- assert((!isBranch ||
- AddedInstrMap[MInst].InstrnsAfter.size() <=
- TM.getInstrInfo()->getNumDelaySlots(MInst->getOpcode())) &&
- "Cannot put more than #delaySlots instrns after "
- "branch or return! Need to handle temps differently.");
-#endif
-
-#ifndef NDEBUG
- // Temporary sanity checking code to detect whether the same machine
- // instruction is ever inserted twice before/after a call.
- // I suspect this is happening but am not sure. --Vikram, 7/1/03.
- std::set<const MachineInstr*> instrsSeen;
- for (int i = 0, N = CallAI.InstrnsBefore.size(); i < N; ++i) {
- assert(instrsSeen.count(CallAI.InstrnsBefore[i]) == 0 &&
- "Duplicate machine instruction in InstrnsBefore!");
- instrsSeen.insert(CallAI.InstrnsBefore[i]);
- }
- for (int i = 0, N = CallAI.InstrnsAfter.size(); i < N; ++i) {
- assert(instrsSeen.count(CallAI.InstrnsAfter[i]) == 0 &&
- "Duplicate machine instruction in InstrnsBefore/After!");
- instrsSeen.insert(CallAI.InstrnsAfter[i]);
- }
-#endif
-
- // Now add the instructions before/after this MI.
- // We do this here to ensure that spill for an instruction is inserted
- // as close as possible to an instruction (see above insertCode4Spill)
- if (! CallAI.InstrnsBefore.empty())
- PrependInstructions(CallAI.InstrnsBefore, MBB, MII,"");
-
- if (! CallAI.InstrnsAfter.empty())
- AppendInstructions(CallAI.InstrnsAfter, MBB, MII,"");
-
- } // if there are any added instructions
- } // for each machine instruction
- }
-}
-
-
-/// Insert spill code for AN operand whose LR was spilled. May be called
-/// repeatedly for a single MachineInstr if it has many spilled operands. On
-/// each call, it finds a register which is not live at that instruction and
-/// also which is not used by other spilled operands of the same
-/// instruction. Then it uses this register temporarily to accommodate the
-/// spilled value.
-///
-void PhyRegAlloc::insertCode4SpilledLR(const V9LiveRange *LR,
- MachineBasicBlock::iterator& MII,
- MachineBasicBlock &MBB,
- const unsigned OpNum) {
- MachineInstr *MInst = MII;
- const BasicBlock *BB = MBB.getBasicBlock();
-
- assert((! TM.getInstrInfo()->isCall(MInst->getOpcode()) || OpNum == 0) &&
- "Outgoing arg of a call must be handled elsewhere (func arg ok)");
- assert(! TM.getInstrInfo()->isReturn(MInst->getOpcode()) &&
- "Return value of a ret must be handled elsewhere");
-
- MachineOperand& Op = MInst->getOperand(OpNum);
- bool isDef = Op.isDef();
- bool isUse = Op.isUse();
- unsigned RegType = MRI.getRegTypeForLR(LR);
- int SpillOff = LR->getSpillOffFromFP();
- RegClass *RC = LR->getRegClass();
-
- // Get the live-variable set to find registers free before this instr.
- const ValueSet &LVSetBef = LVI->getLiveVarSetBeforeMInst(MInst, BB);
-
-#ifndef NDEBUG
- // If this instr. is in the delay slot of a branch or return, we need to
- // include all live variables before that branch or return -- we don't want to
- // trample those! Verify that the set is included in the LV set before MInst.
- if (MII != MBB.begin()) {
- MachineBasicBlock::iterator PredMI = prior(MII);
- if (unsigned DS = TM.getInstrInfo()->getNumDelaySlots(PredMI->getOpcode()))
- assert(set_difference(LVI->getLiveVarSetBeforeMInst(PredMI), LVSetBef)
- .empty() && "Live-var set before branch should be included in "
- "live-var set of each delay slot instruction!");
- }
-#endif
-
- MF->getInfo<SparcV9FunctionInfo>()->pushTempValue(MRI.getSpilledRegSize(RegType));
-
- std::vector<MachineInstr*> MIBef, MIAft;
- std::vector<MachineInstr*> AdIMid;
-
- // Choose a register to hold the spilled value, if one was not preallocated.
- // This may insert code before and after MInst to free up the value. If so,
- // this code should be first/last in the spill sequence before/after MInst.
- int TmpRegU=(LR->hasColor()
- ? MRI.getUnifiedRegNum(LR->getRegClassID(),LR->getColor())
- : getUsableUniRegAtMI(RegType, &LVSetBef, MInst, MIBef,MIAft));
-
- // Set the operand first so that it this register does not get used
- // as a scratch register for later calls to getUsableUniRegAtMI below
- MInst->SetRegForOperand(OpNum, TmpRegU);
-
- // get the added instructions for this instruction
- AddedInstrns &AI = AddedInstrMap[MInst];
-
- // We may need a scratch register to copy the spilled value to/from memory.
- // This may itself have to insert code to free up a scratch register.
- // Any such code should go before (after) the spill code for a load (store).
- // The scratch reg is not marked as used because it is only used
- // for the copy and not used across MInst.
- int scratchRegType = -1;
- int scratchReg = -1;
- if (MRI.regTypeNeedsScratchReg(RegType, scratchRegType)) {
- scratchReg = getUsableUniRegAtMI(scratchRegType, &LVSetBef,
- MInst, MIBef, MIAft);
- assert(scratchReg != MRI.getInvalidRegNum());
- }
-
- if (isUse) {
- // for a USE, we have to load the value of LR from stack to a TmpReg
- // and use the TmpReg as one operand of instruction
-
- // actual loading instruction(s)
- MRI.cpMem2RegMI(AdIMid, MRI.getFramePointer(), SpillOff, TmpRegU,
- RegType, scratchReg);
-
- // the actual load should be after the instructions to free up TmpRegU
- MIBef.insert(MIBef.end(), AdIMid.begin(), AdIMid.end());
- AdIMid.clear();
- }
-
- if (isDef) { // if this is a Def
- // for a DEF, we have to store the value produced by this instruction
- // on the stack position allocated for this LR
-
- // actual storing instruction(s)
- MRI.cpReg2MemMI(AdIMid, TmpRegU, MRI.getFramePointer(), SpillOff,
- RegType, scratchReg);
-
- MIAft.insert(MIAft.begin(), AdIMid.begin(), AdIMid.end());
- } // if !DEF
-
- // Finally, insert the entire spill code sequences before/after MInst
- AI.InstrnsBefore.insert(AI.InstrnsBefore.end(), MIBef.begin(), MIBef.end());
- AI.InstrnsAfter.insert(AI.InstrnsAfter.begin(), MIAft.begin(), MIAft.end());
- ++RASpills;
-
- if (DEBUG_RA) {
- std::cerr << "\nFor Inst:\n " << *MInst;
- std::cerr << "SPILLED LR# " << LR->getUserIGNode()->getIndex();
- std::cerr << "; added Instructions:";
- for_each(MIBef.begin(), MIBef.end(), std::mem_fun(&MachineInstr::dump));
- for_each(MIAft.begin(), MIAft.end(), std::mem_fun(&MachineInstr::dump));
- }
-}
-
-
-/// Insert caller saving/restoring instructions before/after a call machine
-/// instruction (before or after any other instructions that were inserted for
-/// the call).
-///
-void
-PhyRegAlloc::insertCallerSavingCode(std::vector<MachineInstr*> &instrnsBefore,
- std::vector<MachineInstr*> &instrnsAfter,
- MachineInstr *CallMI,
- const BasicBlock *BB) {
- assert(TM.getInstrInfo()->isCall(CallMI->getOpcode()));
-
- // hash set to record which registers were saved/restored
- hash_set<unsigned> PushedRegSet;
-
- CallArgsDescriptor* argDesc = CallArgsDescriptor::get(CallMI);
-
- // if the call is to a instrumentation function, do not insert save and
- // restore instructions the instrumentation function takes care of save
- // restore for volatile regs.
- //
- // FIXME: this should be made general, not specific to the reoptimizer!
- const Function *Callee = argDesc->getCallInst()->getCalledFunction();
- bool isLLVMFirstTrigger = Callee && Callee->getName() == "llvm_first_trigger";
-
- // Now check if the call has a return value (using argDesc) and if so,
- // find the LR of the TmpInstruction representing the return value register.
- // (using the last or second-last *implicit operand* of the call MI).
- // Insert it to to the PushedRegSet since we must not save that register
- // and restore it after the call.
- // We do this because, we look at the LV set *after* the instruction
- // to determine, which LRs must be saved across calls. The return value
- // of the call is live in this set - but we must not save/restore it.
- if (const Value *origRetVal = argDesc->getReturnValue()) {
- unsigned retValRefNum = (CallMI->getNumImplicitRefs() -
- (argDesc->getIndirectFuncPtr()? 1 : 2));
- const TmpInstruction* tmpRetVal =
- cast<TmpInstruction>(CallMI->getImplicitRef(retValRefNum));
- assert(tmpRetVal->getOperand(0) == origRetVal &&
- tmpRetVal->getType() == origRetVal->getType() &&
- "Wrong implicit ref?");
- V9LiveRange *RetValLR = LRI->getLiveRangeForValue(tmpRetVal);
- assert(RetValLR && "No LR for RetValue of call");
-
- if (! RetValLR->isMarkedForSpill())
- PushedRegSet.insert(MRI.getUnifiedRegNum(RetValLR->getRegClassID(),
- RetValLR->getColor()));
- }
-
- const ValueSet &LVSetAft = LVI->getLiveVarSetAfterMInst(CallMI, BB);
- ValueSet::const_iterator LIt = LVSetAft.begin();
-
- // for each live var in live variable set after machine inst
- for( ; LIt != LVSetAft.end(); ++LIt) {
- // get the live range corresponding to live var
- V9LiveRange *const LR = LRI->getLiveRangeForValue(*LIt);
-
- // LR can be null if it is a const since a const
- // doesn't have a dominating def - see Assumptions above
- if (LR) {
- if (! LR->isMarkedForSpill()) {
- assert(LR->hasColor() && "LR is neither spilled nor colored?");
- unsigned RCID = LR->getRegClassID();
- unsigned Color = LR->getColor();
-
- if (MRI.isRegVolatile(RCID, Color) ) {
- // if this is a call to the first-level reoptimizer
- // instrumentation entry point, and the register is not
- // modified by call, don't save and restore it.
- if (isLLVMFirstTrigger && !MRI.modifiedByCall(RCID, Color))
- continue;
-
- // if the value is in both LV sets (i.e., live before and after
- // the call machine instruction)
- unsigned Reg = MRI.getUnifiedRegNum(RCID, Color);
-
- // if we haven't already pushed this register...
- if( PushedRegSet.find(Reg) == PushedRegSet.end() ) {
- unsigned RegType = MRI.getRegTypeForLR(LR);
-
- // Now get two instructions - to push on stack and pop from stack
- // and add them to InstrnsBefore and InstrnsAfter of the
- // call instruction
- int StackOff =
- MF->getInfo<SparcV9FunctionInfo>()->pushTempValue(MRI.getSpilledRegSize(RegType));
-
- //---- Insert code for pushing the reg on stack ----------
-
- std::vector<MachineInstr*> AdIBef, AdIAft;
-
- // We may need a scratch register to copy the saved value
- // to/from memory. This may itself have to insert code to
- // free up a scratch register. Any such code should go before
- // the save code. The scratch register, if any, is by default
- // temporary and not "used" by the instruction unless the
- // copy code itself decides to keep the value in the scratch reg.
- int scratchRegType = -1;
- int scratchReg = -1;
- if (MRI.regTypeNeedsScratchReg(RegType, scratchRegType))
- { // Find a register not live in the LVSet before CallMI
- const ValueSet &LVSetBef =
- LVI->getLiveVarSetBeforeMInst(CallMI, BB);
- scratchReg = getUsableUniRegAtMI(scratchRegType, &LVSetBef,
- CallMI, AdIBef, AdIAft);
- assert(scratchReg != MRI.getInvalidRegNum());
- }
-
- if (AdIBef.size() > 0)
- instrnsBefore.insert(instrnsBefore.end(),
- AdIBef.begin(), AdIBef.end());
-
- MRI.cpReg2MemMI(instrnsBefore, Reg, MRI.getFramePointer(),
- StackOff, RegType, scratchReg);
-
- if (AdIAft.size() > 0)
- instrnsBefore.insert(instrnsBefore.end(),
- AdIAft.begin(), AdIAft.end());
-
- //---- Insert code for popping the reg from the stack ----------
- AdIBef.clear();
- AdIAft.clear();
-
- // We may need a scratch register to copy the saved value
- // from memory. This may itself have to insert code to
- // free up a scratch register. Any such code should go
- // after the save code. As above, scratch is not marked "used".
- scratchRegType = -1;
- scratchReg = -1;
- if (MRI.regTypeNeedsScratchReg(RegType, scratchRegType))
- { // Find a register not live in the LVSet after CallMI
- scratchReg = getUsableUniRegAtMI(scratchRegType, &LVSetAft,
- CallMI, AdIBef, AdIAft);
- assert(scratchReg != MRI.getInvalidRegNum());
- }
-
- if (AdIBef.size() > 0)
- instrnsAfter.insert(instrnsAfter.end(),
- AdIBef.begin(), AdIBef.end());
-
- MRI.cpMem2RegMI(instrnsAfter, MRI.getFramePointer(), StackOff,
- Reg, RegType, scratchReg);
-
- if (AdIAft.size() > 0)
- instrnsAfter.insert(instrnsAfter.end(),
- AdIAft.begin(), AdIAft.end());
-
- PushedRegSet.insert(Reg);
-
- if(DEBUG_RA) {
- std::cerr << "\nFor call inst:" << *CallMI;
- std::cerr << " -inserted caller saving instrs: Before:\n\t ";
- for_each(instrnsBefore.begin(), instrnsBefore.end(),
- std::mem_fun(&MachineInstr::dump));
- std::cerr << " -and After:\n\t ";
- for_each(instrnsAfter.begin(), instrnsAfter.end(),
- std::mem_fun(&MachineInstr::dump));
- }
- } // if not already pushed
- } // if LR has a volatile color
- } // if LR has color
- } // if there is a LR for Var
- } // for each value in the LV set after instruction
-}
-
-
-/// Returns the unified register number of a temporary register to be used
-/// BEFORE MInst. If no register is available, it will pick one and modify
-/// MIBef and MIAft to contain instructions used to free up this returned
-/// register.
-///
-int PhyRegAlloc::getUsableUniRegAtMI(const int RegType,
- const ValueSet *LVSetBef,
- MachineInstr *MInst,
- std::vector<MachineInstr*>& MIBef,
- std::vector<MachineInstr*>& MIAft) {
- RegClass* RC = getRegClassByID(MRI.getRegClassIDOfRegType(RegType));
-
- int RegU = getUnusedUniRegAtMI(RC, RegType, MInst, LVSetBef);
-
- if (RegU == -1) {
- // we couldn't find an unused register. Generate code to free up a reg by
- // saving it on stack and restoring after the instruction
-
- int TmpOff = MF->getInfo<SparcV9FunctionInfo>()->pushTempValue(MRI.getSpilledRegSize(RegType));
-
- RegU = getUniRegNotUsedByThisInst(RC, RegType, MInst);
-
- // Check if we need a scratch register to copy this register to memory.
- int scratchRegType = -1;
- if (MRI.regTypeNeedsScratchReg(RegType, scratchRegType)) {
- int scratchReg = getUsableUniRegAtMI(scratchRegType, LVSetBef,
- MInst, MIBef, MIAft);
- assert(scratchReg != MRI.getInvalidRegNum());
-
- // We may as well hold the value in the scratch register instead
- // of copying it to memory and back. But we have to mark the
- // register as used by this instruction, so it does not get used
- // as a scratch reg. by another operand or anyone else.
- ScratchRegsUsed.insert(std::make_pair(MInst, scratchReg));
- MRI.cpReg2RegMI(MIBef, RegU, scratchReg, RegType);
- MRI.cpReg2RegMI(MIAft, scratchReg, RegU, RegType);
- } else { // the register can be copied directly to/from memory so do it.
- MRI.cpReg2MemMI(MIBef, RegU, MRI.getFramePointer(), TmpOff, RegType);
- MRI.cpMem2RegMI(MIAft, MRI.getFramePointer(), TmpOff, RegU, RegType);
- }
- }
-
- return RegU;
-}
-
-
-/// Returns the register-class register number of a new unused register that
-/// can be used to accommodate a temporary value. May be called repeatedly
-/// for a single MachineInstr. On each call, it finds a register which is not
-/// live at that instruction and which is not used by any spilled operands of
-/// that instruction.
-///
-int PhyRegAlloc::getUnusedUniRegAtMI(RegClass *RC, const int RegType,
- const MachineInstr *MInst,
- const ValueSet* LVSetBef) {
- RC->clearColorsUsed(); // Reset array
-
- if (LVSetBef == NULL) {
- LVSetBef = &LVI->getLiveVarSetBeforeMInst(MInst);
- assert(LVSetBef != NULL && "Unable to get live-var set before MInst?");
- }
-
- ValueSet::const_iterator LIt = LVSetBef->begin();
-
- // for each live var in live variable set after machine inst
- for ( ; LIt != LVSetBef->end(); ++LIt) {
- // Get the live range corresponding to live var, and its RegClass
- V9LiveRange *const LRofLV = LRI->getLiveRangeForValue(*LIt );
-
- // LR can be null if it is a const since a const
- // doesn't have a dominating def - see Assumptions above
- if (LRofLV && LRofLV->getRegClass() == RC && LRofLV->hasColor())
- RC->markColorsUsed(LRofLV->getColor(),
- MRI.getRegTypeForLR(LRofLV), RegType);
- }
-
- // It is possible that one operand of this MInst was already spilled
- // and it received some register temporarily. If that's the case,
- // it is recorded in machine operand. We must skip such registers.
- setRelRegsUsedByThisInst(RC, RegType, MInst);
-
- int unusedReg = RC->getUnusedColor(RegType); // find first unused color
- if (unusedReg >= 0)
- return MRI.getUnifiedRegNum(RC->getID(), unusedReg);
-
- return -1;
-}
-
-
-/// Return the unified register number of a register in class RC which is not
-/// used by any operands of MInst.
-///
-int PhyRegAlloc::getUniRegNotUsedByThisInst(RegClass *RC,
- const int RegType,
- const MachineInstr *MInst) {
- RC->clearColorsUsed();
-
- setRelRegsUsedByThisInst(RC, RegType, MInst);
-
- // find the first unused color
- int unusedReg = RC->getUnusedColor(RegType);
- assert(unusedReg >= 0 &&
- "FATAL: No free register could be found in reg class!!");
-
- return MRI.getUnifiedRegNum(RC->getID(), unusedReg);
-}
-
-
-/// Modify the IsColorUsedArr of register class RC, by setting the bits
-/// corresponding to register RegNo. This is a helper method of
-/// setRelRegsUsedByThisInst().
-///
-static void markRegisterUsed(int RegNo, RegClass *RC, int RegType,
- const SparcV9RegInfo &TRI) {
- unsigned classId = 0;
- int classRegNum = TRI.getClassRegNum(RegNo, classId);
- if (RC->getID() == classId)
- RC->markColorsUsed(classRegNum, RegType, RegType);
-}
-
-void PhyRegAlloc::setRelRegsUsedByThisInst(RegClass *RC, int RegType,
- const MachineInstr *MI) {
- assert(OperandsColoredMap[MI] == true &&
- "Illegal to call setRelRegsUsedByThisInst() until colored operands "
- "are marked for an instruction.");
-
- // Add the registers already marked as used by the instruction. Both
- // explicit and implicit operands are set.
- for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i)
- if (MI->getOperand(i).hasAllocatedReg())
- markRegisterUsed(MI->getOperand(i).getReg(), RC, RegType,MRI);
-
- for (unsigned i = 0, e = MI->getNumImplicitRefs(); i != e; ++i)
- if (MI->getImplicitOp(i).hasAllocatedReg())
- markRegisterUsed(MI->getImplicitOp(i).getReg(), RC, RegType,MRI);
-
- // Add all of the scratch registers that are used to save values across the
- // instruction (e.g., for saving state register values).
- std::pair<ScratchRegsUsedTy::iterator, ScratchRegsUsedTy::iterator>
- IR = ScratchRegsUsed.equal_range(MI);
- for (ScratchRegsUsedTy::iterator I = IR.first; I != IR.second; ++I)
- markRegisterUsed(I->second, RC, RegType, MRI);
-
- // If there are implicit references, mark their allocated regs as well
- for (unsigned z=0; z < MI->getNumImplicitRefs(); z++)
- if (const V9LiveRange*
- LRofImpRef = LRI->getLiveRangeForValue(MI->getImplicitRef(z)))
- if (LRofImpRef->hasColor())
- // this implicit reference is in a LR that received a color
- RC->markColorsUsed(LRofImpRef->getColor(),
- MRI.getRegTypeForLR(LRofImpRef), RegType);
-}
-
-
-/// If there are delay slots for an instruction, the instructions added after
-/// it must really go after the delayed instruction(s). So, we Move the
-/// InstrAfter of that instruction to the corresponding delayed instruction
-/// using the following method.
-///
-void PhyRegAlloc::move2DelayedInstr(const MachineInstr *OrigMI,
- const MachineInstr *DelayedMI)
-{
- // "added after" instructions of the original instr
- std::vector<MachineInstr *> &OrigAft = AddedInstrMap[OrigMI].InstrnsAfter;
-
- if (DEBUG_RA && OrigAft.size() > 0) {
- std::cerr << "\nRegAlloc: Moved InstrnsAfter for: " << *OrigMI;
- std::cerr << " to last delay slot instrn: " << *DelayedMI;
- }
-
- // "added after" instructions of the delayed instr
- std::vector<MachineInstr *> &DelayedAft=AddedInstrMap[DelayedMI].InstrnsAfter;
-
- // go thru all the "added after instructions" of the original instruction
- // and append them to the "added after instructions" of the delayed
- // instructions
- DelayedAft.insert(DelayedAft.end(), OrigAft.begin(), OrigAft.end());
-
- // empty the "added after instructions" of the original instruction
- OrigAft.clear();
-}
-
-
-void PhyRegAlloc::colorIncomingArgs()
-{
- MRI.colorMethodArgs(Fn, *LRI, AddedInstrAtEntry.InstrnsBefore,
- AddedInstrAtEntry.InstrnsAfter);
-}
-
-
-/// Determine whether the suggested color of each live range is really usable,
-/// and then call its setSuggestedColorUsable() method to record the answer. A
-/// suggested color is NOT usable when the suggested color is volatile AND
-/// when there are call interferences.
-///
-void PhyRegAlloc::markUnusableSugColors()
-{
- LiveRangeMapType::const_iterator HMI = (LRI->getLiveRangeMap())->begin();
- LiveRangeMapType::const_iterator HMIEnd = (LRI->getLiveRangeMap())->end();
-
- for (; HMI != HMIEnd ; ++HMI ) {
- if (HMI->first) {
- V9LiveRange *L = HMI->second; // get the V9LiveRange
- if (L && L->hasSuggestedColor ())
- L->setSuggestedColorUsable
- (!(MRI.isRegVolatile (L->getRegClassID (), L->getSuggestedColor ())
- && L->isCallInterference ()));
- }
- } // for all LR's in hash map
-}
-
-
-/// For each live range that is spilled, allocates a new spill position on the
-/// stack, and set the stack offsets of the live range that will be spilled to
-/// that position. This must be called just after coloring the LRs.
-///
-void PhyRegAlloc::allocateStackSpace4SpilledLRs() {
- if (DEBUG_RA) std::cerr << "\nSetting LR stack offsets for spills...\n";
-
- LiveRangeMapType::const_iterator HMI = LRI->getLiveRangeMap()->begin();
- LiveRangeMapType::const_iterator HMIEnd = LRI->getLiveRangeMap()->end();
-
- for ( ; HMI != HMIEnd ; ++HMI) {
- if (HMI->first && HMI->second) {
- V9LiveRange *L = HMI->second; // get the V9LiveRange
- if (L->isMarkedForSpill()) { // NOTE: allocating size of long Type **
- int stackOffset = MF->getInfo<SparcV9FunctionInfo>()->allocateSpilledValue(Type::LongTy);
- L->setSpillOffFromFP(stackOffset);
- if (DEBUG_RA)
- std::cerr << " LR# " << L->getUserIGNode()->getIndex()
- << ": stack-offset = " << stackOffset << "\n";
- }
- }
- } // for all LR's in hash map
-}
-
-
-void PhyRegAlloc::saveStateForValue (std::vector<AllocInfo> &state,
- const Value *V, int Insn, int Opnd) {
- LiveRangeMapType::const_iterator HMI = LRI->getLiveRangeMap ()->find (V);
- LiveRangeMapType::const_iterator HMIEnd = LRI->getLiveRangeMap ()->end ();
- AllocInfo::AllocStateTy AllocState = AllocInfo::NotAllocated;
- int Placement = -1;
- if ((HMI != HMIEnd) && HMI->second) {
- V9LiveRange *L = HMI->second;
- assert ((L->hasColor () || L->isMarkedForSpill ())
- && "Live range exists but not colored or spilled");
- if (L->hasColor ()) {
- AllocState = AllocInfo::Allocated;
- Placement = MRI.getUnifiedRegNum (L->getRegClassID (),
- L->getColor ());
- } else if (L->isMarkedForSpill ()) {
- AllocState = AllocInfo::Spilled;
- assert (L->hasSpillOffset ()
- && "Live range marked for spill but has no spill offset");
- Placement = L->getSpillOffFromFP ();
- }
- }
- state.push_back (AllocInfo (Insn, Opnd, AllocState, Placement));
-}
-
-
-/// Save the global register allocation decisions made by the register
-/// allocator so that they can be accessed later (sort of like "poor man's
-/// debug info").
-///
-void PhyRegAlloc::saveState () {
- std::vector<AllocInfo> &state = FnAllocState[Fn];
- unsigned ArgNum = 0;
- // Arguments encoded as instruction # -1
- for (Function::const_arg_iterator i=Fn->arg_begin (), e=Fn->arg_end (); i != e; ++i) {
- const Argument *Arg = &*i;
- saveStateForValue (state, Arg, -1, ArgNum);
- ++ArgNum;
- }
- unsigned InstCount = 0;
- // Instructions themselves encoded as operand # -1
- for (const_inst_iterator II=inst_begin (Fn), IE=inst_end (Fn); II!=IE; ++II){
- const Instruction *Inst = &*II;
- saveStateForValue (state, Inst, InstCount, -1);
- if (isa<PHINode> (Inst)) {
- MachineCodeForInstruction &MCforPN = MachineCodeForInstruction::get(Inst);
- // Last instr should be the copy...figure out what reg it is reading from
- if (Value *PhiCpRes = MCforPN.back()->getOperand(0).getVRegValueOrNull()){
- if (DEBUG_RA)
- std::cerr << "Found Phi copy result: " << PhiCpRes->getName()
- << " in: " << *MCforPN.back() << "\n";
- saveStateForValue (state, PhiCpRes, InstCount, -2);
- }
- }
- ++InstCount;
- }
-}
-
-
-bool PhyRegAlloc::doFinalization (Module &M) {
- if (SaveRegAllocState) finishSavingState (M);
- return false;
-}
-
-
-/// Finish the job of saveState(), by collapsing FnAllocState into an LLVM
-/// Constant and stuffing it inside the Module.
-///
-/// FIXME: There should be other, better ways of storing the saved
-/// state; this one is cumbersome and does not work well with the JIT.
-///
-void PhyRegAlloc::finishSavingState (Module &M) {
- if (DEBUG_RA)
- std::cerr << "---- Saving reg. alloc state; SaveStateToModule = "
- << SaveStateToModule << " ----\n";
-
- // If saving state into the module, just copy new elements to the
- // correct global.
- if (!SaveStateToModule) {
- ExportedFnAllocState = FnAllocState;
- // FIXME: should ONLY copy new elements in FnAllocState
- return;
- }
-
- // Convert FnAllocState to a single Constant array and add it
- // to the Module.
- ArrayType *AT = ArrayType::get (AllocInfo::getConstantType (), 0);
- std::vector<const Type *> TV;
- TV.push_back (Type::UIntTy);
- TV.push_back (AT);
- PointerType *PT = PointerType::get (StructType::get (TV));
-
- std::vector<Constant *> allstate;
- for (Module::iterator I = M.begin (), E = M.end (); I != E; ++I) {
- Function *F = I;
- if (F->isExternal ()) continue;
- if (FnAllocState.find (F) == FnAllocState.end ()) {
- allstate.push_back (ConstantPointerNull::get (PT));
- } else {
- std::vector<AllocInfo> &state = FnAllocState[F];
-
- // Convert state into an LLVM ConstantArray, and put it in a
- // ConstantStruct (named S) along with its size.
- std::vector<Constant *> stateConstants;
- for (unsigned i = 0, s = state.size (); i != s; ++i)
- stateConstants.push_back (state[i].toConstant ());
- unsigned Size = stateConstants.size ();
- ArrayType *AT = ArrayType::get (AllocInfo::getConstantType (), Size);
- std::vector<const Type *> TV;
- TV.push_back (Type::UIntTy);
- TV.push_back (AT);
- StructType *ST = StructType::get (TV);
- std::vector<Constant *> CV;
- CV.push_back (ConstantUInt::get (Type::UIntTy, Size));
- CV.push_back (ConstantArray::get (AT, stateConstants));
- Constant *S = ConstantStruct::get (ST, CV);
-
- GlobalVariable *GV =
- new GlobalVariable (ST, true,
- GlobalValue::InternalLinkage, S,
- F->getName () + ".regAllocState", &M);
-
- // Have: { uint, [Size x { uint, int, uint, int }] } *
- // Cast it to: { uint, [0 x { uint, int, uint, int }] } *
- Constant *CE = ConstantExpr::getCast (GV, PT);
- allstate.push_back (CE);
- }
- }
-
- unsigned Size = allstate.size ();
- // Final structure type is:
- // { uint, [Size x { uint, [0 x { uint, int, uint, int }] } *] }
- std::vector<const Type *> TV2;
- TV2.push_back (Type::UIntTy);
- ArrayType *AT2 = ArrayType::get (PT, Size);
- TV2.push_back (AT2);
- StructType *ST2 = StructType::get (TV2);
- std::vector<Constant *> CV2;
- CV2.push_back (ConstantUInt::get (Type::UIntTy, Size));
- CV2.push_back (ConstantArray::get (AT2, allstate));
- new GlobalVariable (ST2, true, GlobalValue::ExternalLinkage,
- ConstantStruct::get (ST2, CV2), "_llvm_regAllocState",
- &M);
-}
-
-
-/// Allocate registers for the machine code previously generated for F using
-/// the graph-coloring algorithm.
-///
-bool PhyRegAlloc::runOnFunction (Function &F) {
- if (DEBUG_RA)
- std::cerr << "\n********* Function "<< F.getName () << " ***********\n";
-
- Fn = &F;
- MF = &MachineFunction::get (Fn);
- LVI = &getAnalysis<FunctionLiveVarInfo> ();
- LRI = new LiveRangeInfo (Fn, TM, RegClassList);
- LoopDepthCalc = &getAnalysis<LoopInfo> ();
-
- // Create each RegClass for the target machine and add it to the
- // RegClassList. This must be done before calling constructLiveRanges().
- for (unsigned rc = 0; rc != NumOfRegClasses; ++rc)
- RegClassList.push_back (new RegClass (Fn, TM.getRegInfo(),
- MRI.getMachineRegClass(rc)));
-
- LRI->constructLiveRanges(); // create LR info
- if (DEBUG_RA >= RA_DEBUG_LiveRanges)
- LRI->printLiveRanges();
-
- createIGNodeListsAndIGs(); // create IGNode list and IGs
-
- buildInterferenceGraphs(); // build IGs in all reg classes
-
- if (DEBUG_RA >= RA_DEBUG_LiveRanges) {
- // print all LRs in all reg classes
- for ( unsigned rc=0; rc < NumOfRegClasses ; rc++)
- RegClassList[rc]->printIGNodeList();
-
- // print IGs in all register classes
- for ( unsigned rc=0; rc < NumOfRegClasses ; rc++)
- RegClassList[rc]->printIG();
- }
-
- LRI->coalesceLRs(); // coalesce all live ranges
-
- if (DEBUG_RA >= RA_DEBUG_LiveRanges) {
- // print all LRs in all reg classes
- for (unsigned rc=0; rc < NumOfRegClasses; rc++)
- RegClassList[rc]->printIGNodeList();
-
- // print IGs in all register classes
- for (unsigned rc=0; rc < NumOfRegClasses; rc++)
- RegClassList[rc]->printIG();
- }
-
- // mark un-usable suggested color before graph coloring algorithm.
- // When this is done, the graph coloring algo will not reserve
- // suggested color unnecessarily - they can be used by another LR
- markUnusableSugColors();
-
- // color all register classes using the graph coloring algo
- for (unsigned rc=0; rc < NumOfRegClasses ; rc++)
- RegClassList[rc]->colorAllRegs();
-
- // After graph coloring, if some LRs did not receive a color (i.e, spilled)
- // a position for such spilled LRs
- allocateStackSpace4SpilledLRs();
-
- // Reset the temp. area on the stack before use by the first instruction.
- // This will also happen after updating each instruction.
- MF->getInfo<SparcV9FunctionInfo>()->popAllTempValues();
-
- // color incoming args - if the correct color was not received
- // insert code to copy to the correct register
- colorIncomingArgs();
-
- // Save register allocation state for this function in a Constant.
- if (SaveRegAllocState)
- saveState();
-
- // Now update the machine code with register names and add any additional
- // code inserted by the register allocator to the instruction stream.
- updateMachineCode();
-
- if (SaveRegAllocState && !SaveStateToModule)
- finishSavingState (const_cast<Module&> (*Fn->getParent ()));
-
- if (DEBUG_RA) {
- std::cerr << "\n**** Machine Code After Register Allocation:\n\n";
- MF->dump();
- }
-
- // Tear down temporary data structures
- for (unsigned rc = 0; rc < NumOfRegClasses; ++rc)
- delete RegClassList[rc];
- RegClassList.clear ();
- AddedInstrMap.clear ();
- OperandsColoredMap.clear ();
- ScratchRegsUsed.clear ();
- AddedInstrAtEntry.clear ();
- delete LRI;
-
- if (DEBUG_RA) std::cerr << "\nRegister allocation complete!\n";
- return false; // Function was not modified
-}
-
-} // End llvm namespace
+++ /dev/null
-//===-- 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
+++ /dev/null
-//===-- 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
+++ /dev/null
-//===-- 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
+++ /dev/null
-//===-- 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
+++ /dev/null
-%{ // -*- 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]);
-}
+++ /dev/null
-//===- 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;
-}
+++ /dev/null
-//===-- 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);
-}
+++ /dev/null
-//===- SparcV9BurgISel.cpp - SparcV9 BURG-based Instruction Selector ------===//
-//
-// 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.
-//
-//===----------------------------------------------------------------------===//
-//
-// SparcV9 BURG-based instruction selector. It uses the SSA graph to
-// construct a forest of BURG instruction trees (class InstrForest) and then
-// uses the BURG-generated tree grammar (BURM) to find the optimal instruction
-// sequences for the SparcV9.
-//
-//===----------------------------------------------------------------------===//
-
-#include "MachineInstrAnnot.h"
-#include "SparcV9BurgISel.h"
-#include "SparcV9InstrForest.h"
-#include "SparcV9Internals.h"
-#include "SparcV9TmpInstr.h"
-#include "SparcV9FrameInfo.h"
-#include "SparcV9RegisterInfo.h"
-#include "MachineFunctionInfo.h"
-#include "llvm/CodeGen/IntrinsicLowering.h"
-#include "llvm/CodeGen/MachineConstantPool.h"
-#include "llvm/CodeGen/MachineFunction.h"
-#include "llvm/CodeGen/MachineInstr.h"
-#include "llvm/CodeGen/MachineInstrBuilder.h"
-#include "llvm/Constants.h"
-#include "llvm/DerivedTypes.h"
-#include "llvm/Instructions.h"
-#include "llvm/Intrinsics.h"
-#include "llvm/Module.h"
-#include "llvm/Pass.h"
-#include "llvm/Support/CFG.h"
-#include "llvm/Target/TargetInstrInfo.h"
-#include "llvm/Target/TargetMachine.h"
-#include "llvm/Type.h"
-#include "llvm/Config/alloca.h"
-#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/LeakDetector.h"
-#include "llvm/Support/MathExtras.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/hash_map"
-#include <algorithm>
-#include <cmath>
-#include <iostream>
-using namespace llvm;
-
-//==------------------------------------------------------------------------==//
-// InstrForest (V9ISel BURG instruction trees) implementation
-//==------------------------------------------------------------------------==//
-
-namespace llvm {
-
-class InstructionNode : public InstrTreeNode {
- bool codeIsFoldedIntoParent;
-
-public:
- InstructionNode(Instruction *_instr);
-
- Instruction *getInstruction() const {
- assert(treeNodeType == NTInstructionNode);
- return cast<Instruction>(val);
- }
-
- void markFoldedIntoParent() { codeIsFoldedIntoParent = true; }
- bool isFoldedIntoParent() { return codeIsFoldedIntoParent; }
-
- // Methods to support type inquiry through isa, cast, and dyn_cast:
- static inline bool classof(const InstructionNode *N) { return true; }
- static inline bool classof(const InstrTreeNode *N) {
- return N->getNodeType() == InstrTreeNode::NTInstructionNode;
- }
-
-protected:
- virtual void dumpNode(int indent) const;
-};
-
-class VRegListNode : public InstrTreeNode {
-public:
- VRegListNode() : InstrTreeNode(NTVRegListNode, 0) { opLabel = VRegListOp; }
- // Methods to support type inquiry through isa, cast, and dyn_cast:
- static inline bool classof(const VRegListNode *N) { return true; }
- static inline bool classof(const InstrTreeNode *N) {
- return N->getNodeType() == InstrTreeNode::NTVRegListNode;
- }
-protected:
- virtual void dumpNode(int indent) const;
-};
-
-class VRegNode : public InstrTreeNode {
-public:
- VRegNode(Value* _val) : InstrTreeNode(NTVRegNode, _val) {
- opLabel = VRegNodeOp;
- }
- // Methods to support type inquiry through isa, cast, and dyn_cast:
- static inline bool classof(const VRegNode *N) { return true; }
- static inline bool classof(const InstrTreeNode *N) {
- return N->getNodeType() == InstrTreeNode::NTVRegNode;
- }
-protected:
- virtual void dumpNode(int indent) const;
-};
-
-class ConstantNode : public InstrTreeNode {
-public:
- ConstantNode(Constant *constVal)
- : InstrTreeNode(NTConstNode, (Value*)constVal) {
- opLabel = ConstantNodeOp;
- }
- Constant *getConstVal() const { return (Constant*) val;}
- // Methods to support type inquiry through isa, cast, and dyn_cast:
- static inline bool classof(const ConstantNode *N) { return true; }
- static inline bool classof(const InstrTreeNode *N) {
- return N->getNodeType() == InstrTreeNode::NTConstNode;
- }
-protected:
- virtual void dumpNode(int indent) const;
-};
-
-class LabelNode : public InstrTreeNode {
-public:
- LabelNode(BasicBlock* BB) : InstrTreeNode(NTLabelNode, (Value*)BB) {
- opLabel = LabelNodeOp;
- }
- BasicBlock *getBasicBlock() const { return (BasicBlock*)val;}
- // Methods to support type inquiry through isa, cast, and dyn_cast:
- static inline bool classof(const LabelNode *N) { return true; }
- static inline bool classof(const InstrTreeNode *N) {
- return N->getNodeType() == InstrTreeNode::NTLabelNode;
- }
-protected:
- virtual void dumpNode(int indent) const;
-};
-
-/// InstrForest - A forest of instruction trees for a single function.
-/// The goal of InstrForest is to group instructions into a single
-/// tree if one or more of them might be potentially combined into a
-/// single complex instruction in the target machine. We group two
-/// instructions O and I if: (1) Instruction O computes an operand used
-/// by instruction I, and (2) O and I are part of the same basic block,
-/// and (3) O has only a single use, viz., I.
-///
-class InstrForest : private hash_map<const Instruction *, InstructionNode*> {
-public:
- // Use a vector for the root set to get a deterministic iterator
- // for stable code generation. Even though we need to erase nodes
- // during forest construction, a vector should still be efficient
- // because the elements to erase are nearly always near the end.
- typedef std::vector<InstructionNode*> RootSet;
- typedef RootSet:: iterator root_iterator;
- typedef RootSet::const_iterator const_root_iterator;
-
-private:
- RootSet treeRoots;
-
-public:
- /*ctor*/ InstrForest (Function *F);
- /*dtor*/ ~InstrForest ();
-
- /// getTreeNodeForInstr - Returns the tree node for an Instruction.
- ///
- inline InstructionNode *getTreeNodeForInstr(Instruction* instr) {
- return (*this)[instr];
- }
-
- /// Iterators for the root nodes for all the trees.
- ///
- const_root_iterator roots_begin() const { return treeRoots.begin(); }
- root_iterator roots_begin() { return treeRoots.begin(); }
- const_root_iterator roots_end () const { return treeRoots.end(); }
- root_iterator roots_end () { return treeRoots.end(); }
-
- void dump() const;
-
-private:
- // Methods used to build the instruction forest.
- void eraseRoot (InstructionNode* node);
- void setLeftChild (InstrTreeNode* parent, InstrTreeNode* child);
- void setRightChild(InstrTreeNode* parent, InstrTreeNode* child);
- void setParent (InstrTreeNode* child, InstrTreeNode* parent);
- void noteTreeNodeForInstr(Instruction* instr, InstructionNode* treeNode);
- InstructionNode* buildTreeForInstruction(Instruction* instr);
-};
-
-void InstrTreeNode::dump(int dumpChildren, int indent) const {
- dumpNode(indent);
-
- if (dumpChildren) {
- if (LeftChild)
- LeftChild->dump(dumpChildren, indent+1);
- if (RightChild)
- RightChild->dump(dumpChildren, indent+1);
- }
-}
-
-InstructionNode::InstructionNode(Instruction* I)
- : InstrTreeNode(NTInstructionNode, I), codeIsFoldedIntoParent(false) {
- opLabel = I->getOpcode();
-
- // Distinguish special cases of some instructions such as Ret and Br
- //
- if (opLabel == Instruction::Ret && cast<ReturnInst>(I)->getReturnValue()) {
- opLabel = RetValueOp; // ret(value) operation
- }
- else if (opLabel ==Instruction::Br && !cast<BranchInst>(I)->isUnconditional())
- {
- opLabel = BrCondOp; // br(cond) operation
- } else if (opLabel >= Instruction::SetEQ && opLabel <= Instruction::SetGT) {
- opLabel = SetCCOp; // common label for all SetCC ops
- } else if (opLabel == Instruction::Alloca && I->getNumOperands() > 0) {
- opLabel = AllocaN; // Alloca(ptr, N) operation
- } else if (opLabel == Instruction::GetElementPtr &&
- cast<GetElementPtrInst>(I)->hasIndices()) {
- opLabel = opLabel + 100; // getElem with index vector
- } else if (opLabel == Instruction::Xor &&
- BinaryOperator::isNot(I)) {
- opLabel = (I->getType() == Type::BoolTy)? NotOp // boolean Not operator
- : BNotOp; // bitwise Not operator
- } else if (opLabel == Instruction::And || opLabel == Instruction::Or ||
- opLabel == Instruction::Xor) {
- // Distinguish bitwise operators from logical operators!
- if (I->getType() != Type::BoolTy)
- opLabel = opLabel + 100; // bitwise operator
- } else if (opLabel == Instruction::Cast) {
- const Type *ITy = I->getType();
- switch(ITy->getTypeID())
- {
- case Type::BoolTyID: opLabel = ToBoolTy; break;
- case Type::UByteTyID: opLabel = ToUByteTy; break;
- case Type::SByteTyID: opLabel = ToSByteTy; break;
- case Type::UShortTyID: opLabel = ToUShortTy; break;
- case Type::ShortTyID: opLabel = ToShortTy; break;
- case Type::UIntTyID: opLabel = ToUIntTy; break;
- case Type::IntTyID: opLabel = ToIntTy; break;
- case Type::ULongTyID: opLabel = ToULongTy; break;
- case Type::LongTyID: opLabel = ToLongTy; break;
- case Type::FloatTyID: opLabel = ToFloatTy; break;
- case Type::DoubleTyID: opLabel = ToDoubleTy; break;
- case Type::ArrayTyID: opLabel = ToArrayTy; break;
- case Type::PointerTyID: opLabel = ToPointerTy; break;
- default:
- // Just use `Cast' opcode otherwise. It's probably ignored.
- break;
- }
- }
-}
-
-void InstructionNode::dumpNode(int indent) const {
- for (int i=0; i < indent; i++)
- std::cerr << " ";
- std::cerr << getInstruction()->getOpcodeName()
- << " [label " << getOpLabel() << "]" << "\n";
-}
-
-void VRegListNode::dumpNode(int indent) const {
- for (int i=0; i < indent; i++)
- std::cerr << " ";
-
- std::cerr << "List" << "\n";
-}
-
-void VRegNode::dumpNode(int indent) const {
- for (int i=0; i < indent; i++)
- std::cerr << " ";
- std::cerr << "VReg " << *getValue() << "\n";
-}
-
-void ConstantNode::dumpNode(int indent) const {
- for (int i=0; i < indent; i++)
- std::cerr << " ";
- std::cerr << "Constant " << *getValue() << "\n";
-}
-
-void LabelNode::dumpNode(int indent) const {
- for (int i=0; i < indent; i++)
- std::cerr << " ";
-
- std::cerr << "Label " << *getValue() << "\n";
-}
-
-/// InstrForest ctor - Create a forest of instruction trees for a
-/// single function.
-///
-InstrForest::InstrForest(Function *F) {
- for (Function::iterator BB = F->begin(), FE = F->end(); BB != FE; ++BB) {
- for(BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I)
- buildTreeForInstruction(I);
- }
-}
-
-InstrForest::~InstrForest() {
- for_each(treeRoots.begin(), treeRoots.end(), deleter<InstructionNode>);
-}
-
-void InstrForest::dump() const {
- for (const_root_iterator I = roots_begin(); I != roots_end(); ++I)
- (*I)->dump(/*dumpChildren*/ 1, /*indent*/ 0);
-}
-
-inline void InstrForest::eraseRoot(InstructionNode* node) {
- for (RootSet::reverse_iterator RI=treeRoots.rbegin(), RE=treeRoots.rend();
- RI != RE; ++RI)
- if (*RI == node)
- treeRoots.erase(RI.base()-1);
-}
-
-inline void InstrForest::noteTreeNodeForInstr(Instruction *instr,
- InstructionNode *treeNode) {
- (*this)[instr] = treeNode;
- treeRoots.push_back(treeNode); // mark node as root of a new tree
-}
-
-inline void InstrForest::setLeftChild(InstrTreeNode *parent,
- InstrTreeNode *child) {
- parent->LeftChild = child;
- child->Parent = parent;
- if (InstructionNode* instrNode = dyn_cast<InstructionNode>(child))
- eraseRoot(instrNode); // no longer a tree root
-}
-
-inline void InstrForest::setRightChild(InstrTreeNode *parent,
- InstrTreeNode *child) {
- parent->RightChild = child;
- child->Parent = parent;
- if (InstructionNode* instrNode = dyn_cast<InstructionNode>(child))
- eraseRoot(instrNode); // no longer a tree root
-}
-
-InstructionNode* InstrForest::buildTreeForInstruction(Instruction *instr) {
- InstructionNode *treeNode = getTreeNodeForInstr(instr);
- if (treeNode) {
- // treeNode has already been constructed for this instruction
- assert(treeNode->getInstruction() == instr);
- return treeNode;
- }
-
- // Otherwise, create a new tree node for this instruction.
- treeNode = new InstructionNode(instr);
- noteTreeNodeForInstr(instr, treeNode);
-
- if (instr->getOpcode() == Instruction::Call) {
- // Operands of call instruction
- return treeNode;
- }
-
- // If the instruction has more than 2 instruction operands,
- // then we need to create artificial list nodes to hold them.
- // (Note that we only count operands that get tree nodes, and not
- // others such as branch labels for a branch or switch instruction.)
- // To do this efficiently, we'll walk all operands, build treeNodes
- // for all appropriate operands and save them in an array. We then
- // insert children at the end, creating list nodes where needed.
- // As a performance optimization, allocate a child array only
- // if a fixed array is too small.
- int numChildren = 0;
- InstrTreeNode** childArray = new InstrTreeNode*[instr->getNumOperands()];
-
- // Walk the operands of the instruction
- for (Instruction::op_iterator O = instr->op_begin(); O!=instr->op_end();
- ++O) {
- Value* operand = *O;
-
- // Check if the operand is a data value, not an branch label, type,
- // method or module. If the operand is an address type (i.e., label
- // or method) that is used in an non-branching operation, e.g., `add'.
- // that should be considered a data value.
- // Check latter condition here just to simplify the next IF.
- bool includeAddressOperand =
- (isa<BasicBlock>(operand) || isa<Function>(operand))
- && !instr->isTerminator();
-
- if (includeAddressOperand || isa<Instruction>(operand) ||
- isa<Constant>(operand) || isa<Argument>(operand)) {
- // This operand is a data value.
- // An instruction that computes the incoming value is added as a
- // child of the current instruction if:
- // the value has only a single use
- // AND both instructions are in the same basic block.
- // AND the current instruction is not a PHI (because the incoming
- // value is conceptually in a predecessor block,
- // even though it may be in the same static block)
- // (Note that if the value has only a single use (viz., `instr'),
- // the def of the value can be safely moved just before instr
- // and therefore it is safe to combine these two instructions.)
- // In all other cases, the virtual register holding the value
- // is used directly, i.e., made a child of the instruction node.
- InstrTreeNode* opTreeNode;
- if (isa<Instruction>(operand) && operand->hasOneUse() &&
- cast<Instruction>(operand)->getParent() == instr->getParent() &&
- instr->getOpcode() != Instruction::PHI &&
- instr->getOpcode() != Instruction::Call) {
- // Recursively create a treeNode for it.
- opTreeNode = buildTreeForInstruction((Instruction*)operand);
- } else if (Constant *CPV = dyn_cast<Constant>(operand)) {
- if (isa<GlobalValue>(CPV))
- opTreeNode = new VRegNode(operand);
- else if (isa<UndefValue>(CPV)) {
- opTreeNode = new
- ConstantNode(Constant::getNullValue(CPV->getType()));
- } else {
- // Create a leaf node for a constant
- opTreeNode = new ConstantNode(CPV);
- }
- } else {
- // Create a leaf node for the virtual register
- opTreeNode = new VRegNode(operand);
- }
-
- childArray[numChildren++] = opTreeNode;
- }
- }
-
- // Add any selected operands as children in the tree.
- // Certain instructions can have more than 2 in some instances (viz.,
- // a CALL or a memory access -- LOAD, STORE, and GetElemPtr -- to an
- // array or struct). Make the operands of every such instruction into
- // a right-leaning binary tree with the operand nodes at the leaves
- // and VRegList nodes as internal nodes.
- InstrTreeNode *parent = treeNode;
-
- if (numChildren > 2) {
- unsigned instrOpcode = treeNode->getInstruction()->getOpcode();
- assert(instrOpcode == Instruction::PHI ||
- instrOpcode == Instruction::Call ||
- instrOpcode == Instruction::Load ||
- instrOpcode == Instruction::Store ||
- instrOpcode == Instruction::GetElementPtr);
- }
-
- // Insert the first child as a direct child
- if (numChildren >= 1)
- setLeftChild(parent, childArray[0]);
-
- int n;
-
- // Create a list node for children 2 .. N-1, if any
- for (n = numChildren-1; n >= 2; n--) {
- // We have more than two children
- InstrTreeNode *listNode = new VRegListNode();
- setRightChild(parent, listNode);
- setLeftChild(listNode, childArray[numChildren - n]);
- parent = listNode;
- }
-
- // Now insert the last remaining child (if any).
- if (numChildren >= 2) {
- assert(n == 1);
- setRightChild(parent, childArray[numChildren - 1]);
- }
-
- delete [] childArray;
- return treeNode;
-}
-//==------------------------------------------------------------------------==//
-// V9ISel Command-line options and declarations
-//==------------------------------------------------------------------------==//
-
-namespace {
- /// Allow the user to select the amount of debugging information printed
- /// out by V9ISel.
- ///
- enum SelectDebugLevel_t {
- Select_NoDebugInfo,
- Select_PrintMachineCode,
- Select_DebugInstTrees,
- Select_DebugBurgTrees,
- };
- cl::opt<SelectDebugLevel_t>
- SelectDebugLevel("dselect", cl::Hidden,
- cl::desc("enable instruction selection debug information"),
- cl::values(
- clEnumValN(Select_NoDebugInfo, "n", "disable debug output"),
- clEnumValN(Select_PrintMachineCode, "y", "print generated machine code"),
- clEnumValN(Select_DebugInstTrees, "i",
- "print debugging info for instruction selection"),
- clEnumValN(Select_DebugBurgTrees, "b", "print burg trees"),
- clEnumValEnd));
-
-
- /// V9ISel - This is the FunctionPass that drives the instruction selection
- /// process on the SparcV9 target.
- ///
- class V9ISel : public FunctionPass {
- TargetMachine &Target;
- void InsertCodeForPhis(Function &F);
- void InsertPhiElimInstructions(BasicBlock *BB,
- const std::vector<MachineInstr*>& CpVec);
- void SelectInstructionsForTree(InstrTreeNode* treeRoot, int goalnt);
- void PostprocessMachineCodeForTree(InstructionNode* instrNode,
- int ruleForNode, short* nts);
- public:
- V9ISel(TargetMachine &TM) : Target(TM) {}
-
- virtual void getAnalysisUsage(AnalysisUsage &AU) const {
- AU.setPreservesCFG();
- }
-
- bool runOnFunction(Function &F);
- virtual const char *getPassName() const {
- return "SparcV9 BURG Instruction Selector";
- }
- };
-}
-
-
-//==------------------------------------------------------------------------==//
-// Various V9ISel helper functions
-//==------------------------------------------------------------------------==//
-
-static const uint32_t MAXLO = (1 << 10) - 1; // set bits set by %lo(*)
-static const uint32_t MAXSIMM = (1 << 12) - 1; // set bits in simm13 field of OR
-
-/// ConvertConstantToIntType - Function to get the value of an integral
-/// constant in the form that must be put into the machine register. The
-/// specified constant is interpreted as (i.e., converted if necessary to) the
-/// specified destination type. The result is always returned as an uint64_t,
-/// since the representation of int64_t and uint64_t are identical. The
-/// argument can be any known const. isValidConstant is set to true if a valid
-/// constant was found.
-///
-uint64_t ConvertConstantToIntType(const TargetMachine &target, const Value *V,
- const Type *destType, bool &isValidConstant) {
- isValidConstant = false;
- uint64_t C = 0;
-
- if (! destType->isIntegral() && ! isa<PointerType>(destType))
- return C;
-
- if (! isa<Constant>(V) || isa<GlobalValue>(V))
- return C;
-
- // GlobalValue: no conversions needed: get value and return it
- if (const GlobalValue* GV = dyn_cast<GlobalValue>(V)) {
- isValidConstant = true; // may be overwritten by recursive call
- return ConvertConstantToIntType(target, GV, destType, isValidConstant);
- }
-
- // ConstantBool: no conversions needed: get value and return it
- if (const ConstantBool *CB = dyn_cast<ConstantBool>(V)) {
- isValidConstant = true;
- return (uint64_t) CB->getValue();
- }
-
- // ConstantPointerNull: it's really just a big, shiny version of zero.
- if (isa<ConstantPointerNull>(V)) {
- isValidConstant = true;
- return 0;
- }
-
- // For other types of constants, some conversion may be needed.
- // First, extract the constant operand according to its own type
- if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(V))
- switch(CE->getOpcode()) {
- case Instruction::Cast: // recursively get the value as cast
- C = ConvertConstantToIntType(target, CE->getOperand(0), CE->getType(),
- isValidConstant);
- break;
- default: // not simplifying other ConstantExprs
- break;
- }
- else if (const ConstantInt *CI = dyn_cast<ConstantInt>(V)) {
- isValidConstant = true;
- C = CI->getRawValue();
- } else if (const ConstantFP *CFP = dyn_cast<ConstantFP>(V)) {
- isValidConstant = true;
- double fC = CFP->getValue();
- C = (destType->isSigned()? (uint64_t) (int64_t) fC
- : (uint64_t) fC);
- } else if (isa<UndefValue>(V)) {
- isValidConstant = true;
- C = 0;
- }
-
- // Now if a valid value was found, convert it to destType.
- if (isValidConstant) {
- unsigned opSize = target.getTargetData().getTypeSize(V->getType());
- unsigned destSize = target.getTargetData().getTypeSize(destType);
- uint64_t maskHi = (destSize < 8)? (1U << 8*destSize) - 1 : ~0;
- assert(opSize <= 8 && destSize <= 8 && ">8-byte int type unexpected");
-
- if (destType->isSigned()) {
- if (opSize > destSize) // operand is larger than dest:
- C = C & maskHi; // mask high bits
-
- if (opSize > destSize ||
- (opSize == destSize && ! V->getType()->isSigned()))
- if (C & (1U << (8*destSize - 1)))
- C = C | ~maskHi; // sign-extend from destSize to 64 bits
- }
- else {
- if (opSize > destSize || (V->getType()->isSigned() && destSize < 8)) {
- // operand is larger than dest,
- // OR both are equal but smaller than the full register size
- // AND operand is signed, so it may have extra sign bits:
- // mask high bits
- C = C & maskHi;
- }
- }
- }
-
- return C;
-}
-
-/// CreateSETUWConst - Copy a 32-bit unsigned constant into the register
-/// `dest', using SETHI, OR in the worst case. This function correctly emulates
-/// the SETUW pseudo-op for SPARC v9 (if argument isSigned == false). The
-/// isSigned=true case is used to implement SETSW without duplicating code. It
-/// optimizes some common cases:
-/// (1) Small value that fits in simm13 field of OR: don't need SETHI.
-/// (2) isSigned = true and C is a small negative signed value, i.e.,
-/// high bits are 1, and the remaining bits fit in simm13(OR).
-static inline void
-CreateSETUWConst(uint32_t C,
- Instruction* dest, std::vector<MachineInstr*>& mvec,
- MachineCodeForInstruction& mcfi, Value* val, bool isSigned = false) {
- MachineInstr *miSETHI = NULL, *miOR = NULL;
-
- // In order to get efficient code, we should not generate the SETHI if
- // all high bits are 1 (i.e., this is a small signed value that fits in
- // the simm13 field of OR). So we check for and handle that case specially.
- // NOTE: The value C = 0x80000000 is bad: sC < 0 *and* -sC < 0.
- // In fact, sC == -sC, so we have to check for this explicitly.
- int32_t sC = (int32_t) C;
- bool smallNegValue =isSigned && sC < 0 && sC != -sC && -sC < (int32_t)MAXSIMM;
-
- //Create TmpInstruction for intermediate values
- TmpInstruction *tmpReg = 0;
-
- // Set the high 22 bits in dest if non-zero and simm13 field of OR not enough
- if (!smallNegValue && (C & ~MAXLO) && C > MAXSIMM) {
- tmpReg = new TmpInstruction(mcfi, PointerType::get(val->getType()), (Instruction*) val);
- miSETHI = BuildMI(V9::SETHI, 2).addZImm(C).addRegDef(tmpReg);
- miSETHI->getOperand(0).markHi32();
- mvec.push_back(miSETHI);
- }
-
- // Set the low 10 or 12 bits in dest. This is necessary if no SETHI
- // was generated, or if the low 10 bits are non-zero.
- if (miSETHI==NULL || C & MAXLO) {
- if (miSETHI) {
- // unsigned value with high-order bits set using SETHI
- miOR = BuildMI(V9::ORi,3).addReg(tmpReg).addZImm(C).addRegDef(dest);
- miOR->getOperand(1).markLo32();
- } else {
- // unsigned or small signed value that fits in simm13 field of OR
- assert(smallNegValue || (C & ~MAXSIMM) == 0);
- miOR = BuildMI(V9::ORi, 3).addMReg(SparcV9::g0)
- .addSImm(sC).addRegDef(dest);
- }
- mvec.push_back(miOR);
- }
- else
- mvec.push_back(BuildMI(V9::ORr,3).addReg(tmpReg).addMReg(SparcV9::g0).addRegDef(dest));
-
- assert((miSETHI || miOR) && "Oops, no code was generated!");
-}
-
-/// CreateSETSWConst - Set a 32-bit signed constant in the register `dest',
-/// with sign-extension to 64 bits. This uses SETHI, OR, SRA in the worst case.
-/// This function correctly emulates the SETSW pseudo-op for SPARC v9. It
-/// optimizes the same cases as SETUWConst, plus:
-/// (1) SRA is not needed for positive or small negative values.
-///
-static inline void
-CreateSETSWConst(int32_t C,
- Instruction* dest, std::vector<MachineInstr*>& mvec,
- MachineCodeForInstruction& mcfi, Value* val) {
-
- //TmpInstruction for intermediate values
- TmpInstruction *tmpReg = new TmpInstruction(mcfi, (Instruction*) val);
-
- // Set the low 32 bits of dest
- CreateSETUWConst((uint32_t) C, tmpReg, mvec, mcfi, val, /*isSigned*/true);
-
- // Sign-extend to the high 32 bits if needed.
- // NOTE: The value C = 0x80000000 is bad: -C == C and so -C is < MAXSIMM
- if (C < 0 && (C == -C || -C > (int32_t) MAXSIMM))
- mvec.push_back(BuildMI(V9::SRAi5,3).addReg(tmpReg).addZImm(0).addRegDef(dest));
- else
- mvec.push_back(BuildMI(V9::ORr,3).addReg(tmpReg).addMReg(SparcV9::g0).addRegDef(dest));
-}
-
-/// CreateSETXConst - Set a 64-bit signed or unsigned constant in the
-/// register `dest'. Use SETUWConst for each 32 bit word, plus a
-/// left-shift-by-32 in between. This function correctly emulates the SETX
-/// pseudo-op for SPARC v9. It optimizes the same cases as SETUWConst for each
-/// 32 bit word.
-///
-static inline void
-CreateSETXConst(uint64_t C,
- Instruction* tmpReg, Instruction* dest,
- std::vector<MachineInstr*>& mvec,
- MachineCodeForInstruction& mcfi, Value* val) {
- assert(C > (unsigned int) ~0 && "Use SETUW/SETSW for 32-bit values!");
-
- MachineInstr* MI;
-
- // Code to set the upper 32 bits of the value in register `tmpReg'
- CreateSETUWConst((C >> 32), tmpReg, mvec, mcfi, val);
-
- //TmpInstruction for intermediate values
- TmpInstruction *tmpReg2 = new TmpInstruction(mcfi, (Instruction*) val);
-
- // Shift tmpReg left by 32 bits
- mvec.push_back(BuildMI(V9::SLLXi6, 3).addReg(tmpReg).addZImm(32)
- .addRegDef(tmpReg2));
-
- //TmpInstruction for intermediate values
- TmpInstruction *tmpReg3 = new TmpInstruction(mcfi, (Instruction*) val);
-
- // Code to set the low 32 bits of the value in register `dest'
- CreateSETUWConst(C, tmpReg3, mvec, mcfi, val);
-
- // dest = OR(tmpReg, dest)
- mvec.push_back(BuildMI(V9::ORr,3).addReg(tmpReg3).addReg(tmpReg2).addRegDef(dest));
-}
-
-/// CreateSETUWLabel - Set a 32-bit constant (given by a symbolic label) in
-/// the register `dest'.
-///
-static inline void
-CreateSETUWLabel(Value* val,
- Instruction* dest, std::vector<MachineInstr*>& mvec) {
- MachineInstr* MI;
-
- MachineCodeForInstruction &mcfi = MachineCodeForInstruction::get((Instruction*) val);
- TmpInstruction* tmpReg = new TmpInstruction(mcfi, val);
-
- // Set the high 22 bits in dest
- MI = BuildMI(V9::SETHI, 2).addReg(val).addRegDef(tmpReg);
- MI->getOperand(0).markHi32();
- mvec.push_back(MI);
-
- // Set the low 10 bits in dest
- MI = BuildMI(V9::ORr, 3).addReg(tmpReg).addReg(val).addRegDef(dest);
- MI->getOperand(1).markLo32();
- mvec.push_back(MI);
-}
-
-/// CreateSETXLabel - Set a 64-bit constant (given by a symbolic label) in the
-/// register `dest'.
-///
-static inline void
-CreateSETXLabel(Value* val, Instruction* tmpReg,
- Instruction* dest, std::vector<MachineInstr*>& mvec,
- MachineCodeForInstruction& mcfi) {
- assert(isa<Constant>(val) &&
- "I only know about constant values and global addresses");
-
- MachineInstr* MI;
-
- MI = BuildMI(V9::SETHI, 2).addPCDisp(val).addRegDef(tmpReg);
- MI->getOperand(0).markHi64();
- mvec.push_back(MI);
-
- TmpInstruction* tmpReg2 =
- new TmpInstruction(mcfi, PointerType::get(val->getType()), val);
-
- MI = BuildMI(V9::ORi, 3).addReg(tmpReg).addPCDisp(val).addRegDef(tmpReg2);
- MI->getOperand(1).markLo64();
- mvec.push_back(MI);
-
-
- TmpInstruction* tmpReg3 =
- new TmpInstruction(mcfi, PointerType::get(val->getType()), val);
-
- mvec.push_back(BuildMI(V9::SLLXi6, 3).addReg(tmpReg2).addZImm(32)
- .addRegDef(tmpReg3));
-
-
- TmpInstruction* tmpReg4 =
- new TmpInstruction(mcfi, PointerType::get(val->getType()), val);
- MI = BuildMI(V9::SETHI, 2).addPCDisp(val).addRegDef(tmpReg4);
- MI->getOperand(0).markHi32();
- mvec.push_back(MI);
-
- TmpInstruction* tmpReg5 =
- new TmpInstruction(mcfi, PointerType::get(val->getType()), val);
- MI = BuildMI(V9::ORr, 3).addReg(tmpReg4).addReg(tmpReg3).addRegDef(tmpReg5);
- mvec.push_back(MI);
-
- MI = BuildMI(V9::ORi, 3).addReg(tmpReg5).addPCDisp(val).addRegDef(dest);
- MI->getOperand(1).markLo32();
- mvec.push_back(MI);
-}
-
-/// CreateUIntSetInstruction - Create code to Set an unsigned constant in the
-/// register `dest'. Uses CreateSETUWConst, CreateSETSWConst or CreateSETXConst
-/// as needed. CreateSETSWConst is an optimization for the case that the
-/// unsigned value has all ones in the 33 high bits (so that sign-extension sets
-/// them all).
-///
-static inline void
-CreateUIntSetInstruction(uint64_t C, Instruction* dest,
- std::vector<MachineInstr*>& mvec,
- MachineCodeForInstruction& mcfi, Value* val) {
- static const uint64_t lo32 = (uint32_t) ~0;
- if (C <= lo32) // High 32 bits are 0. Set low 32 bits.
- CreateSETUWConst((uint32_t) C, dest, mvec, mcfi, val);
- else if ((C & ~lo32) == ~lo32 && (C & (1U << 31))) {
- // All high 33 (not 32) bits are 1s: sign-extension will take care
- // of high 32 bits, so use the sequence for signed int
- CreateSETSWConst((int32_t) C, dest, mvec, mcfi, val);
- } else if (C > lo32) {
- // C does not fit in 32 bits
- TmpInstruction* tmpReg = new TmpInstruction(mcfi, Type::IntTy);
- CreateSETXConst(C, tmpReg, dest, mvec, mcfi, val);
- }
-}
-
-/// CreateIntSetInstruction - Create code to Set a signed constant in the
-/// register `dest'. Really the same as CreateUIntSetInstruction.
-///
-static inline void
-CreateIntSetInstruction(int64_t C, Instruction* dest,
- std::vector<MachineInstr*>& mvec,
- MachineCodeForInstruction& mcfi, Value* val) {
- CreateUIntSetInstruction((uint64_t) C, dest, mvec, mcfi, val);
-}
-
-/// MaxConstantsTableTy - Table mapping LLVM opcodes to the max. immediate
-/// constant usable for that operation in the SparcV9 backend. Used by
-/// ConstantMayNotFitInImmedField().
-///
-struct MaxConstantsTableTy {
- // Entry == 0 ==> no immediate constant field exists at all.
- // Entry > 0 ==> abs(immediate constant) <= Entry
- std::vector<int> tbl;
-
- int getMaxConstantForInstr (unsigned llvmOpCode);
- MaxConstantsTableTy ();
- unsigned size() const { return tbl.size (); }
- int &operator[] (unsigned index) { return tbl[index]; }
-};
-
-int MaxConstantsTableTy::getMaxConstantForInstr(unsigned llvmOpCode) {
- int modelOpCode = -1;
-
- if (llvmOpCode >= Instruction::BinaryOpsBegin &&
- llvmOpCode < Instruction::BinaryOpsEnd)
- modelOpCode = V9::ADDi;
- else
- switch(llvmOpCode) {
- case Instruction::Ret: modelOpCode = V9::JMPLCALLi; break;
-
- case Instruction::Malloc:
- case Instruction::Alloca:
- case Instruction::GetElementPtr:
- case Instruction::PHI:
- case Instruction::Cast:
- case Instruction::Call: modelOpCode = V9::ADDi; break;
-
- case Instruction::Shl:
- case Instruction::Shr: modelOpCode = V9::SLLXi6; break;
-
- default: break;
- };
-
- return (modelOpCode < 0)? 0: SparcV9MachineInstrDesc[modelOpCode].maxImmedConst;
-}
-
-MaxConstantsTableTy::MaxConstantsTableTy () : tbl (Instruction::OtherOpsEnd) {
- unsigned op;
- assert(tbl.size() == Instruction::OtherOpsEnd &&
- "assignments below will be illegal!");
- for (op = Instruction::TermOpsBegin; op < Instruction::TermOpsEnd; ++op)
- tbl[op] = getMaxConstantForInstr(op);
- for (op = Instruction::BinaryOpsBegin; op < Instruction::BinaryOpsEnd; ++op)
- tbl[op] = getMaxConstantForInstr(op);
- for (op = Instruction::MemoryOpsBegin; op < Instruction::MemoryOpsEnd; ++op)
- tbl[op] = getMaxConstantForInstr(op);
- for (op = Instruction::OtherOpsBegin; op < Instruction::OtherOpsEnd; ++op)
- tbl[op] = getMaxConstantForInstr(op);
-}
-
-bool ConstantMayNotFitInImmedField(const Constant* CV, const Instruction* I) {
- // The one and only MaxConstantsTable, used only by this function.
- static MaxConstantsTableTy MaxConstantsTable;
-
- if (I->getOpcode() >= MaxConstantsTable.size()) // user-defined op (or bug!)
- return true;
-
- // can always use %g0
- if (isa<ConstantPointerNull>(CV) || isa<UndefValue>(CV))
- return false;
-
- if (isa<SwitchInst>(I)) // Switch instructions will be lowered!
- return false;
-
- if (const ConstantInt* CI = dyn_cast<ConstantInt>(CV))
- return labs((int64_t)CI->getRawValue()) > MaxConstantsTable[I->getOpcode()];
-
- if (isa<ConstantBool>(CV))
- return 1 > MaxConstantsTable[I->getOpcode()];
-
- return true;
-}
-
-/// ChooseLoadInstruction - Return the appropriate load instruction opcode
-/// based on the given LLVM value type.
-///
-static inline MachineOpCode ChooseLoadInstruction(const Type *DestTy) {
- switch (DestTy->getTypeID()) {
- case Type::BoolTyID:
- case Type::UByteTyID: return V9::LDUBr;
- case Type::SByteTyID: return V9::LDSBr;
- case Type::UShortTyID: return V9::LDUHr;
- case Type::ShortTyID: return V9::LDSHr;
- case Type::UIntTyID: return V9::LDUWr;
- case Type::IntTyID: return V9::LDSWr;
- case Type::PointerTyID:
- case Type::ULongTyID:
- case Type::LongTyID: return V9::LDXr;
- case Type::FloatTyID: return V9::LDFr;
- case Type::DoubleTyID: return V9::LDDFr;
- default: assert(0 && "Invalid type for Load instruction");
- }
- return 0;
-}
-
-/// ChooseStoreInstruction - Return the appropriate store instruction opcode
-/// based on the given LLVM value type.
-///
-static inline MachineOpCode ChooseStoreInstruction(const Type *DestTy) {
- switch (DestTy->getTypeID()) {
- case Type::BoolTyID:
- case Type::UByteTyID:
- case Type::SByteTyID: return V9::STBr;
- case Type::UShortTyID:
- case Type::ShortTyID: return V9::STHr;
- case Type::UIntTyID:
- case Type::IntTyID: return V9::STWr;
- case Type::PointerTyID:
- case Type::ULongTyID:
- case Type::LongTyID: return V9::STXr;
- case Type::FloatTyID: return V9::STFr;
- case Type::DoubleTyID: return V9::STDFr;
- default: assert(0 && "Invalid type for Store instruction");
- }
- return 0;
-}
-
-static inline MachineOpCode ChooseAddInstructionByType(const Type* resultType) {
- MachineOpCode opCode = V9::INVALID_OPCODE;
- if (resultType->isIntegral() || isa<PointerType>(resultType)
- || isa<FunctionType>(resultType) || resultType == Type::LabelTy) {
- opCode = V9::ADDr;
- } else
- switch(resultType->getTypeID()) {
- case Type::FloatTyID: opCode = V9::FADDS; break;
- case Type::DoubleTyID: opCode = V9::FADDD; break;
- default: assert(0 && "Invalid type for ADD instruction"); break;
- }
-
- return opCode;
-}
-
-/// convertOpcodeFromRegToImm - Because the SparcV9 instruction selector likes
-/// to re-write operands to instructions, making them change from a Value*
-/// (virtual register) to a Constant* (making an immediate field), we need to
-/// change the opcode from a register-based instruction to an immediate-based
-/// instruction, hence this mapping.
-///
-static unsigned convertOpcodeFromRegToImm(unsigned Opcode) {
- switch (Opcode) {
- /* arithmetic */
- case V9::ADDr: return V9::ADDi;
- case V9::ADDccr: return V9::ADDcci;
- case V9::ADDCr: return V9::ADDCi;
- case V9::ADDCccr: return V9::ADDCcci;
- case V9::SUBr: return V9::SUBi;
- case V9::SUBccr: return V9::SUBcci;
- case V9::SUBCr: return V9::SUBCi;
- case V9::SUBCccr: return V9::SUBCcci;
- case V9::MULXr: return V9::MULXi;
- case V9::SDIVXr: return V9::SDIVXi;
- case V9::UDIVXr: return V9::UDIVXi;
-
- /* logical */
- case V9::ANDr: return V9::ANDi;
- case V9::ANDccr: return V9::ANDcci;
- case V9::ANDNr: return V9::ANDNi;
- case V9::ANDNccr: return V9::ANDNcci;
- case V9::ORr: return V9::ORi;
- case V9::ORccr: return V9::ORcci;
- case V9::ORNr: return V9::ORNi;
- case V9::ORNccr: return V9::ORNcci;
- case V9::XORr: return V9::XORi;
- case V9::XORccr: return V9::XORcci;
- case V9::XNORr: return V9::XNORi;
- case V9::XNORccr: return V9::XNORcci;
-
- /* shift */
- case V9::SLLr5: return V9::SLLi5;
- case V9::SRLr5: return V9::SRLi5;
- case V9::SRAr5: return V9::SRAi5;
- case V9::SLLXr6: return V9::SLLXi6;
- case V9::SRLXr6: return V9::SRLXi6;
- case V9::SRAXr6: return V9::SRAXi6;
-
- /* Conditional move on int comparison with zero */
- case V9::MOVRZr: return V9::MOVRZi;
- case V9::MOVRLEZr: return V9::MOVRLEZi;
- case V9::MOVRLZr: return V9::MOVRLZi;
- case V9::MOVRNZr: return V9::MOVRNZi;
- case V9::MOVRGZr: return V9::MOVRGZi;
- case V9::MOVRGEZr: return V9::MOVRGEZi;
-
-
- /* Conditional move on int condition code */
- case V9::MOVAr: return V9::MOVAi;
- case V9::MOVNr: return V9::MOVNi;
- case V9::MOVNEr: return V9::MOVNEi;
- case V9::MOVEr: return V9::MOVEi;
- case V9::MOVGr: return V9::MOVGi;
- case V9::MOVLEr: return V9::MOVLEi;
- case V9::MOVGEr: return V9::MOVGEi;
- case V9::MOVLr: return V9::MOVLi;
- case V9::MOVGUr: return V9::MOVGUi;
- case V9::MOVLEUr: return V9::MOVLEUi;
- case V9::MOVCCr: return V9::MOVCCi;
- case V9::MOVCSr: return V9::MOVCSi;
- case V9::MOVPOSr: return V9::MOVPOSi;
- case V9::MOVNEGr: return V9::MOVNEGi;
- case V9::MOVVCr: return V9::MOVVCi;
- case V9::MOVVSr: return V9::MOVVSi;
-
- /* Conditional move of int reg on fp condition code */
- case V9::MOVFAr: return V9::MOVFAi;
- case V9::MOVFNr: return V9::MOVFNi;
- case V9::MOVFUr: return V9::MOVFUi;
- case V9::MOVFGr: return V9::MOVFGi;
- case V9::MOVFUGr: return V9::MOVFUGi;
- case V9::MOVFLr: return V9::MOVFLi;
- case V9::MOVFULr: return V9::MOVFULi;
- case V9::MOVFLGr: return V9::MOVFLGi;
- case V9::MOVFNEr: return V9::MOVFNEi;
- case V9::MOVFEr: return V9::MOVFEi;
- case V9::MOVFUEr: return V9::MOVFUEi;
- case V9::MOVFGEr: return V9::MOVFGEi;
- case V9::MOVFUGEr: return V9::MOVFUGEi;
- case V9::MOVFLEr: return V9::MOVFLEi;
- case V9::MOVFULEr: return V9::MOVFULEi;
- case V9::MOVFOr: return V9::MOVFOi;
-
- /* load */
- case V9::LDSBr: return V9::LDSBi;
- case V9::LDSHr: return V9::LDSHi;
- case V9::LDSWr: return V9::LDSWi;
- case V9::LDUBr: return V9::LDUBi;
- case V9::LDUHr: return V9::LDUHi;
- case V9::LDUWr: return V9::LDUWi;
- case V9::LDXr: return V9::LDXi;
- case V9::LDFr: return V9::LDFi;
- case V9::LDDFr: return V9::LDDFi;
- case V9::LDQFr: return V9::LDQFi;
- case V9::LDFSRr: return V9::LDFSRi;
- case V9::LDXFSRr: return V9::LDXFSRi;
-
- /* store */
- case V9::STBr: return V9::STBi;
- case V9::STHr: return V9::STHi;
- case V9::STWr: return V9::STWi;
- case V9::STXr: return V9::STXi;
- case V9::STFr: return V9::STFi;
- case V9::STDFr: return V9::STDFi;
- case V9::STFSRr: return V9::STFSRi;
- case V9::STXFSRr: return V9::STXFSRi;
-
- /* jump & return */
- case V9::JMPLCALLr: return V9::JMPLCALLi;
- case V9::JMPLRETr: return V9::JMPLRETi;
-
- /* save and restore */
- case V9::SAVEr: return V9::SAVEi;
- case V9::RESTOREr: return V9::RESTOREi;
-
- default:
- // It's already in correct format
- // Or, it's just not handled yet, but an assert() would break LLC
-#if 0
- std::cerr << "Unhandled opcode in convertOpcodeFromRegToImm(): " << Opcode
- << "\n";
-#endif
- return Opcode;
- }
-}
-
-/// 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. Any stack space required is
-/// allocated via MachineFunction.
-///
-void CreateCodeToLoadConst(const TargetMachine& target, Function* F,
- Value* val, Instruction* dest,
- std::vector<MachineInstr*>& mvec,
- MachineCodeForInstruction& mcfi) {
- assert(isa<Constant>(val) &&
- "I only know about constant values and global addresses");
-
- // Use a "set" instruction for known constants or symbolic constants (labels)
- // that can go in an integer reg.
- // We have to use a "load" instruction for all other constants,
- // in particular, floating point constants.
- const Type* valType = val->getType();
-
- if (isa<GlobalValue>(val)) {
- TmpInstruction* tmpReg =
- new TmpInstruction(mcfi, PointerType::get(val->getType()), val);
- CreateSETXLabel(val, tmpReg, dest, mvec, mcfi);
- return;
- }
-
- bool isValid;
- uint64_t C = ConvertConstantToIntType(target, val, dest->getType(), isValid);
- if (isValid) {
- if (dest->getType()->isSigned())
- CreateUIntSetInstruction(C, dest, mvec, mcfi, val);
- else
- CreateIntSetInstruction((int64_t) C, dest, mvec, mcfi, val);
-
- } else {
- // Make an instruction sequence to load the constant, viz:
- // SETX <addr-of-constant>, tmpReg, addrReg
- // LOAD /*addr*/ addrReg, /*offset*/ 0, dest
- // First, create a tmp register to be used by the SETX sequence.
- TmpInstruction* tmpReg =
- new TmpInstruction(mcfi, PointerType::get(val->getType()));
-
- // Create another TmpInstruction for the address register
- TmpInstruction* addrReg =
- new TmpInstruction(mcfi, PointerType::get(val->getType()));
-
- // Get the constant pool index for this constant
- MachineConstantPool *CP = MachineFunction::get(F).getConstantPool();
- Constant *C = cast<Constant>(val);
- unsigned Align = target.getTargetData().getTypeAlignmentShift(C->getType());
- unsigned CPI = CP->getConstantPoolIndex(C, Align);
-
- // Put the address of the constant into a register
- MachineInstr* MI;
-
- MI = BuildMI(V9::SETHI, 2).addConstantPoolIndex(CPI).addRegDef(tmpReg);
- MI->getOperand(0).markHi64();
- mvec.push_back(MI);
-
- //Create another tmp register for the SETX sequence to preserve SSA
- TmpInstruction* tmpReg2 =
- new TmpInstruction(mcfi, PointerType::get(val->getType()));
-
- MI = BuildMI(V9::ORi, 3).addReg(tmpReg).addConstantPoolIndex(CPI)
- .addRegDef(tmpReg2);
- MI->getOperand(1).markLo64();
- mvec.push_back(MI);
-
- //Create another tmp register for the SETX sequence to preserve SSA
- TmpInstruction* tmpReg3 =
- new TmpInstruction(mcfi, PointerType::get(val->getType()));
-
- mvec.push_back(BuildMI(V9::SLLXi6, 3).addReg(tmpReg2).addZImm(32)
- .addRegDef(tmpReg3));
- MI = BuildMI(V9::SETHI, 2).addConstantPoolIndex(CPI).addRegDef(addrReg);
- MI->getOperand(0).markHi32();
- mvec.push_back(MI);
-
- // Create another TmpInstruction for the address register
- TmpInstruction* addrReg2 =
- new TmpInstruction(mcfi, PointerType::get(val->getType()));
-
-
- MI = BuildMI(V9::ORr, 3).addReg(addrReg).addReg(tmpReg3).addRegDef(addrReg2);
- mvec.push_back(MI);
-
- // Create another TmpInstruction for the address register
- TmpInstruction* addrReg3 =
- new TmpInstruction(mcfi, PointerType::get(val->getType()));
-
- MI = BuildMI(V9::ORi, 3).addReg(addrReg2).addConstantPoolIndex(CPI)
- .addRegDef(addrReg3);
- MI->getOperand(1).markLo32();
- mvec.push_back(MI);
-
- // Now load the constant from out ConstantPool label
- unsigned Opcode = ChooseLoadInstruction(val->getType());
- Opcode = convertOpcodeFromRegToImm(Opcode);
- mvec.push_back(BuildMI(Opcode, 3)
- .addReg(addrReg3).addSImm((int64_t)0).addRegDef(dest));
- }
-}
-
-/// CreateCodeToCopyFloatToInt - Similarly, create an instruction sequence
-/// to copy an FP register `val' to an integer register `dest' by copying to
-/// memory and back. The generated instructions are returned in `mvec'. Any
-/// temp. virtual registers (TmpInstruction) created are recorded in mcfi.
-/// Temporary stack space required is allocated via MachineFunction.
-///
-void CreateCodeToCopyFloatToInt(const TargetMachine& target, Function* F,
- Value* val, Instruction* dest,
- std::vector<MachineInstr*>& mvec,
- MachineCodeForInstruction& mcfi) {
- const Type* opTy = val->getType();
- const Type* destTy = dest->getType();
- assert(opTy->isFloatingPoint() && "Source type must be float/double");
- assert((destTy->isIntegral() || isa<PointerType>(destTy))
- && "Dest type must be integer, bool or pointer");
-
- // FIXME: For now, we allocate permanent space because the stack frame
- // manager does not allow locals to be allocated (e.g., for alloca) after
- // a temp is allocated!
- int offset = MachineFunction::get(F).getInfo<SparcV9FunctionInfo>()->allocateLocalVar(val);
-
- unsigned FPReg = target.getRegInfo()->getFramePointer();
-
- // Store instruction stores `val' to [%fp+offset].
- // The store opCode is based only the source value being copied.
- unsigned StoreOpcode = ChooseStoreInstruction(opTy);
- StoreOpcode = convertOpcodeFromRegToImm(StoreOpcode);
- mvec.push_back(BuildMI(StoreOpcode, 3)
- .addReg(val).addMReg(FPReg).addSImm(offset));
-
- // Load instruction loads [%fp+offset] to `dest'.
- // The type of the load opCode is the integer type that matches the
- // source type in size:
- // On SparcV9: int for float, long for double.
- // Note that we *must* use signed loads even for unsigned dest types, to
- // ensure correct sign-extension for UByte, UShort or UInt:
- const Type* loadTy = (opTy == Type::FloatTy)? Type::IntTy : Type::LongTy;
- unsigned LoadOpcode = ChooseLoadInstruction(loadTy);
- LoadOpcode = convertOpcodeFromRegToImm(LoadOpcode);
- mvec.push_back(BuildMI(LoadOpcode, 3).addMReg(FPReg)
- .addSImm(offset).addRegDef(dest));
-}
-
-/// CreateBitExtensionInstructions - Helper function for sign-extension and
-/// zero-extension. For SPARC v9, we sign-extend the given operand using SLL;
-/// SRA/SRL.
-///
-inline void
-CreateBitExtensionInstructions(bool signExtend, const TargetMachine& target,
- Function* F, Value* srcVal, Value* destVal,
- unsigned int numLowBits,
- std::vector<MachineInstr*>& mvec,
- MachineCodeForInstruction& mcfi) {
- MachineInstr* M;
-
- assert(numLowBits <= 32 && "Otherwise, nothing should be done here!");
-
- if (numLowBits < 32) {
- // SLL is needed since operand size is < 32 bits.
- TmpInstruction *tmpI = new TmpInstruction(mcfi, destVal->getType(),
- srcVal, destVal, "make32");
- mvec.push_back(BuildMI(V9::SLLXi6, 3).addReg(srcVal)
- .addZImm(32-numLowBits).addRegDef(tmpI));
- srcVal = tmpI;
- }
-
- mvec.push_back(BuildMI(signExtend? V9::SRAi5 : V9::SRLi5, 3)
- .addReg(srcVal).addZImm(32-numLowBits).addRegDef(destVal));
-}
-
-/// CreateSignExtensionInstructions - Create instruction sequence to produce
-/// a sign-extended register value from an arbitrary-sized integer value (sized
-/// in bits, not bytes). The generated instructions are returned in `mvec'. Any
-/// temp. registers (TmpInstruction) created are recorded in mcfi. Any stack
-/// space required is allocated via MachineFunction.
-///
-void CreateSignExtensionInstructions(const TargetMachine& target,
- Function* F, Value* srcVal, Value* destVal,
- unsigned int numLowBits,
- std::vector<MachineInstr*>& mvec,
- MachineCodeForInstruction& mcfi) {
- CreateBitExtensionInstructions(/*signExtend*/ true, target, F, srcVal,
- destVal, numLowBits, mvec, mcfi);
-}
-
-/// CreateZeroExtensionInstructions - Create instruction sequence to produce
-/// a zero-extended register value from an arbitrary-sized integer value (sized
-/// in bits, not bytes). For SPARC v9, we sign-extend the given operand using
-/// SLL; SRL. The generated instructions are returned in `mvec'. Any temp.
-/// registers (TmpInstruction) created are recorded in mcfi. Any stack space
-/// required is allocated via MachineFunction.
-///
-void CreateZeroExtensionInstructions(const TargetMachine& target,
- Function* F, Value* srcVal, Value* destVal,
- unsigned int numLowBits,
- std::vector<MachineInstr*>& mvec,
- MachineCodeForInstruction& mcfi) {
- CreateBitExtensionInstructions(/*signExtend*/ false, target, F, srcVal,
- destVal, numLowBits, mvec, mcfi);
-}
-
-/// CreateCodeToCopyIntToFloat - Create an instruction sequence to copy an
-/// integer register `val' to a floating point register `dest' by copying to
-/// memory and back. val must be an integral type. dest must be a Float or
-/// Double. The generated instructions are returned in `mvec'. Any temp.
-/// registers (TmpInstruction) created are recorded in mcfi. Any stack space
-/// required is allocated via MachineFunction.
-///
-void CreateCodeToCopyIntToFloat(const TargetMachine& target,
- Function* F, Value* val, Instruction* dest,
- std::vector<MachineInstr*>& mvec,
- MachineCodeForInstruction& mcfi) {
- assert((val->getType()->isIntegral() || isa<PointerType>(val->getType()))
- && "Source type must be integral (integer or bool) or pointer");
- assert(dest->getType()->isFloatingPoint()
- && "Dest type must be float/double");
-
- // Get a stack slot to use for the copy
- int offset = MachineFunction::get(F).getInfo<SparcV9FunctionInfo>()->allocateLocalVar(val);
-
- // Get the size of the source value being copied.
- size_t srcSize = target.getTargetData().getTypeSize(val->getType());
-
- // Store instruction stores `val' to [%fp+offset].
- // The store and load opCodes are based on the size of the source value.
- // If the value is smaller than 32 bits, we must sign- or zero-extend it
- // to 32 bits since the load-float will load 32 bits.
- // Note that the store instruction is the same for signed and unsigned ints.
- const Type* storeType = (srcSize <= 4)? Type::IntTy : Type::LongTy;
- Value* storeVal = val;
- if (srcSize < target.getTargetData().getTypeSize(Type::FloatTy)) {
- // sign- or zero-extend respectively
- storeVal = new TmpInstruction(mcfi, storeType, val);
- if (val->getType()->isSigned())
- CreateSignExtensionInstructions(target, F, val, storeVal, 8*srcSize,
- mvec, mcfi);
- else
- CreateZeroExtensionInstructions(target, F, val, storeVal, 8*srcSize,
- mvec, mcfi);
- }
-
- unsigned FPReg = target.getRegInfo()->getFramePointer();
- unsigned StoreOpcode = ChooseStoreInstruction(storeType);
- StoreOpcode = convertOpcodeFromRegToImm(StoreOpcode);
- mvec.push_back(BuildMI(StoreOpcode, 3)
- .addReg(storeVal).addMReg(FPReg).addSImm(offset));
-
- // Load instruction loads [%fp+offset] to `dest'.
- // The type of the load opCode is the floating point type that matches the
- // stored type in size:
- // On SparcV9: float for int or smaller, double for long.
- const Type* loadType = (srcSize <= 4)? Type::FloatTy : Type::DoubleTy;
- unsigned LoadOpcode = ChooseLoadInstruction(loadType);
- LoadOpcode = convertOpcodeFromRegToImm(LoadOpcode);
- mvec.push_back(BuildMI(LoadOpcode, 3)
- .addMReg(FPReg).addSImm(offset).addRegDef(dest));
-}
-
-/// InsertCodeToLoadConstant - Generates code to load the constant
-/// into a TmpInstruction (virtual reg) and returns the virtual register.
-///
-static TmpInstruction*
-InsertCodeToLoadConstant(Function *F, Value* opValue, Instruction* vmInstr,
- std::vector<MachineInstr*>& loadConstVec,
- TargetMachine& target) {
- // Create a tmp virtual register to hold the constant.
- MachineCodeForInstruction &mcfi = MachineCodeForInstruction::get(vmInstr);
- TmpInstruction* tmpReg = new TmpInstruction(mcfi, opValue);
-
- CreateCodeToLoadConst(target, F, opValue, tmpReg, loadConstVec, mcfi);
-
- // Record the mapping from the tmp VM instruction to machine instruction.
- // Do this for all machine instructions that were not mapped to any
- // other temp values created by
- // tmpReg->addMachineInstruction(loadConstVec.back());
- return tmpReg;
-}
-
-MachineOperand::MachineOperandType
-ChooseRegOrImmed(int64_t intValue, bool isSigned,
- MachineOpCode opCode, const TargetMachine& target,
- bool canUseImmed, unsigned int& getMachineRegNum,
- int64_t& getImmedValue) {
- MachineOperand::MachineOperandType opType=MachineOperand::MO_VirtualRegister;
- getMachineRegNum = 0;
- getImmedValue = 0;
-
- if (canUseImmed &&
- target.getInstrInfo()->constantFitsInImmedField(opCode, intValue)) {
- opType = isSigned? MachineOperand::MO_SignExtendedImmed
- : MachineOperand::MO_UnextendedImmed;
- getImmedValue = intValue;
- } else if (intValue == 0 &&
- target.getRegInfo()->getZeroRegNum() != (unsigned)-1) {
- opType = MachineOperand::MO_MachineRegister;
- getMachineRegNum = target.getRegInfo()->getZeroRegNum();
- }
-
- return opType;
-}
-
-MachineOperand::MachineOperandType
-ChooseRegOrImmed(Value* val,
- MachineOpCode opCode, const TargetMachine& target,
- bool canUseImmed, unsigned int& getMachineRegNum,
- int64_t& getImmedValue) {
- getMachineRegNum = 0;
- getImmedValue = 0;
-
- // To use reg or immed, constant needs to be integer, bool, or a NULL pointer.
- // ConvertConstantToIntType() does the right conversions.
- bool isValidConstant;
- uint64_t valueToUse =
- ConvertConstantToIntType(target, val, val->getType(), isValidConstant);
- if (! isValidConstant)
- return MachineOperand::MO_VirtualRegister;
-
- // Now check if the constant value fits in the IMMED field.
- return ChooseRegOrImmed((int64_t) valueToUse, val->getType()->isSigned(),
- opCode, target, canUseImmed,
- getMachineRegNum, getImmedValue);
-}
-
-/// CreateCopyInstructionsByType - Create instruction(s) to copy src to dest,
-/// for arbitrary types. The generated instructions are returned in `mvec'. Any
-/// temp. registers (TmpInstruction) created are recorded in mcfi. Any stack
-/// space required is allocated via MachineFunction.
-///
-void CreateCopyInstructionsByType(const TargetMachine& target,
- Function *F, Value* src, Instruction* dest,
- std::vector<MachineInstr*>& mvec,
- MachineCodeForInstruction& mcfi) {
- bool loadConstantToReg = false;
- const Type* resultType = dest->getType();
- MachineOpCode opCode = ChooseAddInstructionByType(resultType);
- assert (opCode != V9::INVALID_OPCODE
- && "Unsupported result type in CreateCopyInstructionsByType()");
-
- // If `src' is a constant that doesn't fit in the immed field or if it is
- // a global variable (i.e., a constant address), generate a load
- // instruction instead of an add.
- if (isa<GlobalValue>(src))
- loadConstantToReg = true;
- else if (isa<Constant>(src)) {
- unsigned int machineRegNum;
- int64_t immedValue;
- MachineOperand::MachineOperandType opType =
- ChooseRegOrImmed(src, opCode, target, /*canUseImmed*/ true,
- machineRegNum, immedValue);
-
- if (opType == MachineOperand::MO_VirtualRegister)
- loadConstantToReg = true;
- }
-
- if (loadConstantToReg) {
- // `src' is constant and cannot fit in immed field for the ADD.
- // Insert instructions to "load" the constant into a register.
- CreateCodeToLoadConst(target, F, src, dest, mvec, mcfi);
- } else {
- // Create a reg-to-reg copy instruction for the given type:
- // -- For FP values, create a FMOVS or FMOVD instruction
- // -- For non-FP values, create an add-with-0 instruction (opCode as above)
- // Make `src' the second operand, in case it is a small constant!
- MachineInstr* MI;
- if (resultType->isFloatingPoint())
- MI = (BuildMI(resultType == Type::FloatTy? V9::FMOVS : V9::FMOVD, 2)
- .addReg(src).addRegDef(dest));
- else {
- const Type* Ty =isa<PointerType>(resultType)? Type::ULongTy :resultType;
- MI = (BuildMI(opCode, 3)
- .addSImm((int64_t) 0).addReg(src).addRegDef(dest));
- }
- mvec.push_back(MI);
- }
-}
-
-/// FixConstantOperandsForInstr - Make a machine instruction use its constant
-/// operands more efficiently. If the constant is 0, then use the hardwired 0
-/// register, if any. Else, if the constant fits in the IMMEDIATE field, then
-/// use that field. Otherwise, else create instructions to put the constant
-/// into a register, either directly or by loading explicitly from the constant
-/// pool. In the first 2 cases, the operand of `minstr' is modified in place.
-/// Returns a vector of machine instructions generated for operands that fall
-/// under case 3; these must be inserted before `minstr'.
-///
-std::vector<MachineInstr*>
-FixConstantOperandsForInstr(Instruction* vmInstr, MachineInstr* minstr,
- TargetMachine& target) {
- std::vector<MachineInstr*> MVec;
-
- MachineOpCode opCode = minstr->getOpcode();
- const TargetInstrInfo& instrInfo = *target.getInstrInfo();
- int resultPos = instrInfo.get(opCode).resultPos;
- int immedPos = instrInfo.getImmedConstantPos(opCode);
-
- Function *F = vmInstr->getParent()->getParent();
-
- for (unsigned op=0; op < minstr->getNumOperands(); op++) {
- const MachineOperand& mop = minstr->getOperand(op);
-
- // Skip the result position, preallocated machine registers, or operands
- // that cannot be constants (CC regs or PC-relative displacements)
- if (resultPos == (int)op ||
- mop.getType() == MachineOperand::MO_MachineRegister ||
- mop.getType() == MachineOperand::MO_CCRegister ||
- mop.getType() == MachineOperand::MO_PCRelativeDisp)
- continue;
-
- bool constantThatMustBeLoaded = false;
- unsigned int machineRegNum = 0;
- int64_t immedValue = 0;
- Value* opValue = NULL;
- MachineOperand::MachineOperandType opType =
- MachineOperand::MO_VirtualRegister;
-
- // Operand may be a virtual register or a compile-time constant
- if (mop.getType() == MachineOperand::MO_VirtualRegister) {
- assert(mop.getVRegValue() != NULL);
- opValue = mop.getVRegValue();
- if (Constant *opConst = dyn_cast<Constant>(opValue))
- if (!isa<GlobalValue>(opConst)) {
- opType = ChooseRegOrImmed(opConst, opCode, target,
- (immedPos == (int)op), machineRegNum,
- immedValue);
- if (opType == MachineOperand::MO_VirtualRegister)
- constantThatMustBeLoaded = true;
- }
- } else {
- // If the operand is from the constant pool, don't try to change it.
- if (mop.getType() == MachineOperand::MO_ConstantPoolIndex) {
- continue;
- }
- assert(mop.isImmediate());
- bool isSigned = mop.getType() == MachineOperand::MO_SignExtendedImmed;
-
- // Bit-selection flags indicate an instruction that is extracting
- // bits from its operand so ignore this even if it is a big constant.
- if (mop.isHiBits32() || mop.isLoBits32() ||
- mop.isHiBits64() || mop.isLoBits64())
- continue;
-
- opType = ChooseRegOrImmed(mop.getImmedValue(), isSigned,
- opCode, target, (immedPos == (int)op),
- machineRegNum, immedValue);
-
- if (opType == MachineOperand::MO_SignExtendedImmed ||
- opType == MachineOperand::MO_UnextendedImmed) {
- // The optype is an immediate value
- // This means we need to change the opcode, e.g. ADDr -> ADDi
- unsigned newOpcode = convertOpcodeFromRegToImm(opCode);
- minstr->setOpcode(newOpcode);
- }
-
- if (opType == mop.getType())
- continue; // no change: this is the most common case
-
- if (opType == MachineOperand::MO_VirtualRegister) {
- constantThatMustBeLoaded = true;
- opValue = isSigned
- ? (Value*)ConstantSInt::get(Type::LongTy, immedValue)
- : (Value*)ConstantUInt::get(Type::ULongTy,(uint64_t)immedValue);
- }
- }
-
- if (opType == MachineOperand::MO_MachineRegister)
- minstr->SetMachineOperandReg(op, machineRegNum);
- else if (opType == MachineOperand::MO_SignExtendedImmed ||
- opType == MachineOperand::MO_UnextendedImmed) {
- minstr->SetMachineOperandConst(op, opType, immedValue);
- // The optype is or has become an immediate
- // This means we need to change the opcode, e.g. ADDr -> ADDi
- unsigned newOpcode = convertOpcodeFromRegToImm(opCode);
- minstr->setOpcode(newOpcode);
- } else if (constantThatMustBeLoaded ||
- (opValue && isa<GlobalValue>(opValue)))
- { // opValue is a constant that must be explicitly loaded into a reg
- assert(opValue);
- TmpInstruction* tmpReg = InsertCodeToLoadConstant(F, opValue, vmInstr,
- MVec, target);
- minstr->SetMachineOperandVal(op, MachineOperand::MO_VirtualRegister,
- tmpReg);
- }
- }
-
- // Also, check for implicit operands used by the machine instruction
- // (no need to check those defined since they cannot be constants).
- // These include:
- // -- arguments to a Call
- // -- return value of a Return
- // Any such operand that is a constant value needs to be fixed also.
- // The current instructions with implicit refs (viz., Call and Return)
- // have no immediate fields, so the constant always needs to be loaded
- // into a register.
- bool isCall = instrInfo.isCall(opCode);
- unsigned lastCallArgNum = 0; // unused if not a call
- CallArgsDescriptor* argDesc = NULL; // unused if not a call
- if (isCall)
- argDesc = CallArgsDescriptor::get(minstr);
-
- for (unsigned i=0, N=minstr->getNumImplicitRefs(); i < N; ++i)
- if (isa<Constant>(minstr->getImplicitRef(i))) {
- Value* oldVal = minstr->getImplicitRef(i);
- TmpInstruction* tmpReg =
- InsertCodeToLoadConstant(F, oldVal, vmInstr, MVec, target);
- minstr->setImplicitRef(i, tmpReg);
-
- if (isCall) {
- // find and replace the argument in the CallArgsDescriptor
- unsigned i=lastCallArgNum;
- while (argDesc->getArgInfo(i).getArgVal() != oldVal)
- ++i;
- assert(i < argDesc->getNumArgs() &&
- "Constant operands to a call *must* be in the arg list");
- lastCallArgNum = i;
- argDesc->getArgInfo(i).replaceArgVal(tmpReg);
- }
- }
-
- return MVec;
-}
-
-static inline void Add3OperandInstr(unsigned Opcode, InstructionNode* Node,
- std::vector<MachineInstr*>& mvec) {
- mvec.push_back(BuildMI(Opcode, 3).addReg(Node->leftChild()->getValue())
- .addReg(Node->rightChild()->getValue())
- .addRegDef(Node->getValue()));
-}
-
-/// IsZero - Check for a constant 0.
-///
-static inline bool IsZero(Value* idx) {
- return (isa<Constant>(idx) && cast<Constant>(idx)->isNullValue()) ||
- isa<UndefValue>(idx);
-}
-
-/// FoldGetElemChain - Fold a chain of GetElementPtr instructions containing
-/// only constant offsets into an equivalent (Pointer, IndexVector) pair.
-/// Returns the pointer Value, and stores the resulting IndexVector in argument
-/// chainIdxVec. This is a helper function for FoldConstantIndices that does the
-/// actual folding.
-//
-static Value*
-FoldGetElemChain(InstrTreeNode* ptrNode, std::vector<Value*>& chainIdxVec,
- bool lastInstHasLeadingNonZero) {
- InstructionNode* gepNode = dyn_cast<InstructionNode>(ptrNode);
- GetElementPtrInst* gepInst =
- dyn_cast_or_null<GetElementPtrInst>(gepNode ? gepNode->getInstruction() :0);
-
- // ptr value is not computed in this tree or ptr value does not come from GEP
- // instruction
- if (gepInst == NULL)
- return NULL;
-
- // Return NULL if we don't fold any instructions in.
- Value* ptrVal = NULL;
-
- // Now chase the chain of getElementInstr instructions, if any.
- // Check for any non-constant indices and stop there.
- // Also, stop if the first index of child is a non-zero array index
- // and the last index of the current node is a non-array index:
- // in that case, a non-array declared type is being accessed as an array
- // which is not type-safe, but could be legal.
- InstructionNode* ptrChild = gepNode;
- while (ptrChild && (ptrChild->getOpLabel() == Instruction::GetElementPtr ||
- ptrChild->getOpLabel() == GetElemPtrIdx)) {
- // Child is a GetElemPtr instruction
- gepInst = cast<GetElementPtrInst>(ptrChild->getValue());
- User::op_iterator OI, firstIdx = gepInst->idx_begin();
- User::op_iterator lastIdx = gepInst->idx_end();
- bool allConstantOffsets = true;
-
- // The first index of every GEP must be an array index.
- assert((*firstIdx)->getType() == Type::LongTy &&
- "INTERNAL ERROR: Structure index for a pointer type!");
-
- // If the last instruction had a leading non-zero index, check if the
- // current one references a sequential (i.e., indexable) type.
- // If not, the code is not type-safe and we would create an illegal GEP
- // by folding them, so don't fold any more instructions.
- if (lastInstHasLeadingNonZero)
- if (! isa<SequentialType>(gepInst->getType()->getElementType()))
- break; // cannot fold in any preceding getElementPtr instrs.
-
- // Check that all offsets are constant for this instruction
- for (OI = firstIdx; allConstantOffsets && OI != lastIdx; ++OI)
- allConstantOffsets = isa<ConstantInt>(*OI);
-
- if (allConstantOffsets) {
- // Get pointer value out of ptrChild.
- ptrVal = gepInst->getPointerOperand();
-
- // Insert its index vector at the start, skipping any leading [0]
- // Remember the old size to check if anything was inserted.
- unsigned oldSize = chainIdxVec.size();
- int firstIsZero = IsZero(*firstIdx);
- chainIdxVec.insert(chainIdxVec.begin(), firstIdx + firstIsZero, lastIdx);
-
- // Remember if it has leading zero index: it will be discarded later.
- if (oldSize < chainIdxVec.size())
- lastInstHasLeadingNonZero = !firstIsZero;
-
- // Mark the folded node so no code is generated for it.
- ((InstructionNode*) ptrChild)->markFoldedIntoParent();
-
- // Get the previous GEP instruction and continue trying to fold
- ptrChild = dyn_cast<InstructionNode>(ptrChild->leftChild());
- } else // cannot fold this getElementPtr instr. or any preceding ones
- break;
- }
-
- // If the first getElementPtr instruction had a leading [0], add it back.
- // Note that this instruction is the *last* one that was successfully
- // folded *and* contributed any indices, in the loop above.
- if (ptrVal && ! lastInstHasLeadingNonZero)
- chainIdxVec.insert(chainIdxVec.begin(), ConstantSInt::get(Type::LongTy,0));
-
- return ptrVal;
-}
-
-/// GetGEPInstArgs - Helper function for GetMemInstArgs that handles the
-/// final getElementPtr instruction used by (or same as) the memory operation.
-/// Extracts the indices of the current instruction and tries to fold in
-/// preceding ones if all indices of the current one are constant.
-///
-static Value *GetGEPInstArgs(InstructionNode *gepNode,
- std::vector<Value *> &idxVec,
- bool &allConstantIndices) {
- allConstantIndices = true;
- GetElementPtrInst* gepI = cast<GetElementPtrInst>(gepNode->getInstruction());
-
- // Default pointer is the one from the current instruction.
- Value* ptrVal = gepI->getPointerOperand();
- InstrTreeNode* ptrChild = gepNode->leftChild();
-
- // Extract the index vector of the GEP instruction.
- // If all indices are constant and first index is zero, try to fold
- // in preceding GEPs with all constant indices.
- for (User::op_iterator OI=gepI->idx_begin(), OE=gepI->idx_end();
- allConstantIndices && OI != OE; ++OI)
- if (! isa<Constant>(*OI))
- allConstantIndices = false; // note: this also terminates loop!
-
- // If we have only constant indices, fold chains of constant indices
- // in this and any preceding GetElemPtr instructions.
- bool foldedGEPs = false;
- bool leadingNonZeroIdx = gepI && ! IsZero(*gepI->idx_begin());
- if (allConstantIndices && !leadingNonZeroIdx)
- if (Value* newPtr = FoldGetElemChain(ptrChild, idxVec, leadingNonZeroIdx)) {
- ptrVal = newPtr;
- foldedGEPs = true;
- }
-
- // Append the index vector of the current instruction.
- // Skip the leading [0] index if preceding GEPs were folded into this.
- idxVec.insert(idxVec.end(),
- gepI->idx_begin() + (foldedGEPs && !leadingNonZeroIdx),
- gepI->idx_end());
-
- return ptrVal;
-}
-
-/// GetMemInstArgs - Get the pointer value and the index vector for a memory
-/// operation (GetElementPtr, Load, or Store). If all indices of the given
-/// memory operation are constant, fold in constant indices in a chain of
-/// preceding GetElementPtr instructions (if any), and return the pointer value
-/// of the first instruction in the chain. All folded instructions are marked so
-/// no code is generated for them. Returns the pointer Value to use, and
-/// returns the resulting IndexVector in idxVec. Sets allConstantIndices
-/// to true/false if all indices are/aren't const.
-///
-static Value *GetMemInstArgs(InstructionNode *memInstrNode,
- std::vector<Value*> &idxVec,
- bool& allConstantIndices) {
- allConstantIndices = false;
- Instruction* memInst = memInstrNode->getInstruction();
- assert(idxVec.size() == 0 && "Need empty vector to return indices");
-
- // If there is a GetElemPtr instruction to fold in to this instr,
- // it must be in the left child for Load and GetElemPtr, and in the
- // right child for Store instructions.
- InstrTreeNode* ptrChild = (memInst->getOpcode() == Instruction::Store
- ? memInstrNode->rightChild()
- : memInstrNode->leftChild());
-
- // Default pointer is the one from the current instruction.
- Value* ptrVal = ptrChild->getValue();
-
- // Find the "last" GetElemPtr instruction: this one or the immediate child.
- // There will be none if this is a load or a store from a scalar pointer.
- InstructionNode* gepNode = NULL;
- if (isa<GetElementPtrInst>(memInst))
- gepNode = memInstrNode;
- else if (isa<InstructionNode>(ptrChild) && isa<GetElementPtrInst>(ptrVal)) {
- // Child of load/store is a GEP and memInst is its only use.
- // Use its indices and mark it as folded.
- gepNode = cast<InstructionNode>(ptrChild);
- gepNode->markFoldedIntoParent();
- }
-
- // If there are no indices, return the current pointer.
- // Else extract the pointer from the GEP and fold the indices.
- return gepNode ? GetGEPInstArgs(gepNode, idxVec, allConstantIndices)
- : ptrVal;
-}
-
-static inline MachineOpCode
-ChooseBprInstruction(const InstructionNode* instrNode) {
- MachineOpCode opCode;
-
- Instruction* setCCInstr =
- ((InstructionNode*) instrNode->leftChild())->getInstruction();
-
- switch(setCCInstr->getOpcode()) {
- case Instruction::SetEQ: opCode = V9::BRZ; break;
- case Instruction::SetNE: opCode = V9::BRNZ; break;
- case Instruction::SetLE: opCode = V9::BRLEZ; break;
- case Instruction::SetGE: opCode = V9::BRGEZ; break;
- case Instruction::SetLT: opCode = V9::BRLZ; break;
- case Instruction::SetGT: opCode = V9::BRGZ; break;
- default:
- assert(0 && "Unrecognized VM instruction!");
- opCode = V9::INVALID_OPCODE;
- break;
- }
-
- return opCode;
-}
-
-static inline MachineOpCode
-ChooseBpccInstruction(const InstructionNode* instrNode,
- const BinaryOperator* setCCInstr) {
- MachineOpCode opCode = V9::INVALID_OPCODE;
-
- bool isSigned = setCCInstr->getOperand(0)->getType()->isSigned();
-
- if (isSigned) {
- switch(setCCInstr->getOpcode()) {
- case Instruction::SetEQ: opCode = V9::BE; break;
- case Instruction::SetNE: opCode = V9::BNE; break;
- case Instruction::SetLE: opCode = V9::BLE; break;
- case Instruction::SetGE: opCode = V9::BGE; break;
- case Instruction::SetLT: opCode = V9::BL; break;
- case Instruction::SetGT: opCode = V9::BG; break;
- default:
- assert(0 && "Unrecognized VM instruction!");
- break;
- }
- } else {
- switch(setCCInstr->getOpcode()) {
- case Instruction::SetEQ: opCode = V9::BE; break;
- case Instruction::SetNE: opCode = V9::BNE; break;
- case Instruction::SetLE: opCode = V9::BLEU; break;
- case Instruction::SetGE: opCode = V9::BCC; break;
- case Instruction::SetLT: opCode = V9::BCS; break;
- case Instruction::SetGT: opCode = V9::BGU; break;
- default:
- assert(0 && "Unrecognized VM instruction!");
- break;
- }
- }
-
- return opCode;
-}
-
-static inline MachineOpCode
-ChooseBFpccInstruction(const InstructionNode* instrNode,
- const BinaryOperator* setCCInstr) {
- MachineOpCode opCode = V9::INVALID_OPCODE;
-
- switch(setCCInstr->getOpcode()) {
- case Instruction::SetEQ: opCode = V9::FBE; break;
- case Instruction::SetNE: opCode = V9::FBNE; break;
- case Instruction::SetLE: opCode = V9::FBLE; break;
- case Instruction::SetGE: opCode = V9::FBGE; break;
- case Instruction::SetLT: opCode = V9::FBL; break;
- case Instruction::SetGT: opCode = V9::FBG; break;
- default:
- assert(0 && "Unrecognized VM instruction!");
- break;
- }
-
- return opCode;
-}
-
-// GetTmpForCC - Create a unique TmpInstruction for a boolean value,
-// representing the CC register used by a branch on that value.
-// For now, hack this using a little static cache of TmpInstructions.
-// Eventually the entire BURG instruction selection should be put
-// into a separate class that can hold such information.
-// The static cache is not too bad because the memory for these
-// TmpInstructions will be freed along with the rest of the Function anyway.
-//
-static TmpInstruction *GetTmpForCC (Value* boolVal, const Function *F,
- const Type* ccType,
- MachineCodeForInstruction& mcfi) {
- typedef hash_map<const Value*, TmpInstruction*> BoolTmpCache;
- static BoolTmpCache boolToTmpCache; // Map boolVal -> TmpInstruction*
- static const Function *lastFunction = 0;// Use to flush cache between funcs
-
- assert(boolVal->getType() == Type::BoolTy && "Weird but ok! Delete assert");
-
- if (lastFunction != F) {
- lastFunction = F;
- boolToTmpCache.clear();
- }
-
- // Look for tmpI and create a new one otherwise. The new value is
- // directly written to map using the ref returned by operator[].
- TmpInstruction*& tmpI = boolToTmpCache[boolVal];
- if (tmpI == NULL)
- tmpI = new TmpInstruction(mcfi, ccType, boolVal);
-
- return tmpI;
-}
-
-static inline MachineOpCode
-ChooseBccInstruction(const InstructionNode* instrNode, const Type*& setCCType) {
- InstructionNode* setCCNode = (InstructionNode*) instrNode->leftChild();
- assert(setCCNode->getOpLabel() == SetCCOp);
- BinaryOperator* setCCInstr =cast<BinaryOperator>(setCCNode->getInstruction());
- setCCType = setCCInstr->getOperand(0)->getType();
-
- if (setCCType->isFloatingPoint())
- return ChooseBFpccInstruction(instrNode, setCCInstr);
- else
- return ChooseBpccInstruction(instrNode, setCCInstr);
-}
-
-/// ChooseMovFpcciInstruction - WARNING: since this function has only one
-/// caller, it always returns the opcode that expects an immediate and a
-/// register. If this function is ever used in cases where an opcode that takes
-/// two registers is required, then modify this function and use
-/// convertOpcodeFromRegToImm() where required. It will be necessary to expand
-/// convertOpcodeFromRegToImm() to handle the new cases of opcodes.
-///
-static inline MachineOpCode
-ChooseMovFpcciInstruction(const InstructionNode* instrNode) {
- MachineOpCode opCode = V9::INVALID_OPCODE;
-
- switch(instrNode->getInstruction()->getOpcode()) {
- case Instruction::SetEQ: opCode = V9::MOVFEi; break;
- case Instruction::SetNE: opCode = V9::MOVFNEi; break;
- case Instruction::SetLE: opCode = V9::MOVFLEi; break;
- case Instruction::SetGE: opCode = V9::MOVFGEi; break;
- case Instruction::SetLT: opCode = V9::MOVFLi; break;
- case Instruction::SetGT: opCode = V9::MOVFGi; break;
- default:
- assert(0 && "Unrecognized VM instruction!");
- break;
- }
-
- return opCode;
-}
-
-/// ChooseMovpcciForSetCC -- Choose a conditional-move instruction
-/// based on the type of SetCC operation.
-///
-/// WARNING: like the previous function, this function always returns
-/// the opcode that expects an immediate and a register. See above.
-///
-static MachineOpCode ChooseMovpcciForSetCC(const InstructionNode* instrNode) {
- MachineOpCode opCode = V9::INVALID_OPCODE;
-
- const Type* opType = instrNode->leftChild()->getValue()->getType();
- assert(opType->isIntegral() || isa<PointerType>(opType));
- bool noSign = opType->isUnsigned() || isa<PointerType>(opType);
-
- switch(instrNode->getInstruction()->getOpcode()) {
- case Instruction::SetEQ: opCode = V9::MOVEi; break;
- case Instruction::SetLE: opCode = noSign? V9::MOVLEUi : V9::MOVLEi; break;
- case Instruction::SetGE: opCode = noSign? V9::MOVCCi : V9::MOVGEi; break;
- case Instruction::SetLT: opCode = noSign? V9::MOVCSi : V9::MOVLi; break;
- case Instruction::SetGT: opCode = noSign? V9::MOVGUi : V9::MOVGi; break;
- case Instruction::SetNE: opCode = V9::MOVNEi; break;
- default: assert(0 && "Unrecognized LLVM instr!"); break;
- }
-
- return opCode;
-}
-
-/// ChooseMovpregiForSetCC -- Choose a conditional-move-on-register-value
-/// instruction based on the type of SetCC operation. These instructions
-/// compare a register with 0 and perform the move is the comparison is true.
-///
-/// WARNING: like the previous function, this function it always returns
-/// the opcode that expects an immediate and a register. See above.
-///
-static MachineOpCode ChooseMovpregiForSetCC(const InstructionNode* instrNode) {
- MachineOpCode opCode = V9::INVALID_OPCODE;
-
- switch(instrNode->getInstruction()->getOpcode()) {
- case Instruction::SetEQ: opCode = V9::MOVRZi; break;
- case Instruction::SetLE: opCode = V9::MOVRLEZi; break;
- case Instruction::SetGE: opCode = V9::MOVRGEZi; break;
- case Instruction::SetLT: opCode = V9::MOVRLZi; break;
- case Instruction::SetGT: opCode = V9::MOVRGZi; break;
- case Instruction::SetNE: opCode = V9::MOVRNZi; break;
- default: assert(0 && "Unrecognized VM instr!"); break;
- }
-
- return opCode;
-}
-
-static inline MachineOpCode
-ChooseConvertToFloatInstr(const TargetMachine& target,
- OpLabel vopCode, const Type* opType) {
- assert((vopCode == ToFloatTy || vopCode == ToDoubleTy) &&
- "Unrecognized convert-to-float opcode!");
- assert((opType->isIntegral() || opType->isFloatingPoint() ||
- isa<PointerType>(opType))
- && "Trying to convert a non-scalar type to FLOAT/DOUBLE?");
-
- MachineOpCode opCode = V9::INVALID_OPCODE;
-
- unsigned opSize = target.getTargetData().getTypeSize(opType);
-
- if (opType == Type::FloatTy)
- opCode = (vopCode == ToFloatTy? V9::NOP : V9::FSTOD);
- else if (opType == Type::DoubleTy)
- opCode = (vopCode == ToFloatTy? V9::FDTOS : V9::NOP);
- else if (opSize <= 4)
- opCode = (vopCode == ToFloatTy? V9::FITOS : V9::FITOD);
- else {
- assert(opSize == 8 && "Unrecognized type size > 4 and < 8!");
- opCode = (vopCode == ToFloatTy? V9::FXTOS : V9::FXTOD);
- }
-
- return opCode;
-}
-
-static inline MachineOpCode
-ChooseConvertFPToIntInstr(const TargetMachine& target,
- const Type* destType, const Type* opType) {
- assert((opType == Type::FloatTy || opType == Type::DoubleTy)
- && "This function should only be called for FLOAT or DOUBLE");
- assert((destType->isIntegral() || isa<PointerType>(destType))
- && "Trying to convert FLOAT/DOUBLE to a non-scalar type?");
-
- MachineOpCode opCode = V9::INVALID_OPCODE;
-
- unsigned destSize = target.getTargetData().getTypeSize(destType);
-
- if (destType == Type::UIntTy)
- assert(destType != Type::UIntTy && "Expand FP-to-uint beforehand.");
- else if (destSize <= 4)
- opCode = (opType == Type::FloatTy)? V9::FSTOI : V9::FDTOI;
- else {
- assert(destSize == 8 && "Unrecognized type size > 4 and < 8!");
- opCode = (opType == Type::FloatTy)? V9::FSTOX : V9::FDTOX;
- }
-
- return opCode;
-}
-
-static MachineInstr*
-CreateConvertFPToIntInstr(const TargetMachine& target, Value* srcVal,
- Value* destVal, const Type* destType) {
- MachineOpCode opCode = ChooseConvertFPToIntInstr(target, destType,
- srcVal->getType());
- assert(opCode != V9::INVALID_OPCODE && "Expected to need conversion!");
- return BuildMI(opCode, 2).addReg(srcVal).addRegDef(destVal);
-}
-
-/// CreateCodeToConvertFloatToInt: Convert FP value to signed or unsigned
-/// integer. The FP value must be converted to the dest type in an FP register,
-/// and the result is then copied from FP to int register via memory. SPARC
-/// does not have a float-to-uint conversion, only a float-to-int (fdtoi).
-/// Since fdtoi converts to signed integers, any FP value V between MAXINT+1 and
-/// MAXUNSIGNED (i.e., 2^31 <= V <= 2^32-1) would be converted incorrectly.
-/// Therefore, for converting an FP value to uint32_t, we first need to convert
-/// to uint64_t and then to uint32_t.
-///
-static void
-CreateCodeToConvertFloatToInt(const TargetMachine& target,
- Value* opVal, Instruction* destI,
- std::vector<MachineInstr*>& mvec,
- MachineCodeForInstruction& mcfi) {
- Function* F = destI->getParent()->getParent();
-
- // Create a temporary to represent the FP register into which the
- // int value will placed after conversion. The type of this temporary
- // depends on the type of FP register to use: single-prec for a 32-bit
- // int or smaller; double-prec for a 64-bit int.
- size_t destSize = target.getTargetData().getTypeSize(destI->getType());
-
- const Type* castDestType = destI->getType(); // type for the cast instr result
- const Type* castDestRegType; // type for cast instruction result reg
- TmpInstruction* destForCast; // dest for cast instruction
- Instruction* fpToIntCopyDest = destI; // dest for fp-reg-to-int-reg copy instr
-
- // For converting an FP value to uint32_t, we first need to convert to
- // uint64_t and then to uint32_t, as explained above.
- if (destI->getType() == Type::UIntTy) {
- castDestType = Type::ULongTy; // use this instead of type of destI
- castDestRegType = Type::DoubleTy; // uint64_t needs 64-bit FP register.
- destForCast = new TmpInstruction(mcfi, castDestRegType, opVal);
- fpToIntCopyDest = new TmpInstruction(mcfi, castDestType, destForCast);
- } else {
- castDestRegType = (destSize > 4)? Type::DoubleTy : Type::FloatTy;
- destForCast = new TmpInstruction(mcfi, castDestRegType, opVal);
- }
-
- // Create the fp-to-int conversion instruction (src and dest regs are FP regs)
- mvec.push_back(CreateConvertFPToIntInstr(target, opVal, destForCast,
- castDestType));
-
- // Create the fpreg-to-intreg copy code
- CreateCodeToCopyFloatToInt(target, F, destForCast, fpToIntCopyDest, mvec,
- mcfi);
-
- // Create the uint64_t to uint32_t conversion, if needed
- if (destI->getType() == Type::UIntTy)
- CreateZeroExtensionInstructions(target, F, fpToIntCopyDest, destI,
- /*numLowBits*/ 32, mvec, mcfi);
-}
-
-static inline MachineOpCode
-ChooseAddInstruction(const InstructionNode* instrNode) {
- return ChooseAddInstructionByType(instrNode->getInstruction()->getType());
-}
-
-static inline MachineInstr*
-CreateMovFloatInstruction(const InstructionNode* instrNode,
- const Type* resultType) {
- return BuildMI((resultType == Type::FloatTy) ? V9::FMOVS : V9::FMOVD, 2)
- .addReg(instrNode->leftChild()->getValue())
- .addRegDef(instrNode->getValue());
-}
-
-static inline MachineInstr*
-CreateAddConstInstruction(const InstructionNode* instrNode) {
- MachineInstr* minstr = NULL;
-
- Value* constOp = ((InstrTreeNode*) instrNode->rightChild())->getValue();
- assert(isa<Constant>(constOp));
-
- // Cases worth optimizing are:
- // (1) Add with 0 for float or double: use an FMOV of appropriate type,
- // instead of an FADD (1 vs 3 cycles). There is no integer MOV.
- if (ConstantFP *FPC = dyn_cast<ConstantFP>(constOp)) {
- double dval = FPC->getValue();
- if (dval == 0.0)
- minstr = CreateMovFloatInstruction(instrNode,
- instrNode->getInstruction()->getType());
- }
-
- return minstr;
-}
-
-static inline MachineOpCode ChooseSubInstructionByType(const Type* resultType) {
- MachineOpCode opCode = V9::INVALID_OPCODE;
-
- if (resultType->isInteger() || isa<PointerType>(resultType)) {
- opCode = V9::SUBr;
- } else {
- switch(resultType->getTypeID()) {
- case Type::FloatTyID: opCode = V9::FSUBS; break;
- case Type::DoubleTyID: opCode = V9::FSUBD; break;
- default: assert(0 && "Invalid type for SUB instruction"); break;
- }
- }
-
- return opCode;
-}
-
-static inline MachineInstr*
-CreateSubConstInstruction(const InstructionNode* instrNode) {
- MachineInstr* minstr = NULL;
-
- Value* constOp = ((InstrTreeNode*) instrNode->rightChild())->getValue();
- assert(isa<Constant>(constOp));
-
- // Cases worth optimizing are:
- // (1) Sub with 0 for float or double: use an FMOV of appropriate type,
- // instead of an FSUB (1 vs 3 cycles). There is no integer MOV.
- if (ConstantFP *FPC = dyn_cast<ConstantFP>(constOp)) {
- double dval = FPC->getValue();
- if (dval == 0.0)
- minstr = CreateMovFloatInstruction(instrNode,
- instrNode->getInstruction()->getType());
- }
-
- return minstr;
-}
-
-static inline MachineOpCode
-ChooseFcmpInstruction(const InstructionNode* instrNode) {
- MachineOpCode opCode = V9::INVALID_OPCODE;
-
- Value* operand = ((InstrTreeNode*) instrNode->leftChild())->getValue();
- switch(operand->getType()->getTypeID()) {
- case Type::FloatTyID: opCode = V9::FCMPS; break;
- case Type::DoubleTyID: opCode = V9::FCMPD; break;
- default: assert(0 && "Invalid type for FCMP instruction"); break;
- }
-
- return opCode;
-}
-
-/// BothFloatToDouble - Assumes that leftArg and rightArg of instrNode are both
-/// cast instructions. Returns true if both are floats cast to double.
-///
-static inline bool BothFloatToDouble(const InstructionNode* instrNode) {
- InstrTreeNode* leftArg = instrNode->leftChild();
- InstrTreeNode* rightArg = instrNode->rightChild();
- InstrTreeNode* leftArgArg = leftArg->leftChild();
- InstrTreeNode* rightArgArg = rightArg->leftChild();
- assert(leftArg->getValue()->getType() == rightArg->getValue()->getType());
- return (leftArg->getValue()->getType() == Type::DoubleTy &&
- leftArgArg->getValue()->getType() == Type::FloatTy &&
- rightArgArg->getValue()->getType() == Type::FloatTy);
-}
-
-static inline MachineOpCode ChooseMulInstructionByType(const Type* resultType) {
- MachineOpCode opCode = V9::INVALID_OPCODE;
-
- if (resultType->isInteger())
- opCode = V9::MULXr;
- else
- switch(resultType->getTypeID()) {
- case Type::FloatTyID: opCode = V9::FMULS; break;
- case Type::DoubleTyID: opCode = V9::FMULD; break;
- default: assert(0 && "Invalid type for MUL instruction"); break;
- }
-
- return opCode;
-}
-
-static inline MachineInstr*
-CreateIntNegInstruction(const TargetMachine& target, Value* vreg) {
- return BuildMI(V9::SUBr, 3).addMReg(target.getRegInfo()->getZeroRegNum())
- .addReg(vreg).addRegDef(vreg);
-}
-
-static inline MachineInstr*
-CreateIntNegInstruction(const TargetMachine& target, Value* vreg, Value *destreg) {
- return BuildMI(V9::SUBr, 3).addMReg(target.getRegInfo()->getZeroRegNum())
- .addReg(vreg).addRegDef(destreg);
-}
-
-/// CreateShiftInstructions - Create instruction sequence for any shift
-/// operation. SLL or SLLX on an operand smaller than the integer reg. size
-/// (64bits) requires a second instruction for explicit sign-extension. Note
-/// that we only have to worry about a sign-bit appearing in the most
-/// significant bit of the operand after shifting (e.g., bit 32 of Int or bit 16
-/// of Short), so we do not have to worry about results that are as large as a
-/// normal integer register.
-///
-static inline void
-CreateShiftInstructions(const TargetMachine& target, Function* F,
- MachineOpCode shiftOpCode, Value* argVal1,
- Value* optArgVal2, /* Use optArgVal2 if not NULL */
- unsigned optShiftNum, /* else use optShiftNum */
- Instruction* destVal, std::vector<MachineInstr*>& mvec,
- MachineCodeForInstruction& mcfi) {
- assert((optArgVal2 != NULL || optShiftNum <= 64) &&
- "Large shift sizes unexpected, but can be handled below: "
- "You need to check whether or not it fits in immed field below");
-
- // If this is a logical left shift of a type smaller than the standard
- // integer reg. size, we have to extend the sign-bit into upper bits
- // of dest, so we need to put the result of the SLL into a temporary.
- Value* shiftDest = destVal;
- unsigned opSize = target.getTargetData().getTypeSize(argVal1->getType());
-
- if ((shiftOpCode == V9::SLLr5 || shiftOpCode == V9::SLLXr6) && opSize < 8) {
- // put SLL result into a temporary
- shiftDest = new TmpInstruction(mcfi, argVal1, optArgVal2, "sllTmp");
- }
-
- MachineInstr* M = (optArgVal2 != NULL)
- ? BuildMI(shiftOpCode, 3).addReg(argVal1).addReg(optArgVal2)
- .addReg(shiftDest, MachineOperand::Def)
- : BuildMI(shiftOpCode, 3).addReg(argVal1).addZImm(optShiftNum)
- .addReg(shiftDest, MachineOperand::Def);
- mvec.push_back(M);
-
- if (shiftDest != destVal) {
- // extend the sign-bit of the result into all upper bits of dest
- assert(8*opSize <= 32 && "Unexpected type size > 4 and < IntRegSize?");
- CreateSignExtensionInstructions(target, F, shiftDest, destVal, 8*opSize,
- mvec, mcfi);
- }
-}
-
-/// CreateMulConstInstruction - Does not create any instructions if we
-/// cannot exploit constant to create a cheaper instruction. This returns the
-/// approximate cost of the instructions generated, which is used to pick the
-/// cheapest when both operands are constant.
-///
-static unsigned
-CreateMulConstInstruction(const TargetMachine &target, Function* F,
- Value* lval, Value* rval, Instruction* destVal,
- std::vector<MachineInstr*>& mvec,
- MachineCodeForInstruction& mcfi) {
- // Use max. multiply cost, viz., cost of MULX
- unsigned cost = target.getInstrInfo()->minLatency(V9::MULXr);
- unsigned firstNewInstr = mvec.size();
-
- Value* constOp = rval;
- if (! isa<Constant>(constOp))
- return cost;
-
- // Cases worth optimizing are:
- // (1) Multiply by 0 or 1 for any type: replace with copy (ADD or FMOV)
- // (2) Multiply by 2^x for integer types: replace with Shift
- const Type* resultType = destVal->getType();
-
- if (resultType->isInteger() || isa<PointerType>(resultType)) {
- bool isValidConst;
- int64_t C = (int64_t) ConvertConstantToIntType(target, constOp,
- constOp->getType(),
- isValidConst);
- if (isValidConst) {
- bool needNeg = false;
- if (C < 0) {
- needNeg = true;
- C = -C;
- }
- TmpInstruction *tmpNeg = 0;
-
- if (C == 0 || C == 1) {
- cost = target.getInstrInfo()->minLatency(V9::ADDr);
- unsigned Zero = target.getRegInfo()->getZeroRegNum();
- MachineInstr* M;
- if (C == 0)
- M =BuildMI(V9::ADDr,3).addMReg(Zero).addMReg(Zero).addRegDef(destVal);
- else
- M = BuildMI(V9::ADDr,3).addReg(lval).addMReg(Zero).addRegDef(destVal);
- mvec.push_back(M);
- } else if (isPowerOf2_64(C)) {
- unsigned pow = Log2_64(C);
- if(!needNeg) {
- unsigned opSize = target.getTargetData().getTypeSize(resultType);
- MachineOpCode opCode = (opSize <= 32)? V9::SLLr5 : V9::SLLXr6;
- CreateShiftInstructions(target, F, opCode, lval, NULL, pow,
- destVal, mvec, mcfi);
- }
- else {
- //Create tmp instruction to hold intermeidate value, since we need
- //to negate the result
- tmpNeg = new TmpInstruction(mcfi, lval);
- unsigned opSize = target.getTargetData().getTypeSize(resultType);
- MachineOpCode opCode = (opSize <= 32)? V9::SLLr5 : V9::SLLXr6;
- CreateShiftInstructions(target, F, opCode, lval, NULL, pow,
- tmpNeg, mvec, mcfi);
- }
-
- }
-
- if (mvec.size() > 0 && needNeg) {
- MachineInstr* M = 0;
- if(tmpNeg)
- // insert <reg = SUB 0, reg> after the instr to flip the sign
- M = CreateIntNegInstruction(target, tmpNeg, destVal);
- else
- M = CreateIntNegInstruction(target, destVal);
- mvec.push_back(M);
- }
- }
- } else {
- if (ConstantFP *FPC = dyn_cast<ConstantFP>(constOp)) {
- double dval = FPC->getValue();
- if (fabs(dval) == 1) {
- MachineOpCode opCode = (dval < 0)
- ? (resultType == Type::FloatTy? V9::FNEGS : V9::FNEGD)
- : (resultType == Type::FloatTy? V9::FMOVS : V9::FMOVD);
- mvec.push_back(BuildMI(opCode,2).addReg(lval).addRegDef(destVal));
- }
- }
- }
-
- if (firstNewInstr < mvec.size()) {
- cost = 0;
- for (unsigned i=firstNewInstr; i < mvec.size(); ++i)
- cost += target.getInstrInfo()->minLatency(mvec[i]->getOpcode());
- }
-
- return cost;
-}
-
-/// CreateCheapestMulConstInstruction - Does not create any instructions
-/// if we cannot exploit constant to create a cheaper instruction.
-///
-static inline void
-CreateCheapestMulConstInstruction(const TargetMachine &target, Function* F,
- Value* lval, Value* rval,
- Instruction* destVal,
- std::vector<MachineInstr*>& mvec,
- MachineCodeForInstruction& mcfi) {
- Value* constOp;
- if (isa<Constant>(lval) && isa<Constant>(rval)) {
- // both operands are constant: evaluate and "set" in dest
- Constant* P = ConstantExpr::get(Instruction::Mul,
- cast<Constant>(lval),
- cast<Constant>(rval));
- CreateCodeToLoadConst (target, F, P, destVal, mvec, mcfi);
- }
- else if (isa<Constant>(rval)) // rval is constant, but not lval
- CreateMulConstInstruction(target, F, lval, rval, destVal, mvec, mcfi);
- else if (isa<Constant>(lval)) // lval is constant, but not rval
- CreateMulConstInstruction(target, F, lval, rval, destVal, mvec, mcfi);
-
- // else neither is constant
- return;
-}
-
-/// CreateMulInstruction - Returns NULL if we cannot exploit constant
-/// to create a cheaper instruction.
-///
-static inline void
-CreateMulInstruction(const TargetMachine &target, Function* F,
- Value* lval, Value* rval, Instruction* destVal,
- std::vector<MachineInstr*>& mvec,
- MachineCodeForInstruction& mcfi,
- MachineOpCode forceMulOp = -1) {
- unsigned L = mvec.size();
- CreateCheapestMulConstInstruction(target,F, lval, rval, destVal, mvec, mcfi);
- if (mvec.size() == L) {
- // no instructions were added so create MUL reg, reg, reg.
- // Use FSMULD if both operands are actually floats cast to doubles.
- // Otherwise, use the default opcode for the appropriate type.
- MachineOpCode mulOp = ((forceMulOp != -1)
- ? forceMulOp
- : ChooseMulInstructionByType(destVal->getType()));
- mvec.push_back(BuildMI(mulOp, 3).addReg(lval).addReg(rval)
- .addRegDef(destVal));
- }
-}
-
-/// ChooseDivInstruction - Generate a divide instruction for Div or Rem.
-/// For Rem, this assumes that the operand type will be signed if the result
-/// type is signed. This is correct because they must have the same sign.
-///
-static inline MachineOpCode
-ChooseDivInstruction(TargetMachine &target, const InstructionNode* instrNode) {
- MachineOpCode opCode = V9::INVALID_OPCODE;
-
- const Type* resultType = instrNode->getInstruction()->getType();
-
- if (resultType->isInteger())
- opCode = resultType->isSigned()? V9::SDIVXr : V9::UDIVXr;
- else
- switch(resultType->getTypeID()) {
- case Type::FloatTyID: opCode = V9::FDIVS; break;
- case Type::DoubleTyID: opCode = V9::FDIVD; break;
- default: assert(0 && "Invalid type for DIV instruction"); break;
- }
-
- return opCode;
-}
-
-/// CreateDivConstInstruction - Return if we cannot exploit constant to create
-/// a cheaper instruction.
-///
-static void CreateDivConstInstruction(TargetMachine &target,
- const InstructionNode* instrNode,
- std::vector<MachineInstr*>& mvec) {
- Value* LHS = instrNode->leftChild()->getValue();
- Value* constOp = ((InstrTreeNode*) instrNode->rightChild())->getValue();
- if (!isa<Constant>(constOp))
- return;
-
- Instruction* destVal = instrNode->getInstruction();
- unsigned ZeroReg = target.getRegInfo()->getZeroRegNum();
-
- // Cases worth optimizing are:
- // (1) Divide by 1 for any type: replace with copy (ADD or FMOV)
- // (2) Divide by 2^x for integer types: replace with SR[L or A]{X}
- const Type* resultType = instrNode->getInstruction()->getType();
-
- if (resultType->isInteger()) {
- bool isValidConst;
- int64_t C = (int64_t) ConvertConstantToIntType(target, constOp,
- constOp->getType(),
- isValidConst);
- if (isValidConst) {
- bool needNeg = false;
- if (C < 0) {
- needNeg = true;
- C = -C;
- }
-
- if (C == 1) {
- mvec.push_back(BuildMI(V9::ADDr, 3).addReg(LHS).addMReg(ZeroReg)
- .addRegDef(destVal));
- } else if (isPowerOf2_64(C)) {
- unsigned pow = Log2_64(C);
- unsigned opCode;
- Value* shiftOperand;
- unsigned opSize = target.getTargetData().getTypeSize(resultType);
-
- if (resultType->isSigned()) {
- // For N / 2^k, if the operand N is negative,
- // we need to add (2^k - 1) before right-shifting by k, i.e.,
- //
- // (N / 2^k) = N >> k, if N >= 0;
- // (N + 2^k - 1) >> k, if N < 0
- //
- // If N is <= 32 bits, use:
- // sra N, 31, t1 // t1 = ~0, if N < 0, 0 else
- // srl t1, 32-k, t2 // t2 = 2^k - 1, if N < 0, 0 else
- // add t2, N, t3 // t3 = N + 2^k -1, if N < 0, N else
- // sra t3, k, result // result = N / 2^k
- //
- // If N is 64 bits, use:
- // srax N, k-1, t1 // t1 = sign bit in high k positions
- // srlx t1, 64-k, t2 // t2 = 2^k - 1, if N < 0, 0 else
- // add t2, N, t3 // t3 = N + 2^k -1, if N < 0, N else
- // sra t3, k, result // result = N / 2^k
- TmpInstruction *sraTmp, *srlTmp, *addTmp;
- MachineCodeForInstruction& mcfi
- = MachineCodeForInstruction::get(destVal);
- sraTmp = new TmpInstruction(mcfi, resultType, LHS, 0, "getSign");
- srlTmp = new TmpInstruction(mcfi, resultType, LHS, 0, "getPlus2km1");
- addTmp = new TmpInstruction(mcfi, resultType, LHS, srlTmp,"incIfNeg");
-
- // Create the SRA or SRAX instruction to get the sign bit
- mvec.push_back(BuildMI((opSize > 4)? V9::SRAXi6 : V9::SRAi5, 3)
- .addReg(LHS)
- .addSImm((resultType==Type::LongTy)? pow-1 : 31)
- .addRegDef(sraTmp));
-
- // Create the SRL or SRLX instruction to get the sign bit
- mvec.push_back(BuildMI((opSize > 4)? V9::SRLXi6 : V9::SRLi5, 3)
- .addReg(sraTmp)
- .addSImm((resultType==Type::LongTy)? 64-pow : 32-pow)
- .addRegDef(srlTmp));
-
- // Create the ADD instruction to add 2^pow-1 for negative values
- mvec.push_back(BuildMI(V9::ADDr, 3).addReg(LHS).addReg(srlTmp)
- .addRegDef(addTmp));
-
- // Get the shift operand and "right-shift" opcode to do the divide
- shiftOperand = addTmp;
- opCode = (opSize > 4)? V9::SRAXi6 : V9::SRAi5;
- } else {
- // Get the shift operand and "right-shift" opcode to do the divide
- shiftOperand = LHS;
- opCode = (opSize > 4)? V9::SRLXi6 : V9::SRLi5;
- }
-
- // Now do the actual shift!
- mvec.push_back(BuildMI(opCode, 3).addReg(shiftOperand).addZImm(pow)
- .addRegDef(destVal));
- }
-
- if (needNeg && (C == 1 || isPowerOf2_64(C))) {
- // insert <reg = SUB 0, reg> after the instr to flip the sign
- mvec.push_back(CreateIntNegInstruction(target, destVal));
- }
- }
- } else {
- if (ConstantFP *FPC = dyn_cast<ConstantFP>(constOp)) {
- double dval = FPC->getValue();
- if (fabs(dval) == 1) {
- unsigned opCode =
- (dval < 0) ? (resultType == Type::FloatTy? V9::FNEGS : V9::FNEGD)
- : (resultType == Type::FloatTy? V9::FMOVS : V9::FMOVD);
-
- mvec.push_back(BuildMI(opCode, 2).addReg(LHS).addRegDef(destVal));
- }
- }
- }
-}
-
-static void CreateCodeForVariableSizeAlloca(const TargetMachine& target,
- Instruction* result, unsigned tsize,
- Value* numElementsVal,
- std::vector<MachineInstr*>& getMvec)
-{
- Value* totalSizeVal;
- MachineInstr* M;
- MachineCodeForInstruction& mcfi = MachineCodeForInstruction::get(result);
- Function *F = result->getParent()->getParent();
-
- // Enforce the alignment constraints on the stack pointer at
- // compile time if the total size is a known constant.
- if (isa<Constant>(numElementsVal)) {
- bool isValid;
- int64_t numElem = (int64_t)
- ConvertConstantToIntType(target, numElementsVal,
- numElementsVal->getType(), isValid);
- assert(isValid && "Unexpectedly large array dimension in alloca!");
- int64_t total = numElem * tsize;
- if (int extra= total % SparcV9FrameInfo::StackFrameSizeAlignment)
- total += SparcV9FrameInfo::StackFrameSizeAlignment - extra;
- totalSizeVal = ConstantSInt::get(Type::IntTy, total);
- } else {
- // The size is not a constant. Generate code to compute it and
- // code to pad the size for stack alignment.
- // Create a Value to hold the (constant) element size
- Value* tsizeVal = ConstantSInt::get(Type::IntTy, tsize);
-
- // Create temporary values to hold the result of MUL, SLL, SRL
- // To pad `size' to next smallest multiple of 16:
- // size = (size + 15) & (-16 = 0xfffffffffffffff0)
- TmpInstruction* tmpProd = new TmpInstruction(mcfi,numElementsVal, tsizeVal);
- TmpInstruction* tmpAdd15= new TmpInstruction(mcfi,numElementsVal, tmpProd);
- TmpInstruction* tmpAndf0= new TmpInstruction(mcfi,numElementsVal, tmpAdd15);
-
- // Instruction 1: mul numElements, typeSize -> tmpProd
- // This will optimize the MUL as far as possible.
- CreateMulInstruction(target, F, numElementsVal, tsizeVal, tmpProd, getMvec,
- mcfi, -1);
-
- // Instruction 2: andn tmpProd, 0x0f -> tmpAndn
- getMvec.push_back(BuildMI(V9::ADDi, 3).addReg(tmpProd).addSImm(15)
- .addReg(tmpAdd15, MachineOperand::Def));
-
- // Instruction 3: add tmpAndn, 0x10 -> tmpAdd16
- getMvec.push_back(BuildMI(V9::ANDi, 3).addReg(tmpAdd15).addSImm(-16)
- .addReg(tmpAndf0, MachineOperand::Def));
-
- totalSizeVal = tmpAndf0;
- }
-
- // Get the constant offset from SP for dynamically allocated storage
- // and create a temporary Value to hold it.
- MachineFunction& mcInfo = MachineFunction::get(F);
- bool growUp;
- ConstantSInt* dynamicAreaOffset =
- ConstantSInt::get(Type::IntTy,
- target.getFrameInfo()->getDynamicAreaOffset(mcInfo,growUp));
- assert(! growUp && "Has SPARC v9 stack frame convention changed?");
-
- unsigned SPReg = target.getRegInfo()->getStackPointer();
-
- // Instruction 2: sub %sp, totalSizeVal -> %sp
- getMvec.push_back(BuildMI(V9::SUBr, 3).addMReg(SPReg).addReg(totalSizeVal)
- .addMReg(SPReg,MachineOperand::Def));
-
- // Instruction 3: add %sp, frameSizeBelowDynamicArea -> result
- getMvec.push_back(BuildMI(V9::ADDr,3).addMReg(SPReg).addReg(dynamicAreaOffset)
- .addRegDef(result));
-}
-
-static void
-CreateCodeForFixedSizeAlloca(const TargetMachine& target,
- Instruction* result, unsigned tsize,
- unsigned numElements,
- std::vector<MachineInstr*>& getMvec) {
- assert(result && result->getParent() &&
- "Result value is not part of a function?");
- Function *F = result->getParent()->getParent();
- MachineFunction &mcInfo = MachineFunction::get(F);
-
- // If the alloca is of zero bytes (which is perfectly legal) we bump it up to
- // one byte. This is unnecessary, but I really don't want to break any
- // fragile logic in this code. FIXME.
- if (tsize == 0)
- tsize = 1;
-
- // Put the variable in the dynamically sized area of the frame if either:
- // (a) The offset is too large to use as an immediate in load/stores
- // (check LDX because all load/stores have the same-size immed. field).
- // (b) The object is "large", so it could cause many other locals,
- // spills, and temporaries to have large offsets.
- // NOTE: We use LARGE = 8 * argSlotSize = 64 bytes.
- // You've gotta love having only 13 bits for constant offset values :-|.
- //
- unsigned paddedSize;
- int offsetFromFP = mcInfo.getInfo<SparcV9FunctionInfo>()->computeOffsetforLocalVar(result,
- paddedSize,
- tsize * numElements);
-
- if (((int)paddedSize) > 8 * SparcV9FrameInfo::SizeOfEachArgOnStack ||
- !target.getInstrInfo()->constantFitsInImmedField(V9::LDXi,offsetFromFP)) {
- CreateCodeForVariableSizeAlloca(target, result, tsize,
- ConstantSInt::get(Type::IntTy,numElements),
- getMvec);
- return;
- }
-
- // else offset fits in immediate field so go ahead and allocate it.
- offsetFromFP = mcInfo.getInfo<SparcV9FunctionInfo>()->allocateLocalVar(result, tsize *numElements);
-
- // Create a temporary Value to hold the constant offset.
- // This is needed because it may not fit in the immediate field.
- ConstantSInt* offsetVal = ConstantSInt::get(Type::IntTy, offsetFromFP);
-
- // Instruction 1: add %fp, offsetFromFP -> result
- unsigned FPReg = target.getRegInfo()->getFramePointer();
- getMvec.push_back(BuildMI(V9::ADDr, 3).addMReg(FPReg).addReg(offsetVal)
- .addRegDef(result));
-}
-
-/// SetOperandsForMemInstr - Choose addressing mode for the given load or store
-/// instruction. Use [reg+reg] if it is an indexed reference, and the index
-/// offset is not a constant or if it cannot fit in the offset field. Use
-/// [reg+offset] in all other cases. This assumes that all array refs are
-/// "lowered" to one of these forms:
-/// %x = load (subarray*) ptr, constant ; single constant offset
-/// %x = load (subarray*) ptr, offsetVal ; single non-constant offset
-/// Generally, this should happen via strength reduction + LICM. Also, strength
-/// reduction should take care of using the same register for the loop index
-/// variable and an array index, when that is profitable.
-///
-static void SetOperandsForMemInstr(unsigned Opcode,
- std::vector<MachineInstr*>& mvec,
- InstructionNode* vmInstrNode,
- const TargetMachine& target) {
- Instruction* memInst = vmInstrNode->getInstruction();
- // Index vector, ptr value, and flag if all indices are const.
- std::vector<Value*> idxVec;
- bool allConstantIndices;
- Value* ptrVal = GetMemInstArgs(vmInstrNode, idxVec, allConstantIndices);
-
- // Now create the appropriate operands for the machine instruction.
- // First, initialize so we default to storing the offset in a register.
- int64_t smallConstOffset = 0;
- Value* valueForRegOffset = NULL;
- MachineOperand::MachineOperandType offsetOpType =
- MachineOperand::MO_VirtualRegister;
-
- // Check if there is an index vector and if so, compute the
- // right offset for structures and for arrays
- if (!idxVec.empty()) {
- const PointerType* ptrType = cast<PointerType>(ptrVal->getType());
-
- // If all indices are constant, compute the combined offset directly.
- if (allConstantIndices) {
- // Compute the offset value using the index vector. Create a
- // virtual reg. for it since it may not fit in the immed field.
- uint64_t offset = target.getTargetData().getIndexedOffset(ptrType,idxVec);
- valueForRegOffset = ConstantSInt::get(Type::LongTy, offset);
- } else {
- // There is at least one non-constant offset. Therefore, this must
- // be an array ref, and must have been lowered to a single non-zero
- // offset. (An extra leading zero offset, if any, can be ignored.)
- // Generate code sequence to compute address from index.
- bool firstIdxIsZero = IsZero(idxVec[0]);
- assert(idxVec.size() == 1U + firstIdxIsZero
- && "Array refs must be lowered before Instruction Selection");
-
- Value* idxVal = idxVec[firstIdxIsZero];
-
- std::vector<MachineInstr*> mulVec;
- Instruction* addr =
- new TmpInstruction(MachineCodeForInstruction::get(memInst),
- Type::ULongTy, memInst);
-
- // Get the array type indexed by idxVal, and compute its element size.
- // The call to getTypeSize() will fail if size is not constant.
- const Type* vecType = (firstIdxIsZero
- ? GetElementPtrInst::getIndexedType(ptrType,
- std::vector<Value*>(1U, idxVec[0]),
- /*AllowCompositeLeaf*/ true)
- : ptrType);
- const Type* eltType = cast<SequentialType>(vecType)->getElementType();
- ConstantUInt* eltSizeVal = ConstantUInt::get(Type::ULongTy,
- target.getTargetData().getTypeSize(eltType));
-
- // CreateMulInstruction() folds constants intelligently enough.
- CreateMulInstruction(target, memInst->getParent()->getParent(),
- idxVal, /* lval, not likely to be const*/
- eltSizeVal, /* rval, likely to be constant */
- addr, /* result */
- mulVec, MachineCodeForInstruction::get(memInst),
- -1);
-
- assert(mulVec.size() > 0 && "No multiply code created?");
- mvec.insert(mvec.end(), mulVec.begin(), mulVec.end());
-
- valueForRegOffset = addr;
- }
- } else {
- offsetOpType = MachineOperand::MO_SignExtendedImmed;
- smallConstOffset = 0;
- }
-
- // For STORE:
- // Operand 0 is value, operand 1 is ptr, operand 2 is offset
- // For LOAD or GET_ELEMENT_PTR,
- // Operand 0 is ptr, operand 1 is offset, operand 2 is result.
- unsigned offsetOpNum, ptrOpNum;
- MachineInstr *MI;
- if (memInst->getOpcode() == Instruction::Store) {
- if (offsetOpType == MachineOperand::MO_VirtualRegister) {
- MI = BuildMI(Opcode, 3).addReg(vmInstrNode->leftChild()->getValue())
- .addReg(ptrVal).addReg(valueForRegOffset);
- } else {
- Opcode = convertOpcodeFromRegToImm(Opcode);
- MI = BuildMI(Opcode, 3).addReg(vmInstrNode->leftChild()->getValue())
- .addReg(ptrVal).addSImm(smallConstOffset);
- }
- } else {
- if (offsetOpType == MachineOperand::MO_VirtualRegister) {
- MI = BuildMI(Opcode, 3).addReg(ptrVal).addReg(valueForRegOffset)
- .addRegDef(memInst);
- } else {
- Opcode = convertOpcodeFromRegToImm(Opcode);
- MI = BuildMI(Opcode, 3).addReg(ptrVal).addSImm(smallConstOffset)
- .addRegDef(memInst);
- }
- }
- mvec.push_back(MI);
-}
-
-/// ForwardOperand - Substitute operand `operandNum' of the instruction in
-/// node `treeNode' in place of the use(s) of that instruction in node `parent'.
-/// Check both explicit and implicit operands! Also make sure to skip over a
-/// parent who: (1) is a list node in the Burg tree, or (2) itself had its
-/// results forwarded to its parent.
-///
-static void ForwardOperand (InstructionNode *treeNode, InstrTreeNode *parent,
- int operandNum) {
- assert(treeNode && parent && "Invalid invocation of ForwardOperand");
-
- Instruction* unusedOp = treeNode->getInstruction();
- Value* fwdOp = unusedOp->getOperand(operandNum);
-
- // The parent itself may be a list node, so find the real parent instruction
- while (parent->getNodeType() != InstrTreeNode::NTInstructionNode) {
- parent = parent->parent();
- assert(parent && "ERROR: Non-instruction node has no parent in tree.");
- }
- InstructionNode* parentInstrNode = (InstructionNode*) parent;
-
- Instruction* userInstr = parentInstrNode->getInstruction();
- MachineCodeForInstruction &mvec = MachineCodeForInstruction::get(userInstr);
-
- // The parent's mvec would be empty if it was itself forwarded.
- // Recursively call ForwardOperand in that case...
- //
- if (mvec.size() == 0) {
- assert(parent->parent() != NULL &&
- "Parent could not have been forwarded, yet has no instructions?");
- ForwardOperand(treeNode, parent->parent(), operandNum);
- } else {
- for (unsigned i=0, N=mvec.size(); i < N; i++) {
- MachineInstr* minstr = mvec[i];
- for (unsigned i=0, numOps=minstr->getNumOperands(); i < numOps; ++i) {
- const MachineOperand& mop = minstr->getOperand(i);
- if (mop.getType() == MachineOperand::MO_VirtualRegister &&
- mop.getVRegValue() == unusedOp) {
- minstr->SetMachineOperandVal(i, MachineOperand::MO_VirtualRegister,
- fwdOp);
- }
- }
-
- for (unsigned i=0,numOps=minstr->getNumImplicitRefs(); i<numOps; ++i)
- if (minstr->getImplicitRef(i) == unusedOp)
- minstr->setImplicitRef(i, fwdOp);
- }
- }
-}
-
-/// AllUsesAreBranches - Returns true if all the uses of I are
-/// Branch instructions, false otherwise.
-///
-inline bool AllUsesAreBranches(const Instruction* I) {
- for (Value::use_const_iterator UI=I->use_begin(), UE=I->use_end();
- UI != UE; ++UI)
- if (! isa<TmpInstruction>(*UI) // ignore tmp instructions here
- && cast<Instruction>(*UI)->getOpcode() != Instruction::Br)
- return false;
- return true;
-}
-
-/// CodeGenIntrinsic - Generate code for any intrinsic that needs a special
-/// code sequence instead of a regular call. If not that kind of intrinsic, do
-/// nothing. Returns true if code was generated, otherwise false.
-///
-static bool CodeGenIntrinsic(Intrinsic::ID iid, CallInst &callInstr,
- TargetMachine &target,
- std::vector<MachineInstr*>& mvec) {
- switch (iid) {
- default:
- assert(0 && "Unknown intrinsic function call should have been lowered!");
- case Intrinsic::vastart: {
- // Get the address of the first incoming vararg argument on the stack
- Function* func = cast<Function>(callInstr.getParent()->getParent());
- int numFixedArgs = func->getFunctionType()->getNumParams();
- int fpReg = SparcV9::i6;
- int firstVarArgOff = numFixedArgs * 8 +
- SparcV9FrameInfo::FirstIncomingArgOffsetFromFP;
- //What oh what do we pass to TmpInstruction?
- MachineCodeForInstruction& m = MachineCodeForInstruction::get(&callInstr);
- TmpInstruction* T = new TmpInstruction(m, callInstr.getOperand(1)->getType());
- mvec.push_back(BuildMI(V9::ADDi, 3).addMReg(fpReg).addSImm(firstVarArgOff).addRegDef(T));
- mvec.push_back(BuildMI(V9::STXr, 3).addReg(T).addReg(callInstr.getOperand(1)).addSImm(0));
- return true;
- }
-
- case Intrinsic::vaend:
- return true; // no-op on SparcV9
-
- case Intrinsic::vacopy:
- {
- MachineCodeForInstruction& m1 = MachineCodeForInstruction::get(&callInstr);
- TmpInstruction* VReg =
- new TmpInstruction(m1, callInstr.getOperand(1)->getType());
-
- // Simple store of current va_list (arg2) to new va_list (arg1)
- mvec.push_back(BuildMI(V9::LDXi, 3).
- addReg(callInstr.getOperand(2)).addSImm(0).addRegDef(VReg));
- mvec.push_back(BuildMI(V9::STXi, 3).
- addReg(VReg).addReg(callInstr.getOperand(1)).addSImm(0));
- return true;
- }
- }
-}
-
-/// ThisIsAChainRule - returns true if the given BURG rule is a chain rule.
-///
-extern bool ThisIsAChainRule(int eruleno) {
- switch(eruleno) {
- case 111: // stmt: reg
- case 123:
- case 124:
- case 125:
- case 126:
- case 127:
- case 128:
- case 129:
- case 130:
- case 131:
- case 132:
- case 133:
- case 155:
- case 221:
- case 222:
- case 241:
- case 242:
- case 243:
- case 244:
- case 245:
- case 321:
- return true; break;
-
- default:
- break;
- }
- return false;
-}
-
-/// GetInstructionsByRule - Choose machine instructions for the
-/// SPARC V9 according to the patterns chosen by the BURG-generated parser.
-/// This is where most of the work in the V9 instruction selector gets done.
-///
-void GetInstructionsByRule(InstructionNode* subtreeRoot, int ruleForNode,
- short* nts, TargetMachine &target,
- std::vector<MachineInstr*>& mvec) {
- bool checkCast = false; // initialize here to use fall-through
- bool maskUnsignedResult = false;
- int nextRule;
- int forwardOperandNum = -1;
- unsigned allocaSize = 0;
- MachineInstr* M, *M2;
- unsigned L;
- bool foldCase = false;
-
- mvec.clear();
-
- // If the code for this instruction was folded into the parent (user),
- // then do nothing!
- if (subtreeRoot->isFoldedIntoParent())
- return;
-
- // Let's check for chain rules outside the switch so that we don't have
- // to duplicate the list of chain rule production numbers here again
- if (ThisIsAChainRule(ruleForNode)) {
- // Chain rules have a single nonterminal on the RHS.
- // Get the rule that matches the RHS non-terminal and use that instead.
- assert(nts[0] && ! nts[1]
- && "A chain rule should have only one RHS non-terminal!");
- nextRule = burm_rule(subtreeRoot->state, nts[0]);
- nts = burm_nts[nextRule];
- GetInstructionsByRule(subtreeRoot, nextRule, nts, target, mvec);
- } else {
- switch(ruleForNode) {
- case 1: // stmt: Ret
- case 2: // stmt: RetValue(reg)
- { // NOTE: Prepass of register allocation is responsible
- // for moving return value to appropriate register.
- // Copy the return value to the required return register.
- // Mark the return Value as an implicit ref of the RET instr..
- // Mark the return-address register as a hidden virtual reg.
- // Finally put a NOP in the delay slot.
- ReturnInst *returnInstr=cast<ReturnInst>(subtreeRoot->getInstruction());
- Value* retVal = returnInstr->getReturnValue();
- MachineCodeForInstruction& mcfi =
- MachineCodeForInstruction::get(returnInstr);
-
- // Create a hidden virtual reg to represent the return address register
- // used by the machine instruction but not represented in LLVM.
- Instruction* returnAddrTmp = new TmpInstruction(mcfi, returnInstr);
-
- MachineInstr* retMI =
- BuildMI(V9::JMPLRETi, 3).addReg(returnAddrTmp).addSImm(8)
- .addMReg(target.getRegInfo()->getZeroRegNum(), MachineOperand::Def);
-
- // If there is a value to return, we need to:
- // (a) Sign-extend the value if it is smaller than 8 bytes (reg size)
- // (b) Insert a copy to copy the return value to the appropriate reg.
- // -- For FP values, create a FMOVS or FMOVD instruction
- // -- For non-FP values, create an add-with-0 instruction
- if (retVal != NULL) {
- const SparcV9RegInfo& regInfo =
- (SparcV9RegInfo&) *target.getRegInfo();
- const Type* retType = retVal->getType();
- unsigned regClassID = regInfo.getRegClassIDOfType(retType);
- unsigned retRegNum = (retType->isFloatingPoint()
- ? (unsigned) SparcV9FloatRegClass::f0
- : (unsigned) SparcV9IntRegClass::i0);
- retRegNum = regInfo.getUnifiedRegNum(regClassID, retRegNum);
-
- // Insert sign-extension instructions for small signed values.
- Value* retValToUse = retVal;
- if (retType->isIntegral() && retType->isSigned()) {
- unsigned retSize = target.getTargetData().getTypeSize(retType);
- if (retSize <= 4) {
- // Create a temporary virtual reg. to hold the sign-extension.
- retValToUse = new TmpInstruction(mcfi, retVal);
-
- // Sign-extend retVal and put the result in the temporary reg.
- CreateSignExtensionInstructions
- (target, returnInstr->getParent()->getParent(),
- retVal, retValToUse, 8*retSize, mvec, mcfi);
- }
- }
-
- // (b) Now, insert a copy to to the appropriate register:
- // -- For FP values, create a FMOVS or FMOVD instruction
- // -- For non-FP values, create an add-with-0 instruction
- // First, create a virtual register to represent the register and
- // mark this vreg as being an implicit operand of the ret MI.
- TmpInstruction* retVReg =
- new TmpInstruction(mcfi, retValToUse, NULL, "argReg");
-
- retMI->addImplicitRef(retVReg);
-
- if (retType->isFloatingPoint())
- M = (BuildMI(retType==Type::FloatTy? V9::FMOVS : V9::FMOVD, 2)
- .addReg(retValToUse).addReg(retVReg, MachineOperand::Def));
- else
- M = (BuildMI(ChooseAddInstructionByType(retType), 3)
- .addReg(retValToUse).addSImm((int64_t) 0)
- .addReg(retVReg, MachineOperand::Def));
-
- // Mark the operand with the register it should be assigned
- M->SetRegForOperand(M->getNumOperands()-1, retRegNum);
- retMI->SetRegForImplicitRef(retMI->getNumImplicitRefs()-1, retRegNum);
-
- mvec.push_back(M);
- }
-
- // Now insert the RET instruction and a NOP for the delay slot
- mvec.push_back(retMI);
- mvec.push_back(BuildMI(V9::NOP, 0));
-
- break;
- }
-
- case 3: // stmt: Store(reg,reg)
- case 4: // stmt: Store(reg,ptrreg)
- SetOperandsForMemInstr(ChooseStoreInstruction(
- subtreeRoot->leftChild()->getValue()->getType()),
- mvec, subtreeRoot, target);
- break;
-
- case 5: // stmt: BrUncond
- {
- BranchInst *BI = cast<BranchInst>(subtreeRoot->getInstruction());
- mvec.push_back(BuildMI(V9::BA, 1).addPCDisp(BI->getSuccessor(0)));
-
- // delay slot
- mvec.push_back(BuildMI(V9::NOP, 0));
- break;
- }
-
- case 206: // stmt: BrCond(setCCconst)
- { // setCCconst => boolean was computed with `%b = setCC type reg1 const'
- // If the constant is ZERO, we can use the branch-on-integer-register
- // instructions and avoid the SUBcc instruction entirely.
- // Otherwise this is just the same as case 5, so just fall through.
- //
- InstrTreeNode* constNode = subtreeRoot->leftChild()->rightChild();
- assert(constNode &&
- constNode->getNodeType() ==InstrTreeNode::NTConstNode);
- Constant *constVal = cast<Constant>(constNode->getValue());
- bool isValidConst;
-
- if ((constVal->getType()->isInteger()
- || isa<PointerType>(constVal->getType()))
- && ConvertConstantToIntType(target,
- constVal, constVal->getType(), isValidConst) == 0
- && isValidConst)
- {
- // That constant is a zero after all...
- // Use the left child of setCC as the first argument!
- // Mark the setCC node so that no code is generated for it.
- InstructionNode* setCCNode = (InstructionNode*)
- subtreeRoot->leftChild();
- assert(setCCNode->getOpLabel() == SetCCOp);
- setCCNode->markFoldedIntoParent();
-
- BranchInst* brInst=cast<BranchInst>(subtreeRoot->getInstruction());
-
- M = BuildMI(ChooseBprInstruction(subtreeRoot), 2)
- .addReg(setCCNode->leftChild()->getValue())
- .addPCDisp(brInst->getSuccessor(0));
- mvec.push_back(M);
-
- // delay slot
- mvec.push_back(BuildMI(V9::NOP, 0));
-
- // false branch
- mvec.push_back(BuildMI(V9::BA, 1)
- .addPCDisp(brInst->getSuccessor(1)));
-
- // delay slot
- mvec.push_back(BuildMI(V9::NOP, 0));
- break;
- }
- // ELSE FALL THROUGH
- }
-
- case 6: // stmt: BrCond(setCC)
- { // bool => boolean was computed with SetCC.
- // The branch to use depends on whether it is FP, signed, or unsigned.
- // If it is an integer CC, we also need to find the unique
- // TmpInstruction representing that CC.
- //
- BranchInst* brInst = cast<BranchInst>(subtreeRoot->getInstruction());
- const Type* setCCType;
- unsigned Opcode = ChooseBccInstruction(subtreeRoot, setCCType);
- Value* ccValue = GetTmpForCC(subtreeRoot->leftChild()->getValue(),
- brInst->getParent()->getParent(),
- setCCType,
- MachineCodeForInstruction::get(brInst));
- M = BuildMI(Opcode, 2).addCCReg(ccValue)
- .addPCDisp(brInst->getSuccessor(0));
- mvec.push_back(M);
-
- // delay slot
- mvec.push_back(BuildMI(V9::NOP, 0));
-
- // false branch
- mvec.push_back(BuildMI(V9::BA, 1).addPCDisp(brInst->getSuccessor(1)));
-
- // delay slot
- mvec.push_back(BuildMI(V9::NOP, 0));
- break;
- }
-
- case 208: // stmt: BrCond(boolconst)
- {
- // boolconst => boolean is a constant; use BA to first or second label
- Constant* constVal =
- cast<Constant>(subtreeRoot->leftChild()->getValue());
- unsigned dest = cast<ConstantBool>(constVal)->getValue()? 0 : 1;
-
- M = BuildMI(V9::BA, 1).addPCDisp(
- cast<BranchInst>(subtreeRoot->getInstruction())->getSuccessor(dest));
- mvec.push_back(M);
-
- // delay slot
- mvec.push_back(BuildMI(V9::NOP, 0));
- break;
- }
-
- case 8: // stmt: BrCond(boolreg)
- { // boolreg => boolean is recorded in an integer register.
- // Use branch-on-integer-register instruction.
- //
- BranchInst *BI = cast<BranchInst>(subtreeRoot->getInstruction());
- M = BuildMI(V9::BRNZ, 2).addReg(subtreeRoot->leftChild()->getValue())
- .addPCDisp(BI->getSuccessor(0));
- mvec.push_back(M);
-
- // delay slot
- mvec.push_back(BuildMI(V9::NOP, 0));
-
- // false branch
- mvec.push_back(BuildMI(V9::BA, 1).addPCDisp(BI->getSuccessor(1)));
-
- // delay slot
- mvec.push_back(BuildMI(V9::NOP, 0));
- break;
- }
-
- case 9: // stmt: Switch(reg)
- assert(0 && "*** SWITCH instruction is not implemented yet.");
- break;
-
- case 10: // reg: VRegList(reg, reg)
- assert(0 && "VRegList should never be the topmost non-chain rule");
- break;
-
- case 21: // bool: Not(bool,reg): Compute with a conditional-move-on-reg
- { // First find the unary operand. It may be left or right, usually right.
- Instruction* notI = subtreeRoot->getInstruction();
- Value* notArg = BinaryOperator::getNotArgument(
- cast<BinaryOperator>(subtreeRoot->getInstruction()));
- unsigned ZeroReg = target.getRegInfo()->getZeroRegNum();
-
- // Unconditionally set register to 0
- mvec.push_back(BuildMI(V9::SETHI, 2).addZImm(0).addRegDef(notI));
-
- // Now conditionally move 1 into the register.
- // Mark the register as a use (as well as a def) because the old
- // value will be retained if the condition is false.
- mvec.push_back(BuildMI(V9::MOVRZi, 3).addReg(notArg).addZImm(1)
- .addReg(notI, MachineOperand::UseAndDef));
-
- break;
- }
-
- case 421: // reg: BNot(reg,reg): Compute as reg = reg XOR-NOT 0
- { // First find the unary operand. It may be left or right, usually right.
- Value* notArg = BinaryOperator::getNotArgument(
- cast<BinaryOperator>(subtreeRoot->getInstruction()));
- unsigned ZeroReg = target.getRegInfo()->getZeroRegNum();
- mvec.push_back(BuildMI(V9::XNORr, 3).addReg(notArg).addMReg(ZeroReg)
- .addRegDef(subtreeRoot->getValue()));
- break;
- }
-
- case 322: // reg: Not(tobool, reg):
- // Fold CAST-TO-BOOL with NOT by inverting the sense of cast-to-bool
- foldCase = true;
- // Just fall through!
-
- case 22: // reg: ToBoolTy(reg):
- {
- Instruction* castI = subtreeRoot->getInstruction();
- Value* opVal = subtreeRoot->leftChild()->getValue();
- MachineCodeForInstruction &mcfi = MachineCodeForInstruction::get(castI);
- TmpInstruction* tempReg =
- new TmpInstruction(mcfi, opVal);
-
-
-
- assert(opVal->getType()->isIntegral() ||
- isa<PointerType>(opVal->getType()));
-
- // Unconditionally set register to 0
- mvec.push_back(BuildMI(V9::SETHI, 2).addZImm(0).addRegDef(castI));
-
- // Now conditionally move 1 into the register.
- // Mark the register as a use (as well as a def) because the old
- // value will be retained if the condition is false.
- MachineOpCode opCode = foldCase? V9::MOVRZi : V9::MOVRNZi;
- mvec.push_back(BuildMI(opCode, 3).addReg(opVal).addZImm(1)
- .addReg(castI, MachineOperand::UseAndDef));
-
- break;
- }
-
- case 23: // reg: ToUByteTy(reg)
- case 24: // reg: ToSByteTy(reg)
- case 25: // reg: ToUShortTy(reg)
- case 26: // reg: ToShortTy(reg)
- case 27: // reg: ToUIntTy(reg)
- case 28: // reg: ToIntTy(reg)
- case 29: // reg: ToULongTy(reg)
- case 30: // reg: ToLongTy(reg)
- {
- //======================================================================
- // Rules for integer conversions:
- //
- //--------
- // From ISO 1998 C++ Standard, Sec. 4.7:
- //
- // 2. If the destination type is unsigned, the resulting value is
- // the least unsigned integer congruent to the source integer
- // (modulo 2n where n is the number of bits used to represent the
- // unsigned type). [Note: In a two s complement representation,
- // this conversion is conceptual and there is no change in the
- // bit pattern (if there is no truncation). ]
- //
- // 3. If the destination type is signed, the value is unchanged if
- // it can be represented in the destination type (and bitfield width);
- // otherwise, the value is implementation-defined.
- //--------
- //
- // Since we assume 2s complement representations, this implies:
- //
- // -- If operand is smaller than destination, zero-extend or sign-extend
- // according to the signedness of the *operand*: source decides:
- // (1) If operand is signed, sign-extend it.
- // If dest is unsigned, zero-ext the result!
- // (2) If operand is unsigned, our current invariant is that
- // it's high bits are correct, so zero-extension is not needed.
- //
- // -- If operand is same size as or larger than destination,
- // zero-extend or sign-extend according to the signedness of
- // the *destination*: destination decides:
- // (1) If destination is signed, sign-extend (truncating if needed)
- // This choice is implementation defined. We sign-extend the
- // operand, which matches both Sun's cc and gcc3.2.
- // (2) If destination is unsigned, zero-extend (truncating if needed)
- //======================================================================
-
- Instruction* destI = subtreeRoot->getInstruction();
- Function* currentFunc = destI->getParent()->getParent();
- MachineCodeForInstruction& mcfi=MachineCodeForInstruction::get(destI);
-
- Value* opVal = subtreeRoot->leftChild()->getValue();
- const Type* opType = opVal->getType();
- const Type* destType = destI->getType();
- unsigned opSize = target.getTargetData().getTypeSize(opType);
- unsigned destSize = target.getTargetData().getTypeSize(destType);
-
- bool isIntegral = opType->isIntegral() || isa<PointerType>(opType);
-
- if (opType == Type::BoolTy ||
- opType == destType ||
- isIntegral && opSize == destSize && opSize == 8) {
- // nothing to do in all these cases
- forwardOperandNum = 0; // forward first operand to user
-
- } else if (opType->isFloatingPoint()) {
-
- CreateCodeToConvertFloatToInt(target, opVal, destI, mvec, mcfi);
- if (destI->getType()->isUnsigned() && destI->getType() !=Type::UIntTy)
- maskUnsignedResult = true; // not handled by fp->int code
-
- } else if (isIntegral) {
-
- bool opSigned = opType->isSigned();
- bool destSigned = destType->isSigned();
- unsigned extSourceInBits = 8 * std::min<unsigned>(opSize, destSize);
-
- assert(! (opSize == destSize && opSigned == destSigned) &&
- "How can different int types have same size and signedness?");
-
- bool signExtend = (opSize < destSize && opSigned ||
- opSize >= destSize && destSigned);
-
- bool signAndZeroExtend = (opSize < destSize && destSize < 8u &&
- opSigned && !destSigned);
- assert(!signAndZeroExtend || signExtend);
-
- bool zeroExtendOnly = opSize >= destSize && !destSigned;
- assert(!zeroExtendOnly || !signExtend);
-
- if (signExtend) {
- Value* signExtDest = (signAndZeroExtend
- ? new TmpInstruction(mcfi, destType, opVal)
- : destI);
-
- CreateSignExtensionInstructions
- (target, currentFunc,opVal,signExtDest,extSourceInBits,mvec,mcfi);
-
- if (signAndZeroExtend)
- CreateZeroExtensionInstructions
- (target, currentFunc, signExtDest, destI, 8*destSize, mvec, mcfi);
- }
- else if (zeroExtendOnly) {
- CreateZeroExtensionInstructions
- (target, currentFunc, opVal, destI, extSourceInBits, mvec, mcfi);
- }
- else
- forwardOperandNum = 0; // forward first operand to user
-
- } else
- assert(0 && "Unrecognized operand type for convert-to-integer");
-
- break;
- }
-
- case 31: // reg: ToFloatTy(reg):
- case 32: // reg: ToDoubleTy(reg):
- case 232: // reg: ToDoubleTy(Constant):
-
- // If this instruction has a parent (a user) in the tree
- // and the user is translated as an FsMULd instruction,
- // then the cast is unnecessary. So check that first.
- // In the future, we'll want to do the same for the FdMULq instruction,
- // so do the check here instead of only for ToFloatTy(reg).
- //
- if (subtreeRoot->parent() != NULL) {
- const MachineCodeForInstruction& mcfi =
- MachineCodeForInstruction::get(
- cast<InstructionNode>(subtreeRoot->parent())->getInstruction());
- if (mcfi.size() == 0 || mcfi.front()->getOpcode() == V9::FSMULD)
- forwardOperandNum = 0; // forward first operand to user
- }
-
- if (forwardOperandNum != 0) { // we do need the cast
- Value* leftVal = subtreeRoot->leftChild()->getValue();
- const Type* opType = leftVal->getType();
- MachineOpCode opCode=ChooseConvertToFloatInstr(target,
- subtreeRoot->getOpLabel(), opType);
- if (opCode == V9::NOP) { // no conversion needed
- forwardOperandNum = 0; // forward first operand to user
- } else {
- // If the source operand is a non-FP type it must be
- // first copied from int to float register via memory!
- Instruction *dest = subtreeRoot->getInstruction();
- Value* srcForCast;
- int n = 0;
- if (! opType->isFloatingPoint()) {
- // Create a temporary to represent the FP register
- // into which the integer will be copied via memory.
- // The type of this temporary will determine the FP
- // register used: single-prec for a 32-bit int or smaller,
- // double-prec for a 64-bit int.
- //
- uint64_t srcSize =
- target.getTargetData().getTypeSize(leftVal->getType());
- Type* tmpTypeToUse =
- (srcSize <= 4)? Type::FloatTy : Type::DoubleTy;
- MachineCodeForInstruction &destMCFI =
- MachineCodeForInstruction::get(dest);
- srcForCast = new TmpInstruction(destMCFI, tmpTypeToUse, dest);
-
- CreateCodeToCopyIntToFloat(target,
- dest->getParent()->getParent(),
- leftVal, cast<Instruction>(srcForCast),
- mvec, destMCFI);
- } else
- srcForCast = leftVal;
-
- M = BuildMI(opCode, 2).addReg(srcForCast).addRegDef(dest);
- mvec.push_back(M);
- }
- }
- break;
-
- case 19: // reg: ToArrayTy(reg):
- case 20: // reg: ToPointerTy(reg):
- forwardOperandNum = 0; // forward first operand to user
- break;
-
- case 233: // reg: Add(reg, Constant)
- maskUnsignedResult = true;
- M = CreateAddConstInstruction(subtreeRoot);
- if (M != NULL) {
- mvec.push_back(M);
- break;
- }
- // ELSE FALL THROUGH
-
- case 33: // reg: Add(reg, reg)
- maskUnsignedResult = true;
- Add3OperandInstr(ChooseAddInstruction(subtreeRoot), subtreeRoot, mvec);
- break;
-
- case 234: // reg: Sub(reg, Constant)
- maskUnsignedResult = true;
- M = CreateSubConstInstruction(subtreeRoot);
- if (M != NULL) {
- mvec.push_back(M);
- break;
- }
- // ELSE FALL THROUGH
-
- case 34: // reg: Sub(reg, reg)
- maskUnsignedResult = true;
- Add3OperandInstr(ChooseSubInstructionByType(
- subtreeRoot->getInstruction()->getType()),
- subtreeRoot, mvec);
- break;
-
- case 135: // reg: Mul(todouble, todouble)
- checkCast = true;
- // FALL THROUGH
-
- case 35: // reg: Mul(reg, reg)
- {
- maskUnsignedResult = true;
- MachineOpCode forceOp = ((checkCast && BothFloatToDouble(subtreeRoot))
- ? (MachineOpCode)V9::FSMULD
- : -1);
- Instruction* mulInstr = subtreeRoot->getInstruction();
- CreateMulInstruction(target, mulInstr->getParent()->getParent(),
- subtreeRoot->leftChild()->getValue(),
- subtreeRoot->rightChild()->getValue(),
- mulInstr, mvec,
- MachineCodeForInstruction::get(mulInstr),forceOp);
- break;
- }
- case 335: // reg: Mul(todouble, todoubleConst)
- checkCast = true;
- // FALL THROUGH
-
- case 235: // reg: Mul(reg, Constant)
- {
- maskUnsignedResult = true;
- MachineOpCode forceOp = ((checkCast && BothFloatToDouble(subtreeRoot))
- ? (MachineOpCode)V9::FSMULD
- : -1);
- Instruction* mulInstr = subtreeRoot->getInstruction();
- CreateMulInstruction(target, mulInstr->getParent()->getParent(),
- subtreeRoot->leftChild()->getValue(),
- subtreeRoot->rightChild()->getValue(),
- mulInstr, mvec,
- MachineCodeForInstruction::get(mulInstr),
- forceOp);
- break;
- }
- case 236: // reg: Div(reg, Constant)
- maskUnsignedResult = true;
- L = mvec.size();
- CreateDivConstInstruction(target, subtreeRoot, mvec);
- if (mvec.size() > L)
- break;
- // ELSE FALL THROUGH
-
- case 36: // reg: Div(reg, reg)
- {
- maskUnsignedResult = true;
-
- // If either operand of divide is smaller than 64 bits, we have
- // to make sure the unused top bits are correct because they affect
- // the result. These bits are already correct for unsigned values.
- // They may be incorrect for signed values, so sign extend to fill in.
- Instruction* divI = subtreeRoot->getInstruction();
- Value* divOp1 = subtreeRoot->leftChild()->getValue();
- Value* divOp2 = subtreeRoot->rightChild()->getValue();
- Value* divOp1ToUse = divOp1;
- Value* divOp2ToUse = divOp2;
- if (divI->getType()->isSigned()) {
- unsigned opSize=target.getTargetData().getTypeSize(divI->getType());
- if (opSize < 8) {
- MachineCodeForInstruction& mcfi=MachineCodeForInstruction::get(divI);
- divOp1ToUse = new TmpInstruction(mcfi, divOp1);
- divOp2ToUse = new TmpInstruction(mcfi, divOp2);
- CreateSignExtensionInstructions(target,
- divI->getParent()->getParent(),
- divOp1, divOp1ToUse,
- 8*opSize, mvec, mcfi);
- CreateSignExtensionInstructions(target,
- divI->getParent()->getParent(),
- divOp2, divOp2ToUse,
- 8*opSize, mvec, mcfi);
- }
- }
-
- mvec.push_back(BuildMI(ChooseDivInstruction(target, subtreeRoot), 3)
- .addReg(divOp1ToUse)
- .addReg(divOp2ToUse)
- .addRegDef(divI));
-
- break;
- }
-
- case 37: // reg: Rem(reg, reg)
- case 237: // reg: Rem(reg, Constant)
- {
- maskUnsignedResult = true;
-
- Instruction* remI = subtreeRoot->getInstruction();
- Value* divOp1 = subtreeRoot->leftChild()->getValue();
- Value* divOp2 = subtreeRoot->rightChild()->getValue();
-
- MachineCodeForInstruction& mcfi = MachineCodeForInstruction::get(remI);
-
- // If second operand of divide is smaller than 64 bits, we have
- // to make sure the unused top bits are correct because they affect
- // the result. These bits are already correct for unsigned values.
- // They may be incorrect for signed values, so sign extend to fill in.
- //
- Value* divOpToUse = divOp2;
- if (divOp2->getType()->isSigned()) {
- unsigned opSize=target.getTargetData().getTypeSize(divOp2->getType());
- if (opSize < 8) {
- divOpToUse = new TmpInstruction(mcfi, divOp2);
- CreateSignExtensionInstructions(target,
- remI->getParent()->getParent(),
- divOp2, divOpToUse,
- 8*opSize, mvec, mcfi);
- }
- }
-
- // Now compute: result = rem V1, V2 as:
- // result = V1 - (V1 / signExtend(V2)) * signExtend(V2)
- //
- TmpInstruction* quot = new TmpInstruction(mcfi, divOp1, divOpToUse);
- TmpInstruction* prod = new TmpInstruction(mcfi, quot, divOpToUse);
-
- mvec.push_back(BuildMI(ChooseDivInstruction(target, subtreeRoot), 3)
- .addReg(divOp1).addReg(divOpToUse).addRegDef(quot));
-
- mvec.push_back(BuildMI(ChooseMulInstructionByType(remI->getType()), 3)
- .addReg(quot).addReg(divOpToUse).addRegDef(prod));
-
- mvec.push_back(BuildMI(ChooseSubInstructionByType(remI->getType()), 3)
- .addReg(divOp1).addReg(prod).addRegDef(remI));
-
- break;
- }
-
- case 38: // bool: And(bool, bool)
- case 138: // bool: And(bool, not)
- case 238: // bool: And(bool, boolconst)
- case 338: // reg : BAnd(reg, reg)
- case 538: // reg : BAnd(reg, Constant)
- Add3OperandInstr(V9::ANDr, subtreeRoot, mvec);
- break;
-
- case 438: // bool: BAnd(bool, bnot)
- { // Use the argument of NOT as the second argument!
- // Mark the NOT node so that no code is generated for it.
- // If the type is boolean, set 1 or 0 in the result register.
- InstructionNode* notNode = (InstructionNode*) subtreeRoot->rightChild();
- Value* notArg = BinaryOperator::getNotArgument(
- cast<BinaryOperator>(notNode->getInstruction()));
- notNode->markFoldedIntoParent();
- Value *lhs = subtreeRoot->leftChild()->getValue();
- Value *dest = subtreeRoot->getValue();
- mvec.push_back(BuildMI(V9::ANDNr, 3).addReg(lhs).addReg(notArg)
- .addReg(dest, MachineOperand::Def));
-
- if (notArg->getType() == Type::BoolTy) {
- // set 1 in result register if result of above is non-zero
- mvec.push_back(BuildMI(V9::MOVRNZi, 3).addReg(dest).addZImm(1)
- .addReg(dest, MachineOperand::UseAndDef));
- }
-
- break;
- }
-
- case 39: // bool: Or(bool, bool)
- case 139: // bool: Or(bool, not)
- case 239: // bool: Or(bool, boolconst)
- case 339: // reg : BOr(reg, reg)
- case 539: // reg : BOr(reg, Constant)
- Add3OperandInstr(V9::ORr, subtreeRoot, mvec);
- break;
-
- case 439: // bool: BOr(bool, bnot)
- { // Use the argument of NOT as the second argument!
- // Mark the NOT node so that no code is generated for it.
- // If the type is boolean, set 1 or 0 in the result register.
- InstructionNode* notNode = (InstructionNode*) subtreeRoot->rightChild();
- Value* notArg = BinaryOperator::getNotArgument(
- cast<BinaryOperator>(notNode->getInstruction()));
- notNode->markFoldedIntoParent();
- Value *lhs = subtreeRoot->leftChild()->getValue();
- Value *dest = subtreeRoot->getValue();
-
- mvec.push_back(BuildMI(V9::ORNr, 3).addReg(lhs).addReg(notArg)
- .addReg(dest, MachineOperand::Def));
-
- if (notArg->getType() == Type::BoolTy) {
- // set 1 in result register if result of above is non-zero
- mvec.push_back(BuildMI(V9::MOVRNZi, 3).addReg(dest).addZImm(1)
- .addReg(dest, MachineOperand::UseAndDef));
- }
-
- break;
- }
-
- case 40: // bool: Xor(bool, bool)
- case 140: // bool: Xor(bool, not)
- case 240: // bool: Xor(bool, boolconst)
- case 340: // reg : BXor(reg, reg)
- case 540: // reg : BXor(reg, Constant)
- Add3OperandInstr(V9::XORr, subtreeRoot, mvec);
- break;
-
- case 440: // bool: BXor(bool, bnot)
- { // Use the argument of NOT as the second argument!
- // Mark the NOT node so that no code is generated for it.
- // If the type is boolean, set 1 or 0 in the result register.
- InstructionNode* notNode = (InstructionNode*) subtreeRoot->rightChild();
- Value* notArg = BinaryOperator::getNotArgument(
- cast<BinaryOperator>(notNode->getInstruction()));
- notNode->markFoldedIntoParent();
- Value *lhs = subtreeRoot->leftChild()->getValue();
- Value *dest = subtreeRoot->getValue();
- mvec.push_back(BuildMI(V9::XNORr, 3).addReg(lhs).addReg(notArg)
- .addReg(dest, MachineOperand::Def));
-
- if (notArg->getType() == Type::BoolTy) {
- // set 1 in result register if result of above is non-zero
- mvec.push_back(BuildMI(V9::MOVRNZi, 3).addReg(dest).addZImm(1)
- .addReg(dest, MachineOperand::UseAndDef));
- }
- break;
- }
-
- case 41: // setCCconst: SetCC(reg, Constant)
- { // Comparison is with a constant:
- //
- // If the bool result must be computed into a register (see below),
- // and the constant is int ZERO, we can use the MOVR[op] instructions
- // and avoid the SUBcc instruction entirely.
- // Otherwise this is just the same as case 42, so just fall through.
- //
- // The result of the SetCC must be computed and stored in a register if
- // it is used outside the current basic block (so it must be computed
- // as a boolreg) or it is used by anything other than a branch.
- // We will use a conditional move to do this.
- //
- Instruction* setCCInstr = subtreeRoot->getInstruction();
- bool computeBoolVal = (subtreeRoot->parent() == NULL ||
- ! AllUsesAreBranches(setCCInstr));
-
- if (computeBoolVal) {
- InstrTreeNode* constNode = subtreeRoot->rightChild();
- assert(constNode &&
- constNode->getNodeType() ==InstrTreeNode::NTConstNode);
- Constant *constVal = cast<Constant>(constNode->getValue());
- bool isValidConst;
-
- if ((constVal->getType()->isInteger()
- || isa<PointerType>(constVal->getType()))
- && ConvertConstantToIntType(target,
- constVal, constVal->getType(), isValidConst) == 0
- && isValidConst)
- {
- // That constant is an integer zero after all...
- // Use a MOVR[op] to compute the boolean result
- // Unconditionally set register to 0
- mvec.push_back(BuildMI(V9::SETHI, 2).addZImm(0)
- .addRegDef(setCCInstr));
-
- // Now conditionally move 1 into the register.
- // Mark the register as a use (as well as a def) because the old
- // value will be retained if the condition is false.
- MachineOpCode movOpCode = ChooseMovpregiForSetCC(subtreeRoot);
- mvec.push_back(BuildMI(movOpCode, 3)
- .addReg(subtreeRoot->leftChild()->getValue())
- .addZImm(1)
- .addReg(setCCInstr, MachineOperand::UseAndDef));
-
- break;
- }
- }
- // ELSE FALL THROUGH
- }
-
- case 42: // bool: SetCC(reg, reg):
- {
- // This generates a SUBCC instruction, putting the difference in a
- // result reg. if needed, and/or setting a condition code if needed.
- //
- Instruction* setCCInstr = subtreeRoot->getInstruction();
- Value* leftVal = subtreeRoot->leftChild()->getValue();
- Value* rightVal = subtreeRoot->rightChild()->getValue();
- const Type* opType = leftVal->getType();
- bool isFPCompare = opType->isFloatingPoint();
-
- // If the boolean result of the SetCC is used outside the current basic
- // block (so it must be computed as a boolreg) or is used by anything
- // other than a branch, the boolean must be computed and stored
- // in a result register. We will use a conditional move to do this.
- //
- bool computeBoolVal = (subtreeRoot->parent() == NULL ||
- ! AllUsesAreBranches(setCCInstr));
-
- // A TmpInstruction is created to represent the CC "result".
- // Unlike other instances of TmpInstruction, this one is used
- // by machine code of multiple LLVM instructions, viz.,
- // the SetCC and the branch. Make sure to get the same one!
- // Note that we do this even for FP CC registers even though they
- // are explicit operands, because the type of the operand
- // needs to be a floating point condition code, not an integer
- // condition code. Think of this as casting the bool result to
- // a FP condition code register.
- // Later, we mark the 4th operand as being a CC register, and as a def.
- //
- TmpInstruction* tmpForCC = GetTmpForCC(setCCInstr,
- setCCInstr->getParent()->getParent(),
- leftVal->getType(),
- MachineCodeForInstruction::get(setCCInstr));
-
- // If the operands are signed values smaller than 4 bytes, then they
- // must be sign-extended in order to do a valid 32-bit comparison
- // and get the right result in the 32-bit CC register (%icc).
- //
- Value* leftOpToUse = leftVal;
- Value* rightOpToUse = rightVal;
- if (opType->isIntegral() && opType->isSigned()) {
- unsigned opSize = target.getTargetData().getTypeSize(opType);
- if (opSize < 4) {
- MachineCodeForInstruction& mcfi =
- MachineCodeForInstruction::get(setCCInstr);
-
- // create temporary virtual regs. to hold the sign-extensions
- leftOpToUse = new TmpInstruction(mcfi, leftVal);
- rightOpToUse = new TmpInstruction(mcfi, rightVal);
-
- // sign-extend each operand and put the result in the temporary reg.
- CreateSignExtensionInstructions
- (target, setCCInstr->getParent()->getParent(),
- leftVal, leftOpToUse, 8*opSize, mvec, mcfi);
- CreateSignExtensionInstructions
- (target, setCCInstr->getParent()->getParent(),
- rightVal, rightOpToUse, 8*opSize, mvec, mcfi);
- }
- }
-
- if (! isFPCompare) {
- // Integer condition: set CC and discard result.
- mvec.push_back(BuildMI(V9::SUBccr, 4)
- .addReg(leftOpToUse)
- .addReg(rightOpToUse)
- .addMReg(target.getRegInfo()->
- getZeroRegNum(), MachineOperand::Def)
- .addCCReg(tmpForCC, MachineOperand::Def));
- } else {
- // FP condition: dest of FCMP should be some FCCn register
- mvec.push_back(BuildMI(ChooseFcmpInstruction(subtreeRoot), 3)
- .addCCReg(tmpForCC, MachineOperand::Def)
- .addReg(leftOpToUse)
- .addReg(rightOpToUse));
- }
-
- if (computeBoolVal) {
- MachineOpCode movOpCode = (isFPCompare
- ? ChooseMovFpcciInstruction(subtreeRoot)
- : ChooseMovpcciForSetCC(subtreeRoot));
-
- // Unconditionally set register to 0
- M = BuildMI(V9::SETHI, 2).addZImm(0).addRegDef(setCCInstr);
- mvec.push_back(M);
-
- // Now conditionally move 1 into the register.
- // Mark the register as a use (as well as a def) because the old
- // value will be retained if the condition is false.
- M = (BuildMI(movOpCode, 3).addCCReg(tmpForCC).addZImm(1)
- .addReg(setCCInstr, MachineOperand::UseAndDef));
- mvec.push_back(M);
- }
- break;
- }
-
- case 51: // reg: Load(reg)
- case 52: // reg: Load(ptrreg)
- SetOperandsForMemInstr(ChooseLoadInstruction(
- subtreeRoot->getValue()->getType()),
- mvec, subtreeRoot, target);
- break;
-
- case 55: // reg: GetElemPtr(reg)
- case 56: // reg: GetElemPtrIdx(reg,reg)
- // If the GetElemPtr was folded into the user (parent), it will be
- // caught above. For other cases, we have to compute the address.
- SetOperandsForMemInstr(V9::ADDr, mvec, subtreeRoot, target);
- break;
-
- case 57: // reg: Alloca: Implement as 1 instruction:
- { // add %fp, offsetFromFP -> result
- AllocationInst* instr =
- cast<AllocationInst>(subtreeRoot->getInstruction());
- unsigned tsize =
- target.getTargetData().getTypeSize(instr->getAllocatedType());
- assert(tsize != 0);
- CreateCodeForFixedSizeAlloca(target, instr, tsize, 1, mvec);
- break;
- }
-
- case 58: // reg: Alloca(reg): Implement as 3 instructions:
- // mul num, typeSz -> tmp
- // sub %sp, tmp -> %sp
- { // add %sp, frameSizeBelowDynamicArea -> result
- AllocationInst* instr =
- cast<AllocationInst>(subtreeRoot->getInstruction());
- const Type* eltType = instr->getAllocatedType();
-
- // If #elements is constant, use simpler code for fixed-size allocas
- int tsize = (int) target.getTargetData().getTypeSize(eltType);
- Value* numElementsVal = NULL;
- bool isArray = instr->isArrayAllocation();
-
- if (!isArray || isa<Constant>(numElementsVal = instr->getArraySize())) {
- // total size is constant: generate code for fixed-size alloca
- unsigned numElements = isArray?
- cast<ConstantUInt>(numElementsVal)->getValue() : 1;
- CreateCodeForFixedSizeAlloca(target, instr, tsize,
- numElements, mvec);
- } else {
- // total size is not constant.
- CreateCodeForVariableSizeAlloca(target, instr, tsize,
- numElementsVal, mvec);
- }
- break;
- }
-
- case 61: // reg: Call
- { // Generate a direct (CALL) or indirect (JMPL) call.
- // Mark the return-address register, the indirection
- // register (for indirect calls), the operands of the Call,
- // and the return value (if any) as implicit operands
- // of the machine instruction.
- //
- // If this is a varargs function, floating point arguments
- // have to passed in integer registers so insert
- // copy-float-to-int instructions for each float operand.
- //
- CallInst *callInstr = cast<CallInst>(subtreeRoot->getInstruction());
- Value *callee = callInstr->getCalledValue();
- Function* calledFunc = dyn_cast<Function>(callee);
-
- // Check if this is an intrinsic function that needs a special code
- // sequence (e.g., va_start). Indirect calls cannot be special.
- //
- bool specialIntrinsic = false;
- Intrinsic::ID iid;
- if (calledFunc && (iid=(Intrinsic::ID)calledFunc->getIntrinsicID()))
- specialIntrinsic = CodeGenIntrinsic(iid, *callInstr, target, mvec);
-
- // If not, generate the normal call sequence for the function.
- // This can also handle any intrinsics that are just function calls.
- //
- if (! specialIntrinsic) {
- Function* currentFunc = callInstr->getParent()->getParent();
- MachineFunction& MF = MachineFunction::get(currentFunc);
- MachineCodeForInstruction& mcfi =
- MachineCodeForInstruction::get(callInstr);
- const SparcV9RegInfo& regInfo =
- (SparcV9RegInfo&) *target.getRegInfo();
- const TargetFrameInfo& frameInfo = *target.getFrameInfo();
-
- // Create hidden virtual register for return address with type void*
- TmpInstruction* retAddrReg =
- new TmpInstruction(mcfi, PointerType::get(Type::VoidTy), callInstr);
-
- // Generate the machine instruction and its operands.
- // Use CALL for direct function calls; this optimistically assumes
- // the PC-relative address fits in the CALL address field (22 bits).
- // Use JMPL for indirect calls.
- // This will be added to mvec later, after operand copies.
- //
- MachineInstr* callMI;
- if (calledFunc) // direct function call
- callMI = BuildMI(V9::CALL, 1).addPCDisp(callee);
- else // indirect function call
- callMI = (BuildMI(V9::JMPLCALLi,3).addReg(callee)
- .addSImm((int64_t)0).addRegDef(retAddrReg));
-
- const FunctionType* funcType =
- cast<FunctionType>(cast<PointerType>(callee->getType())
- ->getElementType());
- bool isVarArgs = funcType->isVarArg();
- bool noPrototype = isVarArgs && funcType->getNumParams() == 0;
-
- // Use a descriptor to pass information about call arguments
- // to the register allocator. This descriptor will be "owned"
- // and freed automatically when the MachineCodeForInstruction
- // object for the callInstr goes away.
- CallArgsDescriptor* argDesc =
- new CallArgsDescriptor(callInstr, retAddrReg,isVarArgs,noPrototype);
- assert(callInstr->getOperand(0) == callee
- && "This is assumed in the loop below!");
-
- // Insert sign-extension instructions for small signed values,
- // if this is an unknown function (i.e., called via a funcptr)
- // or an external one (i.e., which may not be compiled by llc).
- //
- if (calledFunc == NULL || calledFunc->isExternal()) {
- for (unsigned i=1, N=callInstr->getNumOperands(); i < N; ++i) {
- Value* argVal = callInstr->getOperand(i);
- const Type* argType = argVal->getType();
- if (argType->isIntegral() && argType->isSigned()) {
- unsigned argSize = target.getTargetData().getTypeSize(argType);
- if (argSize <= 4) {
- // create a temporary virtual reg. to hold the sign-extension
- TmpInstruction* argExtend = new TmpInstruction(mcfi, argVal);
-
- // sign-extend argVal and put the result in the temporary reg.
- CreateSignExtensionInstructions
- (target, currentFunc, argVal, argExtend,
- 8*argSize, mvec, mcfi);
-
- // replace argVal with argExtend in CallArgsDescriptor
- argDesc->getArgInfo(i-1).replaceArgVal(argExtend);
- }
- }
- }
- }
-
- // Insert copy instructions to get all the arguments into
- // all the places that they need to be.
- //
- for (unsigned i=1, N=callInstr->getNumOperands(); i < N; ++i) {
- int argNo = i-1;
- CallArgInfo& argInfo = argDesc->getArgInfo(argNo);
- Value* argVal = argInfo.getArgVal(); // don't use callInstr arg here
- const Type* argType = argVal->getType();
- unsigned regType = regInfo.getRegTypeForDataType(argType);
- unsigned argSize = target.getTargetData().getTypeSize(argType);
- int regNumForArg = SparcV9RegInfo::getInvalidRegNum();
- unsigned regClassIDOfArgReg;
-
- // Check for FP arguments to varargs functions.
- // Any such argument in the first $K$ args must be passed in an
- // integer register. If there is no prototype, it must also
- // be passed as an FP register.
- // K = #integer argument registers.
- bool isFPArg = argVal->getType()->isFloatingPoint();
- if (isVarArgs && isFPArg) {
-
- if (noPrototype) {
- // It is a function with no prototype: pass value
- // as an FP value as well as a varargs value. The FP value
- // may go in a register or on the stack. The copy instruction
- // to the outgoing reg/stack is created by the normal argument
- // handling code since this is the "normal" passing mode.
- //
- regNumForArg = regInfo.regNumForFPArg(regType,
- false, false, argNo,
- regClassIDOfArgReg);
- if (regNumForArg == regInfo.getInvalidRegNum())
- argInfo.setUseStackSlot();
- else
- argInfo.setUseFPArgReg();
- }
-
- // If this arg. is in the first $K$ regs, add special copy-
- // float-to-int instructions to pass the value as an int.
- // To check if it is in the first $K$, get the register
- // number for the arg #i. These copy instructions are
- // generated here because they are extra cases and not needed
- // for the normal argument handling (some code reuse is
- // possible though -- later).
- //
- int copyRegNum = regInfo.regNumForIntArg(false, false, argNo,
- regClassIDOfArgReg);
- if (copyRegNum != regInfo.getInvalidRegNum()) {
- // Create a virtual register to represent copyReg. Mark
- // this vreg as being an implicit operand of the call MI
- const Type* loadTy = (argType == Type::FloatTy
- ? Type::IntTy : Type::LongTy);
- TmpInstruction* argVReg = new TmpInstruction(mcfi, loadTy,
- argVal, NULL,
- "argRegCopy");
- callMI->addImplicitRef(argVReg);
-
- // Get a temp stack location to use to copy
- // float-to-int via the stack.
- //
- // FIXME: For now, we allocate permanent space because
- // the stack frame manager does not allow locals to be
- // allocated (e.g., for alloca) after a temp is
- // allocated!
- //
- // int tmpOffset = MF.getInfo<SparcV9FunctionInfo>()->pushTempValue(argSize);
- int tmpOffset = MF.getInfo<SparcV9FunctionInfo>()->allocateLocalVar(argVReg);
-
- // Generate the store from FP reg to stack
- unsigned StoreOpcode = ChooseStoreInstruction(argType);
- M = BuildMI(convertOpcodeFromRegToImm(StoreOpcode), 3)
- .addReg(argVal).addMReg(regInfo.getFramePointer())
- .addSImm(tmpOffset);
- mvec.push_back(M);
-
- // Generate the load from stack to int arg reg
- unsigned LoadOpcode = ChooseLoadInstruction(loadTy);
- M = BuildMI(convertOpcodeFromRegToImm(LoadOpcode), 3)
- .addMReg(regInfo.getFramePointer()).addSImm(tmpOffset)
- .addReg(argVReg, MachineOperand::Def);
-
- // Mark operand with register it should be assigned
- // both for copy and for the callMI
- M->SetRegForOperand(M->getNumOperands()-1, copyRegNum);
- callMI->SetRegForImplicitRef(callMI->getNumImplicitRefs()-1,
- copyRegNum);
- mvec.push_back(M);
-
- // Add info about the argument to the CallArgsDescriptor
- argInfo.setUseIntArgReg();
- argInfo.setArgCopy(copyRegNum);
- } else {
- // Cannot fit in first $K$ regs so pass arg on stack
- argInfo.setUseStackSlot();
- }
- } else if (isFPArg) {
- // Get the outgoing arg reg to see if there is one.
- regNumForArg = regInfo.regNumForFPArg(regType, false, false,
- argNo, regClassIDOfArgReg);
- if (regNumForArg == regInfo.getInvalidRegNum())
- argInfo.setUseStackSlot();
- else {
- argInfo.setUseFPArgReg();
- regNumForArg =regInfo.getUnifiedRegNum(regClassIDOfArgReg,
- regNumForArg);
- }
- } else {
- // Get the outgoing arg reg to see if there is one.
- regNumForArg = regInfo.regNumForIntArg(false,false,
- argNo, regClassIDOfArgReg);
- if (regNumForArg == regInfo.getInvalidRegNum())
- argInfo.setUseStackSlot();
- else {
- argInfo.setUseIntArgReg();
- regNumForArg =regInfo.getUnifiedRegNum(regClassIDOfArgReg,
- regNumForArg);
- }
- }
-
- //
- // Now insert copy instructions to stack slot or arg. register
- //
- if (argInfo.usesStackSlot()) {
- // Get the stack offset for this argument slot.
- // FP args 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.
- int argOffset = frameInfo.getOutgoingArgOffset(MF, argNo);
- if (argType->isFloatingPoint()) {
- unsigned slotSize = SparcV9FrameInfo::SizeOfEachArgOnStack;
- assert(argSize <= slotSize && "Insufficient slot size!");
- argOffset += slotSize - argSize;
- }
-
- // Now generate instruction to copy argument to stack
- MachineOpCode storeOpCode =
- (argType->isFloatingPoint()
- ? ((argSize == 4)? V9::STFi : V9::STDFi) : V9::STXi);
-
- M = BuildMI(storeOpCode, 3).addReg(argVal)
- .addMReg(regInfo.getStackPointer()).addSImm(argOffset);
- mvec.push_back(M);
- }
- else if (regNumForArg != regInfo.getInvalidRegNum()) {
-
- // Create a virtual register to represent the arg reg. Mark
- // this vreg as being an implicit operand of the call MI.
- TmpInstruction* argVReg =
- new TmpInstruction(mcfi, argVal, NULL, "argReg");
-
- callMI->addImplicitRef(argVReg);
-
- // Generate the reg-to-reg copy into the outgoing arg reg.
- // -- For FP values, create a FMOVS or FMOVD instruction
- // -- For non-FP values, create an add-with-0 instruction
- if (argType->isFloatingPoint())
- M=(BuildMI(argType==Type::FloatTy? V9::FMOVS :V9::FMOVD,2)
- .addReg(argVal).addReg(argVReg, MachineOperand::Def));
- else
- M = (BuildMI(ChooseAddInstructionByType(argType), 3)
- .addReg(argVal).addSImm((int64_t) 0)
- .addReg(argVReg, MachineOperand::Def));
-
- // Mark the operand with the register it should be assigned
- M->SetRegForOperand(M->getNumOperands()-1, regNumForArg);
- callMI->SetRegForImplicitRef(callMI->getNumImplicitRefs()-1,
- regNumForArg);
-
- mvec.push_back(M);
- }
- else
- assert(argInfo.getArgCopy() != regInfo.getInvalidRegNum() &&
- "Arg. not in stack slot, primary or secondary register?");
- }
-
- // add call instruction and delay slot before copying return value
- mvec.push_back(callMI);
- mvec.push_back(BuildMI(V9::NOP, 0));
-
- // Add the return value as an implicit ref. The call operands
- // were added above. Also, add code to copy out the return value.
- // This is always register-to-register for int or FP return values.
- //
- if (callInstr->getType() != Type::VoidTy) {
- // Get the return value reg.
- const Type* retType = callInstr->getType();
-
- int regNum = (retType->isFloatingPoint()
- ? (unsigned) SparcV9FloatRegClass::f0
- : (unsigned) SparcV9IntRegClass::o0);
- unsigned regClassID = regInfo.getRegClassIDOfType(retType);
- regNum = regInfo.getUnifiedRegNum(regClassID, regNum);
-
- // Create a virtual register to represent it and mark
- // this vreg as being an implicit operand of the call MI
- TmpInstruction* retVReg =
- new TmpInstruction(mcfi, callInstr, NULL, "argReg");
-
- callMI->addImplicitRef(retVReg, /*isDef*/ true);
-
- // Generate the reg-to-reg copy from the return value reg.
- // -- For FP values, create a FMOVS or FMOVD instruction
- // -- For non-FP values, create an add-with-0 instruction
- if (retType->isFloatingPoint())
- M = (BuildMI(retType==Type::FloatTy? V9::FMOVS : V9::FMOVD, 2)
- .addReg(retVReg).addReg(callInstr, MachineOperand::Def));
- else
- M = (BuildMI(ChooseAddInstructionByType(retType), 3)
- .addReg(retVReg).addSImm((int64_t) 0)
- .addReg(callInstr, MachineOperand::Def));
-
- // Mark the operand with the register it should be assigned
- // Also mark the implicit ref of the call defining this operand
- M->SetRegForOperand(0, regNum);
- callMI->SetRegForImplicitRef(callMI->getNumImplicitRefs()-1,regNum);
-
- mvec.push_back(M);
- }
-
- // For the CALL instruction, the ret. addr. reg. is also implicit
- if (isa<Function>(callee))
- callMI->addImplicitRef(retAddrReg, /*isDef*/ true);
-
- MF.getInfo<SparcV9FunctionInfo>()->popAllTempValues(); // free temps used for this inst
- }
-
- break;
- }
-
- case 62: // reg: Shl(reg, reg)
- {
- Value* argVal1 = subtreeRoot->leftChild()->getValue();
- Value* argVal2 = subtreeRoot->rightChild()->getValue();
- Instruction* shlInstr = subtreeRoot->getInstruction();
-
- const Type* opType = argVal1->getType();
- assert((opType->isInteger() || isa<PointerType>(opType)) &&
- "Shl unsupported for other types");
- unsigned opSize = target.getTargetData().getTypeSize(opType);
-
- CreateShiftInstructions(target, shlInstr->getParent()->getParent(),
- (opSize > 4)? V9::SLLXr6:V9::SLLr5,
- argVal1, argVal2, 0, shlInstr, mvec,
- MachineCodeForInstruction::get(shlInstr));
- break;
- }
-
- case 63: // reg: Shr(reg, reg)
- {
- const Type* opType = subtreeRoot->leftChild()->getValue()->getType();
- assert((opType->isInteger() || isa<PointerType>(opType)) &&
- "Shr unsupported for other types");
- unsigned opSize = target.getTargetData().getTypeSize(opType);
- Add3OperandInstr(opType->isSigned()
- ? (opSize > 4? V9::SRAXr6 : V9::SRAr5)
- : (opSize > 4? V9::SRLXr6 : V9::SRLr5),
- subtreeRoot, mvec);
- break;
- }
-
- case 64: // reg: Phi(reg,reg)
- break; // don't forward the value
-
- case 66: // reg: VAArg (reg): the va_arg instruction
- { // Load argument from stack using current va_list pointer value.
- // Use 64-bit load for all non-FP args, and LDDF or double for FP.
- Instruction* vaArgI = subtreeRoot->getInstruction();
- //but first load the va_list pointer
- // Create a virtual register to represent it
- //What oh what do we pass to TmpInstruction?
- MachineCodeForInstruction& m1 = MachineCodeForInstruction::get(vaArgI);
- TmpInstruction* VReg = new TmpInstruction(m1, vaArgI->getOperand(0)->getType());
- mvec.push_back(BuildMI(V9::LDXi, 3).addReg(vaArgI->getOperand(0))
- .addSImm(0).addRegDef(VReg));
- //OK, now do the load
- MachineOpCode loadOp = (vaArgI->getType()->isFloatingPoint()
- ? (vaArgI->getType() == Type::FloatTy
- ? V9::LDFi : V9::LDDFi)
- : V9::LDXi);
- mvec.push_back(BuildMI(loadOp, 3).addReg(VReg).
- addSImm(0).addRegDef(vaArgI));
- //Also increment the pointer
- MachineCodeForInstruction& m2 = MachineCodeForInstruction::get(vaArgI);
- TmpInstruction* VRegA = new TmpInstruction(m2, vaArgI->getOperand(0)->getType());
- unsigned argSize = SparcV9FrameInfo::SizeOfEachArgOnStack;
- mvec.push_back(BuildMI(V9::ADDi, 3).addReg(VReg).
- addSImm(argSize).addRegDef(VRegA));
- //And store
- mvec.push_back(BuildMI(V9::STXr, 3).addReg(VRegA).
- addReg(vaArgI->getOperand(0)).addSImm(0));
- break;
- }
-
- case 71: // reg: VReg
- case 72: // reg: Constant
- break; // don't forward the value
-
- default:
- assert(0 && "Unrecognized BURG rule");
- break;
- }
- }
-
- if (forwardOperandNum >= 0) {
- // We did not generate a machine instruction but need to use operand.
- // If user is in the same tree, replace Value in its machine operand.
- // If not, insert a copy instruction which should get coalesced away
- // by register allocation.
- if (subtreeRoot->parent() != NULL)
- ForwardOperand(subtreeRoot, subtreeRoot->parent(), forwardOperandNum);
- else {
- std::vector<MachineInstr*> minstrVec;
- Instruction* instr = subtreeRoot->getInstruction();
- CreateCopyInstructionsByType(target,
- instr->getParent()->getParent(),
- instr->getOperand(forwardOperandNum),
- instr, minstrVec,
- MachineCodeForInstruction::get(instr));
- assert(minstrVec.size() > 0);
- mvec.insert(mvec.end(), minstrVec.begin(), minstrVec.end());
- }
- }
-
- if (maskUnsignedResult) {
- // If result is unsigned and smaller than int reg size,
- // we need to clear high bits of result value.
- assert(forwardOperandNum < 0 && "Need mask but no instruction generated");
- Instruction* dest = subtreeRoot->getInstruction();
- if (dest->getType()->isUnsigned()) {
- unsigned destSize=target.getTargetData().getTypeSize(dest->getType());
- if (destSize <= 4) {
- // Mask high 64 - N bits, where N = 4*destSize.
-
- // Use a TmpInstruction to represent the
- // intermediate result before masking. Since those instructions
- // have already been generated, go back and substitute tmpI
- // for dest in the result position of each one of them.
- //
- MachineCodeForInstruction& mcfi = MachineCodeForInstruction::get(dest);
- TmpInstruction *tmpI = new TmpInstruction(mcfi, dest->getType(),
- dest, NULL, "maskHi");
- Value* srlArgToUse = tmpI;
-
- unsigned numSubst = 0;
- for (unsigned i=0, N=mvec.size(); i < N; ++i) {
-
- // Make sure we substitute all occurrences of dest in these instrs.
- // Otherwise, we will have bogus code.
- bool someArgsWereIgnored = false;
-
- // Make sure not to substitute an upwards-exposed use -- that would
- // introduce a use of `tmpI' with no preceding def. Therefore,
- // substitute a use or def-and-use operand only if a previous def
- // operand has already been substituted (i.e., numSubst > 0).
- //
- numSubst += mvec[i]->substituteValue(dest, tmpI,
- /*defsOnly*/ numSubst == 0,
- /*notDefsAndUses*/ numSubst > 0,
- someArgsWereIgnored);
- assert(!someArgsWereIgnored &&
- "Operand `dest' exists but not replaced: probably bogus!");
- }
- assert(numSubst > 0 && "Operand `dest' not replaced: probably bogus!");
-
- // Left shift 32-N if size (N) is less than 32 bits.
- // Use another tmp. virtual register to represent this result.
- if (destSize < 4) {
- srlArgToUse = new TmpInstruction(mcfi, dest->getType(),
- tmpI, NULL, "maskHi2");
- mvec.push_back(BuildMI(V9::SLLXi6, 3).addReg(tmpI)
- .addZImm(8*(4-destSize))
- .addReg(srlArgToUse, MachineOperand::Def));
- }
-
- // Logical right shift 32-N to get zero extension in top 64-N bits.
- mvec.push_back(BuildMI(V9::SRLi5, 3).addReg(srlArgToUse)
- .addZImm(8*(4-destSize))
- .addReg(dest, MachineOperand::Def));
-
- } else if (destSize < 8) {
- assert(0 && "Unsupported type size: 32 < size < 64 bits");
- }
- }
- }
-}
-
-} // End llvm namespace
-
-//==------------------------------------------------------------------------==//
-// Class V9ISel Implementation
-//==------------------------------------------------------------------------==//
-
-bool V9ISel::runOnFunction(Function &F) {
- DefaultIntrinsicLowering IL;
- // First pass - Walk the function, lowering any calls to intrinsic functions
- // which the instruction selector cannot handle.
- for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB)
- for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; )
- if (CallInst *CI = dyn_cast<CallInst>(I++))
- if (Function *F = CI->getCalledFunction())
- switch (F->getIntrinsicID()) {
- case Intrinsic::not_intrinsic:
- case Intrinsic::vastart:
- case Intrinsic::vacopy:
- case Intrinsic::vaend:
- // We directly implement these intrinsics. Note that this knowledge
- // is incestuously entangled with the code in
- // SparcInstrSelection.cpp and must be updated when it is updated.
- // Since ALL of the code in this library is incestuously intertwined
- // with it already and sparc specific, we will live with this.
- break;
- default:
- // All other intrinsic calls we must lower.
- Instruction *Before = CI->getPrev();
- IL.LowerIntrinsicCall(CI);
- if (Before) { // Move iterator to instruction after call
- I = Before; ++I;
- } else {
- I = BB->begin();
- }
- }
-
- // Build the instruction trees to be given as inputs to BURG.
- InstrForest instrForest(&F);
- if (SelectDebugLevel >= Select_DebugInstTrees) {
- std::cerr << "\n\n*** Input to instruction selection for function "
- << F.getName() << "\n\n" << F
- << "\n\n*** Instruction trees for function "
- << F.getName() << "\n\n";
- instrForest.dump();
- }
-
- // Invoke BURG instruction selection for each tree
- for (InstrForest::const_root_iterator RI = instrForest.roots_begin();
- RI != instrForest.roots_end(); ++RI) {
- InstructionNode* basicNode = *RI;
- assert(basicNode->parent() == NULL && "A `root' node has a parent?");
-
- // Invoke BURM to label each tree node with a state
- burm_label(basicNode);
- if (SelectDebugLevel >= Select_DebugBurgTrees) {
- printcover(basicNode, 1, 0);
- std::cerr << "\nCover cost == " << treecost(basicNode, 1, 0) <<"\n\n";
- printMatches(basicNode);
- }
-
- // Then recursively walk the tree to select instructions
- SelectInstructionsForTree(basicNode, /*goalnt*/1);
- }
-
- // Create the MachineBasicBlocks and add all of the MachineInstrs
- // defined in the MachineCodeForInstruction objects to the MachineBasicBlocks.
- MachineFunction &MF = MachineFunction::get(&F);
- std::map<const BasicBlock *, MachineBasicBlock *> MBBMap;
- for (Function::iterator BI = F.begin(), BE = F.end(); BI != BE; ++BI) {
- MachineBasicBlock *MBB = new MachineBasicBlock(BI);
- MF.getBasicBlockList().push_back(MBB);
- MBBMap[BI] = MBB;
-
- for (BasicBlock::iterator II = BI->begin(); II != BI->end(); ++II) {
- MachineCodeForInstruction &mvec = MachineCodeForInstruction::get(II);
- MBB->insert(MBB->end(), mvec.begin(), mvec.end());
- }
- }
-
- // Initialize Machine-CFG for the function.
- for (MachineFunction::iterator i = MF.begin (), e = MF.end (); i != e; ++i) {
- MachineBasicBlock &MBB = *i;
- const BasicBlock *BB = MBB.getBasicBlock ();
- // for each successor S of BB, add MBBMap[S] as a successor of MBB.
- for (succ_const_iterator si = succ_begin(BB), se = succ_end(BB); si != se;
- ++si) {
- MachineBasicBlock *succMBB = MBBMap[*si];
- assert (succMBB && "Can't find MachineBasicBlock for this successor");
- MBB.addSuccessor (succMBB);
- }
- }
-
- // Insert phi elimination code
- InsertCodeForPhis(F);
-
- if (SelectDebugLevel >= Select_PrintMachineCode) {
- std::cerr << "\n*** Machine instructions after INSTRUCTION SELECTION\n";
- MachineFunction::get(&F).dump();
- }
-
- return true;
-}
-
-/// InsertCodeForPhis - This method inserts Phi elimination code for
-/// all Phi nodes in the given function. After this method is called,
-/// the Phi nodes still exist in the LLVM code, but copies are added to the
-/// machine code.
-///
-void V9ISel::InsertCodeForPhis(Function &F) {
- // Iterate over every Phi node PN in F:
- MachineFunction &MF = MachineFunction::get(&F);
- for (MachineFunction::iterator BB = MF.begin(); BB != MF.end(); ++BB) {
- for (BasicBlock::const_iterator IIt = BB->getBasicBlock()->begin();
- const PHINode *PN = dyn_cast<PHINode>(IIt); ++IIt) {
- // Create a new temporary register to hold the result of the Phi copy.
- // The leak detector shouldn't track these nodes. They are not garbage,
- // even though their parent field is never filled in.
- Value *PhiCpRes = new PHINode(PN->getType(), PN->getName() + ":PhiCp");
- LeakDetector::removeGarbageObject(PhiCpRes);
-
- // For each of PN's incoming values, insert a copy in the corresponding
- // predecessor block.
- MachineCodeForInstruction &MCforPN = MachineCodeForInstruction::get (PN);
- for (unsigned i = 0; i < PN->getNumIncomingValues(); ++i) {
- std::vector<MachineInstr*> mvec, CpVec;
- Target.getRegInfo()->cpValue2Value(PN->getIncomingValue(i),
- PhiCpRes, mvec);
- for (std::vector<MachineInstr*>::iterator MI=mvec.begin();
- MI != mvec.end(); ++MI) {
- std::vector<MachineInstr*> CpVec2 =
- FixConstantOperandsForInstr(const_cast<PHINode*>(PN), *MI, Target);
- CpVec2.push_back(*MI);
- CpVec.insert(CpVec.end(), CpVec2.begin(), CpVec2.end());
- }
- // Insert the copy instructions into the predecessor BB.
- InsertPhiElimInstructions(PN->getIncomingBlock(i), CpVec);
- MCforPN.insert (MCforPN.end (), CpVec.begin (), CpVec.end ());
- }
- // Insert a copy instruction from PhiCpRes to PN.
- std::vector<MachineInstr*> mvec;
- Target.getRegInfo()->cpValue2Value(PhiCpRes, const_cast<PHINode*>(PN),
- mvec);
- BB->insert(BB->begin(), mvec.begin(), mvec.end());
- MCforPN.insert (MCforPN.end (), mvec.begin (), mvec.end ());
- } // for each Phi Instr in BB
- } // for all BBs in function
-}
-
-/// InsertPhiElimInstructions - Inserts the instructions in CpVec into the
-/// MachineBasicBlock corresponding to BB, just before its terminator
-/// instruction. This is used by InsertCodeForPhis() to insert copies, above.
-///
-void V9ISel::InsertPhiElimInstructions(BasicBlock *BB,
- const std::vector<MachineInstr*>& CpVec)
-{
- Instruction *TermInst = (Instruction*)BB->getTerminator();
- MachineCodeForInstruction &MC4Term = MachineCodeForInstruction::get(TermInst);
- MachineInstr *FirstMIOfTerm = MC4Term.front();
- assert (FirstMIOfTerm && "No Machine Instrs for terminator");
-
- MachineBasicBlock *MBB = FirstMIOfTerm->getParent();
- assert(MBB && "Machine BB for predecessor's terminator not found");
- MachineBasicBlock::iterator MCIt = FirstMIOfTerm;
- assert(MCIt != MBB->end() && "Start inst of terminator not found");
-
- // Insert the copy instructions just before the first machine instruction
- // generated for the terminator.
- MBB->insert(MCIt, CpVec.begin(), CpVec.end());
-}
-
-/// SelectInstructionsForTree - Recursively walk the tree to select
-/// instructions. Do this top-down so that child instructions can exploit
-/// decisions made at the child instructions.
-///
-/// E.g., if br(setle(reg,const)) decides the constant is 0 and uses
-/// a branch-on-integer-register instruction, then the setle node
-/// can use that information to avoid generating the SUBcc instruction.
-///
-/// Note that this cannot be done bottom-up because setle must do this
-/// only if it is a child of the branch (otherwise, the result of setle
-/// may be used by multiple instructions).
-///
-void V9ISel::SelectInstructionsForTree(InstrTreeNode* treeRoot, int goalnt) {
- // Get the rule that matches this node.
- int ruleForNode = burm_rule(treeRoot->state, goalnt);
-
- if (ruleForNode == 0) {
- std::cerr << "Could not match instruction tree for instr selection\n";
- abort();
- }
-
- // Get this rule's non-terminals and the corresponding child nodes (if any)
- short *nts = burm_nts[ruleForNode];
-
- // First, select instructions for the current node and rule.
- // (If this is a list node, not an instruction, then skip this step).
- // This function is specific to the target architecture.
- if (treeRoot->opLabel != VRegListOp) {
- std::vector<MachineInstr*> minstrVec;
- InstructionNode* instrNode = (InstructionNode*)treeRoot;
- assert(instrNode->getNodeType() == InstrTreeNode::NTInstructionNode);
- GetInstructionsByRule(instrNode, ruleForNode, nts, Target, minstrVec);
- MachineCodeForInstruction &mvec =
- MachineCodeForInstruction::get(instrNode->getInstruction());
- mvec.insert(mvec.end(), minstrVec.begin(), minstrVec.end());
- }
-
- // Then, recursively compile the child nodes, if any.
- //
- if (nts[0]) {
- // i.e., there is at least one kid
- InstrTreeNode* kids[2];
- int currentRule = ruleForNode;
- burm_kids(treeRoot, currentRule, kids);
-
- // First skip over any chain rules so that we don't visit
- // the current node again.
- while (ThisIsAChainRule(currentRule)) {
- currentRule = burm_rule(treeRoot->state, nts[0]);
- nts = burm_nts[currentRule];
- burm_kids(treeRoot, currentRule, kids);
- }
-
- // Now we have the first non-chain rule so we have found
- // the actual child nodes. Recursively compile them.
- for (unsigned i = 0; nts[i]; i++) {
- assert(i < 2);
- InstrTreeNode::InstrTreeNodeType nodeType = kids[i]->getNodeType();
- if (nodeType == InstrTreeNode::NTVRegListNode ||
- nodeType == InstrTreeNode::NTInstructionNode)
- SelectInstructionsForTree(kids[i], nts[i]);
- }
- }
-
- // Finally, do any post-processing on this node after its children
- // have been translated.
- if (treeRoot->opLabel != VRegListOp)
- PostprocessMachineCodeForTree((InstructionNode*)treeRoot, ruleForNode, nts);
-}
-
-/// PostprocessMachineCodeForTree - Apply any final cleanups to
-/// machine code for the root of a subtree after selection for all its
-/// children has been completed.
-///
-void V9ISel::PostprocessMachineCodeForTree(InstructionNode *instrNode,
- int ruleForNode, short *nts) {
- // Fix up any constant operands in the machine instructions to either
- // use an immediate field or to load the constant into a register.
- // Walk backwards and use direct indexes to allow insertion before current.
- Instruction* vmInstr = instrNode->getInstruction();
- MachineCodeForInstruction &mvec = MachineCodeForInstruction::get(vmInstr);
- for (unsigned i = mvec.size(); i != 0; --i) {
- std::vector<MachineInstr*> loadConstVec =
- FixConstantOperandsForInstr(vmInstr, mvec[i-1], Target);
- mvec.insert(mvec.begin()+i-1, loadConstVec.begin(), loadConstVec.end());
- }
-}
-
-/// createSparcV9BurgInstSelector - Creates and returns a new SparcV9
-/// BURG-based instruction selection pass.
-///
-FunctionPass *llvm::createSparcV9BurgInstSelector(TargetMachine &TM) {
- return new V9ISel(TM);
-}
+++ /dev/null
-//===-- 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
+++ /dev/null
-//===-- 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"
-
+++ /dev/null
-//===-- 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
+++ /dev/null
-//===-- 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;
-}
+++ /dev/null
-//===-- 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
+++ /dev/null
-//===-- 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
+++ /dev/null
-//===- 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
+++ /dev/null
-//===-- 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
+++ /dev/null
-//===- 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
-}
+++ /dev/null
-//===-- 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
+++ /dev/null
-//===-- 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;
- }
- }
-}
+++ /dev/null
-//===- 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
+++ /dev/null
-//===-- 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
+++ /dev/null
-//===- 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);
-}
+++ /dev/null
-//===-- 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
+++ /dev/null
-//===-- 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
+++ /dev/null
-//===-- 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
+++ /dev/null
-//===-- 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
+++ /dev/null
-//===-- 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
+++ /dev/null
-//===- 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;
-}
+++ /dev/null
-//===- 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
+++ /dev/null
-//===- 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]>;
+++ /dev/null
-//===- 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
+++ /dev/null
-//===-- 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.
-}
+++ /dev/null
-//===- 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);
-}
-
+++ /dev/null
-//===-- 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"));
-}
-
+++ /dev/null
-//===-- 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
+++ /dev/null
-//===- 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);
-}
+++ /dev/null
-//===-- 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
+++ /dev/null
-//===- 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};
-}
+++ /dev/null
-//===- 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
+++ /dev/null
-//===- 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