Home | History | Annotate | Download | only in NVPTX
      1 //===- NVPTXUtilities.cpp - Utility Functions -----------------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // This file contains miscellaneous utility functions
     11 //===----------------------------------------------------------------------===//
     12 
     13 #include "NVPTXUtilities.h"
     14 #include "NVPTX.h"
     15 #include "llvm/IR/Constants.h"
     16 #include "llvm/IR/Function.h"
     17 #include "llvm/IR/GlobalVariable.h"
     18 #include "llvm/IR/InstIterator.h"
     19 #include "llvm/IR/Module.h"
     20 #include "llvm/IR/Operator.h"
     21 #include "llvm/Support/ManagedStatic.h"
     22 #include "llvm/Support/MutexGuard.h"
     23 #include <algorithm>
     24 #include <cstring>
     25 #include <map>
     26 #include <string>
     27 #include <vector>
     28 
     29 namespace llvm {
     30 
     31 namespace {
     32 typedef std::map<std::string, std::vector<unsigned> > key_val_pair_t;
     33 typedef std::map<const GlobalValue *, key_val_pair_t> global_val_annot_t;
     34 typedef std::map<const Module *, global_val_annot_t> per_module_annot_t;
     35 } // anonymous namespace
     36 
     37 static ManagedStatic<per_module_annot_t> annotationCache;
     38 static sys::Mutex Lock;
     39 
     40 void clearAnnotationCache(const Module *Mod) {
     41   MutexGuard Guard(Lock);
     42   annotationCache->erase(Mod);
     43 }
     44 
     45 static void cacheAnnotationFromMD(const MDNode *md, key_val_pair_t &retval) {
     46   MutexGuard Guard(Lock);
     47   assert(md && "Invalid mdnode for annotation");
     48   assert((md->getNumOperands() % 2) == 1 && "Invalid number of operands");
     49   // start index = 1, to skip the global variable key
     50   // increment = 2, to skip the value for each property-value pairs
     51   for (unsigned i = 1, e = md->getNumOperands(); i != e; i += 2) {
     52     // property
     53     const MDString *prop = dyn_cast<MDString>(md->getOperand(i));
     54     assert(prop && "Annotation property not a string");
     55 
     56     // value
     57     ConstantInt *Val = mdconst::dyn_extract<ConstantInt>(md->getOperand(i + 1));
     58     assert(Val && "Value operand not a constant int");
     59 
     60     std::string keyname = prop->getString().str();
     61     if (retval.find(keyname) != retval.end())
     62       retval[keyname].push_back(Val->getZExtValue());
     63     else {
     64       std::vector<unsigned> tmp;
     65       tmp.push_back(Val->getZExtValue());
     66       retval[keyname] = tmp;
     67     }
     68   }
     69 }
     70 
     71 static void cacheAnnotationFromMD(const Module *m, const GlobalValue *gv) {
     72   MutexGuard Guard(Lock);
     73   NamedMDNode *NMD = m->getNamedMetadata("nvvm.annotations");
     74   if (!NMD)
     75     return;
     76   key_val_pair_t tmp;
     77   for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) {
     78     const MDNode *elem = NMD->getOperand(i);
     79 
     80     GlobalValue *entity =
     81         mdconst::dyn_extract_or_null<GlobalValue>(elem->getOperand(0));
     82     // entity may be null due to DCE
     83     if (!entity)
     84       continue;
     85     if (entity != gv)
     86       continue;
     87 
     88     // accumulate annotations for entity in tmp
     89     cacheAnnotationFromMD(elem, tmp);
     90   }
     91 
     92   if (tmp.empty()) // no annotations for this gv
     93     return;
     94 
     95   if ((*annotationCache).find(m) != (*annotationCache).end())
     96     (*annotationCache)[m][gv] = std::move(tmp);
     97   else {
     98     global_val_annot_t tmp1;
     99     tmp1[gv] = std::move(tmp);
    100     (*annotationCache)[m] = std::move(tmp1);
    101   }
    102 }
    103 
    104 bool findOneNVVMAnnotation(const GlobalValue *gv, const std::string &prop,
    105                            unsigned &retval) {
    106   MutexGuard Guard(Lock);
    107   const Module *m = gv->getParent();
    108   if ((*annotationCache).find(m) == (*annotationCache).end())
    109     cacheAnnotationFromMD(m, gv);
    110   else if ((*annotationCache)[m].find(gv) == (*annotationCache)[m].end())
    111     cacheAnnotationFromMD(m, gv);
    112   if ((*annotationCache)[m][gv].find(prop) == (*annotationCache)[m][gv].end())
    113     return false;
    114   retval = (*annotationCache)[m][gv][prop][0];
    115   return true;
    116 }
    117 
    118 bool findAllNVVMAnnotation(const GlobalValue *gv, const std::string &prop,
    119                            std::vector<unsigned> &retval) {
    120   MutexGuard Guard(Lock);
    121   const Module *m = gv->getParent();
    122   if ((*annotationCache).find(m) == (*annotationCache).end())
    123     cacheAnnotationFromMD(m, gv);
    124   else if ((*annotationCache)[m].find(gv) == (*annotationCache)[m].end())
    125     cacheAnnotationFromMD(m, gv);
    126   if ((*annotationCache)[m][gv].find(prop) == (*annotationCache)[m][gv].end())
    127     return false;
    128   retval = (*annotationCache)[m][gv][prop];
    129   return true;
    130 }
    131 
    132 bool isTexture(const Value &val) {
    133   if (const GlobalValue *gv = dyn_cast<GlobalValue>(&val)) {
    134     unsigned annot;
    135     if (findOneNVVMAnnotation(gv, "texture", annot)) {
    136       assert((annot == 1) && "Unexpected annotation on a texture symbol");
    137       return true;
    138     }
    139   }
    140   return false;
    141 }
    142 
    143 bool isSurface(const Value &val) {
    144   if (const GlobalValue *gv = dyn_cast<GlobalValue>(&val)) {
    145     unsigned annot;
    146     if (findOneNVVMAnnotation(gv, "surface", annot)) {
    147       assert((annot == 1) && "Unexpected annotation on a surface symbol");
    148       return true;
    149     }
    150   }
    151   return false;
    152 }
    153 
    154 bool isSampler(const Value &val) {
    155   const char *AnnotationName = "sampler";
    156 
    157   if (const GlobalValue *gv = dyn_cast<GlobalValue>(&val)) {
    158     unsigned annot;
    159     if (findOneNVVMAnnotation(gv, AnnotationName, annot)) {
    160       assert((annot == 1) && "Unexpected annotation on a sampler symbol");
    161       return true;
    162     }
    163   }
    164   if (const Argument *arg = dyn_cast<Argument>(&val)) {
    165     const Function *func = arg->getParent();
    166     std::vector<unsigned> annot;
    167     if (findAllNVVMAnnotation(func, AnnotationName, annot)) {
    168       if (is_contained(annot, arg->getArgNo()))
    169         return true;
    170     }
    171   }
    172   return false;
    173 }
    174 
    175 bool isImageReadOnly(const Value &val) {
    176   if (const Argument *arg = dyn_cast<Argument>(&val)) {
    177     const Function *func = arg->getParent();
    178     std::vector<unsigned> annot;
    179     if (findAllNVVMAnnotation(func, "rdoimage", annot)) {
    180       if (is_contained(annot, arg->getArgNo()))
    181         return true;
    182     }
    183   }
    184   return false;
    185 }
    186 
    187 bool isImageWriteOnly(const Value &val) {
    188   if (const Argument *arg = dyn_cast<Argument>(&val)) {
    189     const Function *func = arg->getParent();
    190     std::vector<unsigned> annot;
    191     if (findAllNVVMAnnotation(func, "wroimage", annot)) {
    192       if (is_contained(annot, arg->getArgNo()))
    193         return true;
    194     }
    195   }
    196   return false;
    197 }
    198 
    199 bool isImageReadWrite(const Value &val) {
    200   if (const Argument *arg = dyn_cast<Argument>(&val)) {
    201     const Function *func = arg->getParent();
    202     std::vector<unsigned> annot;
    203     if (findAllNVVMAnnotation(func, "rdwrimage", annot)) {
    204       if (is_contained(annot, arg->getArgNo()))
    205         return true;
    206     }
    207   }
    208   return false;
    209 }
    210 
    211 bool isImage(const Value &val) {
    212   return isImageReadOnly(val) || isImageWriteOnly(val) || isImageReadWrite(val);
    213 }
    214 
    215 bool isManaged(const Value &val) {
    216   if(const GlobalValue *gv = dyn_cast<GlobalValue>(&val)) {
    217     unsigned annot;
    218     if (findOneNVVMAnnotation(gv, "managed", annot)) {
    219       assert((annot == 1) && "Unexpected annotation on a managed symbol");
    220       return true;
    221     }
    222   }
    223   return false;
    224 }
    225 
    226 std::string getTextureName(const Value &val) {
    227   assert(val.hasName() && "Found texture variable with no name");
    228   return val.getName();
    229 }
    230 
    231 std::string getSurfaceName(const Value &val) {
    232   assert(val.hasName() && "Found surface variable with no name");
    233   return val.getName();
    234 }
    235 
    236 std::string getSamplerName(const Value &val) {
    237   assert(val.hasName() && "Found sampler variable with no name");
    238   return val.getName();
    239 }
    240 
    241 bool getMaxNTIDx(const Function &F, unsigned &x) {
    242   return findOneNVVMAnnotation(&F, "maxntidx", x);
    243 }
    244 
    245 bool getMaxNTIDy(const Function &F, unsigned &y) {
    246   return findOneNVVMAnnotation(&F, "maxntidy", y);
    247 }
    248 
    249 bool getMaxNTIDz(const Function &F, unsigned &z) {
    250   return findOneNVVMAnnotation(&F, "maxntidz", z);
    251 }
    252 
    253 bool getReqNTIDx(const Function &F, unsigned &x) {
    254   return findOneNVVMAnnotation(&F, "reqntidx", x);
    255 }
    256 
    257 bool getReqNTIDy(const Function &F, unsigned &y) {
    258   return findOneNVVMAnnotation(&F, "reqntidy", y);
    259 }
    260 
    261 bool getReqNTIDz(const Function &F, unsigned &z) {
    262   return findOneNVVMAnnotation(&F, "reqntidz", z);
    263 }
    264 
    265 bool getMinCTASm(const Function &F, unsigned &x) {
    266   return findOneNVVMAnnotation(&F, "minctasm", x);
    267 }
    268 
    269 bool getMaxNReg(const Function &F, unsigned &x) {
    270   return findOneNVVMAnnotation(&F, "maxnreg", x);
    271 }
    272 
    273 bool isKernelFunction(const Function &F) {
    274   unsigned x = 0;
    275   bool retval = findOneNVVMAnnotation(&F, "kernel", x);
    276   if (!retval) {
    277     // There is no NVVM metadata, check the calling convention
    278     return F.getCallingConv() == CallingConv::PTX_Kernel;
    279   }
    280   return (x == 1);
    281 }
    282 
    283 bool getAlign(const Function &F, unsigned index, unsigned &align) {
    284   std::vector<unsigned> Vs;
    285   bool retval = findAllNVVMAnnotation(&F, "align", Vs);
    286   if (!retval)
    287     return false;
    288   for (int i = 0, e = Vs.size(); i < e; i++) {
    289     unsigned v = Vs[i];
    290     if ((v >> 16) == index) {
    291       align = v & 0xFFFF;
    292       return true;
    293     }
    294   }
    295   return false;
    296 }
    297 
    298 bool getAlign(const CallInst &I, unsigned index, unsigned &align) {
    299   if (MDNode *alignNode = I.getMetadata("callalign")) {
    300     for (int i = 0, n = alignNode->getNumOperands(); i < n; i++) {
    301       if (const ConstantInt *CI =
    302               mdconst::dyn_extract<ConstantInt>(alignNode->getOperand(i))) {
    303         unsigned v = CI->getZExtValue();
    304         if ((v >> 16) == index) {
    305           align = v & 0xFFFF;
    306           return true;
    307         }
    308         if ((v >> 16) > index) {
    309           return false;
    310         }
    311       }
    312     }
    313   }
    314   return false;
    315 }
    316 
    317 } // namespace llvm
    318