From fd80c0d506052de09c8f9e8461308d4b61ed58af Mon Sep 17 00:00:00 2001 From: Prakalp Srivastava <psrivas2@illinois.edu> Date: Thu, 3 Mar 2016 18:46:51 -0600 Subject: [PATCH] Added Allocation node analysis pass. Forgot to add the pass in previous commit :) --- llvm/lib/Transforms/LocalMem/CMakeLists.txt | 3 + llvm/lib/Transforms/LocalMem/LocalMem.cpp | 225 ++++++++++++++++++ llvm/lib/Transforms/LocalMem/LocalMem.exports | 0 llvm/lib/Transforms/LocalMem/Makefile | 18 ++ 4 files changed, 246 insertions(+) create mode 100644 llvm/lib/Transforms/LocalMem/CMakeLists.txt create mode 100644 llvm/lib/Transforms/LocalMem/LocalMem.cpp create mode 100644 llvm/lib/Transforms/LocalMem/LocalMem.exports create mode 100644 llvm/lib/Transforms/LocalMem/Makefile diff --git a/llvm/lib/Transforms/LocalMem/CMakeLists.txt b/llvm/lib/Transforms/LocalMem/CMakeLists.txt new file mode 100644 index 0000000000..27810485a5 --- /dev/null +++ b/llvm/lib/Transforms/LocalMem/CMakeLists.txt @@ -0,0 +1,3 @@ +add_llvm_loadable_module( LLVMBuildDFG + LocalMem.cpp + ) diff --git a/llvm/lib/Transforms/LocalMem/LocalMem.cpp b/llvm/lib/Transforms/LocalMem/LocalMem.cpp new file mode 100644 index 0000000000..7041a3bf36 --- /dev/null +++ b/llvm/lib/Transforms/LocalMem/LocalMem.cpp @@ -0,0 +1,225 @@ +//===-------------------------- LocalMem.cpp --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "LocalMem" +#include "llvm/IR/Module.h" +#include "llvm/Pass.h" +#include "llvm/Support/InstIterator.h" +#include "llvm/Transforms/Utils/ValueMapper.h" +#include "llvm/Transforms/Utils/BasicBlockUtils.h" +#include "llvm/Transforms/Utils/Cloning.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/DFG2LLVM.h" + +using namespace llvm; +using namespace builddfg; +using namespace dfg2llvm; + +namespace { +// Helper Functions + +static AllocationNodeProperty* isAllocationNode(DFLeafNode* N); +static Value* getOutValueAt(DFLeafNode*N, unsigned i); + +// LocalMem - The first implementation. +struct LocalMem : public ModulePass { + static char ID; // Pass identification, replacement for typeid + LocalMem() : ModulePass(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 AT_OCL : public CodeGenTraversal { + +private: + //Member variables + + //Functions + + // Virtual Functions + void init() {} + void initRuntimeAPI() {} + void codeGen(DFInternalNode* N); + void codeGen(DFLeafNode* N); + +public: + // Constructor + AT_OCL(Module &_M, BuildDFG &_DFG) : CodeGenTraversal(_M, _DFG) { + //init(); + //initRuntimeAPI(); + } + +}; + +bool LocalMem::runOnModule(Module &M) { + errs() << "\nLocalMem PASS\n"; + + // Get the BuildDFG Analysis Results: + // - Dataflow graph + // - Maps from i8* hansles to DFNode and DFEdge + BuildDFG &DFG = getAnalysis<BuildDFG>(); + + //DFInternalNode *Root = DFG.getRoot(); + std::vector<DFInternalNode*> Roots = DFG.getRoots(); + // BuildDFG::HandleToDFNode &HandleToDFNodeMap = DFG.getHandleToDFNodeMap(); + // BuildDFG::HandleToDFEdge &HandleToDFEdgeMap = DFG.getHandleToDFEdgeMap(); + + // Visitor for Code Generation Graph Traversal + AT_OCL *ATVisitor = new AT_OCL(M, DFG); + + // Iterate over all the DFGs and produce code for each one of them + for (auto rootNode: Roots) { + // Initiate code generation for root DFNode + ATVisitor->visit(rootNode); + // Go ahead and replace the launch intrinsic with pthread call, otherwise return now. + // TODO: Later on, we might like to do this in a separate pass, which would + // allow us the flexibility to switch between complete static code generation + // for DFG or having a customized runtime+scheduler + } + + delete ATVisitor; + return true; +} + +void AT_OCL::codeGen(DFInternalNode* N) { + errs() << "Analysing Node: " << N->getFuncPointer()->getName() << "\n"; +} + +// Code generation for leaf nodes +void AT_OCL::codeGen(DFLeafNode* N) { + errs() << "Analysing Node: " << N->getFuncPointer()->getName() << "\n"; + // Skip code generation if it is a dummy node + if(N->isDummyNode()) { + DEBUG(errs() << "Skipping dummy node\n"); + return; + } + + // Check and mark as allocation node + AllocationNodeProperty* ANP = isAllocationNode(N); + if(ANP != NULL) { + // set Properties of the allocation node + N->setProperty(DFNode::Allocation, ANP); + AllocationNodeProperty* anp = (AllocationNodeProperty*) N->getProperty(DFNode::Allocation); + AllocationNodeProperty::AllocationListType AL = anp->getAllocationList(); + errs() << "Total allocations = " << AL.size() << "\n"; + for(auto P: AL) { + errs() << " EdgePort: " << P.first->getDestPosition(); + errs() << " Size: " << *P.second << "\n"; + } + + } +} + +// Return pointer to property if this leaf node matches the conditions for being an allocation +// node. +// Conditions +// 1. No incoming memory pointer. No in/out attribute on a pointer argument +// 2. Uses visc malloc intrinsic to allocate memory +// 3. Sends it out +// 2. (TODO:) Whether the allocated pointer escapes the parent node +AllocationNodeProperty* isAllocationNode(DFLeafNode* N) { + // Allocation node must be free from side-effects + if(!N->hasSideEffects()) + return NULL; + + // Allocation node must have some outgoing edges + if(N->getOutputType()->isEmptyTy()) + return NULL; + + Function* F = N->getFuncPointer(); + + // Allocation node must use visc malloc intrinsic + bool usesVISCMalloc = false; + for(inst_iterator i = inst_begin(F), e = inst_end(F); i != e; i++) { + Instruction* I = &*i; + if(IntrinsicInst* II = dyn_cast<IntrinsicInst>(I)) { + if(II->getIntrinsicID() == Intrinsic::visc_malloc) { + usesVISCMalloc = true; + break; + } + } + } + if(!usesVISCMalloc) + return NULL; + + // TODO: Check if allocated pointer leaves parent node + + // This is an allocation node + AllocationNodeProperty* ANP = new AllocationNodeProperty(); + // Find the return statement. + // FIXME: For now, assuming their is just one BB. Terminator instruction of + // this BB is a return statement. The value returned is what we need + BasicBlock& BB = F->getEntryBlock(); + assert(isa<ReturnInst>(BB.getTerminator()) + && "Currently we do not handle the case where Allocation Node has multiple BB"); + ReturnInst* RI = dyn_cast<ReturnInst>(BB.getTerminator()); + // Find the returned struct + Value* val = RI->getReturnValue(); + std::vector<Value*> OutValues(6, NULL); + unsigned numOutputs = N->getOutputType()->getNumElements(); + for(unsigned i = 0; i < numOutputs; i++) { + if(InsertValueInst* IV = dyn_cast<InsertValueInst>(val)) { + DEBUG(errs() << "Value at out edge" << numOutputs-1-i << ": " << *val << "\n"); + OutValues[numOutputs-1-i] = IV->getOperand(1); + val = IV->getOperand(0); + } + else { + DEBUG(errs() << "Unexpected value at out edge: " << *val << "\n"); + llvm_unreachable("Expecting InsertValue instruction. Error!"); + } + } + // OutValues vector contains all the values that will go out + // Assume that the Allocation node only sends the pointers and their sizes + // forward + unsigned i=0; + while(i < numOutputs) { + assert(OutValues[i]->getType()->isPointerTy() + && "Expected outgoing edge to be of pointer type"); + if(IntrinsicInst* II = dyn_cast<IntrinsicInst>(OutValues[i])) { + if(II->getIntrinsicID() == Intrinsic::visc_malloc) { + // Sanity check: Size passed to malloc intrinsic is same as the value + // going into the next outgoing edge + DEBUG(errs() << "Visc malloc size: " << *II->getArgOperand(0) << "\n"); + DEBUG(errs() << "Out edge value: " << *OutValues[i+1] << "\n"); + assert(II->getArgOperand(0) == OutValues[i+1] + && "Sanity Check Failed: VISC Malloc size argument != next outgoing edge"); + ANP->insertAllocation(N->getOutDFEdgeAt(i), II->getArgOperand(0)); + i = i+2; + continue; + } + } + llvm_unreachable("Expecting visc malloc intrinsic instruction!"); + } + return ANP; +} + +} // End of namespace + +char LocalMem::ID = 0; +static RegisterPass<LocalMem> X("localmem", + "Pass to identifying nodes amenable to local memory allocation", + false /* does not modify the CFG */, + true /* transformation, not just analysis */); + diff --git a/llvm/lib/Transforms/LocalMem/LocalMem.exports b/llvm/lib/Transforms/LocalMem/LocalMem.exports new file mode 100644 index 0000000000..e69de29bb2 diff --git a/llvm/lib/Transforms/LocalMem/Makefile b/llvm/lib/Transforms/LocalMem/Makefile new file mode 100644 index 0000000000..838964c0b2 --- /dev/null +++ b/llvm/lib/Transforms/LocalMem/Makefile @@ -0,0 +1,18 @@ +##===- lib/Transforms/LocalMem/Makefile -----------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../../../ +LIBRARYNAME = LLVMLocalMem +LOADABLE_MODULE = 1 +CXXFLAGS+= -Wno-c++11-extensions +#SHARED_LIBRARY = 1 +#BUILD_ARCHIVE = 1 +#USEDLIBS = + +include $(LEVEL)/Makefile.common -- GitLab