From 2706983c48d001b042896c4302c19a197b802fb6 Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Thu, 20 Apr 2006 17:15:44 +0000 Subject: [PATCH] This target is no longer built. The ,v files now live in the reoptimizer. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@27885 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/SparcV9/.cvsignore | 4 - lib/Target/SparcV9/DecomposeMultiDimRefs.cpp | 137 - lib/Target/SparcV9/EmitBytecodeToAssembly.cpp | 115 - .../SparcV9/InstrSched/InstrScheduling.cpp | 1499 ------ lib/Target/SparcV9/InstrSched/Makefile | 14 - lib/Target/SparcV9/InstrSched/SchedGraph.cpp | 737 --- lib/Target/SparcV9/InstrSched/SchedGraph.h | 262 - .../SparcV9/InstrSched/SchedGraphCommon.cpp | 180 - .../SparcV9/InstrSched/SchedPriorities.cpp | 284 - .../SparcV9/InstrSched/SchedPriorities.h | 221 - lib/Target/SparcV9/InternalGlobalMapper.cpp | 82 - lib/Target/SparcV9/LiveVar/BBLiveVar.cpp | 233 - lib/Target/SparcV9/LiveVar/BBLiveVar.h | 90 - .../SparcV9/LiveVar/FunctionLiveVarInfo.cpp | 323 -- .../SparcV9/LiveVar/FunctionLiveVarInfo.h | 111 - lib/Target/SparcV9/LiveVar/Makefile | 14 - lib/Target/SparcV9/LiveVar/ValueSet.cpp | 31 - .../SparcV9/MachineCodeForInstruction.cpp | 116 - .../SparcV9/MachineCodeForInstruction.h | 97 - lib/Target/SparcV9/MachineFunctionInfo.cpp | 171 - lib/Target/SparcV9/MachineFunctionInfo.h | 125 - lib/Target/SparcV9/MachineInstrAnnot.h | 95 - lib/Target/SparcV9/Makefile | 35 - lib/Target/SparcV9/MappingInfo.cpp | 216 - lib/Target/SparcV9/MappingInfo.h | 50 - .../ModuloScheduling/DependenceAnalyzer.cpp | 305 -- .../ModuloScheduling/DependenceAnalyzer.h | 92 - .../SparcV9/ModuloScheduling/MSSchedule.cpp | 309 -- .../SparcV9/ModuloScheduling/MSSchedule.h | 72 - .../SparcV9/ModuloScheduling/MSScheduleSB.cpp | 325 -- .../SparcV9/ModuloScheduling/MSScheduleSB.h | 73 - .../SparcV9/ModuloScheduling/MSchedGraph.cpp | 804 --- .../SparcV9/ModuloScheduling/MSchedGraph.h | 398 -- .../ModuloScheduling/MSchedGraphSB.cpp | 870 ---- .../SparcV9/ModuloScheduling/MSchedGraphSB.h | 410 -- lib/Target/SparcV9/ModuloScheduling/Makefile | 14 - .../ModuloScheduling/ModuloScheduling.cpp | 2964 ----------- .../ModuloScheduling/ModuloScheduling.h | 171 - .../ModuloSchedulingSuperBlock.cpp | 3155 ----------- .../ModuloSchedulingSuperBlock.h | 192 - lib/Target/SparcV9/RegAlloc/AllocInfo.h | 95 - lib/Target/SparcV9/RegAlloc/IGNode.cpp | 62 - lib/Target/SparcV9/RegAlloc/IGNode.h | 123 - .../SparcV9/RegAlloc/InterferenceGraph.cpp | 248 - .../SparcV9/RegAlloc/InterferenceGraph.h | 75 - lib/Target/SparcV9/RegAlloc/LiveRange.h | 195 - lib/Target/SparcV9/RegAlloc/LiveRangeInfo.cpp | 415 -- lib/Target/SparcV9/RegAlloc/LiveRangeInfo.h | 121 - lib/Target/SparcV9/RegAlloc/Makefile | 14 - lib/Target/SparcV9/RegAlloc/PhyRegAlloc.cpp | 1366 ----- lib/Target/SparcV9/RegAlloc/PhyRegAlloc.h | 186 - lib/Target/SparcV9/RegAlloc/RegAllocCommon.h | 32 - lib/Target/SparcV9/RegAlloc/RegClass.cpp | 251 - lib/Target/SparcV9/RegAlloc/RegClass.h | 147 - lib/Target/SparcV9/SparcV9.burg.in | 349 -- lib/Target/SparcV9/SparcV9.td | 52 - lib/Target/SparcV9/SparcV9AsmPrinter.cpp | 803 --- lib/Target/SparcV9/SparcV9BurgISel.cpp | 4615 ----------------- lib/Target/SparcV9/SparcV9BurgISel.h | 56 - lib/Target/SparcV9/SparcV9CodeEmitter.cpp | 304 -- lib/Target/SparcV9/SparcV9CodeEmitter.h | 87 - lib/Target/SparcV9/SparcV9FrameInfo.cpp | 57 - lib/Target/SparcV9/SparcV9FrameInfo.h | 117 - lib/Target/SparcV9/SparcV9Instr.def | 547 -- lib/Target/SparcV9/SparcV9InstrForest.h | 134 - lib/Target/SparcV9/SparcV9InstrInfo.h | 77 - lib/Target/SparcV9/SparcV9InstrInfo.td | 777 --- lib/Target/SparcV9/SparcV9Internals.h | 133 - lib/Target/SparcV9/SparcV9JITInfo.cpp | 355 -- lib/Target/SparcV9/SparcV9JITInfo.h | 62 - lib/Target/SparcV9/SparcV9PeepholeOpts.cpp | 163 - lib/Target/SparcV9/SparcV9PreSelection.cpp | 308 -- .../SparcV9/SparcV9PrologEpilogInserter.cpp | 184 - lib/Target/SparcV9/SparcV9RegClassInfo.cpp | 397 -- lib/Target/SparcV9/SparcV9RegClassInfo.h | 224 - lib/Target/SparcV9/SparcV9RegInfo.cpp | 973 ---- lib/Target/SparcV9/SparcV9RegInfo.h | 381 -- lib/Target/SparcV9/SparcV9RegisterInfo.cpp | 333 -- lib/Target/SparcV9/SparcV9RegisterInfo.h | 117 - lib/Target/SparcV9/SparcV9RegisterInfo.td | 49 - lib/Target/SparcV9/SparcV9Relocations.h | 42 - lib/Target/SparcV9/SparcV9SchedInfo.cpp | 761 --- lib/Target/SparcV9/SparcV9StackSlots.cpp | 52 - lib/Target/SparcV9/SparcV9TargetMachine.cpp | 303 -- lib/Target/SparcV9/SparcV9TargetMachine.h | 57 - lib/Target/SparcV9/SparcV9TmpInstr.cpp | 72 - lib/Target/SparcV9/SparcV9TmpInstr.h | 64 - lib/Target/SparcV9/SparcV9_F2.td | 71 - lib/Target/SparcV9/SparcV9_F3.td | 267 - lib/Target/SparcV9/SparcV9_F4.td | 141 - 90 files changed, 32210 deletions(-) delete mode 100644 lib/Target/SparcV9/.cvsignore delete mode 100644 lib/Target/SparcV9/DecomposeMultiDimRefs.cpp delete mode 100644 lib/Target/SparcV9/EmitBytecodeToAssembly.cpp delete mode 100644 lib/Target/SparcV9/InstrSched/InstrScheduling.cpp delete mode 100644 lib/Target/SparcV9/InstrSched/Makefile delete mode 100644 lib/Target/SparcV9/InstrSched/SchedGraph.cpp delete mode 100644 lib/Target/SparcV9/InstrSched/SchedGraph.h delete mode 100644 lib/Target/SparcV9/InstrSched/SchedGraphCommon.cpp delete mode 100644 lib/Target/SparcV9/InstrSched/SchedPriorities.cpp delete mode 100644 lib/Target/SparcV9/InstrSched/SchedPriorities.h delete mode 100644 lib/Target/SparcV9/InternalGlobalMapper.cpp delete mode 100644 lib/Target/SparcV9/LiveVar/BBLiveVar.cpp delete mode 100644 lib/Target/SparcV9/LiveVar/BBLiveVar.h delete mode 100644 lib/Target/SparcV9/LiveVar/FunctionLiveVarInfo.cpp delete mode 100644 lib/Target/SparcV9/LiveVar/FunctionLiveVarInfo.h delete mode 100644 lib/Target/SparcV9/LiveVar/Makefile delete mode 100644 lib/Target/SparcV9/LiveVar/ValueSet.cpp delete mode 100644 lib/Target/SparcV9/MachineCodeForInstruction.cpp delete mode 100644 lib/Target/SparcV9/MachineCodeForInstruction.h delete mode 100644 lib/Target/SparcV9/MachineFunctionInfo.cpp delete mode 100644 lib/Target/SparcV9/MachineFunctionInfo.h delete mode 100644 lib/Target/SparcV9/MachineInstrAnnot.h delete mode 100644 lib/Target/SparcV9/Makefile delete mode 100644 lib/Target/SparcV9/MappingInfo.cpp delete mode 100644 lib/Target/SparcV9/MappingInfo.h delete mode 100644 lib/Target/SparcV9/ModuloScheduling/DependenceAnalyzer.cpp delete mode 100644 lib/Target/SparcV9/ModuloScheduling/DependenceAnalyzer.h delete mode 100644 lib/Target/SparcV9/ModuloScheduling/MSSchedule.cpp delete mode 100644 lib/Target/SparcV9/ModuloScheduling/MSSchedule.h delete mode 100644 lib/Target/SparcV9/ModuloScheduling/MSScheduleSB.cpp delete mode 100644 lib/Target/SparcV9/ModuloScheduling/MSScheduleSB.h delete mode 100644 lib/Target/SparcV9/ModuloScheduling/MSchedGraph.cpp delete mode 100644 lib/Target/SparcV9/ModuloScheduling/MSchedGraph.h delete mode 100644 lib/Target/SparcV9/ModuloScheduling/MSchedGraphSB.cpp delete mode 100644 lib/Target/SparcV9/ModuloScheduling/MSchedGraphSB.h delete mode 100644 lib/Target/SparcV9/ModuloScheduling/Makefile delete mode 100644 lib/Target/SparcV9/ModuloScheduling/ModuloScheduling.cpp delete mode 100644 lib/Target/SparcV9/ModuloScheduling/ModuloScheduling.h delete mode 100644 lib/Target/SparcV9/ModuloScheduling/ModuloSchedulingSuperBlock.cpp delete mode 100644 lib/Target/SparcV9/ModuloScheduling/ModuloSchedulingSuperBlock.h delete mode 100644 lib/Target/SparcV9/RegAlloc/AllocInfo.h delete mode 100644 lib/Target/SparcV9/RegAlloc/IGNode.cpp delete mode 100644 lib/Target/SparcV9/RegAlloc/IGNode.h delete mode 100644 lib/Target/SparcV9/RegAlloc/InterferenceGraph.cpp delete mode 100644 lib/Target/SparcV9/RegAlloc/InterferenceGraph.h delete mode 100644 lib/Target/SparcV9/RegAlloc/LiveRange.h delete mode 100644 lib/Target/SparcV9/RegAlloc/LiveRangeInfo.cpp delete mode 100644 lib/Target/SparcV9/RegAlloc/LiveRangeInfo.h delete mode 100644 lib/Target/SparcV9/RegAlloc/Makefile delete mode 100644 lib/Target/SparcV9/RegAlloc/PhyRegAlloc.cpp delete mode 100644 lib/Target/SparcV9/RegAlloc/PhyRegAlloc.h delete mode 100644 lib/Target/SparcV9/RegAlloc/RegAllocCommon.h delete mode 100644 lib/Target/SparcV9/RegAlloc/RegClass.cpp delete mode 100644 lib/Target/SparcV9/RegAlloc/RegClass.h delete mode 100644 lib/Target/SparcV9/SparcV9.burg.in delete mode 100644 lib/Target/SparcV9/SparcV9.td delete mode 100644 lib/Target/SparcV9/SparcV9AsmPrinter.cpp delete mode 100644 lib/Target/SparcV9/SparcV9BurgISel.cpp delete mode 100644 lib/Target/SparcV9/SparcV9BurgISel.h delete mode 100644 lib/Target/SparcV9/SparcV9CodeEmitter.cpp delete mode 100644 lib/Target/SparcV9/SparcV9CodeEmitter.h delete mode 100644 lib/Target/SparcV9/SparcV9FrameInfo.cpp delete mode 100644 lib/Target/SparcV9/SparcV9FrameInfo.h delete mode 100644 lib/Target/SparcV9/SparcV9Instr.def delete mode 100644 lib/Target/SparcV9/SparcV9InstrForest.h delete mode 100644 lib/Target/SparcV9/SparcV9InstrInfo.h delete mode 100644 lib/Target/SparcV9/SparcV9InstrInfo.td delete mode 100644 lib/Target/SparcV9/SparcV9Internals.h delete mode 100644 lib/Target/SparcV9/SparcV9JITInfo.cpp delete mode 100644 lib/Target/SparcV9/SparcV9JITInfo.h delete mode 100644 lib/Target/SparcV9/SparcV9PeepholeOpts.cpp delete mode 100644 lib/Target/SparcV9/SparcV9PreSelection.cpp delete mode 100644 lib/Target/SparcV9/SparcV9PrologEpilogInserter.cpp delete mode 100644 lib/Target/SparcV9/SparcV9RegClassInfo.cpp delete mode 100644 lib/Target/SparcV9/SparcV9RegClassInfo.h delete mode 100644 lib/Target/SparcV9/SparcV9RegInfo.cpp delete mode 100644 lib/Target/SparcV9/SparcV9RegInfo.h delete mode 100644 lib/Target/SparcV9/SparcV9RegisterInfo.cpp delete mode 100644 lib/Target/SparcV9/SparcV9RegisterInfo.h delete mode 100644 lib/Target/SparcV9/SparcV9RegisterInfo.td delete mode 100644 lib/Target/SparcV9/SparcV9Relocations.h delete mode 100644 lib/Target/SparcV9/SparcV9SchedInfo.cpp delete mode 100644 lib/Target/SparcV9/SparcV9StackSlots.cpp delete mode 100644 lib/Target/SparcV9/SparcV9TargetMachine.cpp delete mode 100644 lib/Target/SparcV9/SparcV9TargetMachine.h delete mode 100644 lib/Target/SparcV9/SparcV9TmpInstr.cpp delete mode 100644 lib/Target/SparcV9/SparcV9TmpInstr.h delete mode 100644 lib/Target/SparcV9/SparcV9_F2.td delete mode 100644 lib/Target/SparcV9/SparcV9_F3.td delete mode 100644 lib/Target/SparcV9/SparcV9_F4.td diff --git a/lib/Target/SparcV9/.cvsignore b/lib/Target/SparcV9/.cvsignore deleted file mode 100644 index d3c6cd758ab..00000000000 --- a/lib/Target/SparcV9/.cvsignore +++ /dev/null @@ -1,4 +0,0 @@ -*.inc -SparcV9.burg.in1 -SparcV9.burm -SparcV9.burm.cpp diff --git a/lib/Target/SparcV9/DecomposeMultiDimRefs.cpp b/lib/Target/SparcV9/DecomposeMultiDimRefs.cpp deleted file mode 100644 index 50077c41917..00000000000 --- a/lib/Target/SparcV9/DecomposeMultiDimRefs.cpp +++ /dev/null @@ -1,137 +0,0 @@ -//===- llvm/Transforms/DecomposeMultiDimRefs.cpp - Lower array refs to 1D -===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// DecomposeMultiDimRefs - Convert multi-dimensional references consisting of -// any combination of 2 or more array and structure indices into a sequence of -// instructions (using getelementpr and cast) so that each instruction has at -// most one index (except structure references, which need an extra leading -// index of [0]). -// -//===----------------------------------------------------------------------===// - -#include "SparcV9Internals.h" -#include "llvm/DerivedTypes.h" -#include "llvm/Constants.h" -#include "llvm/Constant.h" -#include "llvm/Instructions.h" -#include "llvm/BasicBlock.h" -#include "llvm/Pass.h" -#include "llvm/ADT/Statistic.h" -#include "llvm/Support/Debug.h" -#include -using namespace llvm; - -namespace { - Statistic<> NumAdded("lowerrefs", "# of getelementptr instructions added"); - - struct DecomposePass : public BasicBlockPass { - virtual bool runOnBasicBlock(BasicBlock &BB); - }; - RegisterOpt 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(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 (V) && (cast(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 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(LastPtr->getType()); - - // Get the final index vector, including an initial [0] as before. - std::vector 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; -} - diff --git a/lib/Target/SparcV9/EmitBytecodeToAssembly.cpp b/lib/Target/SparcV9/EmitBytecodeToAssembly.cpp deleted file mode 100644 index eeb288a33dc..00000000000 --- a/lib/Target/SparcV9/EmitBytecodeToAssembly.cpp +++ /dev/null @@ -1,115 +0,0 @@ -//===-- EmitBytecodeToAssembly.cpp - Emit bytecode to SparcV9 .s File ------==// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the pass that writes LLVM bytecode as data to a sparc -// assembly file. The bytecode gets assembled into a special bytecode section -// of the executable for use at runtime later. -// -//===----------------------------------------------------------------------===// - -#include "SparcV9Internals.h" -#include "llvm/Pass.h" -#include "llvm/Bytecode/Writer.h" -#include -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(&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); -} - diff --git a/lib/Target/SparcV9/InstrSched/InstrScheduling.cpp b/lib/Target/SparcV9/InstrSched/InstrScheduling.cpp deleted file mode 100644 index e1228d089fa..00000000000 --- a/lib/Target/SparcV9/InstrSched/InstrScheduling.cpp +++ /dev/null @@ -1,1499 +0,0 @@ -//===- 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 -#include - -namespace llvm { - -SchedDebugLevel_t SchedDebugLevel; - -static cl::opt EnableFillingDelaySlots("sched-fill-delay-slots", cl::Hidden, - cl::desc("Fill branch delay slots during local scheduling")); - -static cl::opt -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 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 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 groups; // indexed by cycle number - std::vector startTime; // indexed by node id - - InstrSchedule(InstrSchedule&); // DO NOT IMPLEMENT - void operator=(InstrSchedule&); // DO NOT IMPLEMENT - -public: // iterators - typedef ScheduleIterator iterator; - typedef ScheduleIterator 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; - friend class ScheduleIterator; - /*ctor*/ InstrSchedule (); // Disable: DO NOT IMPLEMENT. -}; - -template -inline NodeType *ScheduleIterator::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 -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 -inline -ScheduleIterator<_NodeType>& -ScheduleIterator<_NodeType>::operator++() // Preincrement -{ - ++slotNum; - if (slotNum == S.nslots) { - ++cycleNum; - slotNum = 0; - } - skipToNextInstr(); - return *this; -} - -template -ScheduleIterator<_NodeType> -ScheduleIterator<_NodeType>::begin(const InstrSchedule& _schedule) -{ - return _Self(_schedule, 0, 0); -} - -template -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 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& 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 > choicesForSlot; - std::vector choiceVec; // indexed by node ptr - std::vector numInClass; // indexed by sched class - std::vector nextEarliestStartTime; // indexed by opCode - hash_map delaySlotInfoForBranches; - // indexed by branch node ptr - -public: - SchedulingManager(const TargetMachine& _target, const SchedGraph* graph, - SchedPriorities& schedPrio); - ~SchedulingManager() { - for (hash_map::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& 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_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& - 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((*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 << "\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& 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 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 sdelayNodeVec, - SchedGraph* graph) -{ - std::vector 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 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(); - 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()); - 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 - diff --git a/lib/Target/SparcV9/InstrSched/Makefile b/lib/Target/SparcV9/InstrSched/Makefile deleted file mode 100644 index ea2c3aa57a4..00000000000 --- a/lib/Target/SparcV9/InstrSched/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -##===- lib/CodeGen/InstrSched/Makefile ---------------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file was developed by the LLVM research group and is distributed under -# the University of Illinois Open Source License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## - -LEVEL = ../../../.. -DIRS = -LIBRARYNAME = LLVMSparcV9InstrSched - -include $(LEVEL)/Makefile.common diff --git a/lib/Target/SparcV9/InstrSched/SchedGraph.cpp b/lib/Target/SparcV9/InstrSched/SchedGraph.cpp deleted file mode 100644 index d9a30c2d317..00000000000 --- a/lib/Target/SparcV9/InstrSched/SchedGraph.cpp +++ /dev/null @@ -1,737 +0,0 @@ -//===- SchedGraph.cpp - Scheduling Graph Implementation -------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Scheduling graph based on SSA graph plus extra dependence edges capturing -// dependences due to machine resources (machine registers, CC registers, and -// any others). -// -//===----------------------------------------------------------------------===// - -#include "SchedGraph.h" -#include "llvm/Function.h" -#include "llvm/Instructions.h" -#include "llvm/CodeGen/MachineFunction.h" -#include "llvm/Target/TargetInstrInfo.h" -#include "llvm/Target/TargetMachine.h" -#include "../MachineCodeForInstruction.h" -#include "../SparcV9RegInfo.h" -#include "../SparcV9InstrInfo.h" -#include "llvm/ADT/STLExtras.h" -#include - -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 > { - typedef std::vector >::iterator iterator; - typedef - std::vector >::const_iterator const_iterator; -}; - -struct RegToRefVecMap: public hash_map { - typedef hash_map:: iterator iterator; - typedef hash_map::const_iterator const_iterator; -}; - -struct ValueToDefVecMap: public hash_map { - typedef hash_map:: iterator iterator; - typedef hash_map::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& 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 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& 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 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 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& memNodeVec, - std::vector& 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& memNodeVec, - std::vector& 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 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 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: . - // - 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 diff --git a/lib/Target/SparcV9/InstrSched/SchedGraph.h b/lib/Target/SparcV9/InstrSched/SchedGraph.h deleted file mode 100644 index aae70c87e70..00000000000 --- a/lib/Target/SparcV9/InstrSched/SchedGraph.h +++ /dev/null @@ -1,262 +0,0 @@ -//===-- SchedGraph.h - Scheduling Graph -------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This is a scheduling graph based on SSA graph plus extra dependence edges -// capturing dependences due to machine resources (machine registers, CC -// registers, and any others). -// -// This graph tries to leverage the SSA graph as much as possible, but captures -// the extra dependences through a common interface. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CODEGEN_SCHEDGRAPH_H -#define LLVM_CODEGEN_SCHEDGRAPH_H - -#include "llvm/CodeGen/SchedGraphCommon.h" -#include "llvm/CodeGen/MachineInstr.h" -#include "llvm/Transforms/Scalar.h" -#include "llvm/ADT/hash_map" -#include "llvm/ADT/GraphTraits.h" - -namespace llvm { - -class RegToRefVecMap; -class ValueToDefVecMap; -class RefVec; - -class SchedGraphNode : public SchedGraphNodeCommon { - - MachineBasicBlock *MBB; - const MachineInstr *MI; - - - SchedGraphNode(unsigned nodeId, MachineBasicBlock *mbb, int indexInBB, - const TargetMachine& Target); - ~SchedGraphNode(); - - friend class SchedGraph; // give access for ctor and dtor - friend class SchedGraphEdge; // give access for adding edges - -public: - - // Accessor methods - const MachineInstr* getMachineInstr() const { return MI; } - const MachineOpCode getOpcode() const { return MI->getOpcode(); } - bool isDummyNode() const { return (MI == NULL); } - MachineBasicBlock &getMachineBasicBlock() const { return *MBB; } - - void print(std::ostream &os) const; -}; - -class SchedGraph : public SchedGraphCommon { - MachineBasicBlock &MBB; - hash_map GraphMap; - -public: - typedef hash_map::const_iterator iterator; - typedef hash_map::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. - // - hash_map::const_iterator begin() const { - return GraphMap.begin(); - } - hash_map::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& memNV, - std::vector& callNV, - RegToRefVecMap& regToRefVecMap, - ValueToDefVecMap& valueToDefVecMap); - - - void findDefUseInfoAtInstr(const TargetMachine& target, SchedGraphNode* node, - std::vector& memNV, - std::vector& 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& memNod, - const TargetMachine& target); - - void addCallCCEdges(const std::vector& memNod, - MachineBasicBlock& bbMvec, - const TargetMachine& target); - - void addCallDepEdges(const std::vector& 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 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::const_iterator iterator; - typedef std::vector::const_iterator const_iterator; - - std::vector::const_iterator begin() const { return Graphs.begin(); } - std::vector::const_iterator end() const { return Graphs.end(); } - - // Debugging support - void dump() const; -}; - - - - -// -// sg_pred_iterator -// sg_pred_const_iterator -// -typedef SGPredIterator - sg_pred_iterator; -typedef SGPredIterator - 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 - sg_succ_iterator; -typedef SGSuccIterator - 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 { - 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 { - 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 diff --git a/lib/Target/SparcV9/InstrSched/SchedGraphCommon.cpp b/lib/Target/SparcV9/InstrSched/SchedGraphCommon.cpp deleted file mode 100644 index bf6d6689899..00000000000 --- a/lib/Target/SparcV9/InstrSched/SchedGraphCommon.cpp +++ /dev/null @@ -1,180 +0,0 @@ -//===- SchedGraphCommon.cpp - Scheduling Graphs Base Class- ---------------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Scheduling graph base class that contains common information for SchedGraph -// and ModuloSchedGraph scheduling graphs. -// -//===----------------------------------------------------------------------===// - -#include "llvm/CodeGen/SchedGraphCommon.h" -#include "llvm/ADT/STLExtras.h" -#include -#include - -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); -} - -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 diff --git a/lib/Target/SparcV9/InstrSched/SchedPriorities.cpp b/lib/Target/SparcV9/InstrSched/SchedPriorities.cpp deleted file mode 100644 index d7d2007684a..00000000000 --- a/lib/Target/SparcV9/InstrSched/SchedPriorities.cpp +++ /dev/null @@ -1,284 +0,0 @@ -//===-- SchedPriorities.h - Encapsulate scheduling heuristics -------------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Strategy: -// Priority ordering rules: -// (1) Max delay, which is the order of the heap S.candsAsHeap. -// (2) Instruction that frees up a register. -// (3) Instruction that has the maximum number of dependent instructions. -// Note that rules 2 and 3 are only used if issue conflicts prevent -// choosing a higher priority instruction by rule 1. -// -//===----------------------------------------------------------------------===// - -#include "SchedPriorities.h" -#include "../LiveVar/FunctionLiveVarInfo.h" -#include "llvm/CodeGen/MachineBasicBlock.h" -#include "llvm/Support/CFG.h" -#include "llvm/ADT/PostOrderIterator.h" -#include - -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 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(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(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& mcands) { - return (mcands.size() == 1)? 0 // only one choice exists so take it - : -1; // -1 indicates multiple choices -} - -inline int -SchedPriorities::chooseByRule2(std::vector& 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& 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& 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_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 diff --git a/lib/Target/SparcV9/InstrSched/SchedPriorities.h b/lib/Target/SparcV9/InstrSched/SchedPriorities.h deleted file mode 100644 index 02c0b8a4e7a..00000000000 --- a/lib/Target/SparcV9/InstrSched/SchedPriorities.h +++ /dev/null @@ -1,221 +0,0 @@ -//===-- SchedPriorities.h - Encapsulate scheduling heuristics --*- C++ -*--===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Strategy: -// Priority ordering rules: -// (1) Max delay, which is the order of the heap S.candsAsHeap. -// (2) Instruction that frees up a register. -// (3) Instruction that has the maximum number of dependent instructions. -// Note that rules 2 and 3 are only used if issue conflicts prevent -// choosing a higher priority instruction by rule 1. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CODEGEN_SCHEDPRIORITIES_H -#define LLVM_CODEGEN_SCHEDPRIORITIES_H - -#include "SchedGraph.h" -#include "llvm/CodeGen/InstrScheduling.h" -#include "llvm/Target/TargetSchedInfo.h" -#include "llvm/ADT/hash_set" -#include - -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 { - NodeHeap(const NodeHeap&); // DO NOT IMPLEMENT - void operator=(const NodeHeap&); // DO NOT IMPLEMENT -public: - typedef std::list::iterator iterator; - typedef std::list::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::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 lastUseMap; - std::vector nodeDelayVec; - std::vector nodeEarliestUseVec; - std::vector earliestReadyTimeForNode; - CycleCount_t earliestReadyTime; - NodeHeap candsAsHeap; // candidate nodes, ready to go - hash_set candsAsSet; //same entries as candsAsHeap, - // but as set for fast lookup - std::vector mcands; // holds pointers into cands - candIndex nextToTry; // next cand after the last - // one tried in this cycle - - int chooseByRule1 (std::vector& mcands); - int chooseByRule2 (std::vector& mcands); - int chooseByRule3 (std::vector& mcands); - - void findSetWithMaxDelay (std::vector& 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 diff --git a/lib/Target/SparcV9/InternalGlobalMapper.cpp b/lib/Target/SparcV9/InternalGlobalMapper.cpp deleted file mode 100644 index f59e921be0b..00000000000 --- a/lib/Target/SparcV9/InternalGlobalMapper.cpp +++ /dev/null @@ -1,82 +0,0 @@ -//===-- InternalGlobalMapper.cpp - Mapping Info for Internal Globals ------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// InternalGlobalMapper is a pass that helps the runtime trace optimizer map -// the names of internal GlobalValues (which may have mangled, -// unreconstructible names in the executable) to pointers. If the name mangler -// is changed at some point in the future to allow its results to be -// reconstructible (for instance, by making the type mangling symbolic instead -// of using a UniqueID) this pass should probably be phased out. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Constants.h" -#include "llvm/Module.h" -#include "llvm/Pass.h" -#include "llvm/DerivedTypes.h" -using namespace llvm; - -typedef std::vector 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 FieldTypes; - FieldTypes.push_back (Type::UIntTy); - FieldTypes.push_back (ATy); - StructType *STy = StructType::get (FieldTypes); - std::vector 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. -} diff --git a/lib/Target/SparcV9/LiveVar/BBLiveVar.cpp b/lib/Target/SparcV9/LiveVar/BBLiveVar.cpp deleted file mode 100644 index c4602d14fda..00000000000 --- a/lib/Target/SparcV9/LiveVar/BBLiveVar.cpp +++ /dev/null @@ -1,233 +0,0 @@ -//===-- BBLiveVar.cpp - Live Variable Analysis for a BasicBlock -----------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This is a wrapper class for BasicBlock which is used by live var analysis. -// -//===----------------------------------------------------------------------===// - -#include "BBLiveVar.h" -#include "FunctionLiveVarInfo.h" -#include "llvm/CodeGen/MachineInstr.h" -#include "llvm/CodeGen/MachineBasicBlock.h" -#include "llvm/Support/CFG.h" -#include "llvm/ADT/SetOperations.h" -#include "../SparcV9Internals.h" -#include - -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(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(*++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 &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 diff --git a/lib/Target/SparcV9/LiveVar/BBLiveVar.h b/lib/Target/SparcV9/LiveVar/BBLiveVar.h deleted file mode 100644 index f33a6768b52..00000000000 --- a/lib/Target/SparcV9/LiveVar/BBLiveVar.h +++ /dev/null @@ -1,90 +0,0 @@ -//===-- BBLiveVar.h - Live Variable Analysis for a BasicBlock ---*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This is a BasicBlock annotation class that is used by live var analysis to -// hold data flow information for a basic block. -// -//===----------------------------------------------------------------------===// - -#ifndef LIVE_VAR_BB_H -#define LIVE_VAR_BB_H - -#include "llvm/CodeGen/ValueSet.h" -#include "llvm/ADT/hash_map" - -namespace llvm { - -class BasicBlock; -class Value; -class MachineBasicBlock; - -enum LiveVarDebugLevel_t { - LV_DEBUG_None, - LV_DEBUG_Normal, - LV_DEBUG_Instr, - LV_DEBUG_Verbose -}; - -extern LiveVarDebugLevel_t DEBUG_LV; - -class BBLiveVar { - const BasicBlock &BB; // pointer to BasicBlock - const MachineBasicBlock &MBB; // Pointer to MachineBasicBlock - unsigned POID; // Post-Order ID - - ValueSet DefSet; // Def set (with no preceding uses) for LV analysis - ValueSet InSet, OutSet; // In & Out for LV analysis - bool InSetChanged, OutSetChanged; // set if the InSet/OutSet is modified - - // map that contains PredBB -> Phi arguments - // coming in on that edge. such uses have to be - // treated differently from ordinary uses. - hash_map 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 &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 diff --git a/lib/Target/SparcV9/LiveVar/FunctionLiveVarInfo.cpp b/lib/Target/SparcV9/LiveVar/FunctionLiveVarInfo.cpp deleted file mode 100644 index e748e439031..00000000000 --- a/lib/Target/SparcV9/LiveVar/FunctionLiveVarInfo.cpp +++ /dev/null @@ -1,323 +0,0 @@ -//===-- FunctionLiveVarInfo.cpp - Live Variable Analysis for a Function ---===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This is the interface to function level live variable information that is -// provided by live variable analysis. -// -//===----------------------------------------------------------------------===// - -#include "FunctionLiveVarInfo.h" -#include "llvm/CodeGen/MachineInstr.h" -#include "llvm/CodeGen/MachineFunction.h" -#include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetInstrInfo.h" -#include "llvm/Support/CFG.h" -#include "llvm/ADT/PostOrderIterator.h" -#include "llvm/ADT/SetOperations.h" -#include "llvm/Support/CommandLine.h" -#include "BBLiveVar.h" -#include - -namespace llvm { - -static RegisterAnalysis -X("livevar", "Live Variable Analysis"); - -LiveVarDebugLevel_t DEBUG_LV; - -static cl::opt -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 PONumbering; - - for (po_iterator 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::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 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::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(*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 diff --git a/lib/Target/SparcV9/LiveVar/FunctionLiveVarInfo.h b/lib/Target/SparcV9/LiveVar/FunctionLiveVarInfo.h deleted file mode 100644 index 0518e6c5942..00000000000 --- a/lib/Target/SparcV9/LiveVar/FunctionLiveVarInfo.h +++ /dev/null @@ -1,111 +0,0 @@ -//===-- CodeGen/FunctionLiveVarInfo.h - LiveVar Analysis --------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This is the interface for live variable info of a function that is required -// by any other part of the compiler -// -// After the analysis, getInSetOfBB or getOutSetofBB can be called to get -// live var info of a BB. -// -// The live var set before an instruction can be obtained in 2 ways: -// -// 1. Use the method getLiveVarSetAfterInst(Instruction *) to get the LV Info -// just after an instruction. (also exists getLiveVarSetBeforeInst(..)) -// -// This function caluclates the LV info for a BB only once and caches that -// info. If the cache does not contain the LV info of the instruction, it -// calculates the LV info for the whole BB and caches them. -// -// Getting liveVar info this way uses more memory since, LV info should be -// cached. However, if you need LV info of nearly all the instructions of a -// BB, this is the best and simplest interfrace. -// -// 2. Use the OutSet and applyTranferFuncForInst(const Instruction *const Inst) -// declared in LiveVarSet and traverse the instructions of a basic block in -// reverse (using const_reverse_iterator in the BB class). -// -//===----------------------------------------------------------------------===// - -#ifndef FUNCTION_LIVE_VAR_INFO_H -#define FUNCTION_LIVE_VAR_INFO_H - -#include "llvm/ADT/hash_map" -#include "llvm/Pass.h" -#include "llvm/CodeGen/ValueSet.h" - -namespace llvm { - -class BBLiveVar; -class MachineInstr; - -class FunctionLiveVarInfo : public FunctionPass { - // Machine Instr to LiveVarSet Map for providing LVset BEFORE each inst - // These sets are owned by this map and will be freed in releaseMemory(). - hash_map 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 MInst2LVSetAI; - - hash_map 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 diff --git a/lib/Target/SparcV9/LiveVar/Makefile b/lib/Target/SparcV9/LiveVar/Makefile deleted file mode 100644 index a2a53e6ca3a..00000000000 --- a/lib/Target/SparcV9/LiveVar/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -##===- lib/Target/Sparc/LiveVar/Makefile -------------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file was developed by the LLVM research group and is distributed under -# the University of Illinois Open Source License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## - -LEVEL = ../../../.. -LIBRARYNAME = LLVMSparcV9LiveVar - -include $(LEVEL)/Makefile.common - diff --git a/lib/Target/SparcV9/LiveVar/ValueSet.cpp b/lib/Target/SparcV9/LiveVar/ValueSet.cpp deleted file mode 100644 index 627c5162c42..00000000000 --- a/lib/Target/SparcV9/LiveVar/ValueSet.cpp +++ /dev/null @@ -1,31 +0,0 @@ -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// FIXME: Eliminate this file. - -#include "llvm/CodeGen/ValueSet.h" -#include "llvm/Value.h" -#include - -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(v) && !isa(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 diff --git a/lib/Target/SparcV9/MachineCodeForInstruction.cpp b/lib/Target/SparcV9/MachineCodeForInstruction.cpp deleted file mode 100644 index a3fc7254688..00000000000 --- a/lib/Target/SparcV9/MachineCodeForInstruction.cpp +++ /dev/null @@ -1,116 +0,0 @@ -//===-- MachineCodeForInstruction.cpp -------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Container for the sequence of MachineInstrs created for a single -// LLVM Instruction. MachineCodeForInstruction also tracks temporary values -// (TmpInstruction objects) created during SparcV9 code generation, so that -// they can be deleted when they are no longer needed, and finally, it also -// holds some extra information for 'call' Instructions (using the -// CallArgsDescriptor object, which is also implemented in this file). -// -//===----------------------------------------------------------------------===// - -#include "MachineCodeForInstruction.h" -#include "llvm/Function.h" -#include "llvm/Instructions.h" -#include "llvm/Type.h" -#include "llvm/CodeGen/MachineInstr.h" -#include "llvm/CodeGen/MachineFunction.h" -#include "MachineFunctionInfo.h" -#include "MachineInstrAnnot.h" -#include "SparcV9TmpInstr.h" -#include "SparcV9RegisterInfo.h" -using namespace llvm; - -MachineCodeForInstruction &MachineCodeForInstruction::get(const Instruction *I){ - MachineFunction &MF = MachineFunction::get(I->getParent()->getParent()); - return MF.getInfo()->MCFIEntries[I]; -} - -void MachineCodeForInstruction::destroy(const Instruction *I) { - MachineFunction &MF = MachineFunction::get(I->getParent()->getParent()); - MF.getInfo()->MCFIEntries.erase(I); -} - -void MachineCodeForInstruction::dropAllReferences() { - for (unsigned i=0, N=tempVec.size(); i < N; i++) - cast(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(_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 (MI->getOperand (0).getVRegValue ()))) { - retAddrVal = MI->getOperand (2).getVRegValue (); - } else { - retAddrVal = MI->getImplicitRef (MI->getNumImplicitRefs () - 1); - } - - const TmpInstruction* retAddrReg = cast (retAddrVal); - assert(retAddrReg->getNumOperands() == 1 && - isa(retAddrReg->getOperand(0)) && - "Location of callInstr arg for CALL instr. changed? FIX THIS CODE!"); - - const CallInst* callInstr = cast(retAddrReg->getOperand(0)); - - CallArgsDescriptor* desc = - MachineCodeForInstruction::get(callInstr).getCallArgsDescriptor(); - assert(desc->getCallInst()==callInstr && "Incorrect call args descriptor?"); - return desc; -} diff --git a/lib/Target/SparcV9/MachineCodeForInstruction.h b/lib/Target/SparcV9/MachineCodeForInstruction.h deleted file mode 100644 index d9617234503..00000000000 --- a/lib/Target/SparcV9/MachineCodeForInstruction.h +++ /dev/null @@ -1,97 +0,0 @@ -//===-- MachineCodeForInstruction.h -----------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// FIXME: This file is SparcV9 specific. Do not rely on this class for new -// targets, it will go away in the future. -// -// Representation of the sequence of machine instructions created for a single -// VM instruction. Additionally records information about hidden and implicit -// values used by the machine instructions: about hidden values used by the -// machine instructions: -// -// "Temporary values" are intermediate values used in the machine instruction -// sequence, but not in the VM instruction Note that such values should be -// treated as pure SSA values with no interpretation of their operands (i.e., as -// a TmpInstruction object which actually represents such a value). -// -// (2) "Implicit uses" are values used in the VM instruction but not in -// the machine instruction sequence -// -//===----------------------------------------------------------------------===// - -#ifndef MACHINECODE_FOR_INSTRUCTION_H -#define MACHINECODE_FOR_INSTRUCTION_H - -#include - -namespace llvm { - -class MachineInstr; -class Instruction; -class Value; -class CallArgsDescriptor; - - class MachineCodeForInstruction { - std::vector tempVec; // used by m/c instr but not VM instr - std::vector 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::iterator iterator; - typedef std::vector::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 - 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 &getTempValues() const { return tempVec; } - std::vector &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 diff --git a/lib/Target/SparcV9/MachineFunctionInfo.cpp b/lib/Target/SparcV9/MachineFunctionInfo.cpp deleted file mode 100644 index d44117f08e7..00000000000 --- a/lib/Target/SparcV9/MachineFunctionInfo.cpp +++ /dev/null @@ -1,171 +0,0 @@ -//===-- SparcV9FunctionInfo.cpp -------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This implements the SparcV9 specific MachineFunctionInfo class. -// -//===----------------------------------------------------------------------===// - -#include "MachineFunctionInfo.h" -#include "llvm/Instructions.h" -#include "llvm/Function.h" -#include "llvm/Type.h" -#include "llvm/CodeGen/MachineFunction.h" -#include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetFrameInfo.h" -using namespace llvm; - -static unsigned -ComputeMaxOptionalArgsSize(const TargetMachine& target, const Function *F, - unsigned &maxOptionalNumArgs) -{ - unsigned maxSize = 0; - - for (Function::const_iterator BB = F->begin(), BBE = F->end(); BB !=BBE; ++BB) - for (BasicBlock::const_iterator I = BB->begin(), E = BB->end(); I != E; ++I) - if (const CallInst *callInst = dyn_cast(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_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 -} diff --git a/lib/Target/SparcV9/MachineFunctionInfo.h b/lib/Target/SparcV9/MachineFunctionInfo.h deleted file mode 100644 index 39c924c8750..00000000000 --- a/lib/Target/SparcV9/MachineFunctionInfo.h +++ /dev/null @@ -1,125 +0,0 @@ -//===-- SparcV9FunctionInfo.h -----------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This class keeps track of information about the stack frame and about the -// per-function constant pool. -// -// FIXME: This class is completely SparcV9 specific. Do not use it for future -// targets. This file will be eliminated in future versions of LLVM. -// -//===----------------------------------------------------------------------===// - -#ifndef MACHINEFUNCTIONINFO_H -#define MACHINEFUNCTIONINFO_H - -#include "MachineCodeForInstruction.h" -#include "llvm/CodeGen/MachineFunction.h" -#include "llvm/ADT/HashExtras.h" -#include "llvm/ADT/hash_set" - -namespace llvm { - -class MachineFunction; -class Constant; -class Type; - -class SparcV9FunctionInfo : public MachineFunctionInfo { - hash_set constantsForConstPool; - hash_map 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 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 &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 diff --git a/lib/Target/SparcV9/MachineInstrAnnot.h b/lib/Target/SparcV9/MachineInstrAnnot.h deleted file mode 100644 index 96975e022d4..00000000000 --- a/lib/Target/SparcV9/MachineInstrAnnot.h +++ /dev/null @@ -1,95 +0,0 @@ -//===-- MachineInstrAnnot.h -------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Annotations used to pass information between SparcV9 code generation phases. -// -//===----------------------------------------------------------------------===// - -#ifndef MACHINEINSTRANNOT_H -#define MACHINEINSTRANNOT_H - -#include "llvm/CodeGen/MachineInstr.h" -#include "SparcV9RegInfo.h" - -namespace llvm { - -class Value; -class TmpInstruction; -class CallInst; - -class CallArgInfo { - // Flag values for different argument passing methods - static const unsigned char IntArgReg = 0x1; - static const unsigned char FPArgReg = 0x2; - static const unsigned char StackSlot = 0x4; - - Value* argVal; // this argument - int argCopyReg; // register used for second copy of arg. when - // multiple copies must be passed in registers - unsigned char passingMethod; // flags recording passing methods - -public: - // Constructors - CallArgInfo(Value* _argVal) - : argVal(_argVal), argCopyReg(SparcV9RegInfo::getInvalidRegNum()), - passingMethod(0x0) {} - - CallArgInfo(const CallArgInfo& obj) - : argVal(obj.argVal), argCopyReg(obj.argCopyReg), - passingMethod(obj.passingMethod) {} - - // Accessor methods - Value* getArgVal() { return argVal; } - int getArgCopy() { return argCopyReg; } - bool usesIntArgReg() { return (bool) (passingMethod & IntArgReg);} - bool usesFPArgReg() { return (bool) (passingMethod & FPArgReg); } - bool usesStackSlot() { return (bool) (passingMethod & StackSlot);} - - // Modifier methods - void replaceArgVal(Value* newVal) { argVal = newVal; } - void setUseIntArgReg() { passingMethod |= IntArgReg; } - void setUseFPArgReg() { passingMethod |= FPArgReg; } - void setUseStackSlot() { passingMethod |= StackSlot; } - void setArgCopy(int copyReg) { argCopyReg = copyReg; } -}; - - -class CallArgsDescriptor { - - std::vector 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 diff --git a/lib/Target/SparcV9/Makefile b/lib/Target/SparcV9/Makefile deleted file mode 100644 index 26661cc8e6f..00000000000 --- a/lib/Target/SparcV9/Makefile +++ /dev/null @@ -1,35 +0,0 @@ -##===- lib/Target/SparcV9/Makefile -------------------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file was developed by the LLVM research group and is distributed under -# the University of Illinois Open Source License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## -LEVEL = ../../.. -LIBRARYNAME = LLVMSparcV9 -PARALLEL_DIRS = InstrSched LiveVar ModuloScheduling RegAlloc - -TARGET = SparcV9 - -BUILT_SOURCES = \ - SparcV9GenCodeEmitter.inc \ - SparcV9.burm.cpp - -include $(LEVEL)/Makefile.common - -SparcV9.burg.in1 : $(PROJ_SRC_DIR)/SparcV9.burg.in - $(Echo) Pre-processing SparcV9.burg.in - $(Verb) $(CXX) -E $(CPP.Flags) -x c++ $< | $(SED) '/^#/d' | $(SED) 's/Ydefine/#define/' > $@ - -SparcV9.burm : SparcV9.burg.in1 - $(Echo) Pre-processing SparcV9.burg.in - $(Verb) $(CXX) -E $(CPP.Flags) -x c++ $< | $(SED) '/^#/d' | $(SED) 's/^Xinclude/#include/' | $(SED) 's/^Xdefine/#define/' > $@ - -SparcV9.burm.cpp: SparcV9.burm - $(Echo) "Burging `basename $<`" - $(Verb) $(BURG) -I $< -o $@ - -clean:: - $(Verb) $(RM) -f SparcV9.burg.in1 SparcV9.burm SparcV9.burm.cpp - diff --git a/lib/Target/SparcV9/MappingInfo.cpp b/lib/Target/SparcV9/MappingInfo.cpp deleted file mode 100644 index f8c0aa13a03..00000000000 --- a/lib/Target/SparcV9/MappingInfo.cpp +++ /dev/null @@ -1,216 +0,0 @@ -//===- MappingInfo.cpp - create LLVM info and output to .s file -----------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file contains a FunctionPass called MappingInfoAsmPrinter, -// which creates a map between MachineBasicBlocks and -// MachineInstrs (the "BB TO MI MAP"). -// -// As a side effect, it outputs this information as .byte directives to -// the assembly file. The output is designed to survive the SPARC assembler, -// in order that the Reoptimizer may read it in from memory later when the -// binary is loaded. Therefore, it may contain some hidden SPARC-architecture -// dependencies. Currently this question is purely theoretical as the -// Reoptimizer works only on the SPARC. -// -// The BB TO MI MAP consists of a three-element tuple for each -// MachineBasicBlock in a function, ordered from begin() to end() of -// its MachineFunction: first, the index of the MachineBasicBlock in the -// function; second, the number of the MachineBasicBlock in the function -// as computed by create_BB_to_MInumber_Key; and third, the number of -// MachineInstrs in the MachineBasicBlock. -// -//===--------------------------------------------------------------------===// - -#include "MappingInfo.h" -#include "llvm/Pass.h" -#include "llvm/Module.h" -#include "llvm/CodeGen/MachineFunction.h" -#include "llvm/ADT/StringExtras.h" - -namespace llvm { - -namespace { - class MappingInfoAsmPrinter : public FunctionPass { - std::ostream &Out; - public: - MappingInfoAsmPrinter(std::ostream &out) : Out(out){} - const char *getPassName () const { return "Instr. Mapping Info Collector"; } - bool runOnFunction(Function &FI); - typedef std::map InstructionKey; - private: - MappingInfo *currentOutputMap; - std::map 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 diff --git a/lib/Target/SparcV9/MappingInfo.h b/lib/Target/SparcV9/MappingInfo.h deleted file mode 100644 index 4fbd04fbae9..00000000000 --- a/lib/Target/SparcV9/MappingInfo.h +++ /dev/null @@ -1,50 +0,0 @@ -//===- lib/Target/SparcV9/MappingInfo.h -------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Data structures to support the Reoptimizer's Instruction-to-MachineInstr -// mapping information gatherer. -// -//===----------------------------------------------------------------------===// - -#ifndef MAPPINGINFO_H -#define MAPPINGINFO_H - -#include -#include -#include - -namespace llvm { - -class ModulePass; - -ModulePass *getMappingInfoAsmPrinterPass(std::ostream &out); -ModulePass *createInternalGlobalMapperPass(); - -class MappingInfo { - struct byteVector : public std::vector { - 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 diff --git a/lib/Target/SparcV9/ModuloScheduling/DependenceAnalyzer.cpp b/lib/Target/SparcV9/ModuloScheduling/DependenceAnalyzer.cpp deleted file mode 100644 index 9c3422d54a6..00000000000 --- a/lib/Target/SparcV9/ModuloScheduling/DependenceAnalyzer.cpp +++ /dev/null @@ -1,305 +0,0 @@ -//===-- DependenceAnalyzer.cpp - DependenceAnalyzer ------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// -// -// -//===----------------------------------------------------------------------===// -#define DEBUG_TYPE "ModuloSched" - -#include "DependenceAnalyzer.h" -#include "llvm/Type.h" -#include "llvm/Support/Debug.h" -#include "llvm/ADT/Statistic.h" -#include "llvm/Constants.h" -#include -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(); - TD = &getAnalysis(); - SE = &getAnalysis(); - - return false; -} - -static RegisterAnalysisX("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 &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(val)) - if(valInst->getParent() == BB) - loopInvariant = false; - if(Instruction *val2Inst = dyn_cast(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(val); - GetElementPtrInst *GP2 = dyn_cast(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 &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(gp1->getOperand(1))) - if(Constant *c2 = dyn_cast(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(Gep1Idx)) - Gep1Idx = c1->getOperand(0); - if(CastInst *c2 = dyn_cast(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(SV1); - SCEVAddRecExpr *SVAdd2 = dyn_cast(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(SVAdd1->getOperand(1)); - SCEVConstant *B2 = dyn_cast(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(SVAdd1->getOperand(0)); - SCEVConstant *A2 = dyn_cast(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 &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 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(inst1)) { - - if(StoreInst *stInst = dyn_cast(inst2)) - AnalyzeDeps(ldInst->getOperand(0), stInst->getOperand(1), - true, false, deps, ldInst->getParent(), srcBeforeDest); - } - else if(StoreInst *stInst = dyn_cast(inst1)) { - - if(LoadInst *ldInst = dyn_cast(inst2)) - AnalyzeDeps(stInst->getOperand(1), ldInst->getOperand(0), false, true, - deps, ldInst->getParent(), srcBeforeDest); - - else if(StoreInst *stInst2 = dyn_cast(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; -} - diff --git a/lib/Target/SparcV9/ModuloScheduling/DependenceAnalyzer.h b/lib/Target/SparcV9/ModuloScheduling/DependenceAnalyzer.h deleted file mode 100644 index f9aac5c0101..00000000000 --- a/lib/Target/SparcV9/ModuloScheduling/DependenceAnalyzer.h +++ /dev/null @@ -1,92 +0,0 @@ -//===-- DependenceAnalyzer.h - Dependence Analyzer--------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_DEPENDENCEANALYZER_H -#define LLVM_DEPENDENCEANALYZER_H - -#include "llvm/Instructions.h" -#include "llvm/Function.h" -#include "llvm/Pass.h" -#include "llvm/Analysis/AliasAnalysis.h" -#include "llvm/Analysis/ScalarEvolutionExpressions.h" -#include "llvm/Target/TargetData.h" -#include - -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 dependences; - DependenceResult(const std::vector &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 &deps, bool srcBeforeDest); - - void AnalyzeDeps(Value *val, Value *val2, bool val1Load, bool val2Load, - std::vector &deps, BasicBlock *BB, - bool srcBeforeDest); - - void createDep(std::vector &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(); - AU.addRequired(); - AU.addRequired(); - AU.setPreservesAll(); - } - - //get dependence info - DependenceResult getDependenceInfo(Instruction *inst1, Instruction *inst2, - bool srcBeforeDest); - - }; - -} - - - -#endif diff --git a/lib/Target/SparcV9/ModuloScheduling/MSSchedule.cpp b/lib/Target/SparcV9/ModuloScheduling/MSSchedule.cpp deleted file mode 100644 index 52d53243f9e..00000000000 --- a/lib/Target/SparcV9/ModuloScheduling/MSSchedule.cpp +++ /dev/null @@ -1,309 +0,0 @@ -//===-- MSSchedule.cpp Schedule ---------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// -// -//===----------------------------------------------------------------------===// -#define DEBUG_TYPE "ModuloSched" - -#include "MSSchedule.h" -#include "llvm/Support/Debug.h" -#include "llvm/Target/TargetSchedInfo.h" -#include "../SparcV9Internals.h" -#include "llvm/CodeGen/MachineInstr.h" -#include -using namespace llvm; - -//Check if all resources are free -bool resourcesFree(MSchedGraphNode*, int, -std::map > &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 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 nodesAtCycle = schedule[cycle]; - - std::map indexMap; - for(unsigned i=0; i < nodesAtCycle.size(); ++i) { - indexMap[nodesAtCycle[i]->getIndex()] = nodesAtCycle[i]; - } - - indexMap[node->getIndex()] = node; - - std::vector nodes; - for(std::map::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 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 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 > 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 > 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 &branches, std::map &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 > 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::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 >::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 tmpMap; - - //Loop over induction variable instructions in the map that come before this instr - for(std::map::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::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 tmpMap; - - //Add remaining invar instructions - for(std::map::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::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 >::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::const_iterator node = I->second.begin(), nodeEnd = I->second.end(); node != nodeEnd; ++node) - os << **node << "\n"; - } - - os << "Kernel:\n"; - for(std::vector >::const_iterator I = kernel.begin(), - E = kernel.end(); I != E; ++I) - os << "Node: " << *(I->first) << " Stage: " << I->second << "\n"; -} - diff --git a/lib/Target/SparcV9/ModuloScheduling/MSSchedule.h b/lib/Target/SparcV9/ModuloScheduling/MSSchedule.h deleted file mode 100644 index 34a37db8b65..00000000000 --- a/lib/Target/SparcV9/ModuloScheduling/MSSchedule.h +++ /dev/null @@ -1,72 +0,0 @@ -//===-- MSSchedule.h - Schedule ------- -------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// The schedule generated by a scheduling algorithm -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_MSSCHEDULE_H -#define LLVM_MSSCHEDULE_H - -#include "MSchedGraph.h" -#include -#include - -namespace llvm { - - class MSSchedule { - std::map > schedule; - unsigned numIssue; - - //Internal map to keep track of explicit resources - std::map > 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 > 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 >* getKernel() { return &kernel; } - bool constructKernel(int II, std::vector &branches, std::map &indVar); - int getMaxStage() { return maxStage; } - bool defPreviousStage(Value *def, int stage); - - //iterators - typedef std::map >::iterator schedule_iterator; - typedef std::map >::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 >::iterator kernel_iterator; - typedef std::vector >::const_iterator kernel_const_iterator; - kernel_iterator kernel_begin() { return kernel.begin(); } - kernel_iterator kernel_end() { return kernel.end(); } - - }; - -} - - -#endif diff --git a/lib/Target/SparcV9/ModuloScheduling/MSScheduleSB.cpp b/lib/Target/SparcV9/ModuloScheduling/MSScheduleSB.cpp deleted file mode 100644 index 487fb336e06..00000000000 --- a/lib/Target/SparcV9/ModuloScheduling/MSScheduleSB.cpp +++ /dev/null @@ -1,325 +0,0 @@ -//===-- MSScheduleSB.cpp Schedule ---------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// -// -//===----------------------------------------------------------------------===// -#define DEBUG_TYPE "ModuloSchedSB" - -#include "MSScheduleSB.h" -#include "llvm/Support/Debug.h" -#include "llvm/Target/TargetSchedInfo.h" -#include "../SparcV9Internals.h" -#include "llvm/CodeGen/MachineInstr.h" -#include -using namespace llvm; - -//Check if all resources are free -bool resourcesFree(MSchedGraphSBNode*, int, -std::map > &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 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 nodesAtCycle = schedule[cycle]; - - std::map indexMap; - for(unsigned i=0; i < nodesAtCycle.size(); ++i) { - indexMap[nodesAtCycle[i]->getIndex()] = nodesAtCycle[i]; - } - - indexMap[node->getIndex()] = node; - - std::vector nodes; - for(std::map::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 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 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 > 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 > 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 &branches, std::map &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 > 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::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 >::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 tmpMap; - - //Loop over induction variable instructions in the map that come before this instr - for(std::map::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::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 otherInstrs = I->first->getOtherInstrs(); - for(std::vector::iterator O = otherInstrs.begin(), OE = otherInstrs.end(); O != OE; ++O) { - kernel.push_back(std::make_pair((MachineInstr*) *O, I->second)); - } - } - - } - - std::map tmpMap; - - //Add remaining invar instructions - for(std::map::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::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 >::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::const_iterator node = I->second.begin(), nodeEnd = I->second.end(); node != nodeEnd; ++node) - os << **node << "\n"; - } - - os << "Kernel:\n"; - for(std::vector >::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::const_iterator node = I->second.begin(), nodeEnd = I->second.end(); node != nodeEnd; ++node) - os << **node << "\n"; - } -} diff --git a/lib/Target/SparcV9/ModuloScheduling/MSScheduleSB.h b/lib/Target/SparcV9/ModuloScheduling/MSScheduleSB.h deleted file mode 100644 index 40bcb873e22..00000000000 --- a/lib/Target/SparcV9/ModuloScheduling/MSScheduleSB.h +++ /dev/null @@ -1,73 +0,0 @@ -//===-- MSScheduleSB.h - Schedule ------- -------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// The schedule generated by a scheduling algorithm -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_MSSCHEDULESB_H -#define LLVM_MSSCHEDULESB_H - -#include "MSchedGraphSB.h" -#include -#include - -namespace llvm { - - class MSScheduleSB { - std::map > schedule; - unsigned numIssue; - - //Internal map to keep track of explicit resources - std::map > 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 > 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 >* getKernel() { return &kernel; } - bool constructKernel(int II, std::vector &branches, std::map &indVar); - int getMaxStage() { return maxStage; } - bool defPreviousStage(Value *def, int stage); - - //iterators - typedef std::map >::iterator schedule_iterator; - typedef std::map >::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 >::iterator kernel_iterator; - typedef std::vector >::const_iterator kernel_const_iterator; - kernel_iterator kernel_begin() { return kernel.begin(); } - kernel_iterator kernel_end() { return kernel.end(); } - - }; - -} - - -#endif diff --git a/lib/Target/SparcV9/ModuloScheduling/MSchedGraph.cpp b/lib/Target/SparcV9/ModuloScheduling/MSchedGraph.cpp deleted file mode 100644 index d9b1f9b1202..00000000000 --- a/lib/Target/SparcV9/ModuloScheduling/MSchedGraph.cpp +++ /dev/null @@ -1,804 +0,0 @@ -//===-- MSchedGraph.cpp - Scheduling Graph ----------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// A graph class for dependencies. This graph only contains true, anti, and -// output data dependencies for a given MachineBasicBlock. Dependencies -// across iterations are also computed. Unless data dependence analysis -// is provided, a conservative approach of adding dependencies between all -// loads and stores is taken. -//===----------------------------------------------------------------------===// - -#define DEBUG_TYPE "ModuloSched" -#include "MSchedGraph.h" -#include "../SparcV9RegisterInfo.h" -#include "../MachineCodeForInstruction.h" -#include "llvm/BasicBlock.h" -#include "llvm/Constants.h" -#include "llvm/Instructions.h" -#include "llvm/Type.h" -#include "llvm/CodeGen/MachineBasicBlock.h" -#include "llvm/Target/TargetInstrInfo.h" -#include "llvm/Support/Debug.h" -#include -#include -#include -#include -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::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 &ignoreInstrs, - DependenceAnalyzer &DA, - std::map &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 &bbs, - const TargetMachine &targ, - std::map &ignoreInstrs, - DependenceAnalyzer &DA, - std::map &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 &newNodes) - : Target(G.Target) { - - BBs = G.BBs; - - std::map 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 &visited, - std::set &branches, MSchedGraphNode *startNode, - std::set > &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 branches; - std::set 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 > newEdges; - for(MSchedGraph::iterator I = GraphMap.begin(), E = GraphMap.end(); - I != E; ++I) { - std::set 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 >::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 &ignoreInstrs, - DependenceAnalyzer &DA, - std::map &machineTollvm) { - - - //Get Machine target information for calculating latency - const TargetInstrInfo *MTI = Target.getInstrInfo(); - - std::vector memInstructions; - std::map > regNumtoNodeMap; - std::map > valuetoNodeMap; - - //Save PHI instructions to deal with later - std::vector phiInstrs; - unsigned index = 0; - - for(std::vector::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 >::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(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::iterator I = phiInstrs.begin(), - E = phiInstrs.end(); I != E; ++I) { - - //Get Node for this instruction - std::map::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 >::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 &NodesInMap, - MSchedGraphNode *destNode, bool nodeIsUse, - bool nodeIsDef, std::vector &phiInstrs, int diff) { - - for(std::vector::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 >& regNumtoNodeMap) { - //Loop over all machine registers in the map, and add dependencies - //between the instructions that use it - typedef std::map > 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 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& memInst, - DependenceAnalyzer &DA, - std::map &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(srcLLVM) - && !isa(srcLLVM)) { - if(isa(srcLLVM)) { - if(isa(srcLLVM->getOperand(0)) || isa(srcLLVM->getOperand(1))) - continue; - } - useDepAnalyzer = false; - } - if(!isa(destLLVM) - && !isa(destLLVM)) { - if(isa(destLLVM)) { - if(isa(destLLVM->getOperand(0)) || isa(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::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); - } - } - } - } -} diff --git a/lib/Target/SparcV9/ModuloScheduling/MSchedGraph.h b/lib/Target/SparcV9/ModuloScheduling/MSchedGraph.h deleted file mode 100644 index 201b3083a19..00000000000 --- a/lib/Target/SparcV9/ModuloScheduling/MSchedGraph.h +++ /dev/null @@ -1,398 +0,0 @@ -//===-- MSchedGraph.h - Scheduling Graph ------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// A graph class for dependencies. This graph only contains true, anti, and -// output data dependencies for a given MachineBasicBlock. Dependencies -// across iterations are also computed. Unless data dependence analysis -// is provided, a conservative approach of adding dependencies between all -// loads and stores is taken. -//===----------------------------------------------------------------------===// - -#ifndef LLVM_MSCHEDGRAPH_H -#define LLVM_MSCHEDGRAPH_H -#include "DependenceAnalyzer.h" -#include "llvm/Analysis/AliasAnalysis.h" -#include "llvm/CodeGen/MachineInstr.h" -#include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetData.h" -#include "llvm/ADT/GraphTraits.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/iterator" -#include - -namespace llvm { - - class MSchedGraph; - class MSchedGraphNode; - template - 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 Predecessors; //Predecessor Nodes - std::vector 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::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::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::const_iterator, - const MSchedGraphNode> succ_const_iterator; - succ_const_iterator succ_begin() const; - succ_const_iterator succ_end() const; - - typedef MSchedGraphNodeIterator::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 MSchedGraphNodeIterator : public forward_iterator { - IteratorType I; // std::vector::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 { - 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 BBs; //Machine basic block - const TargetMachine &Target; //Target Machine - - //Nodes - std::map GraphMap; - - //Add Nodes and Edges to this graph for our BB - typedef std::pair OpIndexNodePair; - void buildNodesAndEdges(std::map &ignoreInstrs, DependenceAnalyzer &DA, std::map &machineTollvm); - void addValueEdges(std::vector &NodesInMap, - MSchedGraphNode *node, - bool nodeIsUse, bool nodeIsDef, std::vector &phiInstrs, int diff=0); - void addMachRegEdges(std::map >& regNumtoNodeMap); - void addMemEdges(const std::vector& memInst, - DependenceAnalyzer &DA, std::map &machineTollvm); - void addBranchEdges(); - - public: - MSchedGraph(const MachineBasicBlock *bb, const TargetMachine &targ, - std::map &ignoreInstrs, - DependenceAnalyzer &DA, std::map &machineTollvm); - - //Copy constructor with maps to link old nodes to new nodes - MSchedGraph(const MSchedGraph &G, std::map &newNodes); - - MSchedGraph(std::vector &bbs, - const TargetMachine &targ, - std::map &ignoreInstrs, - DependenceAnalyzer &DA, - std::map &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::iterator iterator; - typedef std::map::const_iterator const_iterator; - typedef std::map::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 getBBs() { return BBs; } - }; - - - - - - // Provide specializations of GraphTraits to be able to use graph - // iterators on the scheduling graph - static MSchedGraphNode& getSecond(std::pair &Pair) { - return *Pair.second; - } - - template <> struct GraphTraits { - 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&, MSchedGraphNode&> DerefFun; - - typedef mapped_iterator 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 { - 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&, MSchedGraphNode&> DerefFun; - - typedef mapped_iterator 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 > { - 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&, MSchedGraphNode&> DerefFun; - - typedef mapped_iterator 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 > { - 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&, MSchedGraphNode&> DerefFun; - - typedef mapped_iterator 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 diff --git a/lib/Target/SparcV9/ModuloScheduling/MSchedGraphSB.cpp b/lib/Target/SparcV9/ModuloScheduling/MSchedGraphSB.cpp deleted file mode 100644 index bd879f87786..00000000000 --- a/lib/Target/SparcV9/ModuloScheduling/MSchedGraphSB.cpp +++ /dev/null @@ -1,870 +0,0 @@ -//===-- MSchedGraphSB.cpp - Scheduling Graph ----------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// A graph class for dependencies. This graph only contains true, anti, and -// output data dependencies for a given MachineBasicBlock. Dependencies -// across iterations are also computed. Unless data dependence analysis -// is provided, a conservative approach of adding dependencies between all -// loads and stores is taken. -//===----------------------------------------------------------------------===// - -#define DEBUG_TYPE "ModuloSchedSB" -#include "MSchedGraphSB.h" -#include "../SparcV9RegisterInfo.h" -#include "../MachineCodeForInstruction.h" -#include "llvm/BasicBlock.h" -#include "llvm/Constants.h" -#include "llvm/Instructions.h" -#include "llvm/Type.h" -#include "llvm/CodeGen/MachineBasicBlock.h" -#include "llvm/Target/TargetInstrInfo.h" -#include "llvm/Support/Debug.h" -#include -#include -#include -#include "llvm/Target/TargetSchedInfo.h" -#include "../SparcV9Internals.h" -#include -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 &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::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 &bbs, - const TargetMachine &targ, - std::map &ignoreInstrs, - DependenceAnalyzer &DA, - std::map &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 > liveOutsideTrace; - std::set llvmBBs; - - for(std::vector::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::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(BB->getTerminator()); - - std::vector 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(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(*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 &newNodes) - : Target(G.Target) { - - BBs = G.BBs; - - std::map 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 &ignoreInstrs, - DependenceAnalyzer &DA, - std::map &machineTollvm, - std::map > &liveOutsideTrace) { - - - //Get Machine target information for calculating latency - const TargetInstrInfo *MTI = Target.getInstrInfo(); - - std::vector memInstructions; - std::map > regNumtoNodeMap; - std::map > valuetoNodeMap; - - //Save PHI instructions to deal with later - std::vector phiInstrs; - unsigned index = 0; - - MSchedGraphSBNode *lastPred = 0; - - - for(std::vector::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::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 >::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(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::iterator I = phiInstrs.begin(), - E = phiInstrs.end(); I != E; ++I) { - - //Get Node for this instruction - std::map::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 >::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 &NodesInMap, - MSchedGraphSBNode *destNode, bool nodeIsUse, - bool nodeIsDef, std::vector &phiInstrs, int diff) { - - for(std::vector::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 >& regNumtoNodeMap) { - //Loop over all machine registers in the map, and add dependencies - //between the instructions that use it - typedef std::map > 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 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& memInst, - DependenceAnalyzer &DA, - std::map &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(srcLLVM) - && !isa(srcLLVM)) { - if(isa(srcLLVM)) { - if(isa(srcLLVM->getOperand(0)) || isa(srcLLVM->getOperand(1))) - continue; - } - useDepAnalyzer = false; - } - if(!isa(destLLVM) - && !isa(destLLVM)) { - if(isa(destLLVM)) { - if(isa(destLLVM->getOperand(0)) || isa(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::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); - } - } - } - } -} diff --git a/lib/Target/SparcV9/ModuloScheduling/MSchedGraphSB.h b/lib/Target/SparcV9/ModuloScheduling/MSchedGraphSB.h deleted file mode 100644 index 2e43f7ed6f6..00000000000 --- a/lib/Target/SparcV9/ModuloScheduling/MSchedGraphSB.h +++ /dev/null @@ -1,410 +0,0 @@ -//===-- MSchedGraphSB.h - Scheduling Graph ------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// A graph class for dependencies. This graph only contains true, anti, and -// output data dependencies for a vector of MachineBasicBlock. Dependencies -// across iterations are also computed. Unless data dependence analysis -// is provided, a conservative approach of adding dependencies between all -// loads and stores is taken. It also includes pseudo predicate nodes for -// modulo scheduling superblocks. -//===----------------------------------------------------------------------===// - -#ifndef LLVM_MSCHEDGRAPHSB_H -#define LLVM_MSCHEDGRAPHSB_H -#include "DependenceAnalyzer.h" -#include "llvm/Analysis/AliasAnalysis.h" -#include "llvm/CodeGen/MachineInstr.h" -#include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetData.h" -#include "llvm/ADT/GraphTraits.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/iterator" -#include - - -namespace llvm { - - class MSchedGraphSB; - class MSchedGraphSBNode; - template - 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 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 Predecessors; //Predecessor Nodes - std::vector Successors; //Successor edges - - public: - MSchedGraphSBNode(const MachineInstr* inst, MSchedGraphSB *graph, - unsigned index, unsigned late=0, bool isBranch=false); - MSchedGraphSBNode(const MachineInstr* inst, std::vector &other, - MSchedGraphSB *graph, - unsigned index, unsigned late=0, bool isPNode=true); - MSchedGraphSBNode(const MSchedGraphSBNode &N); - - //Iterators - Predecessor and Succussor - typedef std::vector::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::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::const_iterator, - const MSchedGraphSBNode> succ_const_iterator; - succ_const_iterator succ_begin() const; - succ_const_iterator succ_end() const; - - typedef MSchedGraphSBNodeIterator::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 getOtherInstrs() { return otherInstrs; } - - //Debug support - void print(std::ostream &os) const; - void setParent(MSchedGraphSB *p) { Parent = p; } - }; - - //Node iterator for graph generation - template - class MSchedGraphSBNodeIterator : public forward_iterator { - IteratorType I; // std::vector::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 { - 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 BBs; //Machine basic block - const TargetMachine &Target; //Target Machine - - //Nodes - std::map GraphMap; - - //Add Nodes and Edges to this graph for our BB - typedef std::pair OpIndexNodePair; - void buildNodesAndEdges(std::map &ignoreInstrs, DependenceAnalyzer &DA, std::map &machineTollvm, std::map > &liveOutsideTrace); - void addValueEdges(std::vector &NodesInMap, - MSchedGraphSBNode *node, - bool nodeIsUse, bool nodeIsDef, std::vector &phiInstrs, int diff=0); - void addMachRegEdges(std::map >& regNumtoNodeMap); - void addMemEdges(const std::vector& memInst, - DependenceAnalyzer &DA, std::map &machineTollvm); - - - bool instrCauseException(MachineOpCode opCode); - - public: - MSchedGraphSB(const MachineBasicBlock *bb, const TargetMachine &targ, - std::map &ignoreInstrs, - DependenceAnalyzer &DA, std::map &machineTollvm); - - //Copy constructor with maps to link old nodes to new nodes - MSchedGraphSB(const MSchedGraphSB &G, std::map &newNodes); - - MSchedGraphSB(std::vector &bbs, - const TargetMachine &targ, - std::map &ignoreInstrs, - DependenceAnalyzer &DA, - std::map &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::iterator iterator; - typedef std::map::const_iterator const_iterator; - typedef std::map::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 getBBs() { return BBs; } - }; - - - - - - // Provide specializations of GraphTraits to be able to use graph - // iterators on the scheduling graph - static MSchedGraphSBNode& getSecond(std::pair &Pair) { - return *Pair.second; - } - - template <> struct GraphTraits { - 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&, MSchedGraphSBNode&> DerefFun; - - typedef mapped_iterator 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 { - 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&, MSchedGraphSBNode&> DerefFun; - - typedef mapped_iterator 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 > { - 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&, MSchedGraphSBNode&> DerefFun; - - typedef mapped_iterator 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 > { - 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&, MSchedGraphSBNode&> DerefFun; - - typedef mapped_iterator 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 diff --git a/lib/Target/SparcV9/ModuloScheduling/Makefile b/lib/Target/SparcV9/ModuloScheduling/Makefile deleted file mode 100644 index 2ec0503a173..00000000000 --- a/lib/Target/SparcV9/ModuloScheduling/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -##===- lib/Target/SparcV9/ModuloScheduling/Makefile --------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file was developed by the LLVM research group and is distributed under -# the University of Illinois Open Source License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## - -LEVEL = ../../../.. -DIRS = -LIBRARYNAME = LLVMSparcV9ModuloSched - -include $(LEVEL)/Makefile.common diff --git a/lib/Target/SparcV9/ModuloScheduling/ModuloScheduling.cpp b/lib/Target/SparcV9/ModuloScheduling/ModuloScheduling.cpp deleted file mode 100644 index a5e9661f1cd..00000000000 --- a/lib/Target/SparcV9/ModuloScheduling/ModuloScheduling.cpp +++ /dev/null @@ -1,2964 +0,0 @@ -//===-- 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 -#include -#include -#include -#include -#include -#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 -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 : 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 - -/// 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(); - - - //Worklist - std::vector 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::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::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::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 >::iterator I = partialOrder.begin(), - E = partialOrder.end(); I !=E; ++I) { - std::cerr << "Start set in PO\n"; - for(std::set::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::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(V) && !isa(V) && !isa(V) && !isa(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(((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 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(((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 indVar; - std::vector stack; - - BasicBlock *BB = (BasicBlock*) BI->getBasicBlock(); - - //Add branch - indVar.insert(b); - - if(Instruction *I = dyn_cast(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::iterator N = indVar.begin(), NE = indVar.end(); N != NE; ++N) { - std::cerr << **N << "\n"; - }); - - //Create map of machine instr to llvm instr - std::map 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 mIndVar; - for(std::set::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(*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 &indVar, - std::vector &stack, BasicBlock *BB) { - - stack.push_back(I); - - //If this is a phi node, check if its the canonical indvar - if(PHINode *PN = dyn_cast(I)) { - if (Instruction *Inc = - dyn_cast(PN->getIncomingValueForBlock(BB))) - if (Inc->getOpcode() == Instruction::Add && Inc->getOperand(0) == PN) - if (ConstantInt *CI = dyn_cast(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(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 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 > 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::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 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 > >::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 visitedNodes; - - //Now Loop over map and calculate the node attributes - for(std::map::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::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::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::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 &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 > >::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::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 &blocked, - std::map > &B) { - - //Unblock u - DEBUG(std::cerr << "Unblocking: " << *u << "\n"); - blocked.erase(u); - - //std::set 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 &stack, - std::set &blocked, std::vector &SCC, - MSchedGraphNode *s, std::map > &B, - int II, std::map &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 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::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::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 &stack, std::map &newNodes) { - std::vector 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::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 &SCC, std::map &newNodes) { - - int totalDelay = 0; - int totalDistance = 0; - std::vector recc; - MSchedGraphNode *start = 0; - MSchedGraphNode *end = 0; - - //Loop over recurrence, get delay and distance - for(std::vector::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 newNodes; - - //copy the graph - MSchedGraph *MSG = new MSchedGraph(*g, newNodes); - - DEBUG(std::cerr << "Finding All Circuits\n"); - - //Set of blocked nodes - std::set blocked; - - //Stack holding current circuit - std::vector stack; - - //Map for B Lists - std::map > 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 Visited; - std::vector 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 SCCI = scc_begin(GI->second), - E = scc_end(GI->second); SCCI != E; ++SCCI) { - std::vector &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::iterator N = Vk.begin(), NE = Vk.end(); - N != NE; ++N) { std::cerr << *((*N)->getInst()); }); - - //Iterate over all nodes in this scc - for(std::vector::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 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::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 &visitedNodes, - int II) { - - - if(std::find(visitedNodes.begin(), visitedNodes.end(), node) != visitedNodes.end()) { - std::vector 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::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 &path, - std::set &nodesToAdd, - std::set &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 >::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 &path, - std::set &poSet, - std::set &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::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 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 > >::reverse_iterator - I = recurrenceList.rbegin(), E=recurrenceList.rend(); I !=E; ++I) { - - std::set new_recurrence; - - //Loop through recurrence and remove any nodes already in the partial order - for(std::vector::const_iterator N = I->second.begin(), - NE = I->second.end(); N != NE; ++N) { - - bool found = false; - for(std::vector >::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 path; - std::set nodesToAdd; - - //Dump recc we are dealing with (minus nodes already in PO) - DEBUG(std::cerr << "Recc: "); - DEBUG(for(std::set::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::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::iterator N = nodesToAdd.begin(), NE = nodesToAdd.end(); - N != NE; ++N) { - bool found = false; - for(std::vector >::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 >::iterator I = partialOrder.begin(), - E = partialOrder.end(); I !=E; ++I) { - std::cerr << "Start set in PO\n"; - for(std::set::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 lastNodes; - std::set noPredNodes; - for(std::map::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 >::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::iterator N = noPredNodes.begin(), NE = noPredNodes.end(); - N != NE; ++N) { - DEBUG(std::cerr << "No Pred Path from: " << **N << "\n"); - for(std::vector >::iterator PO = partialOrder.begin(), - PE = partialOrder.end(); PO != PE; ++PO) { - std::vector 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 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 &ccSet, std::set &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 &CurrentSet, std::set &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 &CurrentSet, std::set &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 &IntersectCurrent) { - std::cerr << "Intersection ("; - for(std::set::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 >::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 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::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::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::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 > ::reverse_iterator LastSet = partialOrder.rbegin(); - for(std::set::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 branches; - - //Loop over the final node order and process each node - for(std::vector::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::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::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 &prologues, MachineBasicBlock *origBB, std::vector &llvm_prologues, std::map > &valuesToSave, std::map > &newValues, std::map &newValLocation) { - - //Keep a map to easily know whats in the kernel - std::map > inKernel; - int maxStageCount = 0; - - //Keep a map of new values we consumed in case they need to be added back - std::map > consumedValues; - - MSchedGraphNode *branch = 0; - MSchedGraphNode *BAbranch = 0; - - DEBUG(schedule.print(std::cerr)); - - std::vector 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 &epilogues, const MachineBasicBlock *origBB, std::vector &llvm_epilogues, std::map > &valuesToSave, std::map > &newValues,std::map &newValLocation, std::map > &kernelPHIs ) { - - std::map > 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 valPHIs; - - //some debug stuff, will remove later - DEBUG(for(std::map >::iterator V = newValues.begin(), E = newValues.end(); V !=E; ++V) { - std::cerr << "Old Value: " << *(V->first) << "\n"; - for(std::map::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 >::iterator V = kernelPHIs.begin(), E = kernelPHIs.end(); V !=E; ++V) { - std::cerr << "Old Value: " << *(V->first) << "\n"; - for(std::map::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 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 > &valuesToSave, std::map > &newValues, std::map &newValLocation, std::map > &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 finalPHIValue; - std::map kernelValue; - - //Branches are a special case - std::vector 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::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 >::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::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::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 &prologues, std::vector &epilogues, MachineBasicBlock *kernelBB, std::map &newValLocation) { - - //Worklist to delete things - std::vector > worklist; - - //Worklist of TmpInstructions that need to be added to a MCFI - std::vector addToMCFI; - - //Worklist to add OR instructions to end of kernel so not to invalidate the iterator - //std::vector > 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::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 >::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 > 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 lastInstrs; - std::map 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(srcI) || isa(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(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(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 > newValues; - - //Map to keep track of old to new values in kernel - std::map > 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 newValLocation; - - std::vector prologues; - std::vector 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::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 epilogues; - std::vector 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::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::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 &prologues, std::vector &llvm_prologues, MachineBasicBlock *machineKernelBB, BasicBlock *llvmKernelBB, std::vector &epilogues, std::vector &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(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(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(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(BB->getBasicBlock()->getTerminator()); - //Find where we are supposed to branch to - BasicBlock *nextBlock = 0; - for(unsigned j=0; j 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::vectorPreds (pred_begin(llvmBB), pred_end(llvmBB)); - - //for(pred_const_iterator P = pred_begin(llvmBB), PE = pred_end(llvmBB); P != PE; ++PE) { - for(std::vector::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); - -} - diff --git a/lib/Target/SparcV9/ModuloScheduling/ModuloScheduling.h b/lib/Target/SparcV9/ModuloScheduling/ModuloScheduling.h deleted file mode 100644 index 840623e02d7..00000000000 --- a/lib/Target/SparcV9/ModuloScheduling/ModuloScheduling.h +++ /dev/null @@ -1,171 +0,0 @@ -//===-- ModuloScheduling.h - Swing Modulo Scheduling------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_MODULOSCHEDULING_H -#define LLVM_MODULOSCHEDULING_H - -#include "MSchedGraph.h" -#include "MSSchedule.h" -#include "llvm/Function.h" -#include "llvm/Pass.h" -#include "DependenceAnalyzer.h" -#include "llvm/Target/TargetData.h" -#include "llvm/Analysis/LoopInfo.h" -#include "llvm/Analysis/ScalarEvolution.h" -#include - -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 defMap; - - //Map to hold list of instructions associate to the induction var for each BB - std::map > indVarInstrs; - - //Map to hold machine to llvm instrs for each valid BB - std::map > machineTollvm; - - //LLVM Instruction we know we can add TmpInstructions to its MCFI - Instruction *defaultInst; - - //Map that holds node to node attribute information - std::map nodeToAttributesMap; - - //Map to hold all reccurrences - std::set > > recurrenceList; - - //Set of edges to ignore, stored as src node and index into vector of successors - std::set > edgesToIgnore; - - //Vector containing the partial order - std::vector > partialOrder; - - //Vector containing the final node order - std::vector 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 &indVar, - std::vector &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 &visitedNodes, int II); - void addReccurrence(std::vector &recurrence, int II, MSchedGraphNode*, MSchedGraphNode*); - void addSCC(std::vector &SCC, std::map &newNodes); - - void findAllCircuits(MSchedGraph *MSG, int II); - bool circuit(MSchedGraphNode *v, std::vector &stack, - std::set &blocked, - std::vector &SCC, MSchedGraphNode *s, - std::map > &B, int II, - std::map &newNodes); - - void unblock(MSchedGraphNode *u, std::set &blocked, - std::map > &B); - - void addRecc(std::vector &stack, std::map &newNodes); - - void searchPath(MSchedGraphNode *node, - std::vector &path, - std::set &nodesToAdd, - std::set &new_reccurence); - - void pathToRecc(MSchedGraphNode *node, - std::vector &path, - std::set &poSet, std::set &lastNodes); - - void computePartialOrder(); - - bool computeSchedule(const MachineBasicBlock *BB, MSchedGraph *MSG); - bool scheduleNode(MSchedGraphNode *node, - int start, int end); - - void predIntersect(std::set &CurrentSet, std::set &IntersectResult); - void succIntersect(std::set &CurrentSet, std::set &IntersectResult); - - void reconstructLoop(MachineBasicBlock*); - - //void saveValue(const MachineInstr*, const std::set&, std::vector*); - - void fixBranches(std::vector &prologues, std::vector &llvm_prologues, MachineBasicBlock *machineBB, BasicBlock *llvmBB, std::vector &epilogues, std::vector &llvm_epilogues, MachineBasicBlock*); - - void writePrologues(std::vector &prologues, MachineBasicBlock *origBB, std::vector &llvm_prologues, std::map > &valuesToSave, std::map > &newValues, std::map &newValLocation); - - void writeEpilogues(std::vector &epilogues, const MachineBasicBlock *origBB, std::vector &llvm_epilogues, std::map > &valuesToSave,std::map > &newValues, std::map &newValLocation, std::map > &kernelPHIs); - - - void writeKernel(BasicBlock *llvmBB, MachineBasicBlock *machineBB, std::map > &valuesToSave, std::map > &newValues, std::map &newValLocation, std::map > &kernelPHIs); - - void removePHIs(const MachineBasicBlock* SB, std::vector &prologues, std::vector &epilogues, MachineBasicBlock *kernelBB, std::map &newValLocation); - - void connectedComponentSet(MSchedGraphNode *node, std::set &ccSet, std::set &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(); - AU.addRequired(); - - AU.addRequired(); - } - - }; - -} - - -#endif diff --git a/lib/Target/SparcV9/ModuloScheduling/ModuloSchedulingSuperBlock.cpp b/lib/Target/SparcV9/ModuloScheduling/ModuloSchedulingSuperBlock.cpp deleted file mode 100644 index 8b3185155e1..00000000000 --- a/lib/Target/SparcV9/ModuloScheduling/ModuloSchedulingSuperBlock.cpp +++ /dev/null @@ -1,3155 +0,0 @@ -//===-- 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 -#include -#include -#include - -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 -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 : 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(); - DependenceAnalyzer &DA = getAnalysis(); - - //Worklist of superblocks - std::vector > 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 >::iterator SB = Worklist.begin(), - SBE = Worklist.end(); SB != SBE; ++SB) { - - //Print out Superblock - DEBUG(std::cerr << "ModuloScheduling SB: \n"; - for(std::vector::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::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 >::iterator I = partialOrder.begin(), - E = partialOrder.end(); I !=E; ++I) { - std::cerr << "Start set in PO\n"; - for(std::set::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::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 > &Worklist) { - - //Get MachineFunction - MachineFunction &MF = MachineFunction::get(&F); - - //Map of LLVM BB to machine BB - std::map 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 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 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::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 &superBlock, std::map &bbMap, - std::map &indexMap) { - //See if we can get induction var instructions - std::set 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(((BasicBlock*) (superBlock[superBlock.size()-1])->getBasicBlock())->getTerminator()); - std::set 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 stack; - - //Add branch - indVar.insert(b); - - if(Instruction *I = dyn_cast(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::iterator N = indVar.begin(), NE = indVar.end(); - N != NE; ++N) { - std::cerr << **N << "\n"; - }); - - //Create map of machine instr to llvm instr - std::map mllvm; - for(std::vector::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 mIndVar; - for(std::set::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(*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 &indVar, - std::vector &stack, - std::map &bbMap, - const BasicBlock *last, std::set &llvmSuperBlock) { - - stack.push_back(I); - - //If this is a phi node, check if its the canonical indvar - if(PHINode *PN = dyn_cast(I)) { - if(llvmSuperBlock.count(PN->getParent())) { - if (Instruction *Inc = - dyn_cast(PN->getIncomingValueForBlock(last))) - if (Inc->getOpcode() == Instruction::Add && Inc->getOperand(0) == PN) - if (ConstantInt *CI = dyn_cast(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(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 &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 &SB) { - defaultInst = 0; - - for(std::vector::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(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(V) && !isa(V) && !isa(V) && !isa(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 &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 resourceUsageCount; - - for(std::vector::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 > 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::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 > >::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 &blocked, - std::map > &B) { - - //Unblock u - DEBUG(std::cerr << "Unblocking: " << *u << "\n"); - blocked.erase(u); - - //std::set 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 &SCC, std::map &newNodes) { - - int totalDelay = 0; - int totalDistance = 0; - std::vector recc; - MSchedGraphSBNode *start = 0; - MSchedGraphSBNode *end = 0; - - //Loop over recurrence, get delay and distance - for(std::vector::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 &stack, - std::set &blocked, std::vector &SCC, - MSchedGraphSBNode *s, std::map > &B, - int II, std::map &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 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::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::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 &stack, std::map &newNodes) { - std::vector 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::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 newNodes; - - //copy the graph - MSchedGraphSB *MSG = new MSchedGraphSB(*g, newNodes); - - DEBUG(std::cerr << "Finding All Circuits\n"); - - //Set of blocked nodes - std::set blocked; - - //Stack holding current circuit - std::vector stack; - - //Map for B Lists - std::map > 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 Visited; - std::vector 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 SCCI = scc_begin(GI->second), - E = scc_end(GI->second); SCCI != E; ++SCCI) { - std::vector &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::iterator N = Vk.begin(), NE = Vk.end(); - N != NE; ++N) { std::cerr << *((*N)->getInst()); }); - - //Iterate over all nodes in this scc - for(std::vector::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 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::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 visitedNodes; - - //Now Loop over map and calculate the node attributes - for(std::map::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::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::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::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 > >::reverse_iterator - I = recurrenceList.rbegin(), E=recurrenceList.rend(); I !=E; ++I) { - - std::set new_recurrence; - - //Loop through recurrence and remove any nodes already in the partial order - for(std::vector::const_iterator N = I->second.begin(), - NE = I->second.end(); N != NE; ++N) { - - bool found = false; - for(std::vector >::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 path; - std::set nodesToAdd; - - //Dump recc we are dealing with (minus nodes already in PO) - DEBUG(std::cerr << "Recc: "); - DEBUG(for(std::set::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::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::iterator N = nodesToAdd.begin(), NE = nodesToAdd.end(); - N != NE; ++N) { - bool found = false; - for(std::vector >::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 lastNodes; - std::set noPredNodes; - for(std::map::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 >::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::iterator N = noPredNodes.begin(), NE = noPredNodes.end(); - N != NE; ++N) { - DEBUG(std::cerr << "No Pred Path from: " << **N << "\n"); - for(std::vector >::iterator PO = partialOrder.begin(), - PE = partialOrder.end(); PO != PE; ++PO) { - std::vector 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 ccSet; - connectedComponentSet(*(lastNodes.begin()),ccSet, lastNodes); - if(ccSet.size() > 0) - partialOrder.push_back(ccSet); - } - -} - -void ModuloSchedulingSBPass::connectedComponentSet(MSchedGraphSBNode *node, std::set &ccSet, std::set &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 &path, - std::set &nodesToAdd, - std::set &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 >::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 &IntersectCurrent) { - std::cerr << "Intersection ("; - for(std::set::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 >::iterator CurrentSet = partialOrder.begin(), E= partialOrder.end(); CurrentSet != E; ++CurrentSet) { - for(std::set::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 >::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 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::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::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::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 > ::reverse_iterator LastSet = partialOrder.rbegin(); - for(std::set::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 &CurrentSet, std::set &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 &CurrentSet, std::set &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 &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 branches; - - //Loop over the final node order and process each node - for(std::vector::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::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 &SB) { - - TIME_REGION(X, "reconstructLoop"); - - - DEBUG(std::cerr << "Reconstructing Loop\n"); - - //First find the value *'s that we need to "save" - std::map > 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 lastInstrs; - - - std::set seenBranchesBB; - const TargetInstrInfo *MTI = target.getInstrInfo(); - std::map > > instrsMovedDown; - std::map 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(srcI) || isa(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 > newValues; - - //Map to keep track of old to new values in kernel - std::map > 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 newValLocation; - - std::vector > prologues; - std::vector > llvm_prologues; - - //Map to keep track of where the inner branches go - std::map sideExits; - - - //Write prologue - if(schedule.getMaxStage() != 0) - writePrologues(prologues, SB, llvm_prologues, valuesToSave, newValues, newValLocation); - - std::vector llvmKernelBBs; - std::vector 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 > epilogues; - std::vector > 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 >::iterator PI = prologues.begin(), PE = prologues.end(); - PI != PE; ++PI) { - std::cerr << "PROLOGUE\n"; - for(std::vector::iterator I = PI->begin(), E = PI->end(); I != E; ++I) - (*I)->print(std::cerr); - }); - - DEBUG(std::cerr << "KERNEL\n"); - DEBUG(for(std::vector::iterator I = machineKernelBBs.begin(), E = machineKernelBBs.end(); I != E; ++I) { (*I)->print(std::cerr);}); - - DEBUG(for(std::vector >::iterator EI = epilogues.begin(), EE = epilogues.end(); - EI != EE; ++EI) { - std::cerr << "EPILOGUE\n"; - for(std::vector::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 >::iterator PI = prologues.begin(), PE = prologues.end(); - PI != PE; ++PI) { - std::cerr << "PROLOGUE\n"; - for(std::vector::iterator I = PI->begin(), E = PI->end(); I != E; ++I) - (*I)->print(std::cerr); - }); - - DEBUG(std::cerr << "KERNEL\n"); - DEBUG(for(std::vector::iterator I = machineKernelBBs.begin(), E = machineKernelBBs.end(); I != E; ++I) { (*I)->print(std::cerr);}); - - DEBUG(for(std::vector >::iterator EI = epilogues.begin(), EE = epilogues.end(); - EI != EE; ++EI) { - std::cerr << "EPILOGUE\n"; - for(std::vector::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 > &prologues, std::vector > &llvm_prologues, std::vector &machineKernelBB, std::vector &llvmKernelBB, std::vector > &epilogues, std::vector > &llvm_epilogues, std::vector &SB, std::map &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(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(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(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::vectorPreds (pred_begin(llvmBB), pred_end(llvmBB)); - - for(std::vector::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 > &prologues, std::vector &origSB, std::vector > &llvm_prologues, std::map > &valuesToSave, std::map > &newValues, std::map &newValLocation) { - - //Keep a map to easily know whats in the kernel - std::map > inKernel; - int maxStageCount = 0; - - //Keep a map of new values we consumed in case they need to be added back - std::map > 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 current_prologue; - std::vector current_llvm_prologue; - - for(std::vector::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 > &epilogues, std::vector &origSB, std::vector > &llvm_epilogues, std::map > &valuesToSave, std::map > &newValues,std::map &newValLocation, std::map > &kernelPHIs ) { - - std::map > 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 valPHIs; - - //some debug stuff, will remove later - DEBUG(for(std::map >::iterator V = newValues.begin(), E = newValues.end(); V !=E; ++V) { - std::cerr << "Old Value: " << *(V->first) << "\n"; - for(std::map::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 current_epilogue; - std::vector current_llvm_epilogue; - - for(std::vector::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 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::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 &llvmBB, std::vector &machineBB, std::map > &valuesToSave, std::map > &newValues, std::map &newValLocation, std::map > &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 finalPHIValue; - std::map kernelValue; - - //Branches are a special case - std::vector 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 >::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::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::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 &SB, std::vector > &prologues, std::vector > &epilogues, std::vector &kernelBB, std::map &newValLocation) { - - //Worklist to delete things - std::vector > worklist; - - //Worklist of TmpInstructions that need to be added to a MCFI - std::vector addToMCFI; - - //Worklist to add OR instructions to end of kernel so not to invalidate the iterator - //std::vector > 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 >::iterator MB = epilogues.begin(), - ME = epilogues.end(); MB != ME; ++MB) { - - for(std::vector::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 >::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 > &prologues, std::vector > &llvm_prologues, std::vector > &epilogues, std::vector > &llvm_epilogues, std::map &sideExits, std::map > > &instrsMovedDown, std::vector &SB, std::vector &kernelMBBs, std::map branchStage) { - - const TargetInstrInfo *TMI = target.getInstrInfo(); - - //Repeat for each side exit - for(unsigned sideExitNum = 0; sideExitNum < SB.size()-1; ++sideExitNum) { - - std::vector > side_llvm_epilogues; - std::vector > 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 >::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(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 MB = epilogues[i]; - - std::vector newEp; - std::vector newLLVMEp; - - for(std::vector::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); - } - } - } -} - diff --git a/lib/Target/SparcV9/ModuloScheduling/ModuloSchedulingSuperBlock.h b/lib/Target/SparcV9/ModuloScheduling/ModuloSchedulingSuperBlock.h deleted file mode 100644 index 669611e9261..00000000000 --- a/lib/Target/SparcV9/ModuloScheduling/ModuloSchedulingSuperBlock.h +++ /dev/null @@ -1,192 +0,0 @@ -//===-- ModuloSchedulingSuperBlock.h -Swing Modulo Scheduling-----*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -//Swing Modulo Scheduling done on Superblocks ( entry, multiple exit, -//multiple basic block loops). -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_MODULOSCHEDULINGSB_H -#define LLVM_MODULOSCHEDULINGSB_H - -#include "llvm/Analysis/LoopInfo.h" -#include "llvm/Analysis/ScalarEvolution.h" -#include "llvm/Function.h" -#include "llvm/Pass.h" -#include "llvm/CodeGen/MachineBasicBlock.h" -#include "MSScheduleSB.h" -#include "MSchedGraphSB.h" - - -namespace llvm { - - //Struct to contain ModuloScheduling Specific Information for each node - struct MSNodeSBAttributes { - int ASAP; //Earliest time at which the opreation can be scheduled - int ALAP; //Latest time at which the operation can be scheduled. - int MOB; - int depth; - int height; - MSNodeSBAttributes(int asap=-1, int alap=-1, int mob=-1, - int d=-1, int h=-1) : ASAP(asap), ALAP(alap), - MOB(mob), depth(d), - height(h) {} - }; - - - typedef std::vector SuperBlock; - - class ModuloSchedulingSBPass : public FunctionPass { - const TargetMachine ⌖ - - //Map to hold Value* defs - std::map defMap; - - //Map to hold list of instructions associate to the induction var for each BB - std::map > indVarInstrs; - - //Map to hold machine to llvm instrs for each valid BB - std::map > machineTollvm; - - //LLVM Instruction we know we can add TmpInstructions to its MCFI - Instruction *defaultInst; - - //Map that holds node to node attribute information - std::map nodeToAttributesMap; - - //Map to hold all reccurrences - std::set > > recurrenceList; - - //Set of edges to ignore, stored as src node and index into vector of successors - std::set > edgesToIgnore; - - //Vector containing the partial order - std::vector > partialOrder; - - //Vector containing the final node order - std::vector 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 > &Worklist); - bool MachineBBisValid(const MachineBasicBlock *B, - std::map &indexMap, - unsigned &offset); - bool CreateDefMap(std::vector &SB); - bool getIndVar(std::vector &superBlock, - std::map &bbMap, - std::map &indexMap); - bool assocIndVar(Instruction *I, std::set &indVar, - std::vector &stack, - std::map &bbMap, - const BasicBlock *first, - std::set &llvmSuperBlock); - int calculateResMII(std::vector &superBlock); - int calculateRecMII(MSchedGraphSB *graph, int MII); - void findAllCircuits(MSchedGraphSB *g, int II); - void addRecc(std::vector &stack, - std::map &newNodes); - bool circuit(MSchedGraphSBNode *v, std::vector &stack, - std::set &blocked, std::vector &SCC, - MSchedGraphSBNode *s, std::map > &B, - int II, std::map &newNodes); - void unblock(MSchedGraphSBNode *u, std::set &blocked, - std::map > &B); - void addSCC(std::vector &SCC, std::map &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 &ccSet, - std::set &lastNodes); - void searchPath(MSchedGraphSBNode *node, - std::vector &path, - std::set &nodesToAdd, - std::set &new_reccurrence); - void orderNodes(); - bool computeSchedule(std::vector &BB, MSchedGraphSB *MSG); - bool scheduleNode(MSchedGraphSBNode *node, int start, int end); - void predIntersect(std::set &CurrentSet, std::set &IntersectResult); - void succIntersect(std::set &CurrentSet, std::set &IntersectResult); - void reconstructLoop(std::vector &SB); - void fixBranches(std::vector > &prologues, - std::vector > &llvm_prologues, - std::vector &machineKernelBB, - std::vector &llvmKernelBB, - std::vector > &epilogues, - std::vector > &llvm_epilogues, - std::vector &SB, - std::map &sideExits); - - void writePrologues(std::vector > &prologues, - std::vector &origBB, - std::vector > &llvm_prologues, - std::map > &valuesToSave, - std::map > &newValues, - std::map &newValLocation); - - void writeKernel(std::vector &llvmBB, std::vector &machineBB, - std::map > &valuesToSave, - std::map > &newValues, - std::map &newValLocation, - std::map > &kernelPHIs); - - void removePHIs(std::vector &SB, - std::vector > &prologues, - std::vector > &epilogues, - std::vector &kernelBB, - std::map &newValLocation); - - void writeEpilogues(std::vector > &epilogues, - std::vector &origSB, - std::vector > &llvm_epilogues, - std::map > &valuesToSave, - std::map > &newValues, - std::map &newValLocation, - std::map > &kernelPHIs); - - void writeSideExits(std::vector > &prologues, - std::vector > &llvm_prologues, - std::vector > &epilogues, - std::vector > &llvm_epilogues, - std::map &sideExits, - std::map > > &instrsMovedDown, - std::vector &SB, - std::vector &kernelMBBs, - std::map 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(); - AU.addRequired(); - AU.addRequired(); - } - }; -} -#endif diff --git a/lib/Target/SparcV9/RegAlloc/AllocInfo.h b/lib/Target/SparcV9/RegAlloc/AllocInfo.h deleted file mode 100644 index da1d3c4a661..00000000000 --- a/lib/Target/SparcV9/RegAlloc/AllocInfo.h +++ /dev/null @@ -1,95 +0,0 @@ -//===-- AllocInfo.h - Store info about regalloc decisions -------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This header file contains the data structure used to save the state -// of the global, graph-coloring register allocator. -// -//===----------------------------------------------------------------------===// - -#ifndef ALLOCINFO_H -#define ALLOCINFO_H - -#include "llvm/Type.h" -#include "llvm/DerivedTypes.h" -#include "llvm/Constants.h" - -namespace llvm { - -/// AllocInfo - Structure representing one instruction's operand's-worth of -/// register allocation state. We create tables made out of these data -/// structures to generate mapping information for this register allocator. -/// -struct AllocInfo { - int Instruction; // (-1 if Argument, or 0 .. n - 1 for an instruction). - int Operand; // (-1 if Instruction, or 0 .. n-1 for an operand). - enum AllocStateTy { NotAllocated = 0, Allocated, Spilled }; - AllocStateTy AllocState; - int Placement; - - AllocInfo (int Inst_, int Op_, AllocStateTy State_, int Place_) : - Instruction(Inst_), Operand(Op_), AllocState(State_), Placement(Place_) { } - - /// AllocInfo constructor -- Default constructor creates an invalid AllocInfo - /// (presumably to be replaced with something meaningful later). - /// - AllocInfo () : - Instruction(-1), Operand(-1), AllocState(NotAllocated), Placement(-1) { } - - /// getConstantType - Return a StructType representing an AllocInfo object. - /// - static StructType *getConstantType () { - std::vector 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 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 diff --git a/lib/Target/SparcV9/RegAlloc/IGNode.cpp b/lib/Target/SparcV9/RegAlloc/IGNode.cpp deleted file mode 100644 index 5b67fa34cfe..00000000000 --- a/lib/Target/SparcV9/RegAlloc/IGNode.cpp +++ /dev/null @@ -1,62 +0,0 @@ -//===-- IGNode.cpp --------------------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements an Interference graph node for coloring-based register -// allocation. -// -//===----------------------------------------------------------------------===// - -#include "IGNode.h" -#include -#include - -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::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 nbrs(AdjList); - nbrs.insert(nbrs.end(), otherNode->AdjList.begin(), otherNode->AdjList.end()); - sort(nbrs.begin(), nbrs.end()); - std::vector::iterator new_end = unique(nbrs.begin(), nbrs.end()); - return new_end - nbrs.begin(); -} - -} // End llvm namespace diff --git a/lib/Target/SparcV9/RegAlloc/IGNode.h b/lib/Target/SparcV9/RegAlloc/IGNode.h deleted file mode 100644 index 4399ca6b3b1..00000000000 --- a/lib/Target/SparcV9/RegAlloc/IGNode.h +++ /dev/null @@ -1,123 +0,0 @@ -//===-- IGNode.h - Represent a node in an interference graph ----*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file represents a node in an interference graph. -// -// For efficiency, the AdjList is updated only once - ie. we can add but not -// remove nodes from AdjList. -// -// The removal of nodes from IG is simulated by decrementing the CurDegree. -// If this node is put on stack (that is removed from IG), the CurDegree of all -// the neighbors are decremented and this node is marked OnStack. Hence -// the effective neighbors in the AdjList are the ones that do not have the -// OnStack flag set (therefore, they are in the IG). -// -// The methods that modify/use the CurDegree must be called only -// after all modifications to the IG are over (i.e., all neighbors are fixed). -// -// The vector representation is the most efficient one for adj list. -// Though nodes are removed when coalescing is done, we access it in sequence -// for far many times when coloring (colorNode()). -// -//===----------------------------------------------------------------------===// - -#ifndef IGNODE_H -#define IGNODE_H - -#include "LiveRange.h" -#include - -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 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 diff --git a/lib/Target/SparcV9/RegAlloc/InterferenceGraph.cpp b/lib/Target/SparcV9/RegAlloc/InterferenceGraph.cpp deleted file mode 100644 index 4b5bffce03f..00000000000 --- a/lib/Target/SparcV9/RegAlloc/InterferenceGraph.cpp +++ /dev/null @@ -1,248 +0,0 @@ -//===-- InterferenceGraph.cpp ---------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Interference graph for coloring-based register allocation for LLVM. -// -//===----------------------------------------------------------------------===// - -#include "IGNode.h" -#include "InterferenceGraph.h" -#include "RegAllocCommon.h" -#include "llvm/ADT/STLExtras.h" -#include -#include - -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); -} - - - -//----------------------------------------------------------------------------- -// 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 diff --git a/lib/Target/SparcV9/RegAlloc/InterferenceGraph.h b/lib/Target/SparcV9/RegAlloc/InterferenceGraph.h deleted file mode 100644 index 1a85d6f4efd..00000000000 --- a/lib/Target/SparcV9/RegAlloc/InterferenceGraph.h +++ /dev/null @@ -1,75 +0,0 @@ -//===-- InterferenceGraph.h - Interference graph for register coloring -*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -/* Title: InterferenceGraph.h -*- C++ -*- - Author: Ruchira Sasanka - Date: July 20, 01 - Purpose: Interference Graph used for register coloring. - - Notes: - Adj Info is stored in the lower trangular matrix (i.e., row > col ) - - This class must be used in the following way: - - * Construct class - * call addLRToIG as many times to add ALL LRs to this IG - * call createGraph to create the actual matrix - * Then setInterference, getInterference, mergeIGNodesOfLRs can be - called as desired to modify the graph. - * Once the modifications to the graph are over, call - setCurDegreeOfIGNodes() before pushing IGNodes on to stack for coloring. -*/ - -#ifndef INTERFERENCEGRAPH_H -#define INTERFERENCEGRAPH_H - -#include - -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 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 &getIGNodeList() { return IGNodeList; } - const std::vector &getIGNodeList() const { return IGNodeList; } - - void setCurDegreeOfIGNodes(); - - void printIG() const; - void printIGNodeList() const; -}; - -} // End llvm namespace - -#endif diff --git a/lib/Target/SparcV9/RegAlloc/LiveRange.h b/lib/Target/SparcV9/RegAlloc/LiveRange.h deleted file mode 100644 index 0eecb87da70..00000000000 --- a/lib/Target/SparcV9/RegAlloc/LiveRange.h +++ /dev/null @@ -1,195 +0,0 @@ -//===-- LiveRange.h - Store info about a live range -------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Implements a live range using a SetVector of Value *s. We keep only -// defs in a V9LiveRange. -// -//===----------------------------------------------------------------------===// - -#ifndef LIVERANGE_H -#define LIVERANGE_H - -#include "llvm/Value.h" -#include "llvm/ADT/SetVector.h" -#include - -namespace llvm { - -class RegClass; -class IGNode; - -class V9LiveRange { -public: - typedef SetVector 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 diff --git a/lib/Target/SparcV9/RegAlloc/LiveRangeInfo.cpp b/lib/Target/SparcV9/RegAlloc/LiveRangeInfo.cpp deleted file mode 100644 index 59dd83db363..00000000000 --- a/lib/Target/SparcV9/RegAlloc/LiveRangeInfo.cpp +++ /dev/null @@ -1,415 +0,0 @@ -//===-- LiveRangeInfo.cpp -------------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Live range construction for coloring-based register allocation for LLVM. -// -//===----------------------------------------------------------------------===// - -#include "IGNode.h" -#include "LiveRangeInfo.h" -#include "RegAllocCommon.h" -#include "RegClass.h" -#include "llvm/Function.h" -#include "llvm/Type.h" -#include "llvm/CodeGen/MachineInstr.h" -#include "llvm/CodeGen/MachineFunction.h" -#include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetInstrInfo.h" -#include "../SparcV9RegInfo.h" -#include "llvm/ADT/SetOperations.h" -#include - -namespace llvm { - -unsigned V9LiveRange::getRegClassID() const { return getRegClass()->getID(); } - -LiveRangeInfo::LiveRangeInfo(const Function *F, const TargetMachine &tm, - std::vector &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::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(*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# " << ""; - std::cerr << "\t:Values = " << *HMI->second << "\n"; - } - } -} - -} // End llvm namespace diff --git a/lib/Target/SparcV9/RegAlloc/LiveRangeInfo.h b/lib/Target/SparcV9/RegAlloc/LiveRangeInfo.h deleted file mode 100644 index 0463f51760b..00000000000 --- a/lib/Target/SparcV9/RegAlloc/LiveRangeInfo.h +++ /dev/null @@ -1,121 +0,0 @@ -//===-- LiveRangeInfo.h - Track all LiveRanges for a Function ----*- C++ -*-==// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file contains the class LiveRangeInfo which constructs and keeps -// the LiveRangeMap which contains all the live ranges used in a method. -// -// Assumptions: -// -// All variables (llvm Values) are defined before they are used. However, a -// constant may not be defined in the machine instruction stream if it can be -// used as an immediate value within a machine instruction. However, register -// allocation does not have to worry about immediate constants since they -// do not require registers. -// -// Since an llvm Value has a list of uses associated, it is sufficient to -// record only the defs in a Live Range. -// -//===----------------------------------------------------------------------===// - -#ifndef LIVERANGEINFO_H -#define LIVERANGEINFO_H - -#include "llvm/CodeGen/ValueSet.h" -#include "llvm/ADT/hash_map" - -namespace llvm { - -class V9LiveRange; -class MachineInstr; -class RegClass; -class SparcV9RegInfo; -class TargetMachine; -class Value; -class Function; -class Instruction; - -typedef hash_map 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 & RegClassList;// vector containing register classess - - const SparcV9RegInfo& MRI; // machine reg info - - std::vector 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 & 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 diff --git a/lib/Target/SparcV9/RegAlloc/Makefile b/lib/Target/SparcV9/RegAlloc/Makefile deleted file mode 100644 index e82ce5ce57f..00000000000 --- a/lib/Target/SparcV9/RegAlloc/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -##===- lib/CodeGen/RegAlloc/Makefile -----------------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file was developed by the LLVM research group and is distributed under -# the University of Illinois Open Source License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## - -LEVEL = ../../../.. -DIRS = -LIBRARYNAME = LLVMSparcV9RegAlloc - -include $(LEVEL)/Makefile.common diff --git a/lib/Target/SparcV9/RegAlloc/PhyRegAlloc.cpp b/lib/Target/SparcV9/RegAlloc/PhyRegAlloc.cpp deleted file mode 100644 index 0f06e94e8d0..00000000000 --- a/lib/Target/SparcV9/RegAlloc/PhyRegAlloc.cpp +++ /dev/null @@ -1,1366 +0,0 @@ -//===-- 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 -#include - -namespace llvm { - Statistic<> RASpills("regalloc-spills", "Number of registers spilled"); - -RegAllocDebugLevel_t DEBUG_RA; - -static cl::opt -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 -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 (); - AU.addRequired (); -} - - -/// 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 (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 &IBef, - MachineBasicBlock& MBB, - MachineBasicBlock::iterator& MII, - const std::string& msg) { - if (!IBef.empty()) { - MachineInstr* OrigMI = MII; - std::vector::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 &IAft, - MachineBasicBlock& MBB, - MachineBasicBlock::iterator& MII, - const std::string& msg) { - if (!IAft.empty()) { - MachineInstr* OrigMI = MII; - std::vector::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()->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 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()->pushTempValue(MRI.getSpilledRegSize(RegType)); - - std::vector MIBef, MIAft; - std::vector 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 &instrnsBefore, - std::vector &instrnsAfter, - MachineInstr *CallMI, - const BasicBlock *BB) { - assert(TM.getInstrInfo()->isCall(CallMI->getOpcode())); - - // hash set to record which registers were saved/restored - hash_set 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(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()->pushTempValue(MRI.getSpilledRegSize(RegType)); - - //---- Insert code for pushing the reg on stack ---------- - - std::vector 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& MIBef, - std::vector& 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()->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 - 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 &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 &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()->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 &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 &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 (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 TV; - TV.push_back (Type::UIntTy); - TV.push_back (AT); - PointerType *PT = PointerType::get (StructType::get (TV)); - - std::vector 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 &state = FnAllocState[F]; - - // Convert state into an LLVM ConstantArray, and put it in a - // ConstantStruct (named S) along with its size. - std::vector 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 TV; - TV.push_back (Type::UIntTy); - TV.push_back (AT); - StructType *ST = StructType::get (TV); - std::vector 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 TV2; - TV2.push_back (Type::UIntTy); - ArrayType *AT2 = ArrayType::get (PT, Size); - TV2.push_back (AT2); - StructType *ST2 = StructType::get (TV2); - std::vector 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 (); - LRI = new LiveRangeInfo (Fn, TM, RegClassList); - LoopDepthCalc = &getAnalysis (); - - // 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()->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 (*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 diff --git a/lib/Target/SparcV9/RegAlloc/PhyRegAlloc.h b/lib/Target/SparcV9/RegAlloc/PhyRegAlloc.h deleted file mode 100644 index 78f4b47bf8a..00000000000 --- a/lib/Target/SparcV9/RegAlloc/PhyRegAlloc.h +++ /dev/null @@ -1,186 +0,0 @@ -//===-- PhyRegAlloc.h - Graph Coloring Register Allocator -------*- c++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This is the main entry point for register allocation. -// -// Notes: -// * RegisterClasses: Each RegClass accepts a -// TargetRegClass which contains machine specific info about that register -// class. The code in the RegClass is machine independent and they use -// access functions in the TargetRegClass object passed into it to get -// machine specific info. -// -// * Machine dependent work: All parts of the register coloring algorithm -// except coloring of an individual node are machine independent. -// -//===----------------------------------------------------------------------===// - -#ifndef PHYREGALLOC_H -#define PHYREGALLOC_H - -#include "LiveRangeInfo.h" -#include "llvm/Pass.h" -#include "llvm/CodeGen/MachineBasicBlock.h" -#include "llvm/Target/TargetMachine.h" -#include "../SparcV9RegInfo.h" -#include - -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 InstrnsBefore;//Insts added BEFORE an existing inst - std::vector 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 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 OperandsColoredMap; - - // AddedInstrMap - Used to store instrns added in this phase - std::map AddedInstrMap; - - // ScratchRegsUsed - Contains scratch register uses for a particular MI. - typedef std::multimap 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 > 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 &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& instrnsBefore, - std::vector& 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& MIBef, - std::vector& 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 diff --git a/lib/Target/SparcV9/RegAlloc/RegAllocCommon.h b/lib/Target/SparcV9/RegAlloc/RegAllocCommon.h deleted file mode 100644 index 2628bbd2ef9..00000000000 --- a/lib/Target/SparcV9/RegAlloc/RegAllocCommon.h +++ /dev/null @@ -1,32 +0,0 @@ -//===-- RegAllocCommon.h --------------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Shared declarations for register allocation. -// -//===----------------------------------------------------------------------===// - -#ifndef REGALLOCCOMMON_H -#define REGALLOCCOMMON_H - -namespace llvm { - -enum RegAllocDebugLevel_t { - RA_DEBUG_None = 0, - RA_DEBUG_Results = 1, - RA_DEBUG_Coloring = 2, - RA_DEBUG_Interference = 3, - RA_DEBUG_LiveRanges = 4, - RA_DEBUG_Verbose = 5 -}; - -extern RegAllocDebugLevel_t DEBUG_RA; - -} // End llvm namespace - -#endif diff --git a/lib/Target/SparcV9/RegAlloc/RegClass.cpp b/lib/Target/SparcV9/RegAlloc/RegClass.cpp deleted file mode 100644 index dab86e02a1d..00000000000 --- a/lib/Target/SparcV9/RegAlloc/RegClass.cpp +++ /dev/null @@ -1,251 +0,0 @@ -//===-- RegClass.cpp -----------------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// class RegClass for coloring-based register allocation for LLVM. -// -//===----------------------------------------------------------------------===// - -#include "IGNode.h" -#include "RegAllocCommon.h" -#include "RegClass.h" -#include "../SparcV9RegInfo.h" -#include - -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 diff --git a/lib/Target/SparcV9/RegAlloc/RegClass.h b/lib/Target/SparcV9/RegAlloc/RegClass.h deleted file mode 100644 index 667efe961d8..00000000000 --- a/lib/Target/SparcV9/RegAlloc/RegClass.h +++ /dev/null @@ -1,147 +0,0 @@ -//===-- RegClass.h - Machine Independent register coloring ------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -/* Title: RegClass.h -*- C++ -*- - Author: Ruchira Sasanka - Date: Aug 20, 01 - Purpose: Contains machine independent methods for register coloring. - -*/ - -#ifndef REGCLASS_H -#define REGCLASS_H - -#include "../SparcV9RegInfo.h" -#include "InterferenceGraph.h" -#include - -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 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 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 diff --git a/lib/Target/SparcV9/SparcV9.burg.in b/lib/Target/SparcV9/SparcV9.burg.in deleted file mode 100644 index 0e7c88cb48c..00000000000 --- a/lib/Target/SparcV9/SparcV9.burg.in +++ /dev/null @@ -1,349 +0,0 @@ -%{ // -*- C++ -*- -/* ===----------------------------------------------------------------------=== -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===*/ - -Xinclude -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]); -} diff --git a/lib/Target/SparcV9/SparcV9.td b/lib/Target/SparcV9/SparcV9.td deleted file mode 100644 index 87ed94d497f..00000000000 --- a/lib/Target/SparcV9/SparcV9.td +++ /dev/null @@ -1,52 +0,0 @@ -//===- SparcV9.td - Target Description for SparcV9 Target --*- tablegen -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// TableGen target description file for the SparcV9. This is currently used -// primarily to generate part of the SparcV9CodeEmitter automatically. -// -//===----------------------------------------------------------------------===// - -//===----------------------------------------------------------------------===// -// Target-independent interfaces which we are implementing -//===----------------------------------------------------------------------===// - -include "../Target.td" - -//===----------------------------------------------------------------------===// -// Register File Description -//===----------------------------------------------------------------------===// - -include "SparcV9RegisterInfo.td" - -//===----------------------------------------------------------------------===// -// Instruction Descriptions -//===----------------------------------------------------------------------===// - -include "SparcV9InstrInfo.td" - -def SparcV9InstrInfo : InstrInfo { - // Define how we want to layout our TargetSpecific information field. - let TSFlagsFields = []; - let TSFlagsShifts = []; -} - -//===----------------------------------------------------------------------===// -// Declare the target which we are implementing -//===----------------------------------------------------------------------===// - -def SparcV9 : Target { - // FIXME: Specify the callee saved registers. - let CalleeSavedRegisters = []; - - // Pointers are 64-bits in size. - let PointerType = i64; - - // Information about the instructions... - let InstructionSet = SparcV9InstrInfo; -} diff --git a/lib/Target/SparcV9/SparcV9AsmPrinter.cpp b/lib/Target/SparcV9/SparcV9AsmPrinter.cpp deleted file mode 100644 index 62a31c26640..00000000000 --- a/lib/Target/SparcV9/SparcV9AsmPrinter.cpp +++ /dev/null @@ -1,803 +0,0 @@ -//===-- SparcV9AsmPrinter.cpp - Emit SparcV9 Specific .s File --------------==// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements all of the stuff necessary to output a .s file from -// LLVM. The code in this file assumes that the specified module has already -// been compiled into the internal data structures of the Module. -// -// This code largely consists of two LLVM Pass's: a FunctionPass and a Pass. -// The FunctionPass is pipelined together with all of the rest of the code -// generation stages, and the Pass runs at the end to emit code for global -// variables and such. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Constants.h" -#include "llvm/DerivedTypes.h" -#include "llvm/Module.h" -#include "llvm/Pass.h" -#include "llvm/Assembly/Writer.h" -#include "llvm/CodeGen/MachineConstantPool.h" -#include "llvm/CodeGen/MachineFunction.h" -#include "llvm/CodeGen/MachineInstr.h" -#include "llvm/Support/Mangler.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/Statistic.h" -#include "SparcV9Internals.h" -#include "MachineFunctionInfo.h" -#include -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(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 ""; - default: - return ""; - } - } - - /// 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(CV)) { - const ArrayType *aty = cast(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(CV)) - if (ArrayTypeIsString(cast(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(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(GV)) - return getID(V); - else if (const Function *F = dyn_cast(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(CV) && ! isa(CV)) - && "Aggregate types should be handled outside this function"); - - O << "\t" << TypeToDataDirective(CV->getType()) << "\t"; - - if (const GlobalValue* GV = dyn_cast(CV)) { - O << getID(GV) << "\n"; - } else if (isa(CV) || isa(CV)) { - // Null pointer value - O << "0\n"; - } else if (const ConstantExpr* CE = dyn_cast(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(CV)) { - O << "0\n"; - } else if (CV->getType()->isFloatingPoint()) { - // FP Constants are printed as integer constants to avoid losing - // precision... - double Val = cast(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(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(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(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(CV) || isa(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 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(V)) { - S += getID(GV); - } else if (const Constant* CV = dyn_cast(V)) { // symbolic or known - if (const ConstantBool *CB = dyn_cast(CV)) - S += std::string(CB == ConstantBool::True ? "1" : "0"); - else if (const ConstantSInt *CI = dyn_cast(CV)) - S += itostr(CI->getValue()); - else if (const ConstantUInt *CI = dyn_cast(CV)) - S += utostr(CI->getValue()); - else if (const ConstantFP *CFP = dyn_cast(CV)) - S += ftostr(CFP->getValue()); - else if (isa(CV) || isa(CV)) - S += "0"; - else if (const ConstantExpr *CE = dyn_cast(CV)) - S += ConstantExprToString(CE, target); - else - failed = true; - } else - failed = true; - - if (failed) { - assert(0 && "Cannot convert value to string"); - S += ""; - } - 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 << ""; - } 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(Val)) - O << getID(BB); - else if (const Function *F = dyn_cast(Val)) - O << getID(F); - else if (const GlobalVariable *GV = dyn_cast(Val)) - O << getID(GV); - else if (const Constant *CV = dyn_cast(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 &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(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(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); -} diff --git a/lib/Target/SparcV9/SparcV9BurgISel.cpp b/lib/Target/SparcV9/SparcV9BurgISel.cpp deleted file mode 100644 index dcb99a7fb34..00000000000 --- a/lib/Target/SparcV9/SparcV9BurgISel.cpp +++ /dev/null @@ -1,4615 +0,0 @@ -//===- 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 -#include -#include -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(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 { -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 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(I)->getReturnValue()) { - opLabel = RetValueOp; // ret(value) operation - } - else if (opLabel ==Instruction::Br && !cast(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(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); -} - -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(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(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(operand) || isa(operand)) - && !instr->isTerminator(); - - if (includeAddressOperand || isa(operand) || - isa(operand) || isa(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(operand) && operand->hasOneUse() && - cast(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(operand)) { - if (isa(CPV)) - opTreeNode = new VRegNode(operand); - else if (isa(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("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& 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(destType)) - return C; - - if (! isa(V) || isa(V)) - return C; - - // GlobalValue: no conversions needed: get value and return it - if (const GlobalValue* GV = dyn_cast(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(V)) { - isValidConstant = true; - return (uint64_t) CB->getValue(); - } - - // ConstantPointerNull: it's really just a big, shiny version of zero. - if (isa(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(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(V)) { - isValidConstant = true; - C = CI->getRawValue(); - } else if (const ConstantFP *CFP = dyn_cast(V)) { - isValidConstant = true; - double fC = CFP->getValue(); - C = (destType->isSigned()? (uint64_t) (int64_t) fC - : (uint64_t) fC); - } else if (isa(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& 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& 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& 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& 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& mvec, - MachineCodeForInstruction& mcfi) { - assert(isa(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& 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& 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 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(CV) || isa(CV)) - return false; - - if (isa(I)) // Switch instructions will be lowered! - return false; - - if (const ConstantInt* CI = dyn_cast(CV)) - return labs((int64_t)CI->getRawValue()) > MaxConstantsTable[I->getOpcode()]; - - if (isa(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(resultType) - || isa(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& mvec, - MachineCodeForInstruction& mcfi) { - assert(isa(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(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 , 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(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& 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(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()->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& 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& 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& 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& mvec, - MachineCodeForInstruction& mcfi) { - assert((val->getType()->isIntegral() || isa(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()->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& 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& 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(src)) - loadConstantToReg = true; - else if (isa(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(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 -FixConstantOperandsForInstr(Instruction* vmInstr, MachineInstr* minstr, - TargetMachine& target) { - std::vector 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(opValue)) - if (!isa(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(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(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& 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(idx) && cast(idx)->isNullValue()) || - isa(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& chainIdxVec, - bool lastInstHasLeadingNonZero) { - InstructionNode* gepNode = dyn_cast(ptrNode); - GetElementPtrInst* gepInst = - dyn_cast_or_null(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(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(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(*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(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 &idxVec, - bool &allConstantIndices) { - allConstantIndices = true; - GetElementPtrInst* gepI = cast(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(*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 &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(memInst)) - gepNode = memInstrNode; - else if (isa(ptrChild) && isa(ptrVal)) { - // Child of load/store is a GEP and memInst is its only use. - // Use its indices and mark it as folded. - gepNode = cast(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 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(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(opType)); - bool noSign = opType->isUnsigned() || isa(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(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(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& 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(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(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(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(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(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& 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& 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(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(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 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(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& mvec, - MachineCodeForInstruction& mcfi) { - Value* constOp; - if (isa(lval) && isa(rval)) { - // both operands are constant: evaluate and "set" in dest - Constant* P = ConstantExpr::get(Instruction::Mul, - cast(lval), - cast(rval)); - CreateCodeToLoadConst (target, F, P, destVal, mvec, mcfi); - } - else if (isa(rval)) // rval is constant, but not lval - CreateMulConstInstruction(target, F, lval, rval, destVal, mvec, mcfi); - else if (isa(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& 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& mvec) { - Value* LHS = instrNode->leftChild()->getValue(); - Value* constOp = ((InstrTreeNode*) instrNode->rightChild())->getValue(); - if (!isa(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 after the instr to flip the sign - mvec.push_back(CreateIntNegInstruction(target, destVal)); - } - } - } else { - if (ConstantFP *FPC = dyn_cast(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& 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(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& 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()->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()->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& mvec, - InstructionNode* vmInstrNode, - const TargetMachine& target) { - Instruction* memInst = vmInstrNode->getInstruction(); - // Index vector, ptr value, and flag if all indices are const. - std::vector 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(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 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(1U, idxVec[0]), - /*AllowCompositeLeaf*/ true) - : ptrType); - const Type* eltType = cast(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(); igetImplicitRef(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(*UI) // ignore tmp instructions here - && cast(*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& 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(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& 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(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(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(constNode->getValue()); - bool isValidConst; - - if ((constVal->getType()->isInteger() - || isa(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(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(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(subtreeRoot->leftChild()->getValue()); - unsigned dest = cast(constVal)->getValue()? 0 : 1; - - M = BuildMI(V9::BA, 1).addPCDisp( - cast(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(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(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(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(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(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(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(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(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(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(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(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(constNode->getValue()); - bool isValidConst; - - if ((constVal->getType()->isInteger() - || isa(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(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(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(numElementsVal = instr->getArraySize())) { - // total size is constant: generate code for fixed-size alloca - unsigned numElements = isArray? - cast(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(subtreeRoot->getInstruction()); - Value *callee = callInstr->getCalledValue(); - Function* calledFunc = dyn_cast(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(cast(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()->pushTempValue(argSize); - int tmpOffset = MF.getInfo()->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(callee)) - callMI->addImplicitRef(retAddrReg, /*isDef*/ true); - - MF.getInfo()->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(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(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 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(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 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(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 mvec, CpVec; - Target.getRegInfo()->cpValue2Value(PN->getIncomingValue(i), - PhiCpRes, mvec); - for (std::vector::iterator MI=mvec.begin(); - MI != mvec.end(); ++MI) { - std::vector CpVec2 = - FixConstantOperandsForInstr(const_cast(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 mvec; - Target.getRegInfo()->cpValue2Value(PhiCpRes, const_cast(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& 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 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 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); -} diff --git a/lib/Target/SparcV9/SparcV9BurgISel.h b/lib/Target/SparcV9/SparcV9BurgISel.h deleted file mode 100644 index 8736f25f36d..00000000000 --- a/lib/Target/SparcV9/SparcV9BurgISel.h +++ /dev/null @@ -1,56 +0,0 @@ -//===-- SparcV9BurgISel.h ---------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Global functions exposed by the BURG-based instruction selector -// for the SparcV9 target. -// -//===----------------------------------------------------------------------===// - -#ifndef SPARCV9BURGISEL_H -#define SPARCV9BURGISEL_H - -//#include "llvm/DerivedTypes.h" -//#include "llvm/Instruction.h" -//#include "SparcV9Internals.h" - -namespace llvm { - -class Constant; -class Instruction; -class TargetMachine; -class Function; -class Value; -class MachineInstr; -class MachineCodeForInstruction; -class FunctionPass; - -/// ConstantMayNotFitInImmedField - Test if this constant may not fit in the -/// immediate field of the machine instructions (probably) generated for this -/// instruction. -/// -bool ConstantMayNotFitInImmedField (const Constant *CV, const Instruction *I); - -/// CreateCodeToLoadConst - Create an instruction sequence to put the -/// constant `val' into the virtual register `dest'. `val' may be a Constant -/// or a GlobalValue, viz., the constant address of a global variable or -/// function. The generated instructions are returned in `mvec'. Any temp. -/// registers (TmpInstruction) created are recorded in mcfi. -/// -void CreateCodeToLoadConst (const TargetMachine &target, Function *F, - Value *val, Instruction *dest, std::vector &mvec, - MachineCodeForInstruction &mcfi); - -/// createSparcV9BurgInstSelector - Creates and returns a new SparcV9 -/// BURG-based instruction selection pass. -/// -FunctionPass *createSparcV9BurgInstSelector(TargetMachine &TM); - -} // End llvm namespace - -#endif diff --git a/lib/Target/SparcV9/SparcV9CodeEmitter.cpp b/lib/Target/SparcV9/SparcV9CodeEmitter.cpp deleted file mode 100644 index d691a10f763..00000000000 --- a/lib/Target/SparcV9/SparcV9CodeEmitter.cpp +++ /dev/null @@ -1,304 +0,0 @@ -//===-- SparcV9CodeEmitter.cpp --------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// SPARC-specific backend for emitting machine code to memory. -// -// This module also contains the code for lazily resolving the targets of call -// instructions, including the callback used to redirect calls to functions for -// which the code has not yet been generated into the JIT compiler. -// -// This file #includes SparcV9GenCodeEmitter.inc, which contains the code for -// getBinaryCodeForInstr(), a method that converts a MachineInstr into the -// corresponding binary machine code word. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Constants.h" -#include "llvm/Function.h" -#include "llvm/GlobalVariable.h" -#include "llvm/PassManager.h" -#include "llvm/CodeGen/MachineCodeEmitter.h" -#include "llvm/CodeGen/MachineConstantPool.h" -#include "llvm/CodeGen/MachineFunctionPass.h" -#include "llvm/CodeGen/MachineInstr.h" -#include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetData.h" -#include "llvm/Support/Debug.h" -#include "SparcV9Internals.h" -#include "SparcV9TargetMachine.h" -#include "SparcV9RegInfo.h" -#include "SparcV9CodeEmitter.h" -#include "SparcV9Relocations.h" -#include "MachineFunctionInfo.h" -#include -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(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(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(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" - diff --git a/lib/Target/SparcV9/SparcV9CodeEmitter.h b/lib/Target/SparcV9/SparcV9CodeEmitter.h deleted file mode 100644 index b5e3e217545..00000000000 --- a/lib/Target/SparcV9/SparcV9CodeEmitter.h +++ /dev/null @@ -1,87 +0,0 @@ -//===-- SparcV9CodeEmitter.h ------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Target-specific portions of the machine code emitter for the SparcV9. -// This class interfaces with the JIT's Emitter in order to turn MachineInstrs -// into words of binary machine code. Its code is partially generated by -// TableGen's CodeEmitterGenerator. -// -//===----------------------------------------------------------------------===// - -#ifndef SPARCV9CODEEMITTER_H -#define SPARCV9CODEEMITTER_H - -#include "llvm/BasicBlock.h" -#include "llvm/CodeGen/MachineCodeEmitter.h" -#include "llvm/CodeGen/MachineFunctionPass.h" -#include "llvm/Target/TargetMachine.h" - -namespace llvm { - -class GlobalValue; -class MachineInstr; -class MachineOperand; - -class SparcV9CodeEmitter : public MachineFunctionPass { - TargetMachine &TM; - MachineCodeEmitter &MCE; - const BasicBlock *currBB; - - // Tracks which instruction references which BasicBlock - std::vector > > BBRefs; - // Tracks where each BasicBlock starts - std::map 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 diff --git a/lib/Target/SparcV9/SparcV9FrameInfo.cpp b/lib/Target/SparcV9/SparcV9FrameInfo.cpp deleted file mode 100644 index 5e8fba62153..00000000000 --- a/lib/Target/SparcV9/SparcV9FrameInfo.cpp +++ /dev/null @@ -1,57 +0,0 @@ -//===-- SparcV9FrameInfo.cpp - Stack frame layout info for SparcV9 --------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Interface to stack frame layout info for the UltraSPARC. -// -//===----------------------------------------------------------------------===// - -#include "llvm/CodeGen/MachineFunction.h" -#include "llvm/Target/TargetFrameInfo.h" -#include "MachineFunctionInfo.h" -#include "SparcV9FrameInfo.h" - -using namespace llvm; - -int -SparcV9FrameInfo::getRegSpillAreaOffset(MachineFunction& mcInfo, bool& pos) const -{ - // ensure no more auto vars are added - mcInfo.getInfo()->freezeAutomaticVarsArea(); - - pos = false; // static stack area grows downwards - unsigned autoVarsSize = mcInfo.getInfo()->getAutomaticVarsSize(); - return StaticAreaOffsetFromFP - autoVarsSize; -} - -int SparcV9FrameInfo::getTmpAreaOffset(MachineFunction& mcInfo, bool& pos) const { - SparcV9FunctionInfo *MFI = mcInfo.getInfo(); - 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()->getMaxOptionalArgsSize(); - if (int extra = optArgsSize % 16) - optArgsSize += (16 - extra); - int offset = optArgsSize + FirstOptionalOutgoingArgOffsetFromSP; - assert((offset - OFFSET) % 16 == 0); - return offset; -} diff --git a/lib/Target/SparcV9/SparcV9FrameInfo.h b/lib/Target/SparcV9/SparcV9FrameInfo.h deleted file mode 100644 index eab72cc0e38..00000000000 --- a/lib/Target/SparcV9/SparcV9FrameInfo.h +++ /dev/null @@ -1,117 +0,0 @@ -//===-- SparcV9FrameInfo.h - Define TargetFrameInfo for SparcV9 -*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Interface to stack frame layout info for the UltraSPARC. -// -//---------------------------------------------------------------------------- - -#ifndef SPARC_FRAMEINFO_H -#define SPARC_FRAMEINFO_H - -#include "llvm/Target/TargetFrameInfo.h" -#include "llvm/Target/TargetMachine.h" -#include "SparcV9RegInfo.h" - -namespace llvm { - -class SparcV9FrameInfo: public TargetFrameInfo { - const TargetMachine ⌖ -public: - SparcV9FrameInfo(const TargetMachine &TM) - : TargetFrameInfo(StackGrowsDown, StackFrameSizeAlignment, 0), target(TM) {} - - // This method adjusts a stack offset to meet alignment rules of target. - // The fixed OFFSET (0x7ff) must be subtracted and the result aligned. - virtual int adjustAlignment(int unalignedOffset, bool growUp, - unsigned int align) const { - return unalignedOffset + (growUp? +1:-1)*((unalignedOffset-OFFSET) % align); - } - - // These methods compute offsets using the frame contents for a - // particular function. The frame contents are obtained from the - // MachineCodeInfoForMethod object for the given function. - // - int getFirstAutomaticVarOffset(MachineFunction& mcInfo, bool& growUp) const { - growUp = false; - return StaticAreaOffsetFromFP; - } - int getRegSpillAreaOffset(MachineFunction& mcInfo, bool& growUp) const; - int getTmpAreaOffset(MachineFunction& mcInfo, bool& growUp) const; - int getDynamicAreaOffset(MachineFunction& mcInfo, bool& growUp) const; - - virtual int getIncomingArgOffset(MachineFunction& mcInfo, - unsigned argNum) const { - unsigned relativeOffset = argNum * SizeOfEachArgOnStack; - int firstArg = FirstIncomingArgOffsetFromFP; - return firstArg + relativeOffset; - } - - virtual int getOutgoingArgOffset(MachineFunction& mcInfo, - unsigned argNum) const { - return FirstOutgoingArgOffsetFromSP + argNum * SizeOfEachArgOnStack; - } - - /*---------------------------------------------------------------------- - This diagram shows the stack frame layout used by llc on SparcV9 V9. - Note that only the location of automatic variables, spill area, - temporary storage, and dynamically allocated stack area are chosen - by us. The rest conform to the SparcV9 V9 ABI. - All stack addresses are offset by OFFSET = 0x7ff (2047). - - Alignment assumptions and other invariants: - (1) %sp+OFFSET and %fp+OFFSET are always aligned on 16-byte boundary - (2) Variables in automatic, spill, temporary, or dynamic regions - are aligned according to their size as in all memory accesses. - (3) Everything below the dynamically allocated stack area is only used - during a call to another function, so it is never needed when - the current function is active. This is why space can be allocated - dynamically by incrementing %sp any time within the function. - - STACK FRAME LAYOUT: - - ... - %fp+OFFSET+176 Optional extra incoming arguments# 1..N - %fp+OFFSET+168 Incoming argument #6 - ... ... - %fp+OFFSET+128 Incoming argument #1 - ... ... - ---%fp+OFFSET-0--------Bottom of caller's stack frame-------------------- - %fp+OFFSET-8 Automatic variables <-- ****TOP OF STACK FRAME**** - Spill area - Temporary storage - ... - - %sp+OFFSET+176+8N Bottom of dynamically allocated stack area - %sp+OFFSET+168+8N Optional extra outgoing argument# N - ... ... - %sp+OFFSET+176 Optional extra outgoing argument# 1 - %sp+OFFSET+168 Outgoing argument #6 - ... ... - %sp+OFFSET+128 Outgoing argument #1 - %sp+OFFSET+120 Save area for %i7 - ... ... - %sp+OFFSET+0 Save area for %l0 <-- ****BOTTOM OF STACK FRAME**** - - *----------------------------------------------------------------------*/ - - // All stack addresses must be offset by 0x7ff (2047) on SparcV9 V9. - static const int OFFSET = (int) 0x7ff; - static const int StackFrameSizeAlignment = 16; - static const int MinStackFrameSize = 176; - static const int SizeOfEachArgOnStack = 8; - static const int FirstIncomingArgOffsetFromFP = 128 + OFFSET; - static const int FirstOptionalIncomingArgOffsetFromFP = 176 + OFFSET; - static const int StaticAreaOffsetFromFP = 0 + OFFSET; - static const int FirstOutgoingArgOffsetFromSP = 128 + OFFSET; - static const int FirstOptionalOutgoingArgOffsetFromSP = 176 + OFFSET; -}; - -} // End llvm namespace - -#endif diff --git a/lib/Target/SparcV9/SparcV9Instr.def b/lib/Target/SparcV9/SparcV9Instr.def deleted file mode 100644 index 53d24a596a4..00000000000 --- a/lib/Target/SparcV9/SparcV9Instr.def +++ /dev/null @@ -1,547 +0,0 @@ -//===-- SparcV9Instr.def - SparcV9 Instruction Information -------*- C++ -*-==// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file describes all of the instructions that the sparc backend uses. It -// relys on an external 'I' macro being defined that takes the arguments -// specified below, and is used to make all of the information relevant to an -// instruction be in one place. -// -//===----------------------------------------------------------------------===// - -// NOTE: No include guards desired - -#ifndef I -#errror "Must define I macro before including SparcInstr.def!" -#endif - -// Constants for defining the maximum constant size field. -// One #define per bit size -// -#define B5 ((1 << 5) - 1) -#define B6 ((1 << 6) - 1) -#define B12 ((1 << 12) - 1) -#define B15 ((1 << 15) - 1) -#define B18 ((1 << 18) - 1) -#define B21 ((1 << 21) - 1) -#define B22 ((1 << 22) - 1) -#define B29 ((1 << 29) - 1) - -// Arguments passed into the I macro -// enum name, -// opCodeString, -// numOperands, -// resultPosition (0-based; -1 if no result), -// maxImmedConst, -// immedIsSignExtended, -// numDelaySlots (in cycles) -// latency (in cycles) -// instr sched class (defined above) -// instr class flags (defined in TargetInstrInfo.h) - -#define BRANCHFLAGS M_BRANCH_FLAG|M_TERMINATOR_FLAG -#define RETFLAGS M_RET_FLAG|M_TERMINATOR_FLAG - -I(NOP, "nop", 0, -1, 0, false, 0, 1, SPARC_NONE, M_NOP_FLAG) - -// Set high-order bits of register and clear low-order bits -I(SETHI, "sethi", 2, 1, B22, false, 0, 1, SPARC_IEUN, 0) - -// Add or add with carry. -I(ADDr , "add", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0) -I(ADDi , "add", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0) -I(ADDccr, "addcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_CC_FLAG ) -I(ADDcci, "addcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_CC_FLAG ) -I(ADDCr , "addc", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0) -I(ADDCi , "addc", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0) -I(ADDCccr, "addccc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_CC_FLAG ) -I(ADDCcci, "addccc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_CC_FLAG ) - -// Subtract or subtract with carry. -I(SUBr , "sub", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0) -I(SUBi , "sub", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0) -I(SUBccr , "subcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_CC_FLAG ) -I(SUBcci , "subcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_CC_FLAG ) -I(SUBCr , "subc", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0) -I(SUBCi , "subc", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0) -I(SUBCccr, "subccc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_CC_FLAG ) -I(SUBCcci, "subccc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_CC_FLAG ) - -// Integer multiply, signed divide, unsigned divide. -// Note that the deprecated 32-bit multiply and multiply-step are not used. -I(MULXr , "mulx", 3, 2, B12, true , 0, 3, SPARC_IEUN, 0) -I(MULXi , "mulx", 3, 2, B12, true , 0, 3, SPARC_IEUN, 0) -I(SDIVXr, "sdivx", 3, 2, B12, true , 0, 6, SPARC_IEUN, 0) -I(SDIVXi, "sdivx", 3, 2, B12, true , 0, 6, SPARC_IEUN, 0) -I(UDIVXr, "udivx", 3, 2, B12, true , 0, 6, SPARC_IEUN, 0) -I(UDIVXi, "udivx", 3, 2, B12, true , 0, 6, SPARC_IEUN, 0) - - // Floating point add, subtract, compare. - // Note that destination of FCMP* instructions is operand 0, not operand 2. -I(FADDS, "fadds", 3, 2, 0, false, 0, 3, SPARC_FPA, 0) -I(FADDD, "faddd", 3, 2, 0, false, 0, 3, SPARC_FPA, 0) -I(FADDQ, "faddq", 3, 2, 0, false, 0, 3, SPARC_FPA, 0) -I(FSUBS, "fsubs", 3, 2, 0, false, 0, 3, SPARC_FPA, 0) -I(FSUBD, "fsubd", 3, 2, 0, false, 0, 3, SPARC_FPA, 0) -I(FSUBQ, "fsubq", 3, 2, 0, false, 0, 3, SPARC_FPA, 0) -I(FCMPS, "fcmps", 3, 0, 0, false, 0, 3, SPARC_FPA, M_CC_FLAG ) -I(FCMPD, "fcmpd", 3, 0, 0, false, 0, 3, SPARC_FPA, M_CC_FLAG ) -I(FCMPQ, "fcmpq", 3, 0, 0, false, 0, 3, SPARC_FPA, M_CC_FLAG ) -// NOTE: FCMPE{S,D,Q}: FP Compare With Exception are currently unused! - -// Floating point multiply or divide. -I(FMULS , "fmuls", 3, 2, 0, false, 0, 3, SPARC_FPM, 0) -I(FMULD , "fmuld", 3, 2, 0, false, 0, 3, SPARC_FPM, 0) -I(FMULQ , "fmulq", 3, 2, 0, false, 0, 0, SPARC_FPM, 0) -I(FSMULD, "fsmuld", 3, 2, 0, false, 0, 3, SPARC_FPM, 0) -I(FDMULQ, "fdmulq", 3, 2, 0, false, 0, 0, SPARC_FPM, 0) -I(FDIVS , "fdivs", 3, 2, 0, false, 0, 12, SPARC_FPM, 0) -I(FDIVD , "fdivd", 3, 2, 0, false, 0, 22, SPARC_FPM, 0) -I(FDIVQ , "fdivq", 3, 2, 0, false, 0, 0, SPARC_FPM, 0) -I(FSQRTS, "fsqrts", 3, 2, 0, false, 0, 12, SPARC_FPM, 0) -I(FSQRTD, "fsqrtd", 3, 2, 0, false, 0, 22, SPARC_FPM, 0) -I(FSQRTQ, "fsqrtq", 3, 2, 0, false, 0, 0, SPARC_FPM, 0) - -// Logical operations -I(ANDr , "and", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0) -I(ANDi , "and", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0) -I(ANDccr , "andcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, 0) -I(ANDcci , "andcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, 0) -I(ANDNr , "andn", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0) -I(ANDNi , "andn", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0) -I(ANDNccr, "andncc", 4, 2, B12, true , 0, 1, SPARC_IEU1, 0) -I(ANDNcci, "andncc", 4, 2, B12, true , 0, 1, SPARC_IEU1, 0) - -I(ORr , "or", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0) -I(ORi , "or", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0) -I(ORccr , "orcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, 0) -I(ORcci , "orcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, 0) -I(ORNr , "orn", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0) -I(ORNi , "orn", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0) -I(ORNccr, "orncc", 4, 2, B12, true , 0, 1, SPARC_IEU1, 0) -I(ORNcci, "orncc", 4, 2, B12, true , 0, 1, SPARC_IEU1, 0) - -I(XORr , "xor", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0) -I(XORi , "xor", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0) -I(XORccr , "xorcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, 0) -I(XORcci , "xorcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, 0) -I(XNORr , "xnor", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0) -I(XNORi , "xnor", 3, 2, B12, true , 0, 1, SPARC_IEUN, 0) -I(XNORccr, "xnorcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, 0) -I(XNORcci, "xnorcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, 0) - -// Shift operations -I(SLLr5 , "sll", 3, 2, B5, true , 0, 1, SPARC_IEU0, 0) -I(SLLi5 , "sll", 3, 2, B5, true , 0, 1, SPARC_IEU0, 0) -I(SRLr5 , "srl", 3, 2, B5, true , 0, 1, SPARC_IEU0, 0) -I(SRLi5 , "srl", 3, 2, B5, true , 0, 1, SPARC_IEU0, 0) -I(SRAr5 , "sra", 3, 2, B5, true , 0, 1, SPARC_IEU0, 0) -I(SRAi5 , "sra", 3, 2, B5, true , 0, 1, SPARC_IEU0, 0) -I(SLLXr6, "sllx", 3, 2, B6, true , 0, 1, SPARC_IEU0, 0) -I(SLLXi6, "sllx", 3, 2, B6, true , 0, 1, SPARC_IEU0, 0) -I(SRLXr6, "srlx", 3, 2, B6, true , 0, 1, SPARC_IEU0, 0) -I(SRLXi6, "srlx", 3, 2, B6, true , 0, 1, SPARC_IEU0, 0) -I(SRAXr6, "srax", 3, 2, B6, true , 0, 1, SPARC_IEU0, 0) -I(SRAXi6, "srax", 3, 2, B6, true , 0, 1, SPARC_IEU0, 0) - -// Floating point move, negate, and abs instructions -I(FMOVS, "fmovs", 2, 1, 0, false, 0, 1, SPARC_FPA, 0) -I(FMOVD, "fmovd", 2, 1, 0, false, 0, 1, SPARC_FPA, 0) -//I(FMOVQ, "fmovq", 2, 1, 0, false, 0, ?, SPARC_FPA, 0) -I(FNEGS, "fnegs", 2, 1, 0, false, 0, 1, SPARC_FPA, 0) -I(FNEGD, "fnegd", 2, 1, 0, false, 0, 1, SPARC_FPA, 0) -//I(FNEGQ, "fnegq", 2, 1, 0, false, 0, ?, SPARC_FPA, 0) -I(FABSS, "fabss", 2, 1, 0, false, 0, 1, SPARC_FPA, 0) -I(FABSD, "fabsd", 2, 1, 0, false, 0, 1, SPARC_FPA, 0) -//I(FABSQ, "fabsq", 2, 1, 0, false, 0, ?, SPARC_FPA, 0) - -// Convert from floating point to floating point formats -I(FSTOD, "fstod", 2, 1, 0, false, 0, 3, SPARC_FPA, 0) -I(FSTOQ, "fstoq", 2, 1, 0, false, 0, 0, SPARC_FPA, 0) -I(FDTOS, "fdtos", 2, 1, 0, false, 0, 3, SPARC_FPA, 0) -I(FDTOQ, "fdtoq", 2, 1, 0, false, 0, 0, SPARC_FPA, 0) -I(FQTOS, "fqtos", 2, 1, 0, false, 0, 0, SPARC_FPA, 0) -I(FQTOD, "fqtod", 2, 1, 0, false, 0, 0, SPARC_FPA, 0) - -// Convert from floating point to integer formats. -// Note that this accesses both integer and floating point registers. -I(FSTOX, "fstox", 2, 1, 0, false, 0, 3, SPARC_FPA, 0) -I(FDTOX, "fdtox", 2, 1, 0, false, 0, 0, SPARC_FPA, 0) -I(FQTOX, "fqtox", 2, 1, 0, false, 0, 2, SPARC_FPA, 0) -I(FSTOI, "fstoi", 2, 1, 0, false, 0, 3, SPARC_FPA, 0) -I(FDTOI, "fdtoi", 2, 1, 0, false, 0, 3, SPARC_FPA, 0) -I(FQTOI, "fqtoi", 2, 1, 0, false, 0, 0, SPARC_FPA, 0) - -// Convert from integer to floating point formats -// Note that this accesses both integer and floating point registers. -I(FXTOS, "fxtos", 2, 1, 0, false, 0, 3, SPARC_FPA, 0) -I(FXTOD, "fxtod", 2, 1, 0, false, 0, 3, SPARC_FPA, 0) -I(FXTOQ, "fxtoq", 2, 1, 0, false, 0, 0, SPARC_FPA, 0) -I(FITOS, "fitos", 2, 1, 0, false, 0, 3, SPARC_FPA, 0) -I(FITOD, "fitod", 2, 1, 0, false, 0, 3, SPARC_FPA, 0) -I(FITOQ, "fitoq", 2, 1, 0, false, 0, 0, SPARC_FPA, 0) - -// Branch on integer comparison with zero. -// Latency excludes the delay slot since it can be issued in same cycle. -I(BRZ , "brz", 2, -1, B15, true , 1, 1, SPARC_CTI, BRANCHFLAGS) -I(BRLEZ, "brlez", 2, -1, B15, true , 1, 1, SPARC_CTI, BRANCHFLAGS) -I(BRLZ , "brlz", 2, -1, B15, true , 1, 1, SPARC_CTI, BRANCHFLAGS) -I(BRNZ , "brnz", 2, -1, B15, true , 1, 1, SPARC_CTI, BRANCHFLAGS) -I(BRGZ , "brgz", 2, -1, B15, true , 1, 1, SPARC_CTI, BRANCHFLAGS) -I(BRGEZ, "brgez", 2, -1, B15, true , 1, 1, SPARC_CTI, BRANCHFLAGS) - -// Branch on integer condition code. -// The first argument specifies the ICC register: %icc or %xcc -// Latency includes the delay slot. -I(BA , "ba", 1, -1, B21, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS) -I(BN , "bn", 2, -1, B21, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS) -I(BNE , "bne", 2, -1, B21, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS) -I(BE , "be", 2, -1, B21, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS) -I(BG , "bg", 2, -1, B21, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS) -I(BLE , "ble", 2, -1, B21, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS) -I(BGE , "bge", 2, -1, B21, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS) -I(BL , "bl", 2, -1, B21, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS) -I(BGU , "bgu", 2, -1, B21, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS) -I(BLEU, "bleu", 2, -1, B21, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS) -I(BCC , "bcc", 2, -1, B21, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS) -I(BCS , "bcs", 2, -1, B21, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS) -I(BPOS, "bpos", 2, -1, B21, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS) -I(BNEG, "bneg", 2, -1, B21, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS) -I(BVC , "bvc", 2, -1, B21, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS) -I(BVS , "bvs", 2, -1, B21, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS) - -// Branch on floating point condition code. -// The first argument is the FCCn register (0 <= n <= 3). -// Latency includes the delay slot. -I(FBA , "fba", 2, -1, B18, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS) -I(FBN , "fbn", 2, -1, B18, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS) -I(FBU , "fbu", 2, -1, B18, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS) -I(FBG , "fbg", 2, -1, B18, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS) -I(FBUG , "fbug", 2, -1, B18, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS) -I(FBL , "fbl", 2, -1, B18, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS) -I(FBUL , "fbul", 2, -1, B18, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS) -I(FBLG , "fblg", 2, -1, B18, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS) -I(FBNE , "fbne", 2, -1, B18, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS) -I(FBE , "fbe", 2, -1, B18, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS) -I(FBUE , "fbue", 2, -1, B18, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS) -I(FBGE , "fbge", 2, -1, B18, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS) -I(FBUGE, "fbuge", 2, -1, B18, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS) -I(FBLE , "fble", 2, -1, B18, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS) -I(FBULE, "fbule", 2, -1, B18, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS) -I(FBO , "fbo", 2, -1, B18, true , 1, 2, SPARC_CTI, M_CC_FLAG|BRANCHFLAGS) - -// Conditional move on integer comparison with zero. -I(MOVRZr , "movrz", 3, 2, B12, true , 0, 2, SPARC_SINGLE, 0) -I(MOVRZi , "movrz", 3, 2, B12, true , 0, 2, SPARC_SINGLE, 0) -I(MOVRLEZr, "movrlez", 3, 2, B12, true , 0, 2, SPARC_SINGLE, 0) -I(MOVRLEZi, "movrlez", 3, 2, B12, true , 0, 2, SPARC_SINGLE, 0) -I(MOVRLZr , "movrlz", 3, 2, B12, true , 0, 2, SPARC_SINGLE, 0) -I(MOVRLZi , "movrlz", 3, 2, B12, true , 0, 2, SPARC_SINGLE, 0) -I(MOVRNZr , "movrnz", 3, 2, B12, true , 0, 2, SPARC_SINGLE, 0) -I(MOVRNZi , "movrnz", 3, 2, B12, true , 0, 2, SPARC_SINGLE, 0) -I(MOVRGZr , "movrgz", 3, 2, B12, true , 0, 2, SPARC_SINGLE, 0) -I(MOVRGZi , "movrgz", 3, 2, B12, true , 0, 2, SPARC_SINGLE, 0) -I(MOVRGEZr, "movrgez", 3, 2, B12, true , 0, 2, SPARC_SINGLE, 0) -I(MOVRGEZi, "movrgez", 3, 2, B12, true , 0, 2, SPARC_SINGLE, 0) - -// Conditional move on integer condition code. -// The first argument specifies the ICC register: %icc or %xcc -I(MOVAr , "mova", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVAi , "mova", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVNr , "movn", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVNi , "movn", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVNEr , "movne", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVNEi , "movne", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVEr , "move", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVEi , "move", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVGr , "movg", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVGi , "movg", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVLEr , "movle", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVLEi , "movle", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVGEr , "movge", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVGEi , "movge", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVLr , "movl", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVLi , "movl", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVGUr , "movgu", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVGUi , "movgu", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVLEUr, "movleu", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVLEUi, "movleu", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVCCr , "movcc", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVCCi , "movcc", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVCSr , "movcs", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVCSi , "movcs", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVPOSr, "movpos", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVPOSi, "movpos", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVNEGr, "movneg", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVNEGi, "movneg", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVVCr , "movvc", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVVCi , "movvc", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVVSr , "movvs", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVVSi , "movvs", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) - -// Conditional move (of integer register) on floating point condition code. -// The first argument is the FCCn register (0 <= n <= 3). -// Note that the enum name above is not the same as the assembly mnemonic -// because some of the assembly mnemonics are the same as the move on -// integer CC (e.g., MOVG), and we cannot have the same enum entry twice. -I(MOVFAr , "mova", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVFAi , "mova", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVFNr , "movn", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVFNi , "movn", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVFUr , "movu", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVFUi , "movu", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVFGr , "movg", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVFGi , "movg", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVFUGr , "movug", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVFUGi , "movug", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVFLr , "movl", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVFLi , "movl", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVFULr , "movul", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVFULi , "movul", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVFLGr , "movlg", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVFLGi , "movlg", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVFNEr , "movne", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVFNEi , "movne", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVFEr , "move", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVFEi , "move", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVFUEr , "movue", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVFUEi , "movue", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVFGEr , "movge", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVFGEi , "movge", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVFUGEr, "movuge", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVFUGEi, "movuge", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVFLEr , "movle", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVFLEi , "movle", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVFULEr, "movule", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVFULEi, "movule", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVFOr , "movo", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(MOVFOi , "movo", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG ) - -// Conditional move of floating point register on each of the above: -// i. on integer comparison with zero. -// ii. on integer condition code -// iii. on floating point condition code -// Note that the same set is repeated for S,D,Q register classes. -I(FMOVRSZ ,"fmovrsz", 3, 2, 0, false, 0, 2, SPARC_SINGLE, 0) -I(FMOVRSLEZ,"fmovrslez",3, 2, 0, false, 0, 2, SPARC_SINGLE, 0) -I(FMOVRSLZ ,"fmovrslz", 3, 2, 0, false, 0, 2, SPARC_SINGLE, 0) -I(FMOVRSNZ ,"fmovrsnz", 3, 2, 0, false, 0, 2, SPARC_SINGLE, 0) -I(FMOVRSGZ ,"fmovrsgz", 3, 2, 0, false, 0, 2, SPARC_SINGLE, 0) -I(FMOVRSGEZ,"fmovrsgez",3, 2, 0, false, 0, 2, SPARC_SINGLE, 0) - -I(FMOVSA , "fmovsa", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVSN , "fmovsn", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVSNE , "fmovsne", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVSE , "fmovse", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVSG , "fmovsg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVSLE , "fmovsle", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVSGE , "fmovsge", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVSL , "fmovsl", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVSGU , "fmovsgu", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVSLEU, "fmovsleu", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVSCC , "fmovscc", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVSCS , "fmovscs", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVSPOS, "fmovspos", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVSNEG, "fmovsneg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVSVC , "fmovsvc", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVSVS , "fmovsvs", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) - -I(FMOVSFA , "fmovsa", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVSFN , "fmovsn", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVSFU , "fmovsu", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVSFG , "fmovsg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVSFUG , "fmovsug", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVSFL , "fmovsl", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVSFUL , "fmovsul", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVSFLG , "fmovslg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVSFNE , "fmovsne", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVSFE , "fmovse", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVSFUE , "fmovsue", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVSFGE , "fmovsge", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVSFUGE, "fmovsuge",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVSFLE , "fmovsle", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVSFULE, "fmovslue",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVSFO , "fmovso", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) - -I(FMOVRDZ , "fmovrdz", 3, 2, 0, false, 0, 2, SPARC_SINGLE, 0) -I(FMOVRDLEZ, "fmovrdlez",3, 2, 0, false, 0, 2, SPARC_SINGLE, 0) -I(FMOVRDLZ , "fmovrdlz",3, 2, 0, false, 0, 2, SPARC_SINGLE, 0) -I(FMOVRDNZ , "fmovrdnz",3, 2, 0, false, 0, 2, SPARC_SINGLE, 0) -I(FMOVRDGZ , "fmovrdgz",3, 2, 0, false, 0, 2, SPARC_SINGLE, 0) -I(FMOVRDGEZ, "fmovrdgez",3, 2, 0, false, 0, 2, SPARC_SINGLE, 0) - -I(FMOVDA , "fmovda", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVDN , "fmovdn", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVDNE , "fmovdne", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVDE , "fmovde", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVDG , "fmovdg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVDLE , "fmovdle", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVDGE , "fmovdge", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVDL , "fmovdl", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVDGU , "fmovdgu", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVDLEU, "fmovdleu", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVDCC , "fmovdcc", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVDCS , "fmovdcs", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVDPOS, "fmovdpos", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVDNEG, "fmovdneg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVDVC , "fmovdvc", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVDVS , "fmovdvs", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) - -I(FMOVDFA , "fmovda", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVDFN , "fmovdn", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVDFU , "fmovdu", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVDFG , "fmovdg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVDFUG , "fmovdug", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVDFL , "fmovdl", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVDFUL , "fmovdul", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVDFLG , "fmovdlg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVDFNE , "fmovdne", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVDFE , "fmovde", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVDFUE , "fmovdue", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVDFGE , "fmovdge", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVDFUGE, "fmovduge",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVDFLE , "fmovdle", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVDFULE, "fmovdule",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVDFO , "fmovdo", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) - -I(FMOVRQZ , "fmovrqz", 3, 2, 0, false, 0, 2, SPARC_SINGLE, 0) -I(FMOVRQLEZ, "fmovrqlez",3, 2, 0, false, 0, 2, SPARC_SINGLE, 0) -I(FMOVRQLZ , "fmovrqlz",3, 2, 0, false, 0, 2, SPARC_SINGLE, 0) -I(FMOVRQNZ , "fmovrqnz",3, 2, 0, false, 0, 2, SPARC_SINGLE, 0) -I(FMOVRQGZ , "fmovrqgz",3, 2, 0, false, 0, 2, SPARC_SINGLE, 0) -I(FMOVRQGEZ, "fmovrqgez",3, 2, 0, false, 0, 2, SPARC_SINGLE, 0) - -I(FMOVQA , "fmovqa", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVQN , "fmovqn", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVQNE , "fmovqne", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVQE , "fmovqe", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVQG , "fmovqg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVQLE , "fmovqle", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVQGE , "fmovqge", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVQL , "fmovql", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVQGU , "fmovqgu", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVQLEU, "fmovqleu", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVQCC , "fmovqcc", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVQCS , "fmovqcs", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVQPOS, "fmovqpos", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVQNEG, "fmovqneg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVQVC , "fmovqvc", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVQVS , "fmovqvs", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) - -I(FMOVQFA , "fmovqa", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVQFN , "fmovqn", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVQFU , "fmovqu", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVQFG , "fmovqg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVQFUG , "fmovqug", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVQFL , "fmovql", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVQFUL , "fmovqul", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVQFLG , "fmovqlg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVQFNE , "fmovqne", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVQFE , "fmovqe", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVQFUE , "fmovque", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVQFGE , "fmovqge", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVQFUGE, "fmovquge",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVQFLE , "fmovqle", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVQFULE, "fmovqule",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG ) -I(FMOVQFO , "fmovqo", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG) - -// Load integer instructions -// Latency includes 1 cycle for address generation (Sparc IIi), -// plus 3 cycles assumed for average miss penalty (bias towards L1 hits). -// Signed loads of less than 64 bits need an extra cycle for sign-extension. -// -// Not reflected here: After a 3-cycle loads, all subsequent consecutive -// loads also require 3 cycles to avoid contention for the load return -// stage. Latency returns to 2 cycles after the first cycle with no load. -I(LDSBr, "ldsb", 3, 2, B12, true , 0, 6, SPARC_LD, M_LOAD_FLAG) -I(LDSBi, "ldsb", 3, 2, B12, true , 0, 6, SPARC_LD, M_LOAD_FLAG) -I(LDSHr, "ldsh", 3, 2, B12, true , 0, 6, SPARC_LD, M_LOAD_FLAG) -I(LDSHi, "ldsh", 3, 2, B12, true , 0, 6, SPARC_LD, M_LOAD_FLAG) -I(LDSWr, "ldsw", 3, 2, B12, true , 0, 6, SPARC_LD, M_LOAD_FLAG) -I(LDSWi, "ldsw", 3, 2, B12, true , 0, 6, SPARC_LD, M_LOAD_FLAG) -I(LDUBr, "ldub", 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG) -I(LDUBi, "ldub", 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG) -I(LDUHr, "lduh", 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG) -I(LDUHi, "lduh", 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG) -I(LDUWr, "lduw", 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG) -I(LDUWi, "lduw", 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG) -I(LDXr , "ldx" , 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG) -I(LDXi , "ldx" , 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG) - -// Load floating-point instructions -// Latency includes 1 cycle for address generation (Sparc IIi) -I(LDFr , "ld", 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG) -I(LDFi , "ld", 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG) -I(LDDFr, "ldd", 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG) -I(LDDFi, "ldd", 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG) -I(LDQFr, "ldq", 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG) -I(LDQFi, "ldq", 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG) -I(LDFSRr, "ld", 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG) -I(LDFSRi, "ld", 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG) -I(LDXFSRr, "ldx", 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG) -I(LDXFSRi, "ldx", 3, 2, B12, true , 0, 5, SPARC_LD, M_LOAD_FLAG) - -// Store integer instructions. -// Requires 1 cycle for address generation (Sparc IIi). -// Default latency is 0 because value is not explicitly used. -I(STBr, "stb", 3, -1, B12, true , 0, 0, SPARC_ST, M_STORE_FLAG) -I(STBi, "stb", 3, -1, B12, true , 0, 0, SPARC_ST, M_STORE_FLAG) -I(STHr, "sth", 3, -1, B12, true , 0, 0, SPARC_ST, M_STORE_FLAG) -I(STHi, "sth", 3, -1, B12, true , 0, 0, SPARC_ST, M_STORE_FLAG) -I(STWr, "stw", 3, -1, B12, true , 0, 0, SPARC_ST, M_STORE_FLAG) -I(STWi, "stw", 3, -1, B12, true , 0, 0, SPARC_ST, M_STORE_FLAG) -I(STXr, "stx", 3, -1, B12, true , 0, 0, SPARC_ST, M_STORE_FLAG) -I(STXi, "stx", 3, -1, B12, true , 0, 0, SPARC_ST, M_STORE_FLAG) - -// Store floating-point instructions (Sparc IIi) -I(STFr, "st", 3, -1, B12, true , 0, 0, SPARC_ST, M_STORE_FLAG) -I(STFi, "st", 3, -1, B12, true , 0, 0, SPARC_ST, M_STORE_FLAG) -I(STDFr, "std", 3, -1, B12, true , 0, 0, SPARC_ST, M_STORE_FLAG) -I(STDFi, "std", 3, -1, B12, true , 0, 0, SPARC_ST, M_STORE_FLAG) -I(STFSRr, "st", 3, -1, B12, true , 0, 0, SPARC_ST, M_STORE_FLAG) -I(STFSRi, "st", 3, -1, B12, true , 0, 0, SPARC_ST, M_STORE_FLAG) -I(STXFSRr, "stx", 3, -1, B12, true , 0, 0, SPARC_ST, M_STORE_FLAG) -I(STXFSRi, "stx", 3, -1, B12, true , 0, 0, SPARC_ST, M_STORE_FLAG) - -// Call, Return and "Jump and link". Operand (2) for JMPL is marked as -// a "result" because JMPL stores the return address for the call in it. -// Latency includes the delay slot. -I(CALL, "call", 1, -1, B29, true , 1, 2, SPARC_CTI, M_CALL_FLAG) -I(JMPLCALLr, "jmpl", 3, 2, B12, true , 1, 2, SPARC_CTI, M_CALL_FLAG) -I(JMPLCALLi, "jmpl", 3, 2, B12, true , 1, 2, SPARC_CTI, M_CALL_FLAG) -I(JMPLRETr, "jmpl", 3, 2, B12, true , 1, 2, SPARC_CTI, RETFLAGS) -I(JMPLRETi, "jmpl", 3, 2, B12, true , 1, 2, SPARC_CTI, RETFLAGS) - -// SAVE and restore instructions -I(SAVEr, "save", 3, 2, B12, true , 0, 1, SPARC_SINGLE, 0) -I(SAVEi, "save", 3, 2, B12, true , 0, 1, SPARC_SINGLE, 0) -I(RESTOREr, "restore", 3, 2, B12, true , 0, 1, SPARC_SINGLE, 0) -I(RESTOREi, "restore", 3, 2, B12, true , 0, 1, SPARC_SINGLE, 0) - -// Read and Write CCR register from/to an int reg -I(RDCCR, "rd", 2, 1, 0, false, 0, 1, SPARC_SINGLE, M_CC_FLAG) -I(WRCCRr, "wr", 3, 2, 0, false, 0, 1, SPARC_SINGLE, M_CC_FLAG) -I(WRCCRi, "wr", 3, 2, 0, false, 0, 1, SPARC_SINGLE, M_CC_FLAG) - -// Synthetic phi operation for near-SSA form of machine code -// Number of operands is variable, indicated by -1. Result is the first op. -I(PHI, "", -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 diff --git a/lib/Target/SparcV9/SparcV9InstrForest.h b/lib/Target/SparcV9/SparcV9InstrForest.h deleted file mode 100644 index 8148ff655b2..00000000000 --- a/lib/Target/SparcV9/SparcV9InstrForest.h +++ /dev/null @@ -1,134 +0,0 @@ -//===- SparcV9InstrForest.h - SparcV9 BURG Instruction Selector Trees -----===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// A forest of BURG instruction trees (class InstrForest) which represents -// a function to the BURG-based instruction selector, and a bunch of constants -// and declarations used by the generated BURG code. -// -//===----------------------------------------------------------------------===// - -#ifndef SPARCV9INSTRFOREST_H -#define SPARCV9INSTRFOREST_H - -#include "llvm/Instruction.h" -using namespace llvm; - -/// OpLabel values for special-case nodes created for instruction selection. -/// All op-labels not defined here are identical to the instruction -/// opcode returned by Instruction::getOpcode(). -/// -static const int - InvalidOp = -1, - VRegListOp = 97, - VRegNodeOp = 98, - ConstantNodeOp = 99, - LabelNodeOp = 100, - RetValueOp = 100 + Instruction::Ret, // 101 - BrCondOp = 100 + Instruction::Br, // 102 - BAndOp = 100 + Instruction::And, // 111 - BOrOp = 100 + Instruction::Or, // 112 - BXorOp = 100 + Instruction::Xor, // 113 - BNotOp = 200 + Instruction::Xor, // 213 - NotOp = 300 + Instruction::Xor, // 313 - SetCCOp = 100 + Instruction::SetEQ, // 114 - AllocaN = 100 + Instruction::Alloca, // 122 - LoadIdx = 100 + Instruction::Load, // 123 - GetElemPtrIdx = 100 + Instruction::GetElementPtr, // 125 - ToBoolTy = 100 + Instruction::Cast; // 127 -static const int - ToUByteTy = ToBoolTy + 1, - ToSByteTy = ToBoolTy + 2, - ToUShortTy = ToBoolTy + 3, - ToShortTy = ToBoolTy + 4, - ToUIntTy = ToBoolTy + 5, - ToIntTy = ToBoolTy + 6, - ToULongTy = ToBoolTy + 7, - ToLongTy = ToBoolTy + 8, - ToFloatTy = ToBoolTy + 9, - ToDoubleTy = ToBoolTy + 10, - ToArrayTy = ToBoolTy + 11, - ToPointerTy = ToBoolTy + 12; - -/// Data types needed by BURG -/// -typedef int OpLabel; -typedef int StateLabel; - -/// Declarations of data and functions created by BURG -/// -namespace llvm { - class InstrTreeNode; -}; -extern short* burm_nts[]; -extern StateLabel burm_label (InstrTreeNode* p); -extern StateLabel burm_state (OpLabel op, StateLabel leftState, - StateLabel rightState); -extern StateLabel burm_rule (StateLabel state, int goalNT); -extern InstrTreeNode** burm_kids (InstrTreeNode* p, int eruleno, - InstrTreeNode* kids[]); -extern void printcover (InstrTreeNode*, int, int); -extern void printtree (InstrTreeNode*); -extern int treecost (InstrTreeNode*, int, int); -extern void printMatches (InstrTreeNode*); - -namespace llvm { - -/// InstrTreeNode - A single tree node in the instruction tree used for -/// instruction selection via BURG. -/// -class InstrTreeNode { - InstrTreeNode(const InstrTreeNode &); // DO NOT IMPLEMENT - void operator=(const InstrTreeNode &); // DO NOT IMPLEMENT -public: - enum InstrTreeNodeType { NTInstructionNode, - NTVRegListNode, - NTVRegNode, - NTConstNode, - NTLabelNode }; - InstrTreeNode* LeftChild; - InstrTreeNode* RightChild; - InstrTreeNode* Parent; - OpLabel opLabel; - StateLabel state; - -protected: - InstrTreeNodeType treeNodeType; - Value* val; - -public: - InstrTreeNode(InstrTreeNodeType nodeType, Value* _val) - : treeNodeType(nodeType), val(_val) { - LeftChild = RightChild = Parent = 0; - opLabel = InvalidOp; - } - virtual ~InstrTreeNode() { - delete LeftChild; - delete RightChild; - } - InstrTreeNodeType getNodeType () const { return treeNodeType; } - Value* getValue () const { return val; } - inline OpLabel getOpLabel () const { return opLabel; } - inline InstrTreeNode *leftChild () const { return LeftChild; } - inline InstrTreeNode *parent () const { return Parent; } - - // If right child is a list node, recursively get its *left* child - inline InstrTreeNode* rightChild() const { - return (!RightChild ? 0 : - (RightChild->getOpLabel() == VRegListOp - ? RightChild->LeftChild : RightChild)); - } - void dump(int dumpChildren, int indent) const; -protected: - virtual void dumpNode(int indent) const = 0; - friend class InstrForest; -}; - -} // end namespace llvm. - -#endif diff --git a/lib/Target/SparcV9/SparcV9InstrInfo.h b/lib/Target/SparcV9/SparcV9InstrInfo.h deleted file mode 100644 index ac8fdc018fc..00000000000 --- a/lib/Target/SparcV9/SparcV9InstrInfo.h +++ /dev/null @@ -1,77 +0,0 @@ -//===-- SparcV9InstrInfo.h - Define TargetInstrInfo for SparcV9 -*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This class contains information about individual instructions. -// Also see the SparcV9MachineInstrDesc array, which can be found in -// SparcV9TargetMachine.cpp. -// Other information is computed on demand, and most such functions -// default to member functions in base class TargetInstrInfo. -// -//===----------------------------------------------------------------------===// - -#ifndef SPARCV9INSTRINFO_H -#define SPARCV9INSTRINFO_H - -#include "llvm/Target/TargetInstrInfo.h" -#include "llvm/CodeGen/MachineInstr.h" -#include "SparcV9Internals.h" -#include "SparcV9RegisterInfo.h" - -namespace llvm { - -/// SparcV9InstrInfo - TargetInstrInfo specialized for the SparcV9 target. -/// -struct SparcV9InstrInfo : public TargetInstrInfo { - const SparcV9RegisterInfo RI; -public: - SparcV9InstrInfo() - : TargetInstrInfo(SparcV9MachineInstrDesc, V9::NUM_TOTAL_OPCODES) { } - - /// getRegisterInfo - TargetInstrInfo is a superset of MRegister info. As - /// such, whenever a client has an instance of instruction info, it should - /// always be able to get register info as well (through this method). - /// - virtual const MRegisterInfo &getRegisterInfo() const { return RI; } - - // All immediate constants are in position 1 except the - // store instructions and SETxx. - // - virtual int getImmedConstantPos(MachineOpCode opCode) const { - bool ignore; - if (this->maxImmedConstant(opCode, ignore) != 0) { - // 1st store opcode - assert(! this->isStore((MachineOpCode) V9::STBr - 1)); - // last store opcode - assert(! this->isStore((MachineOpCode) V9::STXFSRi + 1)); - - if (opCode == V9::SETHI) - return 0; - if (opCode >= V9::STBr && opCode <= V9::STXFSRi) - return 2; - return 1; - } - else - return -1; - } - - virtual bool hasResultInterlock(MachineOpCode opCode) const - { - // All UltraSPARC instructions have interlocks (note that delay slots - // are not considered here). - // However, instructions that use the result of an FCMP produce a - // 9-cycle stall if they are issued less than 3 cycles after the FCMP. - // Force the compiler to insert a software interlock (i.e., gap of - // 2 other groups, including NOPs if necessary). - return (opCode == V9::FCMPS || opCode == V9::FCMPD || opCode == V9::FCMPQ); - } -}; - -} // End llvm namespace - -#endif diff --git a/lib/Target/SparcV9/SparcV9InstrInfo.td b/lib/Target/SparcV9/SparcV9InstrInfo.td deleted file mode 100644 index e813cfaddaf..00000000000 --- a/lib/Target/SparcV9/SparcV9InstrInfo.td +++ /dev/null @@ -1,777 +0,0 @@ -//===- SparcV9InstrInfo.td - SparcV9 Instruction defs ------*- tablegen -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This files declares the set of instructions used in the SparcV9 backend. -// -//===----------------------------------------------------------------------===// - -class InstV9 : Instruction { // SparcV9 instruction baseline - field bits<32> Inst; - - let Namespace = "V9"; - - bits<2> op; - let Inst{31-30} = op; // Top two bits are the 'op' field - - // Bit attributes specific to SparcV9 instructions - bit isPasi = 0; // Does this instruction affect an alternate addr space? - bit isDeprecated = 0; // Is this instruction deprecated? - bit isPrivileged = 0; // Is this a privileged instruction? -} - -class Pseudo : 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 -} diff --git a/lib/Target/SparcV9/SparcV9Internals.h b/lib/Target/SparcV9/SparcV9Internals.h deleted file mode 100644 index b770f0bbc4f..00000000000 --- a/lib/Target/SparcV9/SparcV9Internals.h +++ /dev/null @@ -1,133 +0,0 @@ -//===-- SparcV9Internals.h --------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines stuff that is to be private to the SparcV9 backend, but is -// shared among different portions of the backend. -// -//===----------------------------------------------------------------------===// - -#ifndef SPARCV9INTERNALS_H -#define SPARCV9INTERNALS_H - -#include "llvm/CodeGen/MachineInstrBuilder.h" -#include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetSchedInfo.h" -#include "llvm/Target/TargetFrameInfo.h" -#include "SparcV9RegInfo.h" -#include "llvm/Type.h" -#include "SparcV9RegClassInfo.h" - -namespace llvm { - -class V9LiveRange; -class SparcV9TargetMachine; -class ModulePass; -class GetElementPtrInst; - -enum SparcV9InstrSchedClass { - SPARC_NONE, /* Instructions with no scheduling restrictions */ - SPARC_IEUN, /* Integer class that can use IEU0 or IEU1 */ - SPARC_IEU0, /* Integer class IEU0 */ - SPARC_IEU1, /* Integer class IEU1 */ - SPARC_FPM, /* FP Multiply or Divide instructions */ - SPARC_FPA, /* All other FP instructions */ - SPARC_CTI, /* Control-transfer instructions */ - SPARC_LD, /* Load instructions */ - SPARC_ST, /* Store instructions */ - SPARC_SINGLE, /* Instructions that must issue by themselves */ - - SPARC_INV, /* This should stay at the end for the next value */ - SPARC_NUM_SCHED_CLASSES = SPARC_INV -}; - - -//--------------------------------------------------------------------------- -// enum SparcV9MachineOpCode. -// const TargetInstrDescriptor SparcV9MachineInstrDesc[] -// -// Purpose: -// Description of UltraSparcV9 machine instructions. -// -//--------------------------------------------------------------------------- - -namespace V9 { - enum SparcV9MachineOpCode { -#define I(ENUM, OPCODESTRING, NUMOPERANDS, RESULTPOS, MAXIMM, IMMSE, \ - NUMDELAYSLOTS, LATENCY, SCHEDCLASS, INSTFLAGS) \ - ENUM, -#include "SparcV9Instr.def" - - // End-of-array marker - INVALID_OPCODE, - NUM_REAL_OPCODES = PHI, // number of valid opcodes - NUM_TOTAL_OPCODES = INVALID_OPCODE - }; -} - -// Array of machine instruction descriptions... -extern const TargetInstrDescriptor SparcV9MachineInstrDesc[]; - -//--------------------------------------------------------------------------- -// class SparcV9SchedInfo -// -// Purpose: -// Interface to instruction scheduling information for UltraSPARC. -// The parameter values above are based on UltraSPARC IIi. -//--------------------------------------------------------------------------- - -class SparcV9SchedInfo: public TargetSchedInfo { -public: - SparcV9SchedInfo(const TargetMachine &tgt); -protected: - virtual void initializeResources(); -}; - -/// createStackSlotsPass - External interface to stack-slots pass that enters 2 -/// empty slots at the top of each function stack -/// -FunctionPass *createStackSlotsPass(const TargetMachine &TM); - -/// Specializes LLVM code for a target machine. -/// -FunctionPass *createPreSelectionPass(const TargetMachine &TM); - -// DecomposeMultiDimRefs - Convert multi-dimensional references consisting of -// any combination of 2 or more array and structure indices into a sequence of -// instructions (using getelementpr and cast) so that each instruction has at -// most one index (except structure references, which need an extra leading -// index of [0]). -// This pass decomposes all multi-dimensional references in a function. -FunctionPass *createDecomposeMultiDimRefsPass(); - -// This function decomposes a single instance of such a reference. -// Return value: true if the instruction was replaced; false otherwise. -// -bool DecomposeArrayRef(GetElementPtrInst* GEP); - -/// Peephole optimization pass operating on machine code -/// -FunctionPass *createPeepholeOptsPass(const TargetMachine &TM); - -/// Writes out assembly code for the module, one function at a time -/// -FunctionPass *createAsmPrinterPass(std::ostream &Out, TargetMachine &TM); - -/// getPrologEpilogInsertionPass - Inserts prolog/epilog code. -/// -FunctionPass* createPrologEpilogInsertionPass(); - -/// getBytecodeAsmPrinterPass - Emits final LLVM bytecode to assembly file. -/// -ModulePass* createBytecodeAsmPrinterPass(std::ostream &Out); - -FunctionPass *createSparcV9MachineCodeDestructionPass(); - -} // End llvm namespace - -#endif diff --git a/lib/Target/SparcV9/SparcV9JITInfo.cpp b/lib/Target/SparcV9/SparcV9JITInfo.cpp deleted file mode 100644 index 2aefab418ab..00000000000 --- a/lib/Target/SparcV9/SparcV9JITInfo.cpp +++ /dev/null @@ -1,355 +0,0 @@ -//===-- SparcJITInfo.cpp - Implement the JIT interfaces for SparcV9 -------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the JIT interfaces for the SparcV9 target. -// -//===----------------------------------------------------------------------===// - -#define DEBUG_TYPE "jit" -#include "SparcV9JITInfo.h" -#include "SparcV9Relocations.h" -#include "llvm/CodeGen/MachineCodeEmitter.h" -#include "llvm/Config/alloca.h" -#include "llvm/Support/Debug.h" -#include -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 - 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 , 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; - } - } -} diff --git a/lib/Target/SparcV9/SparcV9JITInfo.h b/lib/Target/SparcV9/SparcV9JITInfo.h deleted file mode 100644 index 8bbb2d9358d..00000000000 --- a/lib/Target/SparcV9/SparcV9JITInfo.h +++ /dev/null @@ -1,62 +0,0 @@ -//===- SparcV9JITInfo.h - SparcV9 Target JIT interface ----------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file contains the SparcV9 implementation of the TargetJITInfo class, -// which makes target-specific hooks available to the target-independent -// LLVM JIT compiler. -// -//===----------------------------------------------------------------------===// - -#ifndef SPARCV9JITINFO_H -#define SPARCV9JITINFO_H - -#include "llvm/Target/TargetJITInfo.h" - -namespace llvm { - class TargetMachine; - - class SparcV9JITInfo : public TargetJITInfo { - TargetMachine &TM; - public: - SparcV9JITInfo(TargetMachine &tm) : TM(tm) {useGOT = 0;} - - /// addPassesToJITCompile - Add passes to the specified pass manager to - /// implement a fast dynamic compiler for this target. Return true if this - /// is not supported for this target. - /// - virtual void addPassesToJITCompile(FunctionPassManager &PM); - - /// replaceMachineCodeForFunction - Make it so that calling the function - /// whose machine code is at OLD turns into a call to NEW, perhaps by - /// overwriting OLD with a branch to NEW. This is used for self-modifying - /// code. - /// - virtual void replaceMachineCodeForFunction (void *Old, void *New); - - - /// emitFunctionStub - Use the specified MachineCodeEmitter object to emit a - /// small native function that simply calls the function at the specified - /// address. Return the address of the resultant function. - virtual void *emitFunctionStub(void *Fn, MachineCodeEmitter &MCE); - - /// getLazyResolverFunction - This method is used to initialize the JIT, - /// giving the target the function that should be used to compile a - /// function, and giving the JIT the target function used to do the lazy - /// resolving. - virtual LazyResolverFn getLazyResolverFunction(JITCompilerFn); - - /// relocate - Before the JIT can run a block of code that has been emitted, - /// it must rewrite the code to contain the actual addresses of any - /// referenced global symbols. - virtual void relocate(void *Function, MachineRelocation *MR, - unsigned NumRelocs, unsigned char* GOTBase); - }; -} - -#endif diff --git a/lib/Target/SparcV9/SparcV9PeepholeOpts.cpp b/lib/Target/SparcV9/SparcV9PeepholeOpts.cpp deleted file mode 100644 index 531a1fe96a0..00000000000 --- a/lib/Target/SparcV9/SparcV9PeepholeOpts.cpp +++ /dev/null @@ -1,163 +0,0 @@ -//===-- SparcV9PeepholeOpts.cpp -------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Support for performing several peephole opts in one or a few passes over the -// machine code of a method. -// -//===----------------------------------------------------------------------===// - -#include "SparcV9Internals.h" -#include "llvm/BasicBlock.h" -#include "llvm/Pass.h" -#include "llvm/CodeGen/MachineFunction.h" -#include "llvm/CodeGen/MachineInstr.h" -#include "llvm/Target/TargetInstrInfo.h" -#include "llvm/Target/TargetMachine.h" -#include "llvm/ADT/STLExtras.h" - -namespace llvm { - -//************************* Internal Functions *****************************/ - -static inline void -DeleteInstruction(MachineBasicBlock& mvec, - MachineBasicBlock::iterator& BBI, - const TargetMachine& target) { - // Check if this instruction is in a delay slot of its predecessor. - if (BBI != mvec.begin()) { - const TargetInstrInfo& mii = *target.getInstrInfo(); - MachineBasicBlock::iterator predMI = prior(BBI); - if (unsigned ndelay = mii.getNumDelaySlots(predMI->getOpcode())) { - // This instruction is in a delay slot of its predecessor, so - // replace it with a nop. By replacing in place, we save having - // to update the I-I maps. - // - assert(ndelay == 1 && "Not yet handling multiple-delay-slot targets"); - BBI->replace(V9::NOP, 0); - return; - } - } - - // The instruction is not in a delay slot, so we can simply erase it. - mvec.erase(BBI); - BBI = mvec.end(); -} - -//******************* Individual Peephole Optimizations ********************/ - -//---------------------------------------------------------------------------- -// Function: IsUselessCopy -// Decide whether a machine instruction is a redundant copy: -// -- ADD with g0 and result and operand are identical, or -// -- OR with g0 and result and operand are identical, or -// -- FMOVS or FMOVD and result and operand are identical. -// Other cases are possible but very rare that they would be useless copies, -// so it's not worth analyzing them. -//---------------------------------------------------------------------------- - -static bool IsUselessCopy(const TargetMachine &target, const MachineInstr* MI) { - if (MI->getOpcode() == V9::FMOVS || MI->getOpcode() == V9::FMOVD) { - return (// both operands are allocated to the same register - MI->getOperand(0).getReg() == MI->getOperand(1).getReg()); - } else if (MI->getOpcode() == V9::ADDr || MI->getOpcode() == V9::ORr || - MI->getOpcode() == V9::ADDi || MI->getOpcode() == V9::ORi) { - unsigned srcWithDestReg; - - for (srcWithDestReg = 0; srcWithDestReg < 2; ++srcWithDestReg) - if (MI->getOperand(srcWithDestReg).hasAllocatedReg() && - MI->getOperand(srcWithDestReg).getReg() - == MI->getOperand(2).getReg()) - break; - - if (srcWithDestReg == 2) - return false; - else { - // else source and dest are allocated to the same register - unsigned otherOp = 1 - srcWithDestReg; - return (// either operand otherOp is register %g0 - (MI->getOperand(otherOp).hasAllocatedReg() && - MI->getOperand(otherOp).getReg() == - target.getRegInfo()->getZeroRegNum()) || - - // or operand otherOp == 0 - (MI->getOperand(otherOp).getType() - == MachineOperand::MO_SignExtendedImmed && - MI->getOperand(otherOp).getImmedValue() == 0)); - } - } - else - return false; -} - -inline bool -RemoveUselessCopies(MachineBasicBlock& mvec, - MachineBasicBlock::iterator& BBI, - const TargetMachine& target) { - if (IsUselessCopy(target, BBI)) { - DeleteInstruction(mvec, BBI, target); - return true; - } - return false; -} - - -//************************ Class Implementations **************************/ - -class PeepholeOpts: public BasicBlockPass { - const TargetMachine ⌖ - bool visit(MachineBasicBlock& mvec, - MachineBasicBlock::iterator BBI) const; -public: - PeepholeOpts(const TargetMachine &TM): target(TM) { } - bool runOnBasicBlock(BasicBlock &BB); // apply this pass to each BB - virtual const char *getPassName() const { return "Peephole Optimization"; } - - // getAnalysisUsage - this pass preserves the CFG - void getAnalysisUsage(AnalysisUsage &AU) const { - AU.setPreservesCFG(); - } -}; - -// Apply a list of peephole optimizations to this machine instruction -// within its local context. They are allowed to delete MI or any -// instruction before MI, but not -// -bool PeepholeOpts::visit(MachineBasicBlock& mvec, - MachineBasicBlock::iterator BBI) const { - // Remove redundant copy instructions - return RemoveUselessCopies(mvec, BBI, target); -} - - -bool PeepholeOpts::runOnBasicBlock(BasicBlock &BB) { - // Get the machine instructions for this BB - // FIXME: MachineBasicBlock::get() is deprecated, hence inlining the function - const Function *F = BB.getParent(); - MachineFunction &MF = MachineFunction::get(F); - MachineBasicBlock *MBB = NULL; - for (MachineFunction::iterator I = MF.begin(), E = MF.end(); I != E; ++I) - if (I->getBasicBlock() == &BB) - MBB = I; - - assert(MBB && "MachineBasicBlock object not found for specified block!"); - MachineBasicBlock &mvec = *MBB; - - for (MachineBasicBlock::iterator I = mvec.begin(), E = mvec.end(); I != E; ) - visit(mvec, I++); - - return true; -} - -/// createPeepholeOptsPass - Public entry point for peephole optimization -/// -FunctionPass* createPeepholeOptsPass(const TargetMachine &TM) { - return new PeepholeOpts(TM); -} - -} // End llvm namespace diff --git a/lib/Target/SparcV9/SparcV9PreSelection.cpp b/lib/Target/SparcV9/SparcV9PreSelection.cpp deleted file mode 100644 index a13019e2061..00000000000 --- a/lib/Target/SparcV9/SparcV9PreSelection.cpp +++ /dev/null @@ -1,308 +0,0 @@ -//===- SparcV9PreSelection.cpp - Specialize LLVM code for SparcV9 ---------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the PreSelection pass which specializes LLVM code for -// the SparcV9 instruction selector, while remaining in legal portable LLVM -// form and preserving type information and type safety. This is meant to enable -// dataflow optimizations on SparcV9-specific operations such as accesses to -// constants, globals, and array indexing. -// -//===----------------------------------------------------------------------===// - -#include "SparcV9Internals.h" -#include "SparcV9BurgISel.h" -#include "llvm/Constants.h" -#include "llvm/DerivedTypes.h" -#include "llvm/Instructions.h" -#include "llvm/Module.h" -#include "llvm/Pass.h" -#include "llvm/Support/InstVisitor.h" -#include "llvm/Support/GetElementPtrTypeIterator.h" -#include "llvm/Target/TargetInstrInfo.h" -#include "llvm/Target/TargetMachine.h" -#include "llvm/Transforms/Scalar.h" -#include -using namespace llvm; - -namespace { - - //===--------------------------------------------------------------------===// - // PreSelection Pass - Specialize LLVM code for the SparcV9 instr. selector. - // - class PreSelection : public FunctionPass, public InstVisitor { - 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(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 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(ptr)) - ? new GetElementPtrInst(ptr, - std::vector(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(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(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(getArg1)) - getArg1 = DecomposeConstantExpr(CEarg, insertBefore); - else if (GetElementPtrInst* gep = getGlobalAddr(getArg1, insertBefore)) - getArg1 = gep; - return new GetElementPtrInst(getArg1, - std::vector(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 (C)) - C = DecomposeConstantExpr (CEarg, insertBefore); - S1 = CE->getOperand (1); - if (ConstantExpr* CEarg = dyn_cast (S1)) - S1 = DecomposeConstantExpr (CEarg, insertBefore); - S2 = CE->getOperand (2); - if (ConstantExpr* CEarg = dyn_cast (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(getArg1)) - getArg1 = DecomposeConstantExpr(CEarg, insertBefore); - getArg2 = CE->getOperand(1); - if (ConstantExpr* CEarg = dyn_cast(getArg2)) - getArg2 = DecomposeConstantExpr(CEarg, insertBefore); - return new ShiftInst (static_cast(CE->getOpcode()), - getArg1, getArg2, - "constantShr:" + getArg1->getName(), &insertBefore); - } - - case Instruction::Shl: { - getArg1 = CE->getOperand(0); - if (ConstantExpr* CEarg = dyn_cast(getArg1)) - getArg1 = DecomposeConstantExpr(CEarg, insertBefore); - getArg2 = CE->getOperand(1); - if (ConstantExpr* CEarg = dyn_cast(getArg2)) - getArg2 = DecomposeConstantExpr(CEarg, insertBefore); - return new ShiftInst (static_cast(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(getArg1)) - getArg1 = DecomposeConstantExpr(CEarg, insertBefore); - getArg2 = CE->getOperand(1); - if (ConstantExpr* CEarg = dyn_cast(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(CVT)); - return !(CVT->isIntegral() || isa(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(Op); - if (CV == NULL) - return; - - if (ConstantExpr* CE = dyn_cast(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 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(*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(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); -} diff --git a/lib/Target/SparcV9/SparcV9PrologEpilogInserter.cpp b/lib/Target/SparcV9/SparcV9PrologEpilogInserter.cpp deleted file mode 100644 index 1204dda85dd..00000000000 --- a/lib/Target/SparcV9/SparcV9PrologEpilogInserter.cpp +++ /dev/null @@ -1,184 +0,0 @@ -//===-- SparcV9PrologEpilogCodeInserter.cpp - Insert Fn Prolog & Epilog ---===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This is the SparcV9 target's own PrologEpilogInserter. It creates prolog and -// epilog instructions for functions which have not been compiled using "leaf -// function optimizations". These instructions include the SAVE and RESTORE -// instructions used to rotate the SPARC register windows. Prologs are -// attached to the unique function entry, and epilogs are attached to each -// function exit. -// -//===----------------------------------------------------------------------===// - -#include "SparcV9Internals.h" -#include "SparcV9RegClassInfo.h" -#include "SparcV9RegisterInfo.h" -#include "SparcV9FrameInfo.h" -#include "MachineFunctionInfo.h" -#include "MachineCodeForInstruction.h" -#include "llvm/CodeGen/MachineFunctionPass.h" -#include "llvm/CodeGen/MachineInstrBuilder.h" -#include "llvm/Pass.h" -#include "llvm/Function.h" -#include "llvm/DerivedTypes.h" -#include "llvm/Intrinsics.h" - -namespace llvm { - -namespace { - struct InsertPrologEpilogCode : public MachineFunctionPass { - const char *getPassName() const { return "SparcV9 Prolog/Epilog Inserter"; } - - bool runOnMachineFunction(MachineFunction &F) { - if (!F.getInfo()->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()->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 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 diff --git a/lib/Target/SparcV9/SparcV9RegClassInfo.cpp b/lib/Target/SparcV9/SparcV9RegClassInfo.cpp deleted file mode 100644 index 6467d7bcaf0..00000000000 --- a/lib/Target/SparcV9/SparcV9RegClassInfo.cpp +++ /dev/null @@ -1,397 +0,0 @@ -//===-- SparcV9RegClassInfo.cpp - Register class def'ns for SparcV9 -------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the methods used by the SparcV9 register allocator -// to pick registers of various classes. Most of this code should be -// considered part of the register allocator. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Type.h" -#include "SparcV9RegClassInfo.h" -#include "SparcV9Internals.h" -#include "SparcV9RegInfo.h" -#include "RegAlloc/RegAllocCommon.h" -#include "RegAlloc/IGNode.h" -#include - -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 &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 &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(setCCType)); - int ccReg = ((isa(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(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 &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 &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 &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 &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 &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 diff --git a/lib/Target/SparcV9/SparcV9RegClassInfo.h b/lib/Target/SparcV9/SparcV9RegClassInfo.h deleted file mode 100644 index 532e2e999e8..00000000000 --- a/lib/Target/SparcV9/SparcV9RegClassInfo.h +++ /dev/null @@ -1,224 +0,0 @@ -//===-- SparcV9RegClassInfo.h - Register class def'ns for SparcV9 -*- C++ -*-=// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the register classes used by the SparcV9 target. It -// implicitly defines (using enums) the "class register numbers" used in -// the SparcV9 target, which are converted using a formula in the SparcV9RegInfo -// class to "unified register numbers". -// -//===----------------------------------------------------------------------===// - -#ifndef SPARCV9REGCLASSINFO_H -#define SPARCV9REGCLASSINFO_H - -#include "SparcV9RegInfo.h" - -namespace llvm { - -//----------------------------------------------------------------------------- -// Integer Register Class -//----------------------------------------------------------------------------- - -struct SparcV9IntRegClass : public TargetRegClassInfo { - SparcV9IntRegClass(unsigned ID) - : TargetRegClassInfo(ID, NumOfAvailRegs, NumOfAllRegs) { } - - void colorIGNode(IGNode *Node, - const std::vector &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 &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 &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 &IsColorUsedArr) const; - - void colorIGNode(IGNode *Node, - const std::vector &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 &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 &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 &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 diff --git a/lib/Target/SparcV9/SparcV9RegInfo.cpp b/lib/Target/SparcV9/SparcV9RegInfo.cpp deleted file mode 100644 index 0a88e07fd35..00000000000 --- a/lib/Target/SparcV9/SparcV9RegInfo.cpp +++ /dev/null @@ -1,973 +0,0 @@ -//===-- SparcV9RegInfo.cpp - SparcV9 Target Register Information ----------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file contains implementations of SparcV9 specific helper methods -// used for register allocation. -// -//===----------------------------------------------------------------------===// - -#include "llvm/CodeGen/MachineFunction.h" -#include "llvm/CodeGen/MachineInstrBuilder.h" -#include "MachineFunctionInfo.h" -#include "MachineCodeForInstruction.h" -#include "MachineInstrAnnot.h" -#include "RegAlloc/LiveRangeInfo.h" -#include "RegAlloc/LiveRange.h" -#include "llvm/DerivedTypes.h" -#include "llvm/Function.h" -#include "llvm/Instructions.h" -#include "SparcV9Internals.h" -#include "SparcV9RegClassInfo.h" -#include "SparcV9RegInfo.h" -#include "SparcV9FrameInfo.h" -#include "SparcV9TargetMachine.h" -#include "SparcV9TmpInstr.h" -#include - -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(cast(funcType) - ->getElementType())->isVarArg(); -} - -inline bool -isVarArgsCall(const MachineInstr *CallMI) { - Value* callee = CallMI->getOperand(0).getVRegValue(); - // const Type* funcType = isa(callee)? callee->getType() - // : cast(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& InstrnsBefore, - std::vector& 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()->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(cast(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& 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& 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& 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& 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 diff --git a/lib/Target/SparcV9/SparcV9RegInfo.h b/lib/Target/SparcV9/SparcV9RegInfo.h deleted file mode 100644 index a992b31aa45..00000000000 --- a/lib/Target/SparcV9/SparcV9RegInfo.h +++ /dev/null @@ -1,381 +0,0 @@ -//===-- SparcV9RegInfo.h - SparcV9 Target Register Info ---------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file is used to describe the register file of the SparcV9 target to -// its register allocator. -// -//===----------------------------------------------------------------------===// - -#ifndef SPARCV9REGINFO_H -#define SPARCV9REGINFO_H - -#include "llvm/ADT/hash_map" -#include -#include - -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 &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 &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 &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 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& InstrnsBefore, - std::vector& 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& mvec, - unsigned SrcReg, unsigned DestReg, - int RegType) const; - - void cpReg2MemMI(std::vector& mvec, - unsigned SrcReg, unsigned DestPtrReg, - int Offset, int RegType, int scratchReg = -1) const; - - void cpMem2RegMI(std::vector& mvec, - unsigned SrcPtrReg, int Offset, unsigned DestReg, - int RegType, int scratchReg = -1) const; - - void cpValue2Value(Value *Src, Value *Dest, - std::vector& 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 diff --git a/lib/Target/SparcV9/SparcV9RegisterInfo.cpp b/lib/Target/SparcV9/SparcV9RegisterInfo.cpp deleted file mode 100644 index a49525b46e4..00000000000 --- a/lib/Target/SparcV9/SparcV9RegisterInfo.cpp +++ /dev/null @@ -1,333 +0,0 @@ -//===- SparcV9RegisterInfo.cpp - SparcV9 Register Information ---*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file contains the SparcV9 implementation of the MRegisterInfo class. -// It also contains stuff needed to instantiate that class, which would -// ordinarily be provided by TableGen. -// -// This is NOT used by the SparcV9 backend to do register allocation, yet. -// -//===----------------------------------------------------------------------===// -// -// The first section of this file (immediately following) is what -// you would find in SparcV9GenRegisterInfo.inc, if we were using -// TableGen to generate the register file description automatically. -// It consists of register classes and register class instances -// for the SparcV9 target. -// -// FIXME: the alignments listed here are wild guesses. -// -//===----------------------------------------------------------------------===// - -#include "SparcV9RegisterInfo.h" -#include "llvm/CodeGen/MachineFunction.h" -#include "llvm/CodeGen/ValueTypes.h" -using namespace llvm; - -namespace llvm { - -namespace { - // IR Register Class... - const unsigned IR[] = { - SparcV9::o0, SparcV9::o1, SparcV9::o2, SparcV9::o3, SparcV9::o4, - SparcV9::o5, SparcV9::o7, SparcV9::l0, SparcV9::l1, SparcV9::l2, - SparcV9::l3, SparcV9::l4, SparcV9::l5, SparcV9::l6, SparcV9::l7, - SparcV9::i0, SparcV9::i1, SparcV9::i2, SparcV9::i3, SparcV9::i4, - SparcV9::i5, SparcV9::i6, SparcV9::i7, SparcV9::g0, SparcV9::g1, - SparcV9::g2, SparcV9::g3, SparcV9::g4, SparcV9::g5, SparcV9::g6, - SparcV9::g7, SparcV9::o6 - }; - const MVT::ValueType IRVTs[] = { MVT::i64, MVT::Other }; - struct IRClass : public TargetRegisterClass { - IRClass() : TargetRegisterClass(IRVTs, 8, 8, IR, IR + 32) {} - } IRInstance; - - - // FR Register Class... - const unsigned FR[] = { - SparcV9::f0, SparcV9::f1, SparcV9::f2, SparcV9::f3, SparcV9::f4, - SparcV9::f5, SparcV9::f6, SparcV9::f7, SparcV9::f8, SparcV9::f9, - SparcV9::f10, SparcV9::f11, SparcV9::f12, SparcV9::f13, - SparcV9::f14, SparcV9::f15, SparcV9::f16, SparcV9::f17, - SparcV9::f18, SparcV9::f19, SparcV9::f20, SparcV9::f21, - SparcV9::f22, SparcV9::f23, SparcV9::f24, SparcV9::f25, - SparcV9::f26, SparcV9::f27, SparcV9::f28, SparcV9::f29, - SparcV9::f30, SparcV9::f31, SparcV9::f32, SparcV9::f33, - SparcV9::f34, SparcV9::f35, SparcV9::f36, SparcV9::f37, - SparcV9::f38, SparcV9::f39, SparcV9::f40, SparcV9::f41, - SparcV9::f42, SparcV9::f43, SparcV9::f44, SparcV9::f45, - SparcV9::f46, SparcV9::f47, SparcV9::f48, SparcV9::f49, - SparcV9::f50, SparcV9::f51, SparcV9::f52, SparcV9::f53, - SparcV9::f54, SparcV9::f55, SparcV9::f56, SparcV9::f57, - SparcV9::f58, SparcV9::f59, SparcV9::f60, SparcV9::f61, - SparcV9::f62, SparcV9::f63 - }; - const MVT::ValueType FRVTs[] = { MVT::f32, MVT::Other }; - // FIXME: The size is correct for the first 32 registers. The - // latter 32 do not all really exist; you can only access every other - // one (32, 34, ...), and they must contain double-fp or quad-fp - // values... see below about the aliasing problems. - struct FRClass : public TargetRegisterClass { - FRClass() : TargetRegisterClass(FRVTs, 4, 8, FR, FR + 64) {} - } FRInstance; - - - // ICCR Register Class... - const unsigned ICCR[] = { - SparcV9::xcc, SparcV9::icc, SparcV9::ccr - }; - const MVT::ValueType ICCRVTs[] = { MVT::i1, MVT::Other }; - struct ICCRClass : public TargetRegisterClass { - ICCRClass() : TargetRegisterClass(ICCRVTs, 1, 8, ICCR, ICCR + 3) {} - } ICCRInstance; - - - // FCCR Register Class... - const unsigned FCCR[] = { - SparcV9::fcc0, SparcV9::fcc1, SparcV9::fcc2, SparcV9::fcc3 - }; - const MVT::ValueType FCCRVTs[] = { MVT::i1, MVT::Other }; - struct FCCRClass : public TargetRegisterClass { - FCCRClass() : TargetRegisterClass(FCCRVTs, 1, 8, FCCR, FCCR + 4) {} - } FCCRInstance; - - - // SR Register Class... - const unsigned SR[] = { - SparcV9::fsr - }; - const MVT::ValueType SRVTs[] = { MVT::i64, MVT::Other }; - struct SRClass : public TargetRegisterClass { - SRClass() : TargetRegisterClass(SRVTs, 8, 8, SR, SR + 1) {} - } SRInstance; - - - // Register Classes... - const TargetRegisterClass* const RegisterClasses[] = { - &IRInstance, - &FRInstance, - &ICCRInstance, - &FCCRInstance, - &SRInstance - }; - - - // Register Alias Sets... - // FIXME: Note that the SparcV9 backend does not currently abstract - // very well over the way that double-fp and quad-fp values may alias - // single-fp values in registers. Therefore those aliases are NOT - // reflected here. - const unsigned Empty_AliasSet[] = { 0 }; - const unsigned fcc3_AliasSet[] = { SparcV9::fsr, 0 }; - const unsigned fcc2_AliasSet[] = { SparcV9::fsr, 0 }; - const unsigned fcc1_AliasSet[] = { SparcV9::fsr, 0 }; - const unsigned fcc0_AliasSet[] = { SparcV9::fsr, 0 }; - const unsigned fsr_AliasSet[] = { SparcV9::fcc3, SparcV9::fcc2, - SparcV9::fcc1, SparcV9::fcc0, 0 }; - const unsigned xcc_AliasSet[] = { SparcV9::ccr, 0 }; - const unsigned icc_AliasSet[] = { SparcV9::ccr, 0 }; - const unsigned ccr_AliasSet[] = { SparcV9::xcc, SparcV9::icc, 0 }; - -const TargetRegisterDesc RegisterDescriptors[] = { // Descriptors - { "o0", Empty_AliasSet }, - { "o1", Empty_AliasSet }, - { "o2", Empty_AliasSet }, - { "o3", Empty_AliasSet }, - { "o4", Empty_AliasSet }, - { "o5", Empty_AliasSet }, - { "o7", Empty_AliasSet }, - { "l0", Empty_AliasSet }, - { "l1", Empty_AliasSet }, - { "l2", Empty_AliasSet }, - { "l3", Empty_AliasSet }, - { "l4", Empty_AliasSet }, - { "l5", Empty_AliasSet }, - { "l6", Empty_AliasSet }, - { "l7", Empty_AliasSet }, - { "i0", Empty_AliasSet }, - { "i1", Empty_AliasSet }, - { "i2", Empty_AliasSet }, - { "i3", Empty_AliasSet }, - { "i4", Empty_AliasSet }, - { "i5", Empty_AliasSet }, - { "i6", Empty_AliasSet }, - { "i7", Empty_AliasSet }, - { "g0", Empty_AliasSet }, - { "g1", Empty_AliasSet }, - { "g2", Empty_AliasSet }, - { "g3", Empty_AliasSet }, - { "g4", Empty_AliasSet }, - { "g5", Empty_AliasSet }, - { "g6", Empty_AliasSet }, - { "g7", Empty_AliasSet }, - { "o6", Empty_AliasSet }, - { "f0", Empty_AliasSet }, - { "f1", Empty_AliasSet }, - { "f2", Empty_AliasSet }, - { "f3", Empty_AliasSet }, - { "f4", Empty_AliasSet }, - { "f5", Empty_AliasSet }, - { "f6", Empty_AliasSet }, - { "f7", Empty_AliasSet }, - { "f8", Empty_AliasSet }, - { "f9", Empty_AliasSet }, - { "f10", Empty_AliasSet }, - { "f11", Empty_AliasSet }, - { "f12", Empty_AliasSet }, - { "f13", Empty_AliasSet }, - { "f14", Empty_AliasSet }, - { "f15", Empty_AliasSet }, - { "f16", Empty_AliasSet }, - { "f17", Empty_AliasSet }, - { "f18", Empty_AliasSet }, - { "f19", Empty_AliasSet }, - { "f20", Empty_AliasSet }, - { "f21", Empty_AliasSet }, - { "f22", Empty_AliasSet }, - { "f23", Empty_AliasSet }, - { "f24", Empty_AliasSet }, - { "f25", Empty_AliasSet }, - { "f26", Empty_AliasSet }, - { "f27", Empty_AliasSet }, - { "f28", Empty_AliasSet }, - { "f29", Empty_AliasSet }, - { "f30", Empty_AliasSet }, - { "f31", Empty_AliasSet }, - { "f32", Empty_AliasSet }, - { "f33", Empty_AliasSet }, - { "f34", Empty_AliasSet }, - { "f35", Empty_AliasSet }, - { "f36", Empty_AliasSet }, - { "f37", Empty_AliasSet }, - { "f38", Empty_AliasSet }, - { "f39", Empty_AliasSet }, - { "f40", Empty_AliasSet }, - { "f41", Empty_AliasSet }, - { "f42", Empty_AliasSet }, - { "f43", Empty_AliasSet }, - { "f44", Empty_AliasSet }, - { "f45", Empty_AliasSet }, - { "f46", Empty_AliasSet }, - { "f47", Empty_AliasSet }, - { "f48", Empty_AliasSet }, - { "f49", Empty_AliasSet }, - { "f50", Empty_AliasSet }, - { "f51", Empty_AliasSet }, - { "f52", Empty_AliasSet }, - { "f53", Empty_AliasSet }, - { "f54", Empty_AliasSet }, - { "f55", Empty_AliasSet }, - { "f56", Empty_AliasSet }, - { "f57", Empty_AliasSet }, - { "f58", Empty_AliasSet }, - { "f59", Empty_AliasSet }, - { "f60", Empty_AliasSet }, - { "f61", Empty_AliasSet }, - { "f62", Empty_AliasSet }, - { "f63", Empty_AliasSet }, - { "xcc", xcc_AliasSet }, - { "icc", icc_AliasSet }, - { "ccr", ccr_AliasSet }, - { "fcc0", fcc0_AliasSet }, - { "fcc1", fcc1_AliasSet }, - { "fcc2", fcc2_AliasSet }, - { "fcc3", fcc3_AliasSet }, - { "fsr", fsr_AliasSet }, -}; - -} // end anonymous namespace - -namespace SparcV9 { // Register classes - TargetRegisterClass *IRRegisterClass = &IRInstance; - TargetRegisterClass *FRRegisterClass = &FRInstance; - TargetRegisterClass *ICCRRegisterClass = &ICCRInstance; - TargetRegisterClass *FCCRRegisterClass = &FCCRInstance; - TargetRegisterClass *SRRegisterClass = &SRInstance; -} // end namespace SparcV9 - -const unsigned *SparcV9RegisterInfo::getCalleeSaveRegs() const { - // FIXME: This should be verified against the SparcV9 ABI at some point. - // These are the registers which the SparcV9 backend considers - // "non-volatile". - static const unsigned CalleeSaveRegs[] = { - SparcV9::l0, SparcV9::l1, SparcV9::l2, SparcV9::l3, SparcV9::l4, - SparcV9::l5, SparcV9::l6, SparcV9::l7, SparcV9::i0, SparcV9::i1, - SparcV9::i2, SparcV9::i3, SparcV9::i4, SparcV9::i5, SparcV9::i6, - SparcV9::i7, SparcV9::g0, SparcV9::g1, SparcV9::g2, SparcV9::g3, - SparcV9::g4, SparcV9::g5, SparcV9::g6, SparcV9::g7, SparcV9::o6, - 0 - }; - return CalleeSaveRegs; -} - -} // end namespace llvm - -//===----------------------------------------------------------------------===// -// -// The second section of this file (immediately following) contains the -// SparcV9 implementation of the MRegisterInfo class. It currently consists -// entirely of stub functions, because the SparcV9 target does not use the -// same register allocator that the X86 target uses. -// -//===----------------------------------------------------------------------===// - -SparcV9RegisterInfo::SparcV9RegisterInfo () - : MRegisterInfo (RegisterDescriptors, 104, RegisterClasses, - RegisterClasses + 5) { -} - -void SparcV9RegisterInfo::storeRegToStackSlot(MachineBasicBlock &MBB, - MachineBasicBlock::iterator MI, - unsigned SrcReg, int FrameIndex, - const TargetRegisterClass *RC) const { - abort (); -} - -void SparcV9RegisterInfo::loadRegFromStackSlot(MachineBasicBlock &MBB, - MachineBasicBlock::iterator MI, - unsigned DestReg, int FrameIndex, - const TargetRegisterClass *RC) const { - abort (); -} - -void SparcV9RegisterInfo::copyRegToReg(MachineBasicBlock &MBB, - MachineBasicBlock::iterator MI, - unsigned DestReg, unsigned SrcReg, - const TargetRegisterClass *RC) const { - abort (); -} - -void SparcV9RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator MI) - const { - abort (); -} - -void SparcV9RegisterInfo::emitPrologue(MachineFunction &MF) const { - abort (); -} - -void SparcV9RegisterInfo::emitEpilogue(MachineFunction &MF, - MachineBasicBlock &MBB) const { - abort (); -} - -int SparcV9RegisterInfo::getDwarfRegNum(unsigned RegNum) const { - abort (); - return 0; -} - -unsigned SparcV9RegisterInfo::getRARegister() const { - abort (); - return 0; -} - -unsigned SparcV9RegisterInfo::getFrameRegister(MachineFunction &MF) const { - abort (); - return 0; -} diff --git a/lib/Target/SparcV9/SparcV9RegisterInfo.h b/lib/Target/SparcV9/SparcV9RegisterInfo.h deleted file mode 100644 index c9570d3a933..00000000000 --- a/lib/Target/SparcV9/SparcV9RegisterInfo.h +++ /dev/null @@ -1,117 +0,0 @@ -//===- SparcV9RegisterInfo.h - SparcV9 Register Information Impl -*- C++ -*-==// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file contains the SparcV9 implementation of the MRegisterInfo class. -// It also contains stuff needed to instantiate that class, which would -// ordinarily be provided by TableGen. -// -//===----------------------------------------------------------------------===// - -#ifndef SPARCV9REGISTERINFO_H -#define SPARCV9REGISTERINFO_H - -#include "llvm/Target/MRegisterInfo.h" - -namespace llvm { - -struct SparcV9RegisterInfo : public MRegisterInfo { - SparcV9RegisterInfo (); - const unsigned *getCalleeSaveRegs() const; - const TargetRegisterClass* const *getCalleeSaveRegClasses() const { - return 0; - } - - - // The rest of these are stubs... for now. - void storeRegToStackSlot(MachineBasicBlock &MBB, - MachineBasicBlock::iterator MI, - unsigned SrcReg, int FrameIndex, - const TargetRegisterClass *RC) const; - void loadRegFromStackSlot(MachineBasicBlock &MBB, - MachineBasicBlock::iterator MI, - unsigned DestReg, int FrameIndex, - const TargetRegisterClass *RC) const; - void copyRegToReg(MachineBasicBlock &MBB, - MachineBasicBlock::iterator MI, - unsigned DestReg, unsigned SrcReg, - const TargetRegisterClass *RC) const; - void eliminateFrameIndex (MachineBasicBlock::iterator MI) const; - void emitPrologue (MachineFunction &MF) const; - void emitEpilogue (MachineFunction &MF, MachineBasicBlock &MBB) const; - - // Debug information queries. - int getDwarfRegNum(unsigned RegNum) const; - unsigned getRARegister() const; - unsigned getFrameRegister(MachineFunction &MF) const; -}; - -} // End llvm namespace - -//===----------------------------------------------------------------------===// -// -// The second section of this file (immediately following) contains -// a *handwritten* SparcV9 unified register number enumeration, which -// provides a flat namespace containing all the SparcV9 unified -// register numbers. -// -// It would ordinarily be contained in the file SparcV9GenRegisterNames.inc -// if we were using TableGen to generate the register file description -// automatically. -// -//===----------------------------------------------------------------------===// - -namespace llvm { - namespace SparcV9 { - enum { - // FIXME - Register 0 is not a "non-register" like it is on other targets!! - - // SparcV9IntRegClass(IntRegClassID) - // - unified register numbers 0 ... 31 (32 regs) - /* 0 */ o0, o1, o2, o3, o4, - /* 5 */ o5, o7, l0, l1, l2, - /* 10 */ l3, l4, l5, l6, l7, - /* 15 */ i0, i1, i2, i3, i4, - /* 20 */ i5, i6, i7, g0, g1, // i6 is frame ptr, i7 is ret addr, g0 is zero - /* 25 */ g2, g3, g4, g5, g6, - /* 30 */ g7, o6, // o6 is stack ptr - - // SparcV9FloatRegClass(FloatRegClassID) - // - regs 32 .. 63 are FPSingleRegType, 64 .. 95 are FPDoubleRegType - // - unified register numbers 32 ... 95 (64 regs) - /* 32 */ f0, f1, f2, - /* 35 */ f3, f4, f5, f6, f7, - /* 40 */ f8, f9, f10, f11, f12, - /* 45 */ f13, f14, f15, f16, f17, - /* 50 */ f18, f19, f20, f21, f22, - /* 55 */ f23, f24, f25, f26, f27, - /* 60 */ f28, f29, f30, f31, f32, - /* 65 */ f33, f34, f35, f36, f37, - /* 70 */ f38, f39, f40, f41, f42, - /* 75 */ f43, f44, f45, f46, f47, - /* 80 */ f48, f49, f50, f51, f52, - /* 85 */ f53, f54, f55, f56, f57, - /* 90 */ f58, f59, f60, f61, f62, - /* 95 */ f63, - - // SparcV9IntCCRegClass(IntCCRegClassID) - // - unified register numbers 96 ... 98 (3 regs) - /* 96 */ xcc, icc, ccr, - - // SparcV9FloatCCRegClass(FloatCCRegClassID) - // - unified register numbers 99 ... 102 (4 regs) - /* 99 */ fcc0, fcc1, fcc2, fcc3, - - // SparcV9SpecialRegClass(SpecialRegClassID) - // - unified register number 103 (1 reg) - /* 103 */ fsr - }; - } // end namespace SparcV9 -} // end namespace llvm - -#endif // SPARCV9REGISTERINFO_H diff --git a/lib/Target/SparcV9/SparcV9RegisterInfo.td b/lib/Target/SparcV9/SparcV9RegisterInfo.td deleted file mode 100644 index c2266511c02..00000000000 --- a/lib/Target/SparcV9/SparcV9RegisterInfo.td +++ /dev/null @@ -1,49 +0,0 @@ -//===- SparcV9RegisterInfo.td - SparcV9 Register defs ------*- tablegen -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -//===----------------------------------------------------------------------===// -// Declarations that describe the SparcV9 register file -//===----------------------------------------------------------------------===// - -// Ri - One of the 32 64 bit integer registers -class Ri num, string n> : Register { - 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]>; diff --git a/lib/Target/SparcV9/SparcV9Relocations.h b/lib/Target/SparcV9/SparcV9Relocations.h deleted file mode 100644 index 1ae826aa981..00000000000 --- a/lib/Target/SparcV9/SparcV9Relocations.h +++ /dev/null @@ -1,42 +0,0 @@ -//===- SparcV9Relocations.h - SparcV9 Code Relocations ----------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the SparcV9 target-specific relocation types. -// -//===----------------------------------------------------------------------===// - -#ifndef SPARCV9RELOCATIONS_H -#define SPARCV9RELOCATIONS_H - -#include "llvm/CodeGen/MachineRelocation.h" - -namespace llvm { - namespace V9 { - enum RelocationType { - // reloc_pcrel_call - PC relative relocation, shifted right by two bits, - // inserted into a 30 bit field. This is used to relocate direct call - // instructions. - reloc_pcrel_call = 0, - - // reloc_sethi_hh - Absolute relocation, for 'sethi %hh(G),reg' operation. - reloc_sethi_hh = 1, - - // reloc_sethi_lm - Absolute relocation, for 'sethi %lm(G),reg' operation. - reloc_sethi_lm = 2, - - // reloc_or_hm - Absolute relocation, for 'or reg,%hm(G),reg' operation. - reloc_or_hm = 3, - - // reloc_or_lo - Absolute relocation, for 'or reg,%lo(G),reg' operation. - reloc_or_lo = 4, - }; - } -} - -#endif diff --git a/lib/Target/SparcV9/SparcV9SchedInfo.cpp b/lib/Target/SparcV9/SparcV9SchedInfo.cpp deleted file mode 100644 index 492b881a44f..00000000000 --- a/lib/Target/SparcV9/SparcV9SchedInfo.cpp +++ /dev/null @@ -1,761 +0,0 @@ -//===-- SparcV9SchedInfo.cpp ----------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Describe the scheduling characteristics of the UltraSparc IIi. -// -//===----------------------------------------------------------------------===// - -#include "SparcV9Internals.h" - -using namespace llvm; - -/*--------------------------------------------------------------------------- -Scheduling guidelines for SPARC IIi: - -I-Cache alignment rules (pg 326) --- Align a branch target instruction so that it's entire group is within - the same cache line (may be 1-4 instructions). -** Don't let a branch that is predicted taken be the last instruction - on an I-cache line: delay slot will need an entire line to be fetched --- Make a FP instruction or a branch be the 4th instruction in a group. - For branches, there are tradeoffs in reordering to make this happen - (see pg. 327). -** Don't put a branch in a group that crosses a 32-byte boundary! - An artificial branch is inserted after every 32 bytes, and having - another branch will force the group to be broken into 2 groups. - -iTLB rules: --- Don't let a loop span two memory pages, if possible - -Branch prediction performance: --- Don't make the branch in a delay slot the target of a branch --- Try not to have 2 predicted branches within a group of 4 instructions - (because each such group has a single branch target field). --- Try to align branches in slots 0, 2, 4 or 6 of a cache line (to avoid - the wrong prediction bits being used in some cases). - -D-Cache timing constraints: --- Signed int loads of less than 64 bits have 3 cycle latency, not 2 --- All other loads that hit in D-Cache have 2 cycle latency --- All loads are returned IN ORDER, so a D-Cache miss will delay a later hit --- Mis-aligned loads or stores cause a trap. In particular, replace - mis-aligned FP double precision l/s with 2 single-precision l/s. --- Simulations of integer codes show increase in avg. group size of - 33% when code (including esp. non-faulting loads) is moved across - one branch, and 50% across 2 branches. - -E-Cache timing constraints: --- Scheduling for E-cache (D-Cache misses) is effective (due to load buffering) - -Store buffer timing constraints: --- Stores can be executed in same cycle as instruction producing the value --- Stores are buffered and have lower priority for E-cache until - highwater mark is reached in the store buffer (5 stores) - -Pipeline constraints: --- Shifts can only use IEU0. --- CC setting instructions can only use IEU1. --- Several other instructions must only use IEU1: - EDGE(?), ARRAY(?), CALL, JMPL, BPr, PST, and FCMP. --- Two instructions cannot store to the same register file in a single cycle - (single write port per file). - -Issue and grouping constraints: --- FP and branch instructions must use slot 4. --- Shift instructions cannot be grouped with other IEU0-specific instructions. --- CC setting instructions cannot be grouped with other IEU1-specific instrs. --- Several instructions must be issued in a single-instruction group: - MOVcc or MOVr, MULs/x and DIVs/x, SAVE/RESTORE, many others --- A CALL or JMPL breaks a group, ie, is not combined with subsequent instrs. --- --- - -Branch delay slot scheduling rules: --- A CTI couple (two back-to-back CTI instructions in the dynamic stream) - has a 9-instruction penalty: the entire pipeline is flushed when the - second instruction reaches stage 9 (W-Writeback). --- Avoid putting multicycle instructions, and instructions that may cause - load misses, in the delay slot of an annulling branch. --- Avoid putting WR, SAVE..., RESTORE and RETURN instructions in the - delay slot of an annulling branch. - - *--------------------------------------------------------------------------- */ - -//--------------------------------------------------------------------------- -// List of CPUResources for UltraSPARC IIi. -//--------------------------------------------------------------------------- - -static const CPUResource AllIssueSlots( "All Instr Slots", 4); -static const CPUResource IntIssueSlots( "Int Instr Slots", 3); -static const CPUResource First3IssueSlots("Instr Slots 0-3", 3); -static const CPUResource LSIssueSlots( "Load-Store Instr Slot", 1); -static const CPUResource CTIIssueSlots( "Ctrl Transfer Instr Slot", 1); -static const CPUResource FPAIssueSlots( "FP Instr Slot 1", 1); -static const CPUResource FPMIssueSlots( "FP Instr Slot 2", 1); - -// IEUN instructions can use either Alu and should use IAluN. -// IEU0 instructions must use Alu 1 and should use both IAluN and IAlu0. -// IEU1 instructions must use Alu 2 and should use both IAluN and IAlu1. -static const CPUResource IAluN("Int ALU 1or2", 2); -static const CPUResource IAlu0("Int ALU 1", 1); -static const CPUResource IAlu1("Int ALU 2", 1); - -static const CPUResource LSAluC1("Load/Store Unit Addr Cycle", 1); -static const CPUResource LSAluC2("Load/Store Unit Issue Cycle", 1); -static const CPUResource LdReturn("Load Return Unit", 1); - -static const CPUResource FPMAluC1("FP Mul/Div Alu Cycle 1", 1); -static const CPUResource FPMAluC2("FP Mul/Div Alu Cycle 2", 1); -static const CPUResource FPMAluC3("FP Mul/Div Alu Cycle 3", 1); - -static const CPUResource FPAAluC1("FP Other Alu Cycle 1", 1); -static const CPUResource FPAAluC2("FP Other Alu Cycle 2", 1); -static const CPUResource FPAAluC3("FP Other Alu Cycle 3", 1); - -static const CPUResource IRegReadPorts("Int Reg ReadPorts", INT_MAX); // CHECK -static const CPUResource IRegWritePorts("Int Reg WritePorts", 2); // CHECK -static const CPUResource FPRegReadPorts("FP Reg Read Ports", INT_MAX);// CHECK -static const CPUResource FPRegWritePorts("FP Reg Write Ports", 1); // CHECK - -static const CPUResource CTIDelayCycle( "CTI delay cycle", 1); -static const CPUResource FCMPDelayCycle("FCMP delay cycle", 1); - - - -//--------------------------------------------------------------------------- -// const InstrClassRUsage SparcV9RUsageDesc[] -// -// Purpose: -// Resource usage information for instruction in each scheduling class. -// The InstrRUsage Objects for individual classes are specified first. -// Note that fetch and decode are decoupled from the execution pipelines -// via an instr buffer, so they are not included in the cycles below. -//--------------------------------------------------------------------------- - -static const InstrClassRUsage NoneClassRUsage = { - SPARC_NONE, - /*totCycles*/ 7, - - /* maxIssueNum */ 4, - /* isSingleIssue */ false, - /* breaksGroup */ false, - /* numBubbles */ 0, - - /*numSlots*/ 4, - /* feasibleSlots[] */ { 0, 1, 2, 3 }, - - /*numEntries*/ 0, - /* V[] */ { - /*Cycle G */ - /*Ccle E */ - /*Cycle C */ - /*Cycle N1*/ - /*Cycle N1*/ - /*Cycle N1*/ - /*Cycle W */ - } -}; - -static const InstrClassRUsage IEUNClassRUsage = { - SPARC_IEUN, - /*totCycles*/ 7, - - /* maxIssueNum */ 3, - /* isSingleIssue */ false, - /* breaksGroup */ false, - /* numBubbles */ 0, - - /*numSlots*/ 3, - /* feasibleSlots[] */ { 0, 1, 2 }, - - /*numEntries*/ 4, - /* V[] */ { - /*Cycle G */ { AllIssueSlots.rid, 0, 1 }, - { IntIssueSlots.rid, 0, 1 }, - /*Cycle E */ { IAluN.rid, 1, 1 }, - /*Cycle C */ - /*Cycle N1*/ - /*Cycle N1*/ - /*Cycle N1*/ - /*Cycle W */ { IRegWritePorts.rid, 6, 1 } - } -}; - -static const InstrClassRUsage IEU0ClassRUsage = { - SPARC_IEU0, - /*totCycles*/ 7, - - /* maxIssueNum */ 1, - /* isSingleIssue */ false, - /* breaksGroup */ false, - /* numBubbles */ 0, - - /*numSlots*/ 3, - /* feasibleSlots[] */ { 0, 1, 2 }, - - /*numEntries*/ 5, - /* V[] */ { - /*Cycle G */ { AllIssueSlots.rid, 0, 1 }, - { IntIssueSlots.rid, 0, 1 }, - /*Cycle E */ { IAluN.rid, 1, 1 }, - { IAlu0.rid, 1, 1 }, - /*Cycle C */ - /*Cycle N1*/ - /*Cycle N1*/ - /*Cycle N1*/ - /*Cycle W */ { IRegWritePorts.rid, 6, 1 } - } -}; - -static const InstrClassRUsage IEU1ClassRUsage = { - SPARC_IEU1, - /*totCycles*/ 7, - - /* maxIssueNum */ 1, - /* isSingleIssue */ false, - /* breaksGroup */ false, - /* numBubbles */ 0, - - /*numSlots*/ 3, - /* feasibleSlots[] */ { 0, 1, 2 }, - - /*numEntries*/ 5, - /* V[] */ { - /*Cycle G */ { AllIssueSlots.rid, 0, 1 }, - { IntIssueSlots.rid, 0, 1 }, - /*Cycle E */ { IAluN.rid, 1, 1 }, - { IAlu1.rid, 1, 1 }, - /*Cycle C */ - /*Cycle N1*/ - /*Cycle N1*/ - /*Cycle N1*/ - /*Cycle W */ { IRegWritePorts.rid, 6, 1 } - } -}; - -static const InstrClassRUsage FPMClassRUsage = { - SPARC_FPM, - /*totCycles*/ 7, - - /* maxIssueNum */ 1, - /* isSingleIssue */ false, - /* breaksGroup */ false, - /* numBubbles */ 0, - - /*numSlots*/ 4, - /* feasibleSlots[] */ { 0, 1, 2, 3 }, - - /*numEntries*/ 7, - /* V[] */ { - /*Cycle G */ { AllIssueSlots.rid, 0, 1 }, - { FPMIssueSlots.rid, 0, 1 }, - /*Cycle E */ { FPRegReadPorts.rid, 1, 1 }, - /*Cycle C */ { FPMAluC1.rid, 2, 1 }, - /*Cycle N1*/ { FPMAluC2.rid, 3, 1 }, - /*Cycle N1*/ { FPMAluC3.rid, 4, 1 }, - /*Cycle N1*/ - /*Cycle W */ { FPRegWritePorts.rid, 6, 1 } - } -}; - -static const InstrClassRUsage FPAClassRUsage = { - SPARC_FPA, - /*totCycles*/ 7, - - /* maxIssueNum */ 1, - /* isSingleIssue */ false, - /* breaksGroup */ false, - /* numBubbles */ 0, - - /*numSlots*/ 4, - /* feasibleSlots[] */ { 0, 1, 2, 3 }, - - /*numEntries*/ 7, - /* V[] */ { - /*Cycle G */ { AllIssueSlots.rid, 0, 1 }, - { FPAIssueSlots.rid, 0, 1 }, - /*Cycle E */ { FPRegReadPorts.rid, 1, 1 }, - /*Cycle C */ { FPAAluC1.rid, 2, 1 }, - /*Cycle N1*/ { FPAAluC2.rid, 3, 1 }, - /*Cycle N1*/ { FPAAluC3.rid, 4, 1 }, - /*Cycle N1*/ - /*Cycle W */ { FPRegWritePorts.rid, 6, 1 } - } -}; - -static const InstrClassRUsage LDClassRUsage = { - SPARC_LD, - /*totCycles*/ 7, - - /* maxIssueNum */ 1, - /* isSingleIssue */ false, - /* breaksGroup */ false, - /* numBubbles */ 0, - - /*numSlots*/ 3, - /* feasibleSlots[] */ { 0, 1, 2, }, - - /*numEntries*/ 6, - /* V[] */ { - /*Cycle G */ { AllIssueSlots.rid, 0, 1 }, - { First3IssueSlots.rid, 0, 1 }, - { LSIssueSlots.rid, 0, 1 }, - /*Cycle E */ { LSAluC1.rid, 1, 1 }, - /*Cycle C */ { LSAluC2.rid, 2, 1 }, - { LdReturn.rid, 2, 1 }, - /*Cycle N1*/ - /*Cycle N1*/ - /*Cycle N1*/ - /*Cycle W */ { IRegWritePorts.rid, 6, 1 } - } -}; - -static const InstrClassRUsage STClassRUsage = { - SPARC_ST, - /*totCycles*/ 7, - - /* maxIssueNum */ 1, - /* isSingleIssue */ false, - /* breaksGroup */ false, - /* numBubbles */ 0, - - /*numSlots*/ 3, - /* feasibleSlots[] */ { 0, 1, 2 }, - - /*numEntries*/ 4, - /* V[] */ { - /*Cycle G */ { AllIssueSlots.rid, 0, 1 }, - { First3IssueSlots.rid, 0, 1 }, - { LSIssueSlots.rid, 0, 1 }, - /*Cycle E */ { LSAluC1.rid, 1, 1 }, - /*Cycle C */ { LSAluC2.rid, 2, 1 } - /*Cycle N1*/ - /*Cycle N1*/ - /*Cycle N1*/ - /*Cycle W */ - } -}; - -static const InstrClassRUsage CTIClassRUsage = { - SPARC_CTI, - /*totCycles*/ 7, - - /* maxIssueNum */ 1, - /* isSingleIssue */ false, - /* breaksGroup */ false, - /* numBubbles */ 0, - - /*numSlots*/ 4, - /* feasibleSlots[] */ { 0, 1, 2, 3 }, - - /*numEntries*/ 4, - /* V[] */ { - /*Cycle G */ { AllIssueSlots.rid, 0, 1 }, - { CTIIssueSlots.rid, 0, 1 }, - /*Cycle E */ { IAlu0.rid, 1, 1 }, - /*Cycles E-C */ { CTIDelayCycle.rid, 1, 2 } - /*Cycle C */ - /*Cycle N1*/ - /*Cycle N1*/ - /*Cycle N1*/ - /*Cycle W */ - } -}; - -static const InstrClassRUsage SingleClassRUsage = { - SPARC_SINGLE, - /*totCycles*/ 7, - - /* maxIssueNum */ 1, - /* isSingleIssue */ true, - /* breaksGroup */ false, - /* numBubbles */ 0, - - /*numSlots*/ 1, - /* feasibleSlots[] */ { 0 }, - - /*numEntries*/ 5, - /* V[] */ { - /*Cycle G */ { AllIssueSlots.rid, 0, 1 }, - { AllIssueSlots.rid, 0, 1 }, - { AllIssueSlots.rid, 0, 1 }, - { AllIssueSlots.rid, 0, 1 }, - /*Cycle E */ { IAlu0.rid, 1, 1 } - /*Cycle C */ - /*Cycle N1*/ - /*Cycle N1*/ - /*Cycle N1*/ - /*Cycle W */ - } -}; - - -static const InstrClassRUsage SparcV9RUsageDesc[] = { - NoneClassRUsage, - IEUNClassRUsage, - IEU0ClassRUsage, - IEU1ClassRUsage, - FPMClassRUsage, - FPAClassRUsage, - CTIClassRUsage, - LDClassRUsage, - STClassRUsage, - SingleClassRUsage -}; - - - -//--------------------------------------------------------------------------- -// const InstrIssueDelta SparcV9InstrIssueDeltas[] -// -// Purpose: -// Changes to issue restrictions information in InstrClassRUsage for -// instructions that differ from other instructions in their class. -//--------------------------------------------------------------------------- - -static const InstrIssueDelta SparcV9InstrIssueDeltas[] = { - - // opCode, isSingleIssue, breaksGroup, numBubbles - - // Special cases for single-issue only - // Other single issue cases are below. -//{ V9::LDDA, true, true, 0 }, -//{ V9::STDA, true, true, 0 }, -//{ V9::LDDF, true, true, 0 }, -//{ V9::LDDFA, true, true, 0 }, - { V9::ADDCr, true, true, 0 }, - { V9::ADDCi, true, true, 0 }, - { V9::ADDCccr, true, true, 0 }, - { V9::ADDCcci, true, true, 0 }, - { V9::SUBCr, true, true, 0 }, - { V9::SUBCi, true, true, 0 }, - { V9::SUBCccr, true, true, 0 }, - { V9::SUBCcci, true, true, 0 }, -//{ V9::LDSTUB, true, true, 0 }, -//{ V9::SWAP, true, true, 0 }, -//{ V9::SWAPA, true, true, 0 }, -//{ V9::CAS, true, true, 0 }, -//{ V9::CASA, true, true, 0 }, -//{ V9::CASX, true, true, 0 }, -//{ V9::CASXA, true, true, 0 }, -//{ V9::LDFSR, true, true, 0 }, -//{ V9::LDFSRA, true, true, 0 }, -//{ V9::LDXFSR, true, true, 0 }, -//{ V9::LDXFSRA, true, true, 0 }, -//{ V9::STFSR, true, true, 0 }, -//{ V9::STFSRA, true, true, 0 }, -//{ V9::STXFSR, true, true, 0 }, -//{ V9::STXFSRA, true, true, 0 }, -//{ V9::SAVED, true, true, 0 }, -//{ V9::RESTORED, true, true, 0 }, -//{ V9::FLUSH, true, true, 9 }, -//{ V9::FLUSHW, true, true, 9 }, -//{ V9::ALIGNADDR, true, true, 0 }, -//{ V9::DONE, true, true, 0 }, -//{ V9::RETRY, true, true, 0 }, -//{ V9::TCC, true, true, 0 }, -//{ V9::SHUTDOWN, true, true, 0 }, - - // Special cases for breaking group *before* - // CURRENTLY NOT SUPPORTED! - { V9::CALL, false, false, 0 }, - { V9::JMPLCALLr, false, false, 0 }, - { V9::JMPLCALLi, false, false, 0 }, - { V9::JMPLRETr, false, false, 0 }, - { V9::JMPLRETi, false, false, 0 }, - - // Special cases for breaking the group *after* - { V9::MULXr, true, true, (4+34)/2 }, - { V9::MULXi, true, true, (4+34)/2 }, - { V9::FDIVS, false, true, 0 }, - { V9::FDIVD, false, true, 0 }, - { V9::FDIVQ, false, true, 0 }, - { V9::FSQRTS, false, true, 0 }, - { V9::FSQRTD, false, true, 0 }, - { V9::FSQRTQ, false, true, 0 }, -//{ V9::FCMP{LE,GT,NE,EQ}, false, true, 0 }, - - // Instructions that introduce bubbles -//{ V9::MULScc, true, true, 2 }, -//{ V9::SMULcc, true, true, (4+18)/2 }, -//{ V9::UMULcc, true, true, (4+19)/2 }, - { V9::SDIVXr, true, true, 68 }, - { V9::SDIVXi, true, true, 68 }, - { V9::UDIVXr, true, true, 68 }, - { V9::UDIVXi, true, true, 68 }, -//{ V9::SDIVcc, true, true, 36 }, -//{ V9::UDIVcc, true, true, 37 }, - { V9::WRCCRr, true, true, 4 }, - { V9::WRCCRi, true, true, 4 }, -//{ V9::WRPR, true, true, 4 }, -//{ V9::RDCCR, true, true, 0 }, // no bubbles after, but see below -//{ V9::RDPR, true, true, 0 }, -}; - - - - -//--------------------------------------------------------------------------- -// const InstrRUsageDelta SparcV9InstrUsageDeltas[] -// -// Purpose: -// Changes to resource usage information in InstrClassRUsage for -// instructions that differ from other instructions in their class. -//--------------------------------------------------------------------------- - -static const InstrRUsageDelta SparcV9InstrUsageDeltas[] = { - - // MachineOpCode, Resource, Start cycle, Num cycles - - // - // JMPL counts as a load/store instruction for issue! - // - { V9::JMPLCALLr, LSIssueSlots.rid, 0, 1 }, - { V9::JMPLCALLi, LSIssueSlots.rid, 0, 1 }, - { V9::JMPLRETr, LSIssueSlots.rid, 0, 1 }, - { V9::JMPLRETi, LSIssueSlots.rid, 0, 1 }, - - // - // Many instructions cannot issue for the next 2 cycles after an FCMP - // We model that with a fake resource FCMPDelayCycle. - // - { V9::FCMPS, FCMPDelayCycle.rid, 1, 3 }, - { V9::FCMPD, FCMPDelayCycle.rid, 1, 3 }, - { V9::FCMPQ, FCMPDelayCycle.rid, 1, 3 }, - - { V9::MULXr, FCMPDelayCycle.rid, 1, 1 }, - { V9::MULXi, FCMPDelayCycle.rid, 1, 1 }, - { V9::SDIVXr, FCMPDelayCycle.rid, 1, 1 }, - { V9::SDIVXi, FCMPDelayCycle.rid, 1, 1 }, - { V9::UDIVXr, FCMPDelayCycle.rid, 1, 1 }, - { V9::UDIVXi, FCMPDelayCycle.rid, 1, 1 }, -//{ V9::SMULcc, FCMPDelayCycle.rid, 1, 1 }, -//{ V9::UMULcc, FCMPDelayCycle.rid, 1, 1 }, -//{ V9::SDIVcc, FCMPDelayCycle.rid, 1, 1 }, -//{ V9::UDIVcc, FCMPDelayCycle.rid, 1, 1 }, - { V9::STDFr, FCMPDelayCycle.rid, 1, 1 }, - { V9::STDFi, FCMPDelayCycle.rid, 1, 1 }, - { V9::FMOVRSZ, FCMPDelayCycle.rid, 1, 1 }, - { V9::FMOVRSLEZ,FCMPDelayCycle.rid, 1, 1 }, - { V9::FMOVRSLZ, FCMPDelayCycle.rid, 1, 1 }, - { V9::FMOVRSNZ, FCMPDelayCycle.rid, 1, 1 }, - { V9::FMOVRSGZ, FCMPDelayCycle.rid, 1, 1 }, - { V9::FMOVRSGEZ,FCMPDelayCycle.rid, 1, 1 }, - - // - // Some instructions are stalled in the GROUP stage if a CTI is in - // the E or C stage. We model that with a fake resource CTIDelayCycle. - // - { V9::LDDFr, CTIDelayCycle.rid, 1, 1 }, - { V9::LDDFi, CTIDelayCycle.rid, 1, 1 }, -//{ V9::LDDA, CTIDelayCycle.rid, 1, 1 }, -//{ V9::LDDSTUB, CTIDelayCycle.rid, 1, 1 }, -//{ V9::LDDSTUBA, CTIDelayCycle.rid, 1, 1 }, -//{ V9::SWAP, CTIDelayCycle.rid, 1, 1 }, -//{ V9::SWAPA, CTIDelayCycle.rid, 1, 1 }, -//{ V9::CAS, CTIDelayCycle.rid, 1, 1 }, -//{ V9::CASA, CTIDelayCycle.rid, 1, 1 }, -//{ V9::CASX, CTIDelayCycle.rid, 1, 1 }, -//{ V9::CASXA, CTIDelayCycle.rid, 1, 1 }, - - // - // Signed int loads of less than dword size return data in cycle N1 (not C) - // and put all loads in consecutive cycles into delayed load return mode. - // - { V9::LDSBr, LdReturn.rid, 2, -1 }, - { V9::LDSBr, LdReturn.rid, 3, 1 }, - { V9::LDSBi, LdReturn.rid, 2, -1 }, - { V9::LDSBi, LdReturn.rid, 3, 1 }, - - { V9::LDSHr, LdReturn.rid, 2, -1 }, - { V9::LDSHr, LdReturn.rid, 3, 1 }, - { V9::LDSHi, LdReturn.rid, 2, -1 }, - { V9::LDSHi, LdReturn.rid, 3, 1 }, - - { V9::LDSWr, LdReturn.rid, 2, -1 }, - { V9::LDSWr, LdReturn.rid, 3, 1 }, - { V9::LDSWi, LdReturn.rid, 2, -1 }, - { V9::LDSWi, LdReturn.rid, 3, 1 }, - - // - // RDPR from certain registers and RD from any register are not dispatchable - // until four clocks after they reach the head of the instr. buffer. - // Together with their single-issue requirement, this means all four issue - // slots are effectively blocked for those cycles, plus the issue cycle. - // This does not increase the latency of the instruction itself. - // - { V9::RDCCR, AllIssueSlots.rid, 0, 5 }, - { V9::RDCCR, AllIssueSlots.rid, 0, 5 }, - { V9::RDCCR, AllIssueSlots.rid, 0, 5 }, - { V9::RDCCR, AllIssueSlots.rid, 0, 5 }, - -#undef EXPLICIT_BUBBLES_NEEDED -#ifdef EXPLICIT_BUBBLES_NEEDED - // - // MULScc inserts one bubble. - // This means it breaks the current group (captured in UltraSparcV9SchedInfo) - // *and occupies all issue slots for the next cycle - // -//{ V9::MULScc, AllIssueSlots.rid, 2, 2-1 }, -//{ V9::MULScc, AllIssueSlots.rid, 2, 2-1 }, -//{ V9::MULScc, AllIssueSlots.rid, 2, 2-1 }, -//{ V9::MULScc, AllIssueSlots.rid, 2, 2-1 }, - - // - // SMULcc inserts between 4 and 18 bubbles, depending on #leading 0s in rs1. - // We just model this with a simple average. - // -//{ V9::SMULcc, AllIssueSlots.rid, 2, ((4+18)/2)-1 }, -//{ V9::SMULcc, AllIssueSlots.rid, 2, ((4+18)/2)-1 }, -//{ V9::SMULcc, AllIssueSlots.rid, 2, ((4+18)/2)-1 }, -//{ V9::SMULcc, AllIssueSlots.rid, 2, ((4+18)/2)-1 }, - - // SMULcc inserts between 4 and 19 bubbles, depending on #leading 0s in rs1. -//{ V9::UMULcc, AllIssueSlots.rid, 2, ((4+19)/2)-1 }, -//{ V9::UMULcc, AllIssueSlots.rid, 2, ((4+19)/2)-1 }, -//{ V9::UMULcc, AllIssueSlots.rid, 2, ((4+19)/2)-1 }, -//{ V9::UMULcc, AllIssueSlots.rid, 2, ((4+19)/2)-1 }, - - // - // MULX inserts between 4 and 34 bubbles, depending on #leading 0s in rs1. - // - { V9::MULX, AllIssueSlots.rid, 2, ((4+34)/2)-1 }, - { V9::MULX, AllIssueSlots.rid, 2, ((4+34)/2)-1 }, - { V9::MULX, AllIssueSlots.rid, 2, ((4+34)/2)-1 }, - { V9::MULX, AllIssueSlots.rid, 2, ((4+34)/2)-1 }, - - // - // SDIVcc inserts 36 bubbles. - // -//{ V9::SDIVcc, AllIssueSlots.rid, 2, 36-1 }, -//{ V9::SDIVcc, AllIssueSlots.rid, 2, 36-1 }, -//{ V9::SDIVcc, AllIssueSlots.rid, 2, 36-1 }, -//{ V9::SDIVcc, AllIssueSlots.rid, 2, 36-1 }, - - // UDIVcc inserts 37 bubbles. -//{ V9::UDIVcc, AllIssueSlots.rid, 2, 37-1 }, -//{ V9::UDIVcc, AllIssueSlots.rid, 2, 37-1 }, -//{ V9::UDIVcc, AllIssueSlots.rid, 2, 37-1 }, -//{ V9::UDIVcc, AllIssueSlots.rid, 2, 37-1 }, - - // - // SDIVX inserts 68 bubbles. - // - { V9::SDIVX, AllIssueSlots.rid, 2, 68-1 }, - { V9::SDIVX, AllIssueSlots.rid, 2, 68-1 }, - { V9::SDIVX, AllIssueSlots.rid, 2, 68-1 }, - { V9::SDIVX, AllIssueSlots.rid, 2, 68-1 }, - - // - // UDIVX inserts 68 bubbles. - // - { V9::UDIVX, AllIssueSlots.rid, 2, 68-1 }, - { V9::UDIVX, AllIssueSlots.rid, 2, 68-1 }, - { V9::UDIVX, AllIssueSlots.rid, 2, 68-1 }, - { V9::UDIVX, AllIssueSlots.rid, 2, 68-1 }, - - // - // WR inserts 4 bubbles. - // -//{ V9::WR, AllIssueSlots.rid, 2, 68-1 }, -//{ V9::WR, AllIssueSlots.rid, 2, 68-1 }, -//{ V9::WR, AllIssueSlots.rid, 2, 68-1 }, -//{ V9::WR, AllIssueSlots.rid, 2, 68-1 }, - - // - // WRPR inserts 4 bubbles. - // -//{ V9::WRPR, AllIssueSlots.rid, 2, 68-1 }, -//{ V9::WRPR, AllIssueSlots.rid, 2, 68-1 }, -//{ V9::WRPR, AllIssueSlots.rid, 2, 68-1 }, -//{ V9::WRPR, AllIssueSlots.rid, 2, 68-1 }, - - // - // DONE inserts 9 bubbles. - // -//{ V9::DONE, AllIssueSlots.rid, 2, 9-1 }, -//{ V9::DONE, AllIssueSlots.rid, 2, 9-1 }, -//{ V9::DONE, AllIssueSlots.rid, 2, 9-1 }, -//{ V9::DONE, AllIssueSlots.rid, 2, 9-1 }, - - // - // RETRY inserts 9 bubbles. - // -//{ V9::RETRY, AllIssueSlots.rid, 2, 9-1 }, -//{ V9::RETRY, AllIssueSlots.rid, 2, 9-1 }, -//{ V9::RETRY, AllIssueSlots.rid, 2, 9-1 }, -//{ V9::RETRY, AllIssueSlots.rid, 2, 9-1 }, - -#endif /*EXPLICIT_BUBBLES_NEEDED */ -}; - -// Additional delays to be captured in code: -// 1. RDPR from several state registers (page 349) -// 2. RD from *any* register (page 349) -// 3. Writes to TICK, PSTATE, TL registers and FLUSH{W} instr (page 349) -// 4. Integer store can be in same group as instr producing value to store. -// 5. BICC and BPICC can be in the same group as instr producing CC (pg 350) -// 6. FMOVr cannot be in the same or next group as an IEU instr (pg 351). -// 7. The second instr. of a CTI group inserts 9 bubbles (pg 351) -// 8. WR{PR}, SVAE, SAVED, RESTORE, RESTORED, RETURN, RETRY, and DONE that -// follow an annulling branch cannot be issued in the same group or in -// the 3 groups following the branch. -// 9. A predicted annulled load does not stall dependent instructions. -// Other annulled delay slot instructions *do* stall dependents, so -// nothing special needs to be done for them during scheduling. -//10. Do not put a load use that may be annulled in the same group as the -// branch. The group will stall until the load returns. -//11. Single-prec. FP loads lock 2 registers, for dependency checking. -// -// -// Additional delays we cannot or will not capture: -// 1. If DCTI is last word of cache line, it is delayed until next line can be -// fetched. Also, other DCTI alignment-related delays (pg 352) -// 2. Load-after-store is delayed by 7 extra cycles if load hits in D-Cache. -// Also, several other store-load and load-store conflicts (pg 358) -// 3. MEMBAR, LD{X}FSR, LDD{A} and a bunch of other load stalls (pg 358) -// 4. There can be at most 8 outstanding buffered store instructions -// (including some others like MEMBAR, LDSTUB, CAS{AX}, and FLUSH) - - - -//--------------------------------------------------------------------------- -// class SparcV9SchedInfo -// -// Purpose: -// Scheduling information for the UltraSPARC. -// Primarily just initializes machine-dependent parameters in -// class TargetSchedInfo. -//--------------------------------------------------------------------------- - -/*ctor*/ -SparcV9SchedInfo::SparcV9SchedInfo(const TargetMachine& tgt) - : TargetSchedInfo(tgt, - (unsigned int) SPARC_NUM_SCHED_CLASSES, - SparcV9RUsageDesc, - SparcV9InstrUsageDeltas, - SparcV9InstrIssueDeltas, - sizeof(SparcV9InstrUsageDeltas)/sizeof(InstrRUsageDelta), - sizeof(SparcV9InstrIssueDeltas)/sizeof(InstrIssueDelta)) -{ - maxNumIssueTotal = 4; - longestIssueConflict = 0; // computed from issuesGaps[] - - // must be called after above parameters are initialized. - initializeResources(); -} - -void -SparcV9SchedInfo::initializeResources() -{ - // Compute TargetSchedInfo::instrRUsages and TargetSchedInfo::issueGaps - TargetSchedInfo::initializeResources(); - - // Machine-dependent fixups go here. None for now. -} diff --git a/lib/Target/SparcV9/SparcV9StackSlots.cpp b/lib/Target/SparcV9/SparcV9StackSlots.cpp deleted file mode 100644 index 1db024e4627..00000000000 --- a/lib/Target/SparcV9/SparcV9StackSlots.cpp +++ /dev/null @@ -1,52 +0,0 @@ -//===- SparcV9StackSlots.cpp - Add empty stack slots to functions ---------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This pass adds 2 empty slots at the top of function stack. These two slots -// are later used during code reoptimization for spilling the register values -// when rewriting branches. -// -//===----------------------------------------------------------------------===// - -#include "SparcV9Internals.h" -#include "llvm/Constant.h" -#include "llvm/DerivedTypes.h" -#include "llvm/Function.h" -#include "llvm/CodeGen/MachineFunctionPass.h" -#include "MachineFunctionInfo.h" -using namespace llvm; - -namespace { - class StackSlots : public MachineFunctionPass { - const TargetMachine &Target; - public: - StackSlots(const TargetMachine &T) : Target(T) {} - - const char *getPassName() const { - return "Stack Slot Insertion for profiling code"; - } - - virtual void getAnalysisUsage(AnalysisUsage &AU) const { - AU.setPreservesCFG(); - } - - bool runOnMachineFunction(MachineFunction &MF) { - const Type *PtrInt = PointerType::get(Type::IntTy); - unsigned Size = Target.getTargetData().getTypeSize(PtrInt); - - Value *V = Constant::getNullValue(Type::IntTy); - MF.getInfo()->allocateLocalVar(V, 2*Size); - return true; - } - }; -} - -FunctionPass *llvm::createStackSlotsPass(const TargetMachine &Target) { - return new StackSlots(Target); -} - diff --git a/lib/Target/SparcV9/SparcV9TargetMachine.cpp b/lib/Target/SparcV9/SparcV9TargetMachine.cpp deleted file mode 100644 index a0d76bb4372..00000000000 --- a/lib/Target/SparcV9/SparcV9TargetMachine.cpp +++ /dev/null @@ -1,303 +0,0 @@ -//===-- SparcV9TargetMachine.cpp - SparcV9 Target Machine Implementation --===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Primary interface to machine description for the UltraSPARC. Primarily just -// initializes machine-dependent parameters in class TargetMachine, and creates -// machine-dependent subclasses for classes such as TargetInstrInfo. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Function.h" -#include "llvm/PassManager.h" -#include "llvm/Assembly/PrintModulePass.h" -#include "llvm/CodeGen/InstrScheduling.h" -#include "llvm/CodeGen/MachineFunction.h" -#include "llvm/CodeGen/Passes.h" -#include "llvm/Target/TargetOptions.h" -#include "llvm/Target/TargetMachineRegistry.h" -#include "llvm/Transforms/Scalar.h" -#include "MappingInfo.h" -#include "MachineFunctionInfo.h" -#include "MachineCodeForInstruction.h" -#include "SparcV9Internals.h" -#include "SparcV9TargetMachine.h" -#include "SparcV9BurgISel.h" -#include "llvm/Support/CommandLine.h" -using namespace llvm; - -static const unsigned ImplicitRegUseList[] = { 0 }; /* not used yet */ -// Build the MachineInstruction Description Array... -const TargetInstrDescriptor llvm::SparcV9MachineInstrDesc[] = { -#define I(ENUM, OPCODESTRING, NUMOPERANDS, RESULTPOS, MAXIMM, IMMSE, \ - NUMDELAYSLOTS, LATENCY, SCHEDCLASS, INSTFLAGS) \ - { OPCODESTRING, NUMOPERANDS, RESULTPOS, MAXIMM, IMMSE, \ - NUMDELAYSLOTS, LATENCY, SCHEDCLASS, INSTFLAGS, 0, \ - ImplicitRegUseList, ImplicitRegUseList, 0 }, -#include "SparcV9Instr.def" -}; - -//--------------------------------------------------------------------------- -// Command line options to control choice of code generation passes. -//--------------------------------------------------------------------------- - -namespace llvm { - bool EmitMappingInfo = false; -} - -namespace { - cl::opt DisableSched("disable-sched", - cl::desc("Disable sparcv9 local scheduling pass")); - - cl::opt DisablePeephole("disable-peephole", - cl::desc("Disable sparcv9 peephole optimization pass")); - - cl::opt EmitMappingInfoOpt("enable-maps", cl::ReallyHidden, - cl::location(EmitMappingInfo), - cl::init(false), - cl::desc("Emit LLVM-to-MachineCode mapping info to assembly")); - - cl::opt EnableModSched("enable-modsched", - cl::desc("Enable modulo scheduling pass"), cl::Hidden); - - cl::opt EnableSBModSched("enable-modschedSB", - cl::desc("Enable superblock modulo scheduling (experimental)"), cl::Hidden); - - // Register the target. - RegisterTarget 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()->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")); -} - diff --git a/lib/Target/SparcV9/SparcV9TargetMachine.h b/lib/Target/SparcV9/SparcV9TargetMachine.h deleted file mode 100644 index 3bbb6a4d695..00000000000 --- a/lib/Target/SparcV9/SparcV9TargetMachine.h +++ /dev/null @@ -1,57 +0,0 @@ -//===-- SparcV9TargetMachine.h - Define TargetMachine for SparcV9 -*- C++ -*-=// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file declares the top-level SparcV9 target machine. -// -//===----------------------------------------------------------------------===// - -#ifndef SPARCV9TARGETMACHINE_H -#define SPARCV9TARGETMACHINE_H - -#include "llvm/Target/TargetFrameInfo.h" -#include "llvm/Target/TargetMachine.h" -#include "SparcV9InstrInfo.h" -#include "SparcV9Internals.h" -#include "SparcV9RegInfo.h" -#include "SparcV9FrameInfo.h" -#include "SparcV9JITInfo.h" - -namespace llvm { - class PassManager; - -class SparcV9TargetMachine : public TargetMachine { - SparcV9InstrInfo instrInfo; - SparcV9SchedInfo schedInfo; - SparcV9RegInfo regInfo; - SparcV9FrameInfo frameInfo; - SparcV9JITInfo jitInfo; -public: - SparcV9TargetMachine(const Module &M, const std::string &FS); - - virtual const TargetInstrInfo *getInstrInfo() const { return &instrInfo; } - virtual const TargetSchedInfo *getSchedInfo() const { return &schedInfo; } - virtual const SparcV9RegInfo *getRegInfo() const { return ®Info; } - virtual const TargetFrameInfo *getFrameInfo() const { return &frameInfo; } - virtual TargetJITInfo *getJITInfo() { return &jitInfo; } - virtual const MRegisterInfo *getRegisterInfo() const { - return &instrInfo.getRegisterInfo(); - } - - virtual bool addPassesToEmitFile(PassManager &PM, std::ostream &Out, - CodeGenFileType FileType, bool Fast); - virtual bool addPassesToEmitMachineCode(FunctionPassManager &PM, - MachineCodeEmitter &MCE); - - static unsigned getModuleMatchQuality(const Module &M); - static unsigned getJITMatchQuality(); -}; - -} // End llvm namespace - -#endif diff --git a/lib/Target/SparcV9/SparcV9TmpInstr.cpp b/lib/Target/SparcV9/SparcV9TmpInstr.cpp deleted file mode 100644 index 4e33ed6353b..00000000000 --- a/lib/Target/SparcV9/SparcV9TmpInstr.cpp +++ /dev/null @@ -1,72 +0,0 @@ -//===- SparcV9TmpInstr.cpp - SparcV9 Intermediate Value class -------------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Methods of class for temporary intermediate values used within the current -// SparcV9 backend. -// -//===----------------------------------------------------------------------===// - -#include "SparcV9TmpInstr.h" -#include "llvm/Type.h" -#include "llvm/Support/LeakDetector.h" -using namespace llvm; - -TmpInstruction::TmpInstruction(const TmpInstruction &TI) - : Instruction(TI.getType(), TI.getOpcode(), Ops, TI.getNumOperands()) { - if (TI.getNumOperands()) { - Ops[0].init(TI.Ops[0], this); - if (TI.getNumOperands() == 2) - Ops[1].init(TI.Ops[1], this); - else - assert(0 && "Bad # operands to TmpInstruction!"); - } -} - -TmpInstruction::TmpInstruction(Value *s1, Value *s2, const std::string &name) - : Instruction(s1->getType(), Instruction::UserOp1, Ops, 1+(s2 != 0), name) { - Ops[0].init(s1, this); // s1 must be non-null - if (s2) - Ops[1].init(s2, this); - - // TmpInstructions should not be garbage checked. - LeakDetector::removeGarbageObject(this); -} - -TmpInstruction::TmpInstruction(MachineCodeForInstruction& mcfi, - Value *s1, Value *s2, const std::string &name) - : Instruction(s1->getType(), Instruction::UserOp1, Ops, 1+(s2 != 0), name) { - mcfi.addTemp(this); - - Ops[0].init(s1, this); // s1 must be non-null - if (s2) - Ops[1].init(s2, this); - - // TmpInstructions should not be garbage checked. - LeakDetector::removeGarbageObject(this); -} - -// Constructor that requires the type of the temporary to be specified. -// Both S1 and S2 may be NULL. -TmpInstruction::TmpInstruction(MachineCodeForInstruction& mcfi, - const Type *Ty, Value *s1, Value* s2, - const std::string &name) - : Instruction(Ty, Instruction::UserOp1, Ops, (s1 != 0)+(s2 != 0), name) { - mcfi.addTemp(this); - - assert((s1 != 0 || s2 == 0) && - "s2 cannot be non-null if s1 is non-null!"); - if (s1) { - Ops[0].init(s1, this); - if (s2) - Ops[1].init(s2, this); - } - - // TmpInstructions should not be garbage checked. - LeakDetector::removeGarbageObject(this); -} diff --git a/lib/Target/SparcV9/SparcV9TmpInstr.h b/lib/Target/SparcV9/SparcV9TmpInstr.h deleted file mode 100644 index 613cfb9219b..00000000000 --- a/lib/Target/SparcV9/SparcV9TmpInstr.h +++ /dev/null @@ -1,64 +0,0 @@ -//===-- SparcV9TmpInstr.h ---------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Definition of class for temporary intermediate values used within the current -// SparcV9 backend. -// -//===----------------------------------------------------------------------===// - -#ifndef SPARCV9TMPINSTR_H -#define SPARCV9TMPINSTR_H - -#include "llvm/Instruction.h" -#include "MachineCodeForInstruction.h" - -namespace llvm { - -/// TmpInstruction - This class represents temporary intermediate -/// values used within the SparcV9 machine code for an LLVM instruction. -/// -class TmpInstruction : public Instruction { - Use Ops[2]; - TmpInstruction(const TmpInstruction &TI); -public: - // Constructor that uses the type of S1 as the type of the temporary. - // s1 must be a valid value. s2 may be NULL. - TmpInstruction(MachineCodeForInstruction &mcfi, - Value *s1, Value *s2 = 0, const std::string &name = ""); - - // Constructor that uses the type of S1 as the type of the temporary, - // but does not require a MachineCodeForInstruction. - // s1 must be a valid value. s2 may be NULL. - TmpInstruction(Value *s1, Value *s2 = 0, const std::string &name = ""); - - // Constructor that requires the type of the temporary to be specified. - // Both S1 and S2 may be NULL. - TmpInstruction(MachineCodeForInstruction& mcfi, - const Type *Ty, Value *s1 = 0, Value* s2 = 0, - const std::string &name = ""); - - virtual Instruction *clone() const { - assert(0 && "Cannot clone TmpInstructions!"); - return 0; - } - virtual const char *getOpcodeName() const { return "TmpInstruction"; } - - // Methods for support type inquiry through isa, cast, and dyn_cast: - static inline bool classof(const TmpInstruction *) { return true; } - static inline bool classof(const Instruction *I) { - return (I->getOpcode() == Instruction::UserOp1); - } - static inline bool classof(const Value *V) { - return isa(V) && classof(cast(V)); - } -}; - -} // End llvm namespace - -#endif diff --git a/lib/Target/SparcV9/SparcV9_F2.td b/lib/Target/SparcV9/SparcV9_F2.td deleted file mode 100644 index 3c9ae1e98a2..00000000000 --- a/lib/Target/SparcV9/SparcV9_F2.td +++ /dev/null @@ -1,71 +0,0 @@ -//===- SparcV9_F2.td - SparcV9 Format 2 instructions -------*- tablegen -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -//===----------------------------------------------------------------------===// -// Format #2 classes -// -class F2 : InstV9 { // Format 2 instructions - bits<3> op2; - let op = 0; // Op = 0 - let Inst{24-22} = op2; -} - -// Format 2.1 instructions -class F2_1 : 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 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 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 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}; -} diff --git a/lib/Target/SparcV9/SparcV9_F3.td b/lib/Target/SparcV9/SparcV9_F3.td deleted file mode 100644 index a17b9eae5f4..00000000000 --- a/lib/Target/SparcV9/SparcV9_F3.td +++ /dev/null @@ -1,267 +0,0 @@ -//===- SparcV9_F3.td - SparcV9 Format 3 Instructions -------*- tablegen -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -//===----------------------------------------------------------------------===// -// Format #3 classes -// - -// F3 - Common superclass of all F3 instructions. All instructions have an op3 -// field. -class F3 : InstV9 { - bits<6> op3; - let op{1} = 1; // Op = 2 or 3 - let Inst{24-19} = op3; -} - -// F3_rs1 - Common class of instructions that have an rs1 field -class F3_rs1 : F3 { - bits<5> rs1; - let Inst{18-14} = rs1; -} - -// F3_rs1rs2 - Common class of instructions that only have rs1 and rs2 fields -class F3_rs1rs2 : F3_rs1 { - bits<5> rs2; - let Inst{4-0} = rs2; -} - -// F3_rs1rs2 - Common class of instructions that only have rs1 and rs2 fields -class F3_rs1rs2rd : F3_rs1rs2 { - bits<5> rd; - let Inst{29-25} = rd; -} - -// F3_rs1simm13 - Common class of instructions that only have rs1 and simm13 -class F3_rs1simm13 : F3_rs1 { - bits<13> simm13; - let Inst{12-0} = simm13; -} - -class F3_rs1simm13rd : F3_rs1simm13 { - bits<5> rd; - let Inst{29-25} = rd; -} - -// F3_rs1rd - Common class of instructions that have an rs1 and rd fields -class F3_rs1rd : F3_rs1 { - bits<5> rd; - let Inst{29-25} = rd; -} - -// F3_rs2 - Common class of instructions that don't use an rs1 -class F3_rs2 : F3 { - bits<5> rs2; - let Inst{4-0} = rs2; -} - -// F3_rs2rd - Common class of instructions that use rs2 and rd, but not rs1 -class F3_rs2rd : F3_rs2 { - bits<5> rd; - let Inst{29-25} = rd; -} - -// F3_rd - Common class of instructions that have an rd field -class F3_rd : F3 { - bits<5> rd; - let Inst{29-25} = rd; -} - -// F3_rdrs1 - Common class of instructions that have rd and rs1 fields -class F3_rdrs1 : F3_rd { - bits<5> rs1; - let Inst{18-14} = rs1; -} - -// F3_rdrs1simm13 - Common class of instructions that have rd, rs1, and simm13 -class F3_rdrs1simm13 : F3_rdrs1 { - bits<13> simm13; - let Inst{12-0} = simm13; -} - -// F3_rdrs1rs2 - Common class of instructions that have rd, rs1, and rs2 fields -class F3_rdrs1rs2 : F3_rdrs1 { - bits<5> rs2; - let Inst{4-0} = rs2; -} - - -// Specific F3 classes... -// - -class F3_1 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 diff --git a/lib/Target/SparcV9/SparcV9_F4.td b/lib/Target/SparcV9/SparcV9_F4.td deleted file mode 100644 index 86cd30a37ae..00000000000 --- a/lib/Target/SparcV9/SparcV9_F4.td +++ /dev/null @@ -1,141 +0,0 @@ -//===- SparcV9_F4.td - SparcV9 Format 4 instructions -------*- tablegen -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -//----------------------- F4 classes ----------------------------------------- - -// F4 - Common superclass of all F4 instructions. All instructions have an op3 -// field. -class F4 : InstV9 { - bits<6> op3; - let Inst{24-19} = op3; -} - -// F4_rs1 - Common class of instructions that use an rs1 field -class F4_rs1 : F4 { - bits<5> rs1; - let Inst{18-14} = rs1; -} - -// F4_rs1rs2 - Common class of instructions that have rs1 and rs2 fields -class F4_rs1rs2 : F4_rs1 { - bits<5> rs2; - let Inst{4-0} = rs2; -} - -// F4_rs1rs2rd - Common class of instructions that have 3 register operands -class F4_rs1rs2rd : F4_rs1rs2 { - bits<5> rd; - let Inst{29-25} = rd; -} - -// F4_rs1rs2rd - Common class of instructions that have 2 reg and 1 imm operand -class F4_rs1simm11rd : F4_rs1 { - bits<11> simm11; - bits<5> rd; - - let Inst{10-0} = simm11; - let Inst{29-25} = rd; -} - -// F4_cc - Common class of instructions that have a cond field -class F4_cond : F4 { - bits<4> cond; - let Inst{17-14} = cond; -} - -// F4_cc - Common class of instructions that have cc register as first operand -class F4_condcc : F4_cond { - bits<3> cc; - let Inst{18} = cc{2}; - let Inst{12} = cc{1}; - let Inst{11} = cc{0}; -} - -// Actual F4 instruction classes -// -class F4_1 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 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 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 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 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 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