From ddef1bb056c1fc6806aa0d8f1655795bd7bb5ab7 Mon Sep 17 00:00:00 2001 From: Prakalp Srivastava <prakalps@gmail.com> Date: Sat, 1 Aug 2015 18:38:08 -0500 Subject: [PATCH] Created Abstract class DFG2LLVM. The two passes DFG2LLVM_NVPTX and DFG2LLVM_X86 inherit from this class. Common features/functions have been put in the abstract class DFG2LLVM --- llvm/include/llvm/SupportVISC/DFG2LLVM.h | 234 +++++++++++ .../DFG2LLVM_NVPTX/DFG2LLVM_NVPTX.cpp | 372 +++--------------- .../Transforms/DFG2LLVM_X86/DFG2LLVM_X86.cpp | 242 ++---------- 3 files changed, 316 insertions(+), 532 deletions(-) create mode 100644 llvm/include/llvm/SupportVISC/DFG2LLVM.h diff --git a/llvm/include/llvm/SupportVISC/DFG2LLVM.h b/llvm/include/llvm/SupportVISC/DFG2LLVM.h new file mode 100644 index 0000000000..6f2aa5d02b --- /dev/null +++ b/llvm/include/llvm/SupportVISC/DFG2LLVM.h @@ -0,0 +1,234 @@ + +//===---- DFG2LLVM.h - Header file for "VISC Dataflow Graph to Target" ----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/IR/Module.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/Value.h" +#include "llvm/Pass.h" +#include "llvm/BuildDFG/BuildDFG.h" +#include "llvm/SupportVISC/VISCTimer.h" + +using namespace llvm; +using namespace builddfg; + +#define TIMER(X) do { if (VISCTimer) { X; } } while (0) + +namespace dfg2llvm { +// Helper Functions +static inline ConstantInt* getTimerID(Module&, enum visc_TimerID); + +// DFG2LLVM abstract class implementation +class DFG2LLVM : public ModulePass { +protected: + DFG2LLVM(char ID) : ModulePass(ID) {} + + // Member variables + + // Functions + +public: + // Pure Virtual Functions + virtual bool runOnModule(Module &M) = 0; + + // Functions + void getAnalysisUsage(AnalysisUsage &AU) const { + AU.addRequired<BuildDFG>(); + AU.addPreserved<BuildDFG>(); + } + +}; + +// Abstract Visitor for Code generation traversal (tree traversal for now) +class CodeGenTraversal : public DFNodeVisitor { + +protected: + //Member variables + Module &M; + BuildDFG &DFG; + bool VISCTimer = false; + Twine TargetName = "None"; + + // Map from Old function associated with DFNode to new cloned function with + // extra index and dimension arguments. This map also serves to find out if + // we already have an index and dim extended function copy or not (i.e., + // "Have we visited this function before?") + DenseMap<DFNode*, Value*> OutputMap; + + // VISC Runtime API + Module* runtimeModule; + + Constant* llvm_visc_initializeTimerSet; + Constant* llvm_visc_switchToTimer; + Constant* llvm_visc_printTimerSet; + GlobalVariable* TimerSet; + GlobalVariable* GraphIDAddr; + Instruction* InitCall; + Instruction* CleanupCall; + + + // Functions + Value* getStringPointer(const Twine& S, Instruction* InsertBefore, const Twine& Name = ""); + void addIdxDimArgs(Function* F); + Argument* getArgumentAt(Function* F, unsigned offset); + + // Pure Virtual Functions + virtual void init() = 0; + virtual void initRuntimeAPI() = 0;// { errs () << "*******Oops called from base class*******\n";} + virtual void codeGen(DFInternalNode* N) = 0; + virtual void codeGen(DFLeafNode* N) = 0; + + // Virtual Functions + virtual void initializeTimerSet(Instruction*); + virtual void switchToTimer(enum visc_TimerID, Instruction*); + virtual void printTimerSet(Instruction*); + + virtual ~CodeGenTraversal() {} + + +public: + + // Constructor + CodeGenTraversal(Module &_M, BuildDFG &_DFG) : M(_M), DFG(_DFG) {} + + virtual void visit(DFInternalNode* N) { + // If code has already been generated for this internal node, skip the + // children + if(N->getGenFunc() != NULL) + return; + + DEBUG(errs() << "Start: Generating Code for Node (I) - " << N->getFuncPointer()->getName() << "\n"); + + // Follows a bottom-up approach for code generation. + // First generate code for all the child nodes + for(DFGraph::children_iterator i = N->getChildGraph()->begin(), + e = N->getChildGraph()->end(); i != e; ++i) { + DFNode* child = *i; + child->applyDFNodeVisitor(*this); + } + // Generate code for this internal node now. This way all the cloned + // functions for children exist. + codeGen(N); + DEBUG(errs() << "DONE: Generating Code for Node (I) - " << N->getFuncPointer()->getName() << "\n"); + } + + virtual void visit(DFLeafNode* N) { + DEBUG(errs() << "Start: Generating Code for Node (L) - " << N->getFuncPointer()->getName() << "\n"); + codeGen(N); + DEBUG(errs() << "DONE: Generating Code for Node (L) - " << N->getFuncPointer()->getName() << "\n"); + } +}; + +// -------------- CodeGenTraversal Implementation ----------------- + +// Generate Code for declaring a constant string [L x i8] and return a pointer +// to the start of it. +Value* CodeGenTraversal::getStringPointer(const Twine& S, Instruction* IB, const Twine& Name) { + errs() << "Module pointer: " << &M << "\n"; + + Constant* SConstant = ConstantDataArray::getString(M.getContext(), S.str(), true); + errs () << "String constant = " << *SConstant << "\n"; + Value* SGlobal = new GlobalVariable(M, SConstant->getType(), true, + GlobalValue::InternalLinkage, SConstant, Name); + errs () << "String global = " << *SGlobal << "\n"; + Value* Zero = ConstantInt::get(Type::getInt64Ty(getGlobalContext()), 0); + Value* GEPArgs[] = {Zero, Zero}; + errs () << "Zero = " << *Zero << "\n"; + errs () << "Module = " << *IB->getParent() << "\n"; + GetElementPtrInst* SPtr = GetElementPtrInst::Create(SGlobal, + ArrayRef<Value*>(GEPArgs, 2), Name+"Ptr", IB); + errs() << "String pointer = " << SPtr << "\n"; + return SPtr; +} + +// Change the argument list of function F to add index and limit arguments +void CodeGenTraversal::addIdxDimArgs(Function* F) { + // Add Index and Dim arguments + std::string names[] = {"idx_x", "idx_y", "idx_z", "dim_x", "dim_y", "dim_z"}; + for (int i = 0; i < 6; ++i) { + new Argument(Type::getInt32Ty(F->getContext()), names[i], F); + } + + // Create the argument type list with added argument types + std::vector<Type*> ArgTypes; + for(Function::const_arg_iterator ai = F->arg_begin(), ae = F->arg_end(); + ai != ae; ++ai) { + ArgTypes.push_back(ai->getType()); + } + // Adding new arguments to the function argument list, would not change the + // function type. We need to change the type of this function to reflect the + // added arguments + FunctionType* FTy = FunctionType::get(F->getReturnType(), ArgTypes, F->isVarArg()); + PointerType* PTy = PointerType::get(FTy, cast<PointerType>(F->getType())->getAddressSpace()); + + // Change the function type + F->mutateType(PTy); +} + +// Traverse the function F argument list to get argument at offset +Argument* CodeGenTraversal::getArgumentAt(Function* F, unsigned offset) { + DEBUG(errs() << "Finding argument " << offset << ":\n"); + assert((F->getFunctionType()->getNumParams() > offset && offset >= 0) + && "Invalid offset to access arguments!"); + Argument* arg; + Function::arg_iterator i = F->arg_begin(), e = F->arg_end(); + for(; offset != 0 && i!=e; i++) { + offset--; + } + arg = i; + DEBUG(errs() << "\t" << *arg <<"\n"); + return arg; +} + +// Timer Routines +// Initialize the timer set +void CodeGenTraversal::initializeTimerSet(Instruction* InsertBefore) { + DEBUG(errs() << "Inserting call to: " << *llvm_visc_initializeTimerSet << "\n"); + TIMER(TimerSet = new GlobalVariable(M, + Type::getInt8PtrTy(M.getContext()), + false, + GlobalValue::CommonLinkage, + Constant::getNullValue(Type::getInt8PtrTy(M.getContext())), + "viscTimerSet_"+TargetName); + + Value* TimerSetAddr = CallInst::Create(llvm_visc_initializeTimerSet, + None, + "", + InsertBefore); + new StoreInst(TimerSetAddr, TimerSet, InsertBefore); + ); +} + +void CodeGenTraversal::switchToTimer(enum visc_TimerID timer, Instruction* InsertBefore) { + Value* switchArgs[] = {TimerSet, getTimerID(M, timer)}; + TIMER(CallInst::Create(llvm_visc_switchToTimer, + ArrayRef<Value*>(switchArgs, 2), + "", + InsertBefore)); +} + +void CodeGenTraversal::printTimerSet(Instruction* InsertBefore) { + Value* TimerName; + TIMER(TimerName = getStringPointer(TargetName+"_Timer", InsertBefore)); + Value* printArgs[] = {TimerSet, TimerName}; + TIMER(CallInst::Create(llvm_visc_printTimerSet, + ArrayRef<Value*>(printArgs, 2), + "", + InsertBefore)); +} + +// Implementation of Helper Functions +static inline ConstantInt* getTimerID(Module& M, enum visc_TimerID timer) { + return ConstantInt::get(Type::getInt32Ty(M.getContext()), timer); +} + +} // End of namespace + diff --git a/llvm/lib/Transforms/DFG2LLVM_NVPTX/DFG2LLVM_NVPTX.cpp b/llvm/lib/Transforms/DFG2LLVM_NVPTX/DFG2LLVM_NVPTX.cpp index ce52a029a4..ecaf0a4139 100644 --- a/llvm/lib/Transforms/DFG2LLVM_NVPTX/DFG2LLVM_NVPTX.cpp +++ b/llvm/lib/Transforms/DFG2LLVM_NVPTX/DFG2LLVM_NVPTX.cpp @@ -21,26 +21,29 @@ #include "llvm/Transforms/Utils/ValueMapper.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Transforms/Utils/Cloning.h" -#include "llvm/BuildDFG/BuildDFG.h" #include "llvm/IRReader/IRReader.h" #include "llvm/Linker.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/FileSystem.h" #include "llvm/IR/Attributes.h" #include "llvm/SupportVISC/VISCTimer.h" +#include "llvm/SupportVISC/DFG2LLVM.h" #include <sstream> using namespace llvm; using namespace builddfg; +using namespace dfg2llvm; //STATISTIC(IntrinsicCounter, "Counts number of visc intrinsics greeted"); -#define TIMER(X) do { if (VISCTimer) { X; } } while (0) +#define DECLARE(X) X = M.getOrInsertFunction(#X, \ + runtimeModule->getFunction(#X)->getFunctionType()); \ + DEBUG(errs() << *X) // VISC Command line option to use timer or not static cl::opt<bool> -VISCTimer("visc-timers-ptx", cl::desc("Enable visc timers")); +VISCTimer_NVPTX("visc-timers-ptx", cl::desc("Enable visc timers")); namespace { // Helper class declarations @@ -120,51 +123,30 @@ static std::string getPTXFilename(const Module&); static std::string getFilenameFromModule(const Module& M); static void changeDataLayout(Module &); static void changeTargetTriple(Module &); -static std::string printType(Type*); -static std::string convertInt(int); static void findReturnInst(Function *, std::vector<ReturnInst *> &); -static inline ConstantInt* getTimerID(Module&, enum visc_TimerID); // DFG2LLVM_NVPTX - The first implementation. -struct DFG2LLVM_NVPTX : public ModulePass { +struct DFG2LLVM_NVPTX : public DFG2LLVM { static char ID; // Pass identification, replacement for typeid - DFG2LLVM_NVPTX() : ModulePass(ID) {} + DFG2LLVM_NVPTX() : DFG2LLVM(ID) {} private: - // Member variables - - // Functions public: bool runOnModule(Module &M); - - void getAnalysisUsage(AnalysisUsage &AU) const { - AU.addRequired<BuildDFG>(); - AU.addPreserved<BuildDFG>(); - } - - }; // Visitor for Code generation traversal (tree traversal for now) -class CodeGenTraversal : public DFNodeVisitor { +class CGT_NVPTX : public CodeGenTraversal { private: //Member variables - Module &M; - BuildDFG &DFG; Module &KernelM; DFNode* KernelLaunchNode; Kernel* kernel; - // Map from Old function associated with DFNode to new cloned function with - // extra index and dimension arguments. This map also serves to find out if - // we already have an index and dim extended function copy or not (i.e., - // "Have we visited this function before?") - DenseMap<DFNode*, Value*> OutputMap; // VISC Runtime API - Module* runtimeModule; Constant* llvm_visc_ptx_launch; Constant* llvm_visc_ptx_wait; Constant* llvm_visc_ptx_initContext; @@ -175,44 +157,31 @@ private: Constant* llvm_visc_ptx_getOutput; Constant* llvm_visc_ptx_executeNode; - Constant* llvm_visc_initializeTimerSet; - Constant* llvm_visc_switchToTimer; - Constant* llvm_visc_printTimerSet; - GlobalVariable* TimerSet; - GlobalVariable* GraphIDAddr; - Instruction* InitCall; - Instruction* CleanupCall; - - //Functions std::string getKernelsModuleName(Module &M); void fixValueAddrspace(Value* V, unsigned addrspace); - Value* getStringPointer(const Twine& S, Instruction* InsertBefore, const Twine& Name = ""); void changeArgAddrspace(Function* F, unsigned i); void addCLMetadata(Function* F); void transformFunctionToVoid(Function* F); - void initRuntimeAPI(); - void addIdxDimArgs(Function* F); - Argument* getArgumentAt(Function* F, unsigned offset); - Value* getInValueAt(DFNode* Child, unsigned i, Function* ParentF_X86, - Instruction* InsertBefore); void insertRuntimeCalls(DFInternalNode* N, Kernel* K, const Twine& FileName); - void initializeTimerSet(Instruction*); - void switchToTimer(enum visc_TimerID, Instruction*); - void printTimerSet(Instruction*); + // Virtual Functions + void init() { + VISCTimer = VISCTimer_NVPTX; + TargetName = "NVPTX"; + } + void initRuntimeAPI(); void codeGen(DFInternalNode* N); void codeGen(DFLeafNode* N); public: // Constructor - CodeGenTraversal(Module &_M, BuildDFG &_DFG) : M(_M), DFG(_DFG), KernelM(*CloneModule(&_M)) { - // Initialize Runtime API + CGT_NVPTX(Module &_M, BuildDFG &_DFG) : CodeGenTraversal(_M, _DFG), KernelM(*CloneModule(&_M)) { + init(); initRuntimeAPI(); // Copying instead of creating new, in order to preserve required info (metadata) - // Remove functions, global variables and aliases std::vector<GlobalVariable*> gvv = std::vector<GlobalVariable*>(); for (Module::global_iterator mi = KernelM.global_begin(), @@ -254,30 +223,11 @@ public: } - virtual void visit(DFInternalNode* N) { - for(DFGraph::children_iterator i = N->getChildGraph()->begin(), - e = N->getChildGraph()->end(); i != e; ++i) { - DFNode* child = *i; - child->applyDFNodeVisitor(*this); - } - - DEBUG(errs() << "Generating Code for Node (I) - " << N->getFuncPointer()->getName() << "\n"); - codeGen(N); - DEBUG(errs() << "DONE" << "\n"); - - } - - virtual void visit(DFLeafNode* N) { - DEBUG(errs() << "Generating Code for Node (L) - " << N->getFuncPointer()->getName() << "\n"); - codeGen(N); - DEBUG(errs() << "DONE" << "\n"); - } - void writeKernelsModule(); }; // Initialize the VISC runtime API. This makes it easier to insert these calls -void CodeGenTraversal::initRuntimeAPI() { +void CGT_NVPTX::initRuntimeAPI() { // Load Runtime API Module SMDiagnostic Err; @@ -295,53 +245,18 @@ void CodeGenTraversal::initRuntimeAPI() { DEBUG(errs() << "Successfully loaded visc-rt API module\n"); // Get or insert the global declarations for launch/wait functions - llvm_visc_ptx_launch = M.getOrInsertFunction("llvm_visc_ptx_launch", - runtimeModule->getFunction("llvm_visc_ptx_launch")->getFunctionType()); - DEBUG(errs() << *llvm_visc_ptx_launch); - - llvm_visc_ptx_wait = M.getOrInsertFunction("llvm_visc_ptx_wait", - runtimeModule->getFunction("llvm_visc_ptx_wait")->getFunctionType()); - DEBUG(errs() << *llvm_visc_ptx_wait); - - llvm_visc_ptx_initContext = M.getOrInsertFunction("llvm_visc_ptx_initContext" , - runtimeModule->getFunction("llvm_visc_ptx_initContext")->getFunctionType()); - DEBUG(errs() << *llvm_visc_ptx_initContext); - - llvm_visc_ptx_clearContext = M.getOrInsertFunction("llvm_visc_ptx_clearContext" , - runtimeModule->getFunction("llvm_visc_ptx_clearContext")->getFunctionType()); - DEBUG(errs() << *llvm_visc_ptx_clearContext); - - llvm_visc_ptx_argument_scalar = M.getOrInsertFunction("llvm_visc_ptx_argument_scalar", - runtimeModule->getFunction("llvm_visc_ptx_argument_scalar")->getFunctionType()); - DEBUG(errs() << *llvm_visc_ptx_argument_scalar); - - llvm_visc_ptx_argument_ptr = M.getOrInsertFunction("llvm_visc_ptx_argument_ptr", - runtimeModule->getFunction("llvm_visc_ptx_argument_ptr")->getFunctionType()); - DEBUG(errs() << *llvm_visc_ptx_argument_ptr); - - llvm_visc_ptx_free = M.getOrInsertFunction("llvm_visc_ptx_free", - runtimeModule->getFunction("llvm_visc_ptx_free")->getFunctionType()); - DEBUG(errs() << *llvm_visc_ptx_argument_ptr); - - llvm_visc_ptx_getOutput = M.getOrInsertFunction("llvm_visc_ptx_getOutput", - runtimeModule->getFunction("llvm_visc_ptx_getOutput")->getFunctionType()); - DEBUG(errs() << *llvm_visc_ptx_getOutput); - - llvm_visc_ptx_executeNode = M.getOrInsertFunction("llvm_visc_ptx_executeNode", - runtimeModule->getFunction("llvm_visc_ptx_executeNode")->getFunctionType()); - DEBUG(errs() << *llvm_visc_ptx_executeNode); - - llvm_visc_initializeTimerSet = M.getOrInsertFunction("llvm_visc_initializeTimerSet", - runtimeModule->getFunction("llvm_visc_initializeTimerSet")->getFunctionType()); - DEBUG(errs() << *llvm_visc_initializeTimerSet); - - llvm_visc_switchToTimer = M.getOrInsertFunction("llvm_visc_switchToTimer", - runtimeModule->getFunction("llvm_visc_switchToTimer")->getFunctionType()); - DEBUG(errs() << *llvm_visc_switchToTimer); - - llvm_visc_printTimerSet = M.getOrInsertFunction("llvm_visc_printTimerSet", - runtimeModule->getFunction("llvm_visc_printTimerSet")->getFunctionType()); - DEBUG(errs() << *llvm_visc_printTimerSet); + DECLARE(llvm_visc_ptx_launch); + DECLARE(llvm_visc_ptx_wait); + DECLARE(llvm_visc_ptx_initContext); + DECLARE(llvm_visc_ptx_clearContext); + DECLARE(llvm_visc_ptx_argument_scalar); + DECLARE(llvm_visc_ptx_argument_ptr); + DECLARE(llvm_visc_ptx_free); + DECLARE(llvm_visc_ptx_getOutput); + DECLARE(llvm_visc_ptx_executeNode); + DECLARE(llvm_visc_initializeTimerSet); + DECLARE(llvm_visc_switchToTimer); + DECLARE(llvm_visc_printTimerSet); // Insert init context in main DEBUG(errs() << "Gen Code to initialize NVPTX Timer\n"); @@ -365,102 +280,13 @@ void CodeGenTraversal::initRuntimeAPI() { } -void CodeGenTraversal::addIdxDimArgs(Function* F) { - // Add Index and Dim arguments - std::string names[] = {"idx_x", "idx_y", "idx_z", "dim_x", "dim_y", "dim_z"}; - for (int i = 0; i < 6; ++i) { - new Argument(Type::getInt32Ty(F->getContext()), names[i], F); - } - - // Create the argument type list with added argument types - std::vector<Type*> ArgTypes; - for(Function::const_arg_iterator ai = F->arg_begin(), ae = F->arg_end(); - ai != ae; ++ai) { - ArgTypes.push_back(ai->getType()); - } - // Adding new arguments to the function argument list, would not change the - // function type. We need to change the type of this function to reflect the - // added arguments - FunctionType* FTy = FunctionType::get(F->getReturnType(), ArgTypes, F->isVarArg()); - PointerType* PTy = PointerType::get(FTy, cast<PointerType>(F->getType())->getAddressSpace()); - - // Change the function type - F->mutateType(PTy); -} - -/* Traverse the function F argument list to get argument at offset*/ -Argument* CodeGenTraversal::getArgumentAt(Function* F, unsigned offset) { - DEBUG(errs() << "Finding argument " << offset << ":\n"); - assert((F->getFunctionType()->getNumParams() > offset && offset >= 0) - && "Invalid offset to access arguments!"); - Argument* arg; - Function::arg_iterator i = F->arg_begin(), e = F->arg_end(); - for(; offset != 0 && i!=e; i++) { - offset--; - } - arg = i; - DEBUG(errs() << "\t" << *arg <<"\n"); - return arg; -} - - -Value* CodeGenTraversal::getInValueAt(DFNode* Child, unsigned i, Function* ParentF_X86, - Instruction* InsertBefore) { - // TODO: Assumption is that each input port of a node has just one - // incoming edge. May change later on. - - // Find the incoming edge at the requested input port - DFEdge* E = Child->getInDFEdgeAt(i); - assert(E && "No incoming edge or binding for input element!"); - // Find the Source DFNode associated with the incoming edge - DFNode* SrcDF = E->getSourceDF(); - - // If Source DFNode is a dummyNode, edge is from parent. Get the - // argument from argument list of this internal node - Value* inputVal; - if(SrcDF->isEntryNode()) { - inputVal = getArgumentAt(ParentF_X86, E->getSourcePosition()); - DEBUG(errs() << "Argument "<< i<< " = " << *inputVal << "\n"); - } - else { - // edge is from a sibling - // Check - code should already be generated for this source dfnode - assert(OutputMap.count(SrcDF) - && "Source node call not found. Dependency violation!"); - - // Find CallInst associated with the Source DFNode using OutputMap - Value* CI = OutputMap[SrcDF]; - - // Extract element at source position from this call instruction - std::vector<unsigned> IndexList; - IndexList.push_back(E->getSourcePosition()); - DEBUG(errs() << "Going to generate ExtarctVal inst from "<< *CI <<"\n"); - ExtractValueInst* EI = ExtractValueInst::Create(CI, IndexList, - "", InsertBefore); - inputVal = EI; - } - return inputVal; -} - -// Generate Code for declaring a constant string [L x i8] and return a pointer -// to the start of it. -Value* CodeGenTraversal::getStringPointer(const Twine& S, Instruction* IB, const Twine& Name) { - Constant* SConstant = ConstantDataArray::getString(M.getContext(), S.str(), true); - Value* SGlobal = new GlobalVariable(M, SConstant->getType(), true, - GlobalValue::InternalLinkage, SConstant, Name); - Value* Zero = ConstantInt::get(Type::getInt64Ty(getGlobalContext()), 0); - Value* GEPArgs[] = {Zero, Zero}; - GetElementPtrInst* SPtr = GetElementPtrInst::Create(SGlobal, - ArrayRef<Value*>(GEPArgs, 2), Name+"Ptr", IB); - return SPtr; -} // Generate Code to call the kernel // The plan is to replace the internal node with a leaf node. This method is // used to generate a function to associate with this leaf node. The function // is responsible for all the memory allocation/transfer and invoking the // kernel call on the device -void CodeGenTraversal::insertRuntimeCalls(DFInternalNode* N, Kernel* K, const Twine& FileName) { +void CGT_NVPTX::insertRuntimeCalls(DFInternalNode* N, Kernel* K, const Twine& FileName) { // Check if clone already exists. If it does, it means we have visited this // function before. assert(N->getGenFunc() == NULL && "Code already generated for this node"); @@ -819,7 +645,7 @@ void CodeGenTraversal::insertRuntimeCalls(DFInternalNode* N, Kernel* K, const Tw // Right now, only targeting the one level case. In general, device functions // can return values so we don't need to change them -void CodeGenTraversal::codeGen(DFInternalNode* N) { +void CGT_NVPTX::codeGen(DFInternalNode* N) { if (!KernelLaunchNode) { DEBUG(errs() << "No code generated (host code for kernel launch complete).\n"); @@ -892,46 +718,8 @@ void CodeGenTraversal::codeGen(DFInternalNode* N) { } } -void CodeGenTraversal::initializeTimerSet(Instruction* InsertBefore) { - Value* TimerSetAddr; - StoreInst* SI; - TIMER(TimerSet = new GlobalVariable(M, - Type::getInt8PtrTy(M.getContext()), - false, - GlobalValue::CommonLinkage, - Constant::getNullValue(Type::getInt8PtrTy(M.getContext())), - "viscTimerSet_NVPTX")); - DEBUG(errs() << "Inserting GV: " << *TimerSet->getType() << *TimerSet << "\n"); - DEBUG(errs() << "Inserting call to: " << *llvm_visc_initializeTimerSet << "\n"); - - TIMER(TimerSetAddr = CallInst::Create(llvm_visc_initializeTimerSet, - None, - "", - InsertBefore)); - DEBUG(errs() << "TimerSetAddress = " << *TimerSetAddr << "\n"); - TIMER(SI = new StoreInst(TimerSetAddr, TimerSet, InsertBefore)); - DEBUG(errs() << "Store Timer Address in Global variable: " << *SI << "\n"); -} - -void CodeGenTraversal::switchToTimer(enum visc_TimerID timer, Instruction* InsertBefore) { - Value* switchArgs[] = {TimerSet, getTimerID(M, timer)}; - TIMER(CallInst::Create(llvm_visc_switchToTimer, - ArrayRef<Value*>(switchArgs, 2), - "", - InsertBefore)); -} - -void CodeGenTraversal::printTimerSet(Instruction* InsertBefore) { - Value* TimerName; - TIMER(TimerName = getStringPointer("NVPTX_Timer", InsertBefore)); - Value* printArgs[] = {TimerSet, TimerName}; - TIMER(CallInst::Create(llvm_visc_printTimerSet, - ArrayRef<Value*>(printArgs, 2), - "", - InsertBefore)); -} -void CodeGenTraversal::codeGen(DFLeafNode* N) { +void CGT_NVPTX::codeGen(DFLeafNode* N) { // Skip code generation if it is a dummy node if(N->isDummyNode()) { @@ -1271,7 +1059,7 @@ bool DFG2LLVM_NVPTX::runOnModule(Module &M) { // BuildDFG::HandleToDFEdge &HandleToDFEdgeMap = DFG.getHandleToDFEdgeMap(); // Visitor for Code Generation Graph Traversal - CodeGenTraversal *CGTVisitor = new CodeGenTraversal(M, DFG); + CGT_NVPTX *CGTVisitor = new CGT_NVPTX(M, DFG); // Iterate over all the DFGs and produce code for each one of them for (auto rootNode: Roots) { @@ -1287,7 +1075,7 @@ bool DFG2LLVM_NVPTX::runOnModule(Module &M) { return true; } -std::string CodeGenTraversal::getKernelsModuleName(Module &M) { +std::string CGT_NVPTX::getKernelsModuleName(Module &M) { /*SmallString<128> currentDir; llvm::sys::fs::current_path(currentDir); std::string fileName = getFilenameFromModule(M); @@ -1297,7 +1085,7 @@ std::string CodeGenTraversal::getKernelsModuleName(Module &M) { return mid.append(".kernels.ll"); } -void CodeGenTraversal::fixValueAddrspace(Value* V, unsigned addrspace) { +void CGT_NVPTX::fixValueAddrspace(Value* V, unsigned addrspace) { assert(isa<PointerType>(V->getType()) && "Value should be of Pointer Type!"); PointerType* OldTy = cast<PointerType>(V->getType()); @@ -1314,7 +1102,7 @@ void CodeGenTraversal::fixValueAddrspace(Value* V, unsigned addrspace) { } } -void CodeGenTraversal::changeArgAddrspace(Function* F, unsigned addrspace) { +void CGT_NVPTX::changeArgAddrspace(Function* F, unsigned addrspace) { std::vector<Type*> ArgTypes; for(auto& arg: F->getArgumentList()) { DEBUG(errs() << arg << "\n"); @@ -1333,69 +1121,17 @@ void CodeGenTraversal::changeArgAddrspace(Function* F, unsigned addrspace) { } /* Add metadata to module KernelM, for OpenCL kernels */ -void CodeGenTraversal::addCLMetadata(Function *F) { +void CGT_NVPTX::addCLMetadata(Function *F) { IRBuilder<true> Builder(F->begin()); SmallVector<Value*,8> KernelMD; KernelMD.push_back(F); + + // TODO: There is additional metadata used by kernel files but we skip them as + // they are not mandatory. In future they might be useful to enable + // optimizations - //TODO: For now, we don not add any additional metadata - /* - // MDNode for the kernel argument address space qualifiers. - SmallVector<llvm::Value*, 8> addressQuals; - addressQuals.push_back(MDString::get(KernelM.getContext(), "kernel_arg_addr_space")); - - // We don't support images - // MDNode for the kernel argument access qualifiers (images only). - // SmallVector<llvm::Value*, 8> accessQuals; - // accessQuals.push_back(MDString::get(KernelM.getContext(), "kernel_arg_access_qual")); - - // MDNode for the kernel argument type names. - SmallVector<llvm::Value*, 8> argTypeNames; - argTypeNames.push_back(MDString::get(KernelM.getContext(), "kernel_arg_type")); - - //TODO: MDNode for the kernel argument type qualifiers. - // SmallVector<llvm::Value*, 8> argTypeQuals; - // argTypeQuals.push_back(MDString::get(KernelM.getContext(), "kernel_arg_type_qual")); - - // MDNode for the kernel argument names. - SmallVector<llvm::Value*, 8> argNames; - argNames.push_back(MDString::get(KernelM.getContext(), "kernel_arg_name")); - - for (Function::arg_iterator ai = F->arg_begin(), - ae = F->arg_end(); ai != ae; ++ai) { - Argument *arg = &*ai; - Type *argTy = arg->getType(); - - if (argTy->isPointerTy()) { - Type *pointeeTy = argTy->getPointerElementType(); - std::string typeName = printType(pointeeTy) + "*"; - // Get argument type name. - argTypeNames.push_back(MDString::get(KernelM.getContext(), typeName)); - - // Get address qualifier. - addressQuals.push_back(Builder.getInt32(argTy->getPointerAddressSpace())); - } else { - std::string typeName = printType(argTy); - // Get argument type name. - argTypeNames.push_back(MDString::get(KernelM.getContext(), typeName)); - - // Get address qualifier. - addressQuals.push_back(Builder.getInt32(GENERIC_ADDRSPACE)); - - } - - // Get argument name. - argNames.push_back(MDString::get(KernelM.getContext(), arg->getName())); - } - - KernelMD.push_back(MDNode::get(KernelM.getContext(), addressQuals)); - // KernelMD.push_back(MDNode::get(KernelM.getContext(), accessQuals)); - KernelMD.push_back(MDNode::get(KernelM.getContext(), argTypeNames)); - // KernelMD.push_back(MDNode::get(KernelM.getContext(), argTypeQuals)); - KernelMD.push_back(MDNode::get(KernelM.getContext(), argNames)); - */ MDNode *MDKernelNode = MDNode::get(KernelM.getContext(), KernelMD); NamedMDNode *MDN_kernels = KernelM.getOrInsertNamedMetadata("opencl.kernels"); MDN_kernels->addOperand(MDKernelNode); @@ -1408,10 +1144,9 @@ void CodeGenTraversal::addCLMetadata(Function *F) { NamedMDNode *MDN_annotations = KernelM.getOrInsertNamedMetadata("nvvm.annotations"); MDN_annotations->addOperand(MDNvvmAnnotationsNode); - //!1 = metadata !{void (float addrspace(1)*, float addrspace(1)*, float addrspace(1)*, i32, i32)* @matrixMul, metadata !"kernel", i32 1} } -void CodeGenTraversal::writeKernelsModule() { +void CGT_NVPTX::writeKernelsModule() { char* ErrorMessage = NULL; LLVMModuleRef KernelMRef = wrap(&KernelM); @@ -1426,7 +1161,7 @@ void CodeGenTraversal::writeKernelsModule() { LLVMDisposeModule(KernelMRef); } -void CodeGenTraversal::transformFunctionToVoid(Function* F) { +void CGT_NVPTX::transformFunctionToVoid(Function* F) { // FIXME: Maybe do that using the Node? StructType* FRetTy = cast<StructType>(F->getReturnType()); @@ -1653,21 +1388,6 @@ static void changeTargetTriple(Module &M) { return; } -// Helper function, generate a string representation of a type -static std::string printType(Type* ty) { - std::string type_str; - raw_string_ostream rso(type_str); - ty->print(rso); - return rso.str(); -} - -// Helper function, convert int to string -static std::string convertInt(int number) { - std::stringstream ss;//create a stringstream - ss << number;//add number to the stream - return ss.str();//return a string with the contents of the stream -} - // Helper function, populate a vector with all return statements in a function static void findReturnInst(Function* F, std::vector<ReturnInst *> & ReturnInstVec) { for (inst_iterator i = inst_begin(F), e = inst_end(F); i != e; ++i) { @@ -1679,10 +1399,6 @@ static void findReturnInst(Function* F, std::vector<ReturnInst *> & ReturnInstVe } } -static inline ConstantInt* getTimerID(Module& M, enum visc_TimerID timer) { - return ConstantInt::get(Type::getInt32Ty(M.getContext()), timer); -} - } // End of namespace char DFG2LLVM_NVPTX::ID = 0; diff --git a/llvm/lib/Transforms/DFG2LLVM_X86/DFG2LLVM_X86.cpp b/llvm/lib/Transforms/DFG2LLVM_X86/DFG2LLVM_X86.cpp index e0aa75e988..1419b4446e 100644 --- a/llvm/lib/Transforms/DFG2LLVM_X86/DFG2LLVM_X86.cpp +++ b/llvm/lib/Transforms/DFG2LLVM_X86/DFG2LLVM_X86.cpp @@ -14,33 +14,32 @@ #include "llvm/Transforms/Utils/ValueMapper.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Transforms/Utils/Cloning.h" -#include "llvm/BuildDFG/BuildDFG.h" #include "llvm/IRReader/IRReader.h" #include "llvm/Linker.h" #include "llvm/Support/SourceMgr.h" #include "llvm/IR/Constants.h" #include "llvm/IR/Constant.h" -#include "llvm/SupportVISC/VISCTimer.h" +#include "llvm/SupportVISC/DFG2LLVM.h" using namespace llvm; using namespace builddfg; +using namespace dfg2llvm; //STATISTIC(IntrinsicCounter, "Counts number of visc intrinsics greeted"); -#define TIMER(X) do { if (VISCTimer) { X; } } while (0) +#define DECLARE(X) X = M.getOrInsertFunction(#X, \ + runtimeModule->getFunction(#X)->getFunctionType()); \ + DEBUG(errs() << *X) // VISC Command line option to use timer or not static cl::opt<bool> -VISCTimer("visc-timers-x86", cl::desc("Enable visc timers")); +VISCTimer_X86("visc-timers-x86", cl::desc("Enable visc timers")); namespace { -// Helper Function -static inline ConstantInt* getTimerID(Module&, enum visc_TimerID); - // DFG2LLVM_X86 - The first implementation. -struct DFG2LLVM_X86 : public ModulePass { +struct DFG2LLVM_X86 : public DFG2LLVM { static char ID; // Pass identification, replacement for typeid - DFG2LLVM_X86() : ModulePass(ID) {} + DFG2LLVM_X86() :DFG2LLVM(ID) {} private: // Member variables @@ -49,28 +48,15 @@ private: public: bool runOnModule(Module &M); - - void getAnalysisUsage(AnalysisUsage &AU) const { - AU.addRequired<BuildDFG>(); - AU.addPreserved<BuildDFG>(); - } - - }; // Visitor for Code generation traversal (tree traversal for now) -class CodeGenTraversal : public DFNodeVisitor { +class CGT_X86 : public CodeGenTraversal { private: //Member variables - Module &M; - BuildDFG &DFG; - - // Map from Node to Instruction containing output of a node - DenseMap<DFNode*, Value*> OutputMap; // VISC Runtime API - Module* runtimeModule; Constant* llvm_visc_x86_launch; Constant* llvm_visc_x86_wait; Constant* llvm_visc_x86_push; @@ -78,68 +64,34 @@ private: Constant* llvm_visc_x86_getDimLimit; Constant* llvm_visc_x86_getDimInstance; - Constant* llvm_visc_initializeTimerSet; - Constant* llvm_visc_switchToTimer; - Constant* llvm_visc_printTimerSet; - - GlobalVariable* TimerSet; - - //Functionis - Value* getStringPointer(const Twine& S, Instruction* InsertBefore, const Twine& Name = ""); - void initRuntimeAPI(); + //Functions std::vector<IntrinsicInst*>* getWaitList(Value* LI); - void addIdxDimArgs(Function* F); Value* addLoop(Instruction* I, Value* limit, const Twine& indexName = ""); Argument* getArgumentFromEnd(Function* F, unsigned offset); - Argument* getArgumentAt(Function* F, unsigned offset); Value* getInValueAt(DFNode* Child, unsigned i, Function* ParentF_X86, Instruction* InsertBefore); void invokeChild_X86(DFNode* C, Function* F_X86, ValueToValueMapTy &VMap, Instruction* InsertBefore); void invokeChild_PTX(DFNode* C, Function* F_X86, ValueToValueMapTy &VMap, Instruction* InsertBefore); + + // Virtual Functions + void init() { + VISCTimer = VISCTimer_X86; + TargetName = "X86"; + } + void initRuntimeAPI(); void codeGen(DFInternalNode* N); void codeGen(DFLeafNode* N); - void initializeTimerSet(Instruction*); - void switchToTimer(enum visc_TimerID, Instruction*); - void printTimerSet(Instruction*); public: // Constructor - CodeGenTraversal(Module &_M, BuildDFG &_DFG) : M(_M), DFG(_DFG) { + CGT_X86(Module &_M, BuildDFG &_DFG) : CodeGenTraversal(_M, _DFG) { + init(); initRuntimeAPI(); } void codeGenLaunch(DFInternalNode* Root); - - virtual void visit(DFInternalNode* N) { - // If code has already been generated for this internal node, skip the - // children - if(N->getGenFunc() != NULL) - return; - - DEBUG(errs() << "Start: Generating Code for Node (I) - " << N->getFuncPointer()->getName() << "\n"); - - // Follows a bottom-up approach for code generation. - // First generate code for all the child nodes - for(DFGraph::children_iterator i = N->getChildGraph()->begin(), - e = N->getChildGraph()->end(); i != e; ++i) { - DFNode* child = *i; - child->applyDFNodeVisitor(*this); - } - // Generate code for this internal node now. This way all the cloned - // functions for children exist. - codeGen(N); - DEBUG(errs() << "DONE: Generating Code for Node (I) - " << N->getFuncPointer()->getName() << "\n"); - } - - virtual void visit(DFLeafNode* N) { - DEBUG(errs() << "Start: Generating Code for Node (L) - " << N->getFuncPointer()->getName() << "\n"); - codeGen(N); - DEBUG(errs() << "DONE: Generating Code for Node (L) - " << N->getFuncPointer()->getName() << "\n"); - } - - }; bool DFG2LLVM_X86::runOnModule(Module &M) { @@ -155,7 +107,7 @@ bool DFG2LLVM_X86::runOnModule(Module &M) { // BuildDFG::HandleToDFEdge &HandleToDFEdgeMap = DFG.getHandleToDFEdgeMap(); // Visitor for Code Generation Graph Traversal - CodeGenTraversal *CGTVisitor = new CodeGenTraversal(M, DFG); + CGT_X86 *CGTVisitor = new CGT_X86(M, DFG); // Iterate over all the DFGs and produce code for each one of them for (auto rootNode: Roots) { @@ -173,7 +125,7 @@ bool DFG2LLVM_X86::runOnModule(Module &M) { } // Initialize the VISC runtime API. This makes it easier to insert these calls -void CodeGenTraversal::initRuntimeAPI() { +void CGT_X86::initRuntimeAPI() { // Load Runtime API Module SMDiagnostic Err; @@ -192,41 +144,15 @@ void CodeGenTraversal::initRuntimeAPI() { DEBUG(errs() << "Successfully loaded visc-rt API module\n"); // Get or insert the global declarations for launch/wait functions - llvm_visc_x86_launch = M.getOrInsertFunction("llvm_visc_x86_launch", - runtimeModule->getFunction("llvm_visc_x86_launch")->getFunctionType()); - DEBUG(errs() << *llvm_visc_x86_launch); - - llvm_visc_x86_wait = M.getOrInsertFunction("llvm_visc_x86_wait", - runtimeModule->getFunction("llvm_visc_x86_wait")->getFunctionType()); - DEBUG(errs() << *llvm_visc_x86_wait); - - llvm_visc_x86_push = M.getOrInsertFunction("llvm_visc_x86_push", - runtimeModule->getFunction("llvm_visc_x86_push")->getFunctionType()); - DEBUG(errs() << *llvm_visc_x86_push); - - llvm_visc_x86_pop = M.getOrInsertFunction("llvm_visc_x86_pop", - runtimeModule->getFunction("llvm_visc_x86_pop")->getFunctionType()); - DEBUG(errs() << *llvm_visc_x86_pop); - - llvm_visc_x86_getDimLimit = M.getOrInsertFunction("llvm_visc_x86_getDimLimit", - runtimeModule->getFunction("llvm_visc_x86_getDimLimit")->getFunctionType()); - DEBUG(errs() << *llvm_visc_x86_getDimLimit); - - llvm_visc_x86_getDimInstance = M.getOrInsertFunction("llvm_visc_x86_getDimInstance", - runtimeModule->getFunction("llvm_visc_x86_getDimInstance")->getFunctionType()); - DEBUG(errs() << *llvm_visc_x86_getDimInstance); - - llvm_visc_initializeTimerSet = M.getOrInsertFunction("llvm_visc_initializeTimerSet", - runtimeModule->getFunction("llvm_visc_initializeTimerSet")->getFunctionType()); - DEBUG(errs() << *llvm_visc_initializeTimerSet); - - llvm_visc_switchToTimer = M.getOrInsertFunction("llvm_visc_switchToTimer", - runtimeModule->getFunction("llvm_visc_switchToTimer")->getFunctionType()); - DEBUG(errs() << *llvm_visc_switchToTimer); - - llvm_visc_printTimerSet = M.getOrInsertFunction("llvm_visc_printTimerSet", - runtimeModule->getFunction("llvm_visc_printTimerSet")->getFunctionType()); - DEBUG(errs() << *llvm_visc_printTimerSet); + DECLARE(llvm_visc_x86_launch); + DECLARE(llvm_visc_x86_wait); + DECLARE(llvm_visc_x86_push); + DECLARE(llvm_visc_x86_pop); + DECLARE(llvm_visc_x86_getDimLimit); + DECLARE(llvm_visc_x86_getDimInstance); + DECLARE(llvm_visc_initializeTimerSet); + DECLARE(llvm_visc_switchToTimer); + DECLARE(llvm_visc_printTimerSet); // Insert init context in main Function* VI = M.getFunction("llvm.visc.init"); @@ -248,7 +174,7 @@ void CodeGenTraversal::initRuntimeAPI() { /* Returns vector of all wait instructions */ -std::vector<IntrinsicInst*>* CodeGenTraversal::getWaitList(Value* GraphID) { +std::vector<IntrinsicInst*>* CGT_X86::getWaitList(Value* GraphID) { std::vector<IntrinsicInst*>* WaitList = new std::vector<IntrinsicInst*>(); // It must have been loaded from memory somewhere for(Value::use_iterator ui = GraphID->use_begin(), @@ -265,33 +191,10 @@ std::vector<IntrinsicInst*>* CodeGenTraversal::getWaitList(Value* GraphID) { return WaitList; } -void CodeGenTraversal::addIdxDimArgs(Function* F) { - // Add Index and Dim arguments - std::string names[] = {"idx_x", "idx_y", "idx_z", "dim_x", "dim_y", "dim_z"}; - for (int i = 0; i < 6; ++i) { - new Argument(Type::getInt32Ty(F->getContext()), names[i], F); - } - - // Create the argument type list with added argument types - std::vector<Type*> ArgTypes; - for(Function::const_arg_iterator ai = F->arg_begin(), ae = F->arg_end(); - ai != ae; ++ai) { - ArgTypes.push_back(ai->getType()); - } - // Adding new arguments to the function argument list, would not change the - // function type. We need to change the type of this function to reflect the - // added arguments - FunctionType* FTy = FunctionType::get(F->getReturnType(), ArgTypes, F->isVarArg()); - PointerType* PTy = PointerType::get(FTy, cast<PointerType>(F->getType())->getAddressSpace()); - - // Change the function type - F->mutateType(PTy); -} - /* Traverse the function argument list in reverse order to get argument at a * distance offset fromt he end of argument list of function F */ -Argument* CodeGenTraversal::getArgumentFromEnd(Function* F, unsigned offset) { +Argument* CGT_X86::getArgumentFromEnd(Function* F, unsigned offset) { assert((F->getFunctionType()->getNumParams() >= offset && offset > 0) && "Invalid offset to access arguments!"); Function::arg_iterator e = F->arg_end(); @@ -305,35 +208,6 @@ Argument* CodeGenTraversal::getArgumentFromEnd(Function* F, unsigned offset) { return arg; } -// Generate Code for declaring a constant string [L x i8] and return a pointer -// to the start of it. -Value* CodeGenTraversal::getStringPointer(const Twine& S, Instruction* IB, const Twine& Name) { - Constant* SConstant = ConstantDataArray::getString(M.getContext(), S.str(), true); - Value* SGlobal = new GlobalVariable(M, SConstant->getType(), true, - GlobalValue::InternalLinkage, SConstant, Name); - Value* Zero = ConstantInt::get(Type::getInt64Ty(getGlobalContext()), 0); - Value* GEPArgs[] = {Zero, Zero}; - GetElementPtrInst* SPtr = GetElementPtrInst::Create(SGlobal, - ArrayRef<Value*>(GEPArgs, 2), Name+"Ptr", IB); - return SPtr; -} - - -/* Traverse the function F argument list to get argument at offset*/ -Argument* CodeGenTraversal::getArgumentAt(Function* F, unsigned offset) { - assert((F->getFunctionType()->getNumParams() > offset && offset >= 0) - && "Invalid offset to access arguments!"); - - Argument* arg; - Function::arg_iterator i = F->arg_begin(), e = F->arg_end(); - for(; offset != 0 && i!=e; i++) { - offset--; - } - arg = i; - DEBUG(errs() << *F); - DEBUG(errs() << *arg <<"\n"); - return arg; -} /* Add Loop around the instruction I * Algorithm: @@ -346,7 +220,7 @@ Argument* CodeGenTraversal::getArgumentAt(Function* F, unsigned offset) { * which loops over bidy if true and goes to end if false * (5) Update phi node of body */ -Value* CodeGenTraversal::addLoop(Instruction* I, Value* limit, const Twine& indexName) { +Value* CGT_X86::addLoop(Instruction* I, Value* limit, const Twine& indexName) { BasicBlock* Entry = I->getParent(); BasicBlock* ForBody = Entry->splitBasicBlock(I, "for.body"); @@ -385,7 +259,7 @@ Value* CodeGenTraversal::addLoop(Instruction* I, Value* limit, const Twine& inde return IndexPhi; } -void CodeGenTraversal::codeGenLaunch(DFInternalNode* Root) { +void CGT_X86::codeGenLaunch(DFInternalNode* Root) { // TODO: Place an assert to check if the constant passed by launch intrinsic // as the number of arguments to DFG is same as the number of arguments of the // root of DFG @@ -504,7 +378,7 @@ void CodeGenTraversal::codeGenLaunch(DFInternalNode* Root) { } -Value* CodeGenTraversal::getInValueAt(DFNode* Child, unsigned i, Function* ParentF_X86, Instruction* InsertBefore) { +Value* CGT_X86::getInValueAt(DFNode* Child, unsigned i, Function* ParentF_X86, Instruction* InsertBefore) { // TODO: Assumption is that each input port of a node has just one // incoming edge. May change later on. @@ -541,7 +415,7 @@ Value* CodeGenTraversal::getInValueAt(DFNode* Child, unsigned i, Function* Paren return inputVal; } -void CodeGenTraversal::invokeChild_X86(DFNode* C, Function* F_X86, +void CGT_X86::invokeChild_X86(DFNode* C, Function* F_X86, ValueToValueMapTy &VMap,Instruction* IB) { Function* CF = C->getFuncPointer(); @@ -618,7 +492,7 @@ void CodeGenTraversal::invokeChild_X86(DFNode* C, Function* F_X86, errs() << *CI->getParent()->getParent(); } -void CodeGenTraversal::codeGen(DFInternalNode* N) { +void CGT_X86::codeGen(DFInternalNode* N) { // Check if clone already exists. If it does, it means we have visited this // function before and nothing else needs to be done for this leaf node. if(N->getGenFunc() != NULL) @@ -726,7 +600,7 @@ void CodeGenTraversal::codeGen(DFInternalNode* N) { } // Code generation for leaf nodes -void CodeGenTraversal::codeGen(DFLeafNode* N) { +void CGT_X86::codeGen(DFLeafNode* N) { // Skip code generation if it is a dummy node if(N->isDummyNode()) { DEBUG(errs() << "Skipping dummy node\n"); @@ -957,46 +831,6 @@ void CodeGenTraversal::codeGen(DFLeafNode* N) { DEBUG(errs() << *F_X86); } -void CodeGenTraversal::initializeTimerSet(Instruction* InsertBefore) { - DEBUG(errs() << "Inserting call to: " << *llvm_visc_initializeTimerSet << "\n"); - TIMER(TimerSet = new GlobalVariable(M, - Type::getInt8PtrTy(M.getContext()), - false, - GlobalValue::CommonLinkage, - Constant::getNullValue(Type::getInt8PtrTy(M.getContext())), - "viscTimerSet_X86"); - - Value* TimerSetAddr = CallInst::Create(llvm_visc_initializeTimerSet, - None, - "", - InsertBefore); - StoreInst* SI = new StoreInst(TimerSetAddr, TimerSet, InsertBefore); - ); -} - -void CodeGenTraversal::switchToTimer(enum visc_TimerID timer, Instruction* InsertBefore) { - Value* switchArgs[] = {TimerSet, getTimerID(M, timer)}; - TIMER(CallInst::Create(llvm_visc_switchToTimer, - ArrayRef<Value*>(switchArgs, 2), - "", - InsertBefore)); -} - -void CodeGenTraversal::printTimerSet(Instruction* InsertBefore) { - Value* TimerName; - TIMER(TimerName = getStringPointer("X86_Timer", InsertBefore)); - Value* printArgs[] = {TimerSet, TimerName}; - TIMER(CallInst::Create(llvm_visc_printTimerSet, - ArrayRef<Value*>(printArgs, 2), - "", - InsertBefore)); -} - -static inline ConstantInt* getTimerID(Module& M, enum visc_TimerID timer) { - return ConstantInt::get(Type::getInt32Ty(M.getContext()), timer); -} - - } // End of namespace char DFG2LLVM_X86::ID = 0; -- GitLab