Skip to content
Snippets Groups Projects
Commit d2878d57 authored by kotsifa2's avatar kotsifa2
Browse files

Added DFG2LLVM_NVPTX pass.

parent 92143238
No related branches found
No related tags found
No related merge requests found
add_llvm_loadable_module( LLVMDFG2LLVM_NVPTX
DFG2LLVM_NVPTX.cpp
)
//=== DFG2LLVM_NVPTX.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 "DFG2LLVM_NVPTX"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/Support/InstIterator.h"
#include "llvm/BuildDFG/BuildDFG.h"
using namespace llvm;
using namespace builddfg;
//STATISTIC(IntrinsicCounter, "Counts number of visc intrinsics greeted");
namespace {
// DFG2LLVM_NVPTX - The first implementation.
struct DFG2LLVM_NVPTX : public ModulePass {
static char ID; // Pass identification, replacement for typeid
DFG2LLVM_NVPTX() : ModulePass(ID) {}
private:
// Member variables
// Functions
public:
bool runOnModule(Module &M);
void getAnalysisUsage(AnalysisUsage &AU) const {
AU.addRequired<BuildDFG>();
}
};
// Visitor for Code generation traversal (tree traversal for now)
class CodeGenTraversal : public DFNodeVisitor {
private:
//Member variables
Module &M;
BuildDFG &DFG;
//Functions
void codeGen(DFInternalNode* N) {
}
// Code generation for leaf nodes
void codeGen(DFLeafNode* N) {
std::vector<IntrinsicInst *> IItoRemove;
BuildDFG::HandleToDFNode Leaf_HandleToDFNodeMap;
// Get the function associated woth the dataflow node
Function *F = N->getFuncPointer();
// Go through all the instructions
for (inst_iterator i = inst_begin(F), e = inst_end(F); i != e; ++i) {
Instruction *I = &(*i);
// Leaf nodes should not contain VISC graph intrinsics or launch
assert(!BuildDFG::isViscLaunchIntrinsic(I) && "Launch intrinsic within a dataflow graph!");
assert(!BuildDFG::isViscGraphIntrinsic(I) && "VISC graph intrinsic within a leaf dataflow node!");
if (BuildDFG::isViscQueryIntrinsic(I)) {
IntrinsicInst* II = dyn_cast<IntrinsicInst>(I);
IntrinsicInst* ArgII;
DFNode* ArgDFNode;
/******************************************************************************
* Handle VISC Query intrinsics *
******************************************************************************/
switch (II->getIntrinsicID()) {
/**************************** llvm.visc.getNode() *****************************/
case Intrinsic::visc_getNode: {
// add mapping <intrinsic, this node> to the node-specific map
Leaf_HandleToDFNodeMap[II] = N;
IItoRemove.push_back(II);
}
break;
/************************* llvm.visc.getParentNode() **************************/
case Intrinsic::visc_getParentNode: {
// get the parent node of the arg node
// get argument node
ArgII = cast<IntrinsicInst>((II->getOperand(0))->stripPointerCasts());
ArgDFNode = Leaf_HandleToDFNodeMap[ArgII];
// get the parent node of the arg node
// Add mapping <intrinsic, parent node> to the node-specific map
// the argument node must have been added to the map, orelse the
// code could not refer to it
Leaf_HandleToDFNodeMap[II] = ArgDFNode->getParent();
IItoRemove.push_back(II);
}
break;
/*************************** llvm.visc.getNumDims() ***************************/
case Intrinsic::visc_getNumDims: {
// get node from map
// get the appropriate field
int numOfDim = Leaf_HandleToDFNodeMap[ArgII]->getNumOfDim();
IntegerType* IntTy = Type::getInt32Ty(getGlobalContext());
ConstantInt* numOfDimConstant = ConstantInt::getSigned(IntTy, (int64_t) numOfDim);
// Replace the result of the intrinsic with the computed value
II->replaceAllUsesWith(numOfDimConstant);
IItoRemove.push_back(II);
}
break;
/*********************** llvm.visc.getNodeInstanceID() ************************/
case Intrinsic::visc_getNodeInstanceID: {
ArgII = cast<IntrinsicInst>((II->getOperand(0))->stripPointerCasts());
ArgDFNode = Leaf_HandleToDFNodeMap[ArgII];
// A leaf node always has a parent
DFNode* ParentDFNode = DFG.getHandleToDFNodeMap()[ArgII];
// Get specified dimension
// (dim = 0) => x
// (dim = 1) => y
// (dim = 2) => z
ConstantInt * DimConstant = cast<ConstantInt>(II->getOperand(1));
int dim = (int) DimConstant->getSExtValue();
assert((dim >= 0) && (dim < 3) && "Invalid dimension argument");
// Argument of the function to be called
ArrayRef<Value *> Args(DimConstant);
// The following is to find which function to call
Function * OpenCLFunction;
int parentLevel = ParentDFNode->getLevel();
if (!parentLevel) {
// We only have one level in the hierarchy, but still need to
// specify a global id
assert((dim != 2) && "Invalid dimension argument");
FunctionType* FT =
FunctionType::get(Type::getInt32Ty(getGlobalContext()),
std::vector<Type*>(1, Type::getInt32Ty(getGlobalContext())),
false);
OpenCLFunction = cast<Function>
(M.getOrInsertFunction(StringRef("get_global_id"), FT));
} else if (Leaf_HandleToDFNodeMap[ArgII] == Leaf_HandleToDFNodeMap[II]) {
// We are asking for this node's id with respect to its parent
// this is a local id call
FunctionType* FT =
FunctionType::get(Type::getInt32Ty(getGlobalContext()),
std::vector<Type*>(1, Type::getInt32Ty(getGlobalContext())),
false);
OpenCLFunction = cast<Function>
(M.getOrInsertFunction(StringRef("get_local_id"), FT));
} else if (Leaf_HandleToDFNodeMap[ArgII] == N->getParent()) {
// We are asking for this node's parent's id with respect to its
// parent: this is a group id call
FunctionType* FT =
FunctionType::get(Type::getInt32Ty(getGlobalContext()),
std::vector<Type*>(1, Type::getInt32Ty(getGlobalContext())),
false);
OpenCLFunction = cast<Function>
(M.getOrInsertFunction(StringRef("get_group_id"), FT));
} else {
assert(false && "Unable to translate this intrinsic");
}
// Create call instruction, insert it before the intrinsic and
// replace the uses of the previous instruction with the new one
CallInst* CI = CallInst::Create(OpenCLFunction, Args, "", II);
II->replaceAllUsesWith(CI);
IItoRemove.push_back(II);
}
break;
/********************** llvm.visc.getNumNodeInstances() ***********************/
case Intrinsic::visc_getNumNodeInstances: {
//TODO: think about whether this is the best way to go
// there are hw specific registers. therefore it is good to have the intrinsic
// but then, why do we need to keep that info in the graph?
// (only for the kernel configuration during the call)
ArgII = cast<IntrinsicInst>((II->getOperand(0))->stripPointerCasts());
ArgDFNode = Leaf_HandleToDFNodeMap[ArgII];
// A leaf node always has a parent
DFNode* ParentDFNode = DFG.getHandleToDFNodeMap()[ArgII];
// Get specified dimension
ConstantInt * DimConstant = cast<ConstantInt>(II->getOperand(1));
int dim = (int) DimConstant->getSExtValue();
assert((dim >= 0) && (dim < 3) && "Invalid dimension argument");
// Argument of the function to be called
ArrayRef<Value *> Args(DimConstant);
// The following is to find which function to call
Function * OpenCLFunction;
int parentLevel = ParentDFNode->getLevel();
if (!parentLevel) {
// We only have one level in the hierarchy, thus the node
// instances are global_size (gridDim x blockDim)
FunctionType* FT =
FunctionType::get(Type::getInt32Ty(getGlobalContext()),
std::vector<Type*>(1, Type::getInt32Ty(getGlobalContext())),
false);
OpenCLFunction = cast<Function>
(M.getOrInsertFunction(StringRef("get_global_size"), FT));
} else if (Leaf_HandleToDFNodeMap[ArgII] == Leaf_HandleToDFNodeMap[II]) {
// We are asking for this node's instances
// this is a local size (block dim) call
FunctionType* FT =
FunctionType::get(Type::getInt32Ty(getGlobalContext()),
std::vector<Type*>(1, Type::getInt32Ty(getGlobalContext())),
false);
OpenCLFunction = cast<Function>
(M.getOrInsertFunction(StringRef("get_local_size"), FT));
} else if (Leaf_HandleToDFNodeMap[ArgII] == N->getParent()) {
// We are asking for this node's parent's instances
// this is a (global_size/local_size) (grid dim) call
FunctionType* FT =
FunctionType::get(Type::getInt32Ty(getGlobalContext()),
std::vector<Type*>(1, Type::getInt32Ty(getGlobalContext())),
false);
OpenCLFunction = cast<Function>
(M.getOrInsertFunction(StringRef("get_num_groups"), FT));
} else {
assert(false && "Unable to translate this intrinsic");
}
// Create call instruction, insert it before the intrinsic and
// replace the uses of the previous instruction with the new one
CallInst* CI = CallInst::Create(OpenCLFunction, Args, "", II);
II->replaceAllUsesWith(CI);
IItoRemove.push_back(II);
}
break;
default:
assert(false && "Unknown VISC Intrinsic!");
break;
}
} else {
//TODO: how to handle address space qualifiers in load/store
}
}
//TODO:
// When to replace the uses?
// In which order is it safe to replace the instructions in
// IItoReplace?
// Probably in the reverse order in the vectors
// It is a good idea to have them in one vector and chech the type
// using dyn_cast in order to determine if we replace with inst or value
//We need to do this explicitly: DCE pass will not remove them because we
// have assumed theworst memory behaviour for these function calls
for (std::vector<IntrinsicInst *>::iterator i = IItoRemove.begin();
i != IItoRemove.end(); ++i)
(*i)->eraseFromParent();
}
public:
// Constructor
CodeGenTraversal(Module &_M, BuildDFG &_DFG) : M(_M), DFG(_DFG) { }
virtual void visit(DFInternalNode* N) {
errs() << "Generating Code for Node (I) - " << N->getFuncPointer()->getName() << "\n";
codeGen(N);
errs() << "DONE" << "\n";
for(DFGraph::children_iterator i = N->getChildGraph()->begin(),
e = N->getChildGraph()->end(); i != e; ++i) {
DFNode* child = *i;
child->applyDFNodeVisitor(*this);
}
}
virtual void visit(DFLeafNode* N) {
errs() << "Generating Code for Node (L) - " << N->getFuncPointer()->getName() << "\n";
codeGen(N);
errs() << "DONE" << "\n";
}
};
bool DFG2LLVM_NVPTX::runOnModule(Module &M) {
// Get the BuildDFG Analysis Results:
// - Dataflow graph
// - Maps from i8* hansles to DFNode and DFEdge
BuildDFG &DFG = getAnalysis<BuildDFG>();
DFInternalNode *Root = DFG.getRoot();
// BuildDFG::HandleToDFNode &HandleToDFNodeMap = DFG.getHandleToDFNodeMap();
// BuildDFG::HandleToDFEdge &HandleToDFEdgeMap = DFG.getHandleToDFEdgeMap();
// Visitor for Code Generation Graph Traversal
CodeGenTraversal *CGTVisitor = new CodeGenTraversal(M, DFG);
// Initiate code generation for root DFNode
CGTVisitor->visit(Root);
//TODO: Edit module epilogue to remove the VISC intrinsic declarations
return true;
}
} // End of namespace
char DFG2LLVM_NVPTX::ID = 0;
static RegisterPass<DFG2LLVM_NVPTX> X("DFG2LLVM_NVPTX",
"Dataflow Graph to LLVM for nvptx Pass",
false /* does not modify the CFG */,
true /* transformation, not just analysis */);
##===- lib/Transforms/BuildDFG/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 = LLVMDFG2LLVM_NVPTX
LOADABLE_MODULE = 1
SHARED_LIBRARY = 1
#BUILD_ARCHIVE = 1
#USEDLIBS =
include $(LEVEL)/Makefile.common
......@@ -9,7 +9,7 @@
LEVEL = ../..
PARALLEL_DIRS = Utils Instrumentation Scalar InstCombine IPO Vectorize Hello \
ObjCARC BuildDFG
ObjCARC BuildDFG DFG2LLVM_NVPTX
include $(LEVEL)/Makefile.config
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment