|  | //===- NVPTXUtilities.cpp - Utility Functions -----------------------------===// | 
|  | // | 
|  | //                     The LLVM Compiler Infrastructure | 
|  | // | 
|  | // This file is distributed under the University of Illinois Open Source | 
|  | // License. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // This file contains miscellaneous utility functions | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "NVPTXUtilities.h" | 
|  | #include "NVPTX.h" | 
|  | #include "llvm/IR/Constants.h" | 
|  | #include "llvm/IR/Function.h" | 
|  | #include "llvm/IR/GlobalVariable.h" | 
|  | #include "llvm/IR/Module.h" | 
|  | #include "llvm/IR/Operator.h" | 
|  | #include <algorithm> | 
|  | #include <cstring> | 
|  | #include <map> | 
|  | #include <string> | 
|  | #include <vector> | 
|  | //#include <iostream> | 
|  | #include "llvm/Support/ManagedStatic.h" | 
|  | #include "llvm/Support/InstIterator.h" | 
|  |  | 
|  | using namespace llvm; | 
|  |  | 
|  | typedef std::map<std::string, std::vector<unsigned> > key_val_pair_t; | 
|  | typedef std::map<const GlobalValue *, key_val_pair_t> global_val_annot_t; | 
|  | typedef std::map<const Module *, global_val_annot_t> per_module_annot_t; | 
|  |  | 
|  | ManagedStatic<per_module_annot_t> annotationCache; | 
|  |  | 
|  | static void cacheAnnotationFromMD(const MDNode *md, key_val_pair_t &retval) { | 
|  | assert(md && "Invalid mdnode for annotation"); | 
|  | assert((md->getNumOperands() % 2) == 1 && "Invalid number of operands"); | 
|  | // start index = 1, to skip the global variable key | 
|  | // increment = 2, to skip the value for each property-value pairs | 
|  | for (unsigned i = 1, e = md->getNumOperands(); i != e; i += 2) { | 
|  | // property | 
|  | const MDString *prop = dyn_cast<MDString>(md->getOperand(i)); | 
|  | assert(prop && "Annotation property not a string"); | 
|  |  | 
|  | // value | 
|  | ConstantInt *Val = dyn_cast<ConstantInt>(md->getOperand(i + 1)); | 
|  | assert(Val && "Value operand not a constant int"); | 
|  |  | 
|  | std::string keyname = prop->getString().str(); | 
|  | if (retval.find(keyname) != retval.end()) | 
|  | retval[keyname].push_back(Val->getZExtValue()); | 
|  | else { | 
|  | std::vector<unsigned> tmp; | 
|  | tmp.push_back(Val->getZExtValue()); | 
|  | retval[keyname] = tmp; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static void cacheAnnotationFromMD(const Module *m, const GlobalValue *gv) { | 
|  | NamedMDNode *NMD = m->getNamedMetadata(llvm::NamedMDForAnnotations); | 
|  | if (!NMD) | 
|  | return; | 
|  | key_val_pair_t tmp; | 
|  | for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) { | 
|  | const MDNode *elem = NMD->getOperand(i); | 
|  |  | 
|  | Value *entity = elem->getOperand(0); | 
|  | // entity may be null due to DCE | 
|  | if (!entity) | 
|  | continue; | 
|  | if (entity != gv) | 
|  | continue; | 
|  |  | 
|  | // accumulate annotations for entity in tmp | 
|  | cacheAnnotationFromMD(elem, tmp); | 
|  | } | 
|  |  | 
|  | if (tmp.empty()) // no annotations for this gv | 
|  | return; | 
|  |  | 
|  | if ((*annotationCache).find(m) != (*annotationCache).end()) | 
|  | (*annotationCache)[m][gv] = tmp; | 
|  | else { | 
|  | global_val_annot_t tmp1; | 
|  | tmp1[gv] = tmp; | 
|  | (*annotationCache)[m] = tmp1; | 
|  | } | 
|  | } | 
|  |  | 
|  | bool llvm::findOneNVVMAnnotation(const GlobalValue *gv, std::string prop, | 
|  | unsigned &retval) { | 
|  | const Module *m = gv->getParent(); | 
|  | if ((*annotationCache).find(m) == (*annotationCache).end()) | 
|  | cacheAnnotationFromMD(m, gv); | 
|  | else if ((*annotationCache)[m].find(gv) == (*annotationCache)[m].end()) | 
|  | cacheAnnotationFromMD(m, gv); | 
|  | if ((*annotationCache)[m][gv].find(prop) == (*annotationCache)[m][gv].end()) | 
|  | return false; | 
|  | retval = (*annotationCache)[m][gv][prop][0]; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool llvm::findAllNVVMAnnotation(const GlobalValue *gv, std::string prop, | 
|  | std::vector<unsigned> &retval) { | 
|  | const Module *m = gv->getParent(); | 
|  | if ((*annotationCache).find(m) == (*annotationCache).end()) | 
|  | cacheAnnotationFromMD(m, gv); | 
|  | else if ((*annotationCache)[m].find(gv) == (*annotationCache)[m].end()) | 
|  | cacheAnnotationFromMD(m, gv); | 
|  | if ((*annotationCache)[m][gv].find(prop) == (*annotationCache)[m][gv].end()) | 
|  | return false; | 
|  | retval = (*annotationCache)[m][gv][prop]; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool llvm::isTexture(const llvm::Value &val) { | 
|  | if (const GlobalValue *gv = dyn_cast<GlobalValue>(&val)) { | 
|  | unsigned annot; | 
|  | if (llvm::findOneNVVMAnnotation( | 
|  | gv, llvm::PropertyAnnotationNames[llvm::PROPERTY_ISTEXTURE], | 
|  | annot)) { | 
|  | assert((annot == 1) && "Unexpected annotation on a texture symbol"); | 
|  | return true; | 
|  | } | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool llvm::isSurface(const llvm::Value &val) { | 
|  | if (const GlobalValue *gv = dyn_cast<GlobalValue>(&val)) { | 
|  | unsigned annot; | 
|  | if (llvm::findOneNVVMAnnotation( | 
|  | gv, llvm::PropertyAnnotationNames[llvm::PROPERTY_ISSURFACE], | 
|  | annot)) { | 
|  | assert((annot == 1) && "Unexpected annotation on a surface symbol"); | 
|  | return true; | 
|  | } | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool llvm::isSampler(const llvm::Value &val) { | 
|  | if (const GlobalValue *gv = dyn_cast<GlobalValue>(&val)) { | 
|  | unsigned annot; | 
|  | if (llvm::findOneNVVMAnnotation( | 
|  | gv, llvm::PropertyAnnotationNames[llvm::PROPERTY_ISSAMPLER], | 
|  | annot)) { | 
|  | assert((annot == 1) && "Unexpected annotation on a sampler symbol"); | 
|  | return true; | 
|  | } | 
|  | } | 
|  | if (const Argument *arg = dyn_cast<Argument>(&val)) { | 
|  | const Function *func = arg->getParent(); | 
|  | std::vector<unsigned> annot; | 
|  | if (llvm::findAllNVVMAnnotation( | 
|  | func, llvm::PropertyAnnotationNames[llvm::PROPERTY_ISSAMPLER], | 
|  | annot)) { | 
|  | if (std::find(annot.begin(), annot.end(), arg->getArgNo()) != annot.end()) | 
|  | return true; | 
|  | } | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool llvm::isImageReadOnly(const llvm::Value &val) { | 
|  | if (const Argument *arg = dyn_cast<Argument>(&val)) { | 
|  | const Function *func = arg->getParent(); | 
|  | std::vector<unsigned> annot; | 
|  | if (llvm::findAllNVVMAnnotation(func, | 
|  | llvm::PropertyAnnotationNames[ | 
|  | llvm::PROPERTY_ISREADONLY_IMAGE_PARAM], | 
|  | annot)) { | 
|  | if (std::find(annot.begin(), annot.end(), arg->getArgNo()) != annot.end()) | 
|  | return true; | 
|  | } | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool llvm::isImageWriteOnly(const llvm::Value &val) { | 
|  | if (const Argument *arg = dyn_cast<Argument>(&val)) { | 
|  | const Function *func = arg->getParent(); | 
|  | std::vector<unsigned> annot; | 
|  | if (llvm::findAllNVVMAnnotation(func, | 
|  | llvm::PropertyAnnotationNames[ | 
|  | llvm::PROPERTY_ISWRITEONLY_IMAGE_PARAM], | 
|  | annot)) { | 
|  | if (std::find(annot.begin(), annot.end(), arg->getArgNo()) != annot.end()) | 
|  | return true; | 
|  | } | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool llvm::isImage(const llvm::Value &val) { | 
|  | return llvm::isImageReadOnly(val) || llvm::isImageWriteOnly(val); | 
|  | } | 
|  |  | 
|  | std::string llvm::getTextureName(const llvm::Value &val) { | 
|  | assert(val.hasName() && "Found texture variable with no name"); | 
|  | return val.getName(); | 
|  | } | 
|  |  | 
|  | std::string llvm::getSurfaceName(const llvm::Value &val) { | 
|  | assert(val.hasName() && "Found surface variable with no name"); | 
|  | return val.getName(); | 
|  | } | 
|  |  | 
|  | std::string llvm::getSamplerName(const llvm::Value &val) { | 
|  | assert(val.hasName() && "Found sampler variable with no name"); | 
|  | return val.getName(); | 
|  | } | 
|  |  | 
|  | bool llvm::getMaxNTIDx(const Function &F, unsigned &x) { | 
|  | return (llvm::findOneNVVMAnnotation( | 
|  | &F, llvm::PropertyAnnotationNames[llvm::PROPERTY_MAXNTID_X], x)); | 
|  | } | 
|  |  | 
|  | bool llvm::getMaxNTIDy(const Function &F, unsigned &y) { | 
|  | return (llvm::findOneNVVMAnnotation( | 
|  | &F, llvm::PropertyAnnotationNames[llvm::PROPERTY_MAXNTID_Y], y)); | 
|  | } | 
|  |  | 
|  | bool llvm::getMaxNTIDz(const Function &F, unsigned &z) { | 
|  | return (llvm::findOneNVVMAnnotation( | 
|  | &F, llvm::PropertyAnnotationNames[llvm::PROPERTY_MAXNTID_Z], z)); | 
|  | } | 
|  |  | 
|  | bool llvm::getReqNTIDx(const Function &F, unsigned &x) { | 
|  | return (llvm::findOneNVVMAnnotation( | 
|  | &F, llvm::PropertyAnnotationNames[llvm::PROPERTY_REQNTID_X], x)); | 
|  | } | 
|  |  | 
|  | bool llvm::getReqNTIDy(const Function &F, unsigned &y) { | 
|  | return (llvm::findOneNVVMAnnotation( | 
|  | &F, llvm::PropertyAnnotationNames[llvm::PROPERTY_REQNTID_Y], y)); | 
|  | } | 
|  |  | 
|  | bool llvm::getReqNTIDz(const Function &F, unsigned &z) { | 
|  | return (llvm::findOneNVVMAnnotation( | 
|  | &F, llvm::PropertyAnnotationNames[llvm::PROPERTY_REQNTID_Z], z)); | 
|  | } | 
|  |  | 
|  | bool llvm::getMinCTASm(const Function &F, unsigned &x) { | 
|  | return (llvm::findOneNVVMAnnotation( | 
|  | &F, llvm::PropertyAnnotationNames[llvm::PROPERTY_MINNCTAPERSM], x)); | 
|  | } | 
|  |  | 
|  | bool llvm::isKernelFunction(const Function &F) { | 
|  | unsigned x = 0; | 
|  | bool retval = llvm::findOneNVVMAnnotation( | 
|  | &F, llvm::PropertyAnnotationNames[llvm::PROPERTY_ISKERNEL_FUNCTION], x); | 
|  | if (retval == false) { | 
|  | // There is no NVVM metadata, check the calling convention | 
|  | if (F.getCallingConv() == llvm::CallingConv::PTX_Kernel) | 
|  | return true; | 
|  | else | 
|  | return false; | 
|  | } | 
|  | return (x == 1); | 
|  | } | 
|  |  | 
|  | bool llvm::getAlign(const Function &F, unsigned index, unsigned &align) { | 
|  | std::vector<unsigned> Vs; | 
|  | bool retval = llvm::findAllNVVMAnnotation( | 
|  | &F, llvm::PropertyAnnotationNames[llvm::PROPERTY_ALIGN], Vs); | 
|  | if (retval == false) | 
|  | return false; | 
|  | for (int i = 0, e = Vs.size(); i < e; i++) { | 
|  | unsigned v = Vs[i]; | 
|  | if ((v >> 16) == index) { | 
|  | align = v & 0xFFFF; | 
|  | return true; | 
|  | } | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool llvm::getAlign(const CallInst &I, unsigned index, unsigned &align) { | 
|  | if (MDNode *alignNode = I.getMetadata("callalign")) { | 
|  | for (int i = 0, n = alignNode->getNumOperands(); i < n; i++) { | 
|  | if (const ConstantInt *CI = | 
|  | dyn_cast<ConstantInt>(alignNode->getOperand(i))) { | 
|  | unsigned v = CI->getZExtValue(); | 
|  | if ((v >> 16) == index) { | 
|  | align = v & 0xFFFF; | 
|  | return true; | 
|  | } | 
|  | if ((v >> 16) > index) { | 
|  | return false; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool llvm::isBarrierIntrinsic(Intrinsic::ID id) { | 
|  | if ((id == Intrinsic::nvvm_barrier0) || | 
|  | (id == Intrinsic::nvvm_barrier0_popc) || | 
|  | (id == Intrinsic::nvvm_barrier0_and) || | 
|  | (id == Intrinsic::nvvm_barrier0_or) || | 
|  | (id == Intrinsic::cuda_syncthreads)) | 
|  | return true; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Interface for checking all memory space transfer related intrinsics | 
|  | bool llvm::isMemorySpaceTransferIntrinsic(Intrinsic::ID id) { | 
|  | if (id == Intrinsic::nvvm_ptr_local_to_gen || | 
|  | id == Intrinsic::nvvm_ptr_shared_to_gen || | 
|  | id == Intrinsic::nvvm_ptr_global_to_gen || | 
|  | id == Intrinsic::nvvm_ptr_constant_to_gen || | 
|  | id == Intrinsic::nvvm_ptr_gen_to_global || | 
|  | id == Intrinsic::nvvm_ptr_gen_to_shared || | 
|  | id == Intrinsic::nvvm_ptr_gen_to_local || | 
|  | id == Intrinsic::nvvm_ptr_gen_to_constant || | 
|  | id == Intrinsic::nvvm_ptr_gen_to_param) { | 
|  | return true; | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // consider several special intrinsics in striping pointer casts, and | 
|  | // provide an option to ignore GEP indicies for find out the base address only | 
|  | // which could be used in simple alias disambigurate. | 
|  | const Value * | 
|  | llvm::skipPointerTransfer(const Value *V, bool ignore_GEP_indices) { | 
|  | V = V->stripPointerCasts(); | 
|  | while (true) { | 
|  | if (const IntrinsicInst *IS = dyn_cast<IntrinsicInst>(V)) { | 
|  | if (isMemorySpaceTransferIntrinsic(IS->getIntrinsicID())) { | 
|  | V = IS->getArgOperand(0)->stripPointerCasts(); | 
|  | continue; | 
|  | } | 
|  | } else if (ignore_GEP_indices) | 
|  | if (const GEPOperator *GEP = dyn_cast<GEPOperator>(V)) { | 
|  | V = GEP->getPointerOperand()->stripPointerCasts(); | 
|  | continue; | 
|  | } | 
|  | break; | 
|  | } | 
|  | return V; | 
|  | } | 
|  |  | 
|  | // consider several special intrinsics in striping pointer casts, and | 
|  | // - ignore GEP indicies for find out the base address only, and | 
|  | // - tracking PHINode | 
|  | // which could be used in simple alias disambigurate. | 
|  | const Value * | 
|  | llvm::skipPointerTransfer(const Value *V, std::set<const Value *> &processed) { | 
|  | if (processed.find(V) != processed.end()) | 
|  | return NULL; | 
|  | processed.insert(V); | 
|  |  | 
|  | const Value *V2 = V->stripPointerCasts(); | 
|  | if (V2 != V && processed.find(V2) != processed.end()) | 
|  | return NULL; | 
|  | processed.insert(V2); | 
|  |  | 
|  | V = V2; | 
|  |  | 
|  | while (true) { | 
|  | if (const IntrinsicInst *IS = dyn_cast<IntrinsicInst>(V)) { | 
|  | if (isMemorySpaceTransferIntrinsic(IS->getIntrinsicID())) { | 
|  | V = IS->getArgOperand(0)->stripPointerCasts(); | 
|  | continue; | 
|  | } | 
|  | } else if (const GEPOperator *GEP = dyn_cast<GEPOperator>(V)) { | 
|  | V = GEP->getPointerOperand()->stripPointerCasts(); | 
|  | continue; | 
|  | } else if (const PHINode *PN = dyn_cast<PHINode>(V)) { | 
|  | if (V != V2 && processed.find(V) != processed.end()) | 
|  | return NULL; | 
|  | processed.insert(PN); | 
|  | const Value *common = 0; | 
|  | for (unsigned i = 0; i != PN->getNumIncomingValues(); ++i) { | 
|  | const Value *pv = PN->getIncomingValue(i); | 
|  | const Value *base = skipPointerTransfer(pv, processed); | 
|  | if (base) { | 
|  | if (common == 0) | 
|  | common = base; | 
|  | else if (common != base) | 
|  | return PN; | 
|  | } | 
|  | } | 
|  | if (common == 0) | 
|  | return PN; | 
|  | V = common; | 
|  | } | 
|  | break; | 
|  | } | 
|  | return V; | 
|  | } | 
|  |  | 
|  | // The following are some useful utilities for debuggung | 
|  |  | 
|  | BasicBlock *llvm::getParentBlock(Value *v) { | 
|  | if (BasicBlock *B = dyn_cast<BasicBlock>(v)) | 
|  | return B; | 
|  |  | 
|  | if (Instruction *I = dyn_cast<Instruction>(v)) | 
|  | return I->getParent(); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | Function *llvm::getParentFunction(Value *v) { | 
|  | if (Function *F = dyn_cast<Function>(v)) | 
|  | return F; | 
|  |  | 
|  | if (Instruction *I = dyn_cast<Instruction>(v)) | 
|  | return I->getParent()->getParent(); | 
|  |  | 
|  | if (BasicBlock *B = dyn_cast<BasicBlock>(v)) | 
|  | return B->getParent(); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | // Dump a block by name | 
|  | void llvm::dumpBlock(Value *v, char *blockName) { | 
|  | Function *F = getParentFunction(v); | 
|  | if (F == 0) | 
|  | return; | 
|  |  | 
|  | for (Function::iterator it = F->begin(), ie = F->end(); it != ie; ++it) { | 
|  | BasicBlock *B = it; | 
|  | if (strcmp(B->getName().data(), blockName) == 0) { | 
|  | B->dump(); | 
|  | return; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // Find an instruction by name | 
|  | Instruction *llvm::getInst(Value *base, char *instName) { | 
|  | Function *F = getParentFunction(base); | 
|  | if (F == 0) | 
|  | return 0; | 
|  |  | 
|  | for (inst_iterator it = inst_begin(F), ie = inst_end(F); it != ie; ++it) { | 
|  | Instruction *I = &*it; | 
|  | if (strcmp(I->getName().data(), instName) == 0) { | 
|  | return I; | 
|  | } | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | // Dump an instruction by nane | 
|  | void llvm::dumpInst(Value *base, char *instName) { | 
|  | Instruction *I = getInst(base, instName); | 
|  | if (I) | 
|  | I->dump(); | 
|  | } | 
|  |  | 
|  | // Dump an instruction and all dependent instructions | 
|  | void llvm::dumpInstRec(Value *v, std::set<Instruction *> *visited) { | 
|  | if (Instruction *I = dyn_cast<Instruction>(v)) { | 
|  |  | 
|  | if (visited->find(I) != visited->end()) | 
|  | return; | 
|  |  | 
|  | visited->insert(I); | 
|  |  | 
|  | for (unsigned i = 0, e = I->getNumOperands(); i != e; ++i) | 
|  | dumpInstRec(I->getOperand(i), visited); | 
|  |  | 
|  | I->dump(); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Dump an instruction and all dependent instructions | 
|  | void llvm::dumpInstRec(Value *v) { | 
|  | std::set<Instruction *> visited; | 
|  |  | 
|  | //BasicBlock *B = getParentBlock(v); | 
|  |  | 
|  | dumpInstRec(v, &visited); | 
|  | } | 
|  |  | 
|  | // Dump the parent for Instruction, block or function | 
|  | void llvm::dumpParent(Value *v) { | 
|  | if (Instruction *I = dyn_cast<Instruction>(v)) { | 
|  | I->getParent()->dump(); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (BasicBlock *B = dyn_cast<BasicBlock>(v)) { | 
|  | B->getParent()->dump(); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (Function *F = dyn_cast<Function>(v)) { | 
|  | F->getParent()->dump(); | 
|  | return; | 
|  | } | 
|  | } |