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/Module.h"
19#include "llvm/IR/Operator.h"
20#include <algorithm>
21#include <cstring>
22#include <map>
23#include <string>
24#include <vector>
25#include "llvm/Support/ManagedStatic.h"
26#include "llvm/IR/InstIterator.h"
27#include "llvm/Support/MutexGuard.h"
28
29using namespace llvm;
30
31typedef std::map<std::string, std::vector<unsigned> > key_val_pair_t;
32typedef std::map<const GlobalValue *, key_val_pair_t> global_val_annot_t;
33typedef std::map<const Module *, global_val_annot_t> per_module_annot_t;
34
35ManagedStatic<per_module_annot_t> annotationCache;
36static sys::Mutex Lock;
37
38void llvm::clearAnnotationCache(const llvm::Module *Mod) {
39  MutexGuard Guard(Lock);
40  annotationCache->erase(Mod);
41}
42
43static void cacheAnnotationFromMD(const MDNode *md, key_val_pair_t &retval) {
44  MutexGuard Guard(Lock);
45  assert(md && "Invalid mdnode for annotation");
46  assert((md->getNumOperands() % 2) == 1 && "Invalid number of operands");
47  // start index = 1, to skip the global variable key
48  // increment = 2, to skip the value for each property-value pairs
49  for (unsigned i = 1, e = md->getNumOperands(); i != e; i += 2) {
50    // property
51    const MDString *prop = dyn_cast<MDString>(md->getOperand(i));
52    assert(prop && "Annotation property not a string");
53
54    // value
55    ConstantInt *Val = dyn_cast<ConstantInt>(md->getOperand(i + 1));
56    assert(Val && "Value operand not a constant int");
57
58    std::string keyname = prop->getString().str();
59    if (retval.find(keyname) != retval.end())
60      retval[keyname].push_back(Val->getZExtValue());
61    else {
62      std::vector<unsigned> tmp;
63      tmp.push_back(Val->getZExtValue());
64      retval[keyname] = tmp;
65    }
66  }
67}
68
69static void cacheAnnotationFromMD(const Module *m, const GlobalValue *gv) {
70  MutexGuard Guard(Lock);
71  NamedMDNode *NMD = m->getNamedMetadata(llvm::NamedMDForAnnotations);
72  if (!NMD)
73    return;
74  key_val_pair_t tmp;
75  for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) {
76    const MDNode *elem = NMD->getOperand(i);
77
78    Value *entity = elem->getOperand(0);
79    // entity may be null due to DCE
80    if (!entity)
81      continue;
82    if (entity != gv)
83      continue;
84
85    // accumulate annotations for entity in tmp
86    cacheAnnotationFromMD(elem, tmp);
87  }
88
89  if (tmp.empty()) // no annotations for this gv
90    return;
91
92  if ((*annotationCache).find(m) != (*annotationCache).end())
93    (*annotationCache)[m][gv] = tmp;
94  else {
95    global_val_annot_t tmp1;
96    tmp1[gv] = tmp;
97    (*annotationCache)[m] = tmp1;
98  }
99}
100
101bool llvm::findOneNVVMAnnotation(const GlobalValue *gv, std::string prop,
102                                 unsigned &retval) {
103  MutexGuard Guard(Lock);
104  const Module *m = gv->getParent();
105  if ((*annotationCache).find(m) == (*annotationCache).end())
106    cacheAnnotationFromMD(m, gv);
107  else if ((*annotationCache)[m].find(gv) == (*annotationCache)[m].end())
108    cacheAnnotationFromMD(m, gv);
109  if ((*annotationCache)[m][gv].find(prop) == (*annotationCache)[m][gv].end())
110    return false;
111  retval = (*annotationCache)[m][gv][prop][0];
112  return true;
113}
114
115bool llvm::findAllNVVMAnnotation(const GlobalValue *gv, std::string prop,
116                                 std::vector<unsigned> &retval) {
117  MutexGuard Guard(Lock);
118  const Module *m = gv->getParent();
119  if ((*annotationCache).find(m) == (*annotationCache).end())
120    cacheAnnotationFromMD(m, gv);
121  else if ((*annotationCache)[m].find(gv) == (*annotationCache)[m].end())
122    cacheAnnotationFromMD(m, gv);
123  if ((*annotationCache)[m][gv].find(prop) == (*annotationCache)[m][gv].end())
124    return false;
125  retval = (*annotationCache)[m][gv][prop];
126  return true;
127}
128
129bool llvm::isTexture(const llvm::Value &val) {
130  if (const GlobalValue *gv = dyn_cast<GlobalValue>(&val)) {
131    unsigned annot;
132    if (llvm::findOneNVVMAnnotation(
133            gv, llvm::PropertyAnnotationNames[llvm::PROPERTY_ISTEXTURE],
134            annot)) {
135      assert((annot == 1) && "Unexpected annotation on a texture symbol");
136      return true;
137    }
138  }
139  return false;
140}
141
142bool llvm::isSurface(const llvm::Value &val) {
143  if (const GlobalValue *gv = dyn_cast<GlobalValue>(&val)) {
144    unsigned annot;
145    if (llvm::findOneNVVMAnnotation(
146            gv, llvm::PropertyAnnotationNames[llvm::PROPERTY_ISSURFACE],
147            annot)) {
148      assert((annot == 1) && "Unexpected annotation on a surface symbol");
149      return true;
150    }
151  }
152  return false;
153}
154
155bool llvm::isSampler(const llvm::Value &val) {
156  if (const GlobalValue *gv = dyn_cast<GlobalValue>(&val)) {
157    unsigned annot;
158    if (llvm::findOneNVVMAnnotation(
159            gv, llvm::PropertyAnnotationNames[llvm::PROPERTY_ISSAMPLER],
160            annot)) {
161      assert((annot == 1) && "Unexpected annotation on a sampler symbol");
162      return true;
163    }
164  }
165  if (const Argument *arg = dyn_cast<Argument>(&val)) {
166    const Function *func = arg->getParent();
167    std::vector<unsigned> annot;
168    if (llvm::findAllNVVMAnnotation(
169            func, llvm::PropertyAnnotationNames[llvm::PROPERTY_ISSAMPLER],
170            annot)) {
171      if (std::find(annot.begin(), annot.end(), arg->getArgNo()) != annot.end())
172        return true;
173    }
174  }
175  return false;
176}
177
178bool llvm::isImageReadOnly(const llvm::Value &val) {
179  if (const Argument *arg = dyn_cast<Argument>(&val)) {
180    const Function *func = arg->getParent();
181    std::vector<unsigned> annot;
182    if (llvm::findAllNVVMAnnotation(func,
183                                    llvm::PropertyAnnotationNames[
184                                        llvm::PROPERTY_ISREADONLY_IMAGE_PARAM],
185                                    annot)) {
186      if (std::find(annot.begin(), annot.end(), arg->getArgNo()) != annot.end())
187        return true;
188    }
189  }
190  return false;
191}
192
193bool llvm::isImageWriteOnly(const llvm::Value &val) {
194  if (const Argument *arg = dyn_cast<Argument>(&val)) {
195    const Function *func = arg->getParent();
196    std::vector<unsigned> annot;
197    if (llvm::findAllNVVMAnnotation(func,
198                                    llvm::PropertyAnnotationNames[
199                                        llvm::PROPERTY_ISWRITEONLY_IMAGE_PARAM],
200                                    annot)) {
201      if (std::find(annot.begin(), annot.end(), arg->getArgNo()) != annot.end())
202        return true;
203    }
204  }
205  return false;
206}
207
208bool llvm::isImageReadWrite(const llvm::Value &val) {
209  if (const Argument *arg = dyn_cast<Argument>(&val)) {
210    const Function *func = arg->getParent();
211    std::vector<unsigned> annot;
212    if (llvm::findAllNVVMAnnotation(func,
213                                    llvm::PropertyAnnotationNames[
214                                        llvm::PROPERTY_ISREADWRITE_IMAGE_PARAM],
215                                    annot)) {
216      if (std::find(annot.begin(), annot.end(), arg->getArgNo()) != annot.end())
217        return true;
218    }
219  }
220  return false;
221}
222
223bool llvm::isImage(const llvm::Value &val) {
224  return llvm::isImageReadOnly(val) || llvm::isImageWriteOnly(val) ||
225         llvm::isImageReadWrite(val);
226}
227
228bool llvm::isManaged(const llvm::Value &val) {
229  if(const GlobalValue *gv = dyn_cast<GlobalValue>(&val)) {
230    unsigned annot;
231    if(llvm::findOneNVVMAnnotation(gv,
232                          llvm::PropertyAnnotationNames[llvm::PROPERTY_MANAGED],
233                                   annot)) {
234      assert((annot == 1) && "Unexpected annotation on a managed symbol");
235      return true;
236    }
237  }
238  return false;
239}
240
241std::string llvm::getTextureName(const llvm::Value &val) {
242  assert(val.hasName() && "Found texture variable with no name");
243  return val.getName();
244}
245
246std::string llvm::getSurfaceName(const llvm::Value &val) {
247  assert(val.hasName() && "Found surface variable with no name");
248  return val.getName();
249}
250
251std::string llvm::getSamplerName(const llvm::Value &val) {
252  assert(val.hasName() && "Found sampler variable with no name");
253  return val.getName();
254}
255
256bool llvm::getMaxNTIDx(const Function &F, unsigned &x) {
257  return (llvm::findOneNVVMAnnotation(
258      &F, llvm::PropertyAnnotationNames[llvm::PROPERTY_MAXNTID_X], x));
259}
260
261bool llvm::getMaxNTIDy(const Function &F, unsigned &y) {
262  return (llvm::findOneNVVMAnnotation(
263      &F, llvm::PropertyAnnotationNames[llvm::PROPERTY_MAXNTID_Y], y));
264}
265
266bool llvm::getMaxNTIDz(const Function &F, unsigned &z) {
267  return (llvm::findOneNVVMAnnotation(
268      &F, llvm::PropertyAnnotationNames[llvm::PROPERTY_MAXNTID_Z], z));
269}
270
271bool llvm::getReqNTIDx(const Function &F, unsigned &x) {
272  return (llvm::findOneNVVMAnnotation(
273      &F, llvm::PropertyAnnotationNames[llvm::PROPERTY_REQNTID_X], x));
274}
275
276bool llvm::getReqNTIDy(const Function &F, unsigned &y) {
277  return (llvm::findOneNVVMAnnotation(
278      &F, llvm::PropertyAnnotationNames[llvm::PROPERTY_REQNTID_Y], y));
279}
280
281bool llvm::getReqNTIDz(const Function &F, unsigned &z) {
282  return (llvm::findOneNVVMAnnotation(
283      &F, llvm::PropertyAnnotationNames[llvm::PROPERTY_REQNTID_Z], z));
284}
285
286bool llvm::getMinCTASm(const Function &F, unsigned &x) {
287  return (llvm::findOneNVVMAnnotation(
288      &F, llvm::PropertyAnnotationNames[llvm::PROPERTY_MINNCTAPERSM], x));
289}
290
291bool llvm::isKernelFunction(const Function &F) {
292  unsigned x = 0;
293  bool retval = llvm::findOneNVVMAnnotation(
294      &F, llvm::PropertyAnnotationNames[llvm::PROPERTY_ISKERNEL_FUNCTION], x);
295  if (retval == false) {
296    // There is no NVVM metadata, check the calling convention
297    if (F.getCallingConv() == llvm::CallingConv::PTX_Kernel)
298      return true;
299    else
300      return false;
301  }
302  return (x == 1);
303}
304
305bool llvm::getAlign(const Function &F, unsigned index, unsigned &align) {
306  std::vector<unsigned> Vs;
307  bool retval = llvm::findAllNVVMAnnotation(
308      &F, llvm::PropertyAnnotationNames[llvm::PROPERTY_ALIGN], Vs);
309  if (retval == false)
310    return false;
311  for (int i = 0, e = Vs.size(); i < e; i++) {
312    unsigned v = Vs[i];
313    if ((v >> 16) == index) {
314      align = v & 0xFFFF;
315      return true;
316    }
317  }
318  return false;
319}
320
321bool llvm::getAlign(const CallInst &I, unsigned index, unsigned &align) {
322  if (MDNode *alignNode = I.getMetadata("callalign")) {
323    for (int i = 0, n = alignNode->getNumOperands(); i < n; i++) {
324      if (const ConstantInt *CI =
325              dyn_cast<ConstantInt>(alignNode->getOperand(i))) {
326        unsigned v = CI->getZExtValue();
327        if ((v >> 16) == index) {
328          align = v & 0xFFFF;
329          return true;
330        }
331        if ((v >> 16) > index) {
332          return false;
333        }
334      }
335    }
336  }
337  return false;
338}
339
340bool llvm::isBarrierIntrinsic(Intrinsic::ID id) {
341  if ((id == Intrinsic::nvvm_barrier0) ||
342      (id == Intrinsic::nvvm_barrier0_popc) ||
343      (id == Intrinsic::nvvm_barrier0_and) ||
344      (id == Intrinsic::nvvm_barrier0_or) ||
345      (id == Intrinsic::cuda_syncthreads))
346    return true;
347  return false;
348}
349
350// Interface for checking all memory space transfer related intrinsics
351bool llvm::isMemorySpaceTransferIntrinsic(Intrinsic::ID id) {
352  if (id == Intrinsic::nvvm_ptr_local_to_gen ||
353      id == Intrinsic::nvvm_ptr_shared_to_gen ||
354      id == Intrinsic::nvvm_ptr_global_to_gen ||
355      id == Intrinsic::nvvm_ptr_constant_to_gen ||
356      id == Intrinsic::nvvm_ptr_gen_to_global ||
357      id == Intrinsic::nvvm_ptr_gen_to_shared ||
358      id == Intrinsic::nvvm_ptr_gen_to_local ||
359      id == Intrinsic::nvvm_ptr_gen_to_constant ||
360      id == Intrinsic::nvvm_ptr_gen_to_param) {
361    return true;
362  }
363
364  return false;
365}
366
367// consider several special intrinsics in striping pointer casts, and
368// provide an option to ignore GEP indicies for find out the base address only
369// which could be used in simple alias disambigurate.
370const Value *
371llvm::skipPointerTransfer(const Value *V, bool ignore_GEP_indices) {
372  V = V->stripPointerCasts();
373  while (true) {
374    if (const IntrinsicInst *IS = dyn_cast<IntrinsicInst>(V)) {
375      if (isMemorySpaceTransferIntrinsic(IS->getIntrinsicID())) {
376        V = IS->getArgOperand(0)->stripPointerCasts();
377        continue;
378      }
379    } else if (ignore_GEP_indices)
380      if (const GEPOperator *GEP = dyn_cast<GEPOperator>(V)) {
381        V = GEP->getPointerOperand()->stripPointerCasts();
382        continue;
383      }
384    break;
385  }
386  return V;
387}
388
389// consider several special intrinsics in striping pointer casts, and
390// - ignore GEP indicies for find out the base address only, and
391// - tracking PHINode
392// which could be used in simple alias disambigurate.
393const Value *
394llvm::skipPointerTransfer(const Value *V, std::set<const Value *> &processed) {
395  if (processed.find(V) != processed.end())
396    return nullptr;
397  processed.insert(V);
398
399  const Value *V2 = V->stripPointerCasts();
400  if (V2 != V && processed.find(V2) != processed.end())
401    return nullptr;
402  processed.insert(V2);
403
404  V = V2;
405
406  while (true) {
407    if (const IntrinsicInst *IS = dyn_cast<IntrinsicInst>(V)) {
408      if (isMemorySpaceTransferIntrinsic(IS->getIntrinsicID())) {
409        V = IS->getArgOperand(0)->stripPointerCasts();
410        continue;
411      }
412    } else if (const GEPOperator *GEP = dyn_cast<GEPOperator>(V)) {
413      V = GEP->getPointerOperand()->stripPointerCasts();
414      continue;
415    } else if (const PHINode *PN = dyn_cast<PHINode>(V)) {
416      if (V != V2 && processed.find(V) != processed.end())
417        return nullptr;
418      processed.insert(PN);
419      const Value *common = nullptr;
420      for (unsigned i = 0; i != PN->getNumIncomingValues(); ++i) {
421        const Value *pv = PN->getIncomingValue(i);
422        const Value *base = skipPointerTransfer(pv, processed);
423        if (base) {
424          if (!common)
425            common = base;
426          else if (common != base)
427            return PN;
428        }
429      }
430      if (!common)
431        return PN;
432      V = common;
433    }
434    break;
435  }
436  return V;
437}
438
439// The following are some useful utilities for debuggung
440
441BasicBlock *llvm::getParentBlock(Value *v) {
442  if (BasicBlock *B = dyn_cast<BasicBlock>(v))
443    return B;
444
445  if (Instruction *I = dyn_cast<Instruction>(v))
446    return I->getParent();
447
448  return nullptr;
449}
450
451Function *llvm::getParentFunction(Value *v) {
452  if (Function *F = dyn_cast<Function>(v))
453    return F;
454
455  if (Instruction *I = dyn_cast<Instruction>(v))
456    return I->getParent()->getParent();
457
458  if (BasicBlock *B = dyn_cast<BasicBlock>(v))
459    return B->getParent();
460
461  return nullptr;
462}
463
464// Dump a block by name
465void llvm::dumpBlock(Value *v, char *blockName) {
466  Function *F = getParentFunction(v);
467  if (!F)
468    return;
469
470  for (Function::iterator it = F->begin(), ie = F->end(); it != ie; ++it) {
471    BasicBlock *B = it;
472    if (strcmp(B->getName().data(), blockName) == 0) {
473      B->dump();
474      return;
475    }
476  }
477}
478
479// Find an instruction by name
480Instruction *llvm::getInst(Value *base, char *instName) {
481  Function *F = getParentFunction(base);
482  if (!F)
483    return nullptr;
484
485  for (inst_iterator it = inst_begin(F), ie = inst_end(F); it != ie; ++it) {
486    Instruction *I = &*it;
487    if (strcmp(I->getName().data(), instName) == 0) {
488      return I;
489    }
490  }
491
492  return nullptr;
493}
494
495// Dump an instruction by nane
496void llvm::dumpInst(Value *base, char *instName) {
497  Instruction *I = getInst(base, instName);
498  if (I)
499    I->dump();
500}
501
502// Dump an instruction and all dependent instructions
503void llvm::dumpInstRec(Value *v, std::set<Instruction *> *visited) {
504  if (Instruction *I = dyn_cast<Instruction>(v)) {
505
506    if (visited->find(I) != visited->end())
507      return;
508
509    visited->insert(I);
510
511    for (unsigned i = 0, e = I->getNumOperands(); i != e; ++i)
512      dumpInstRec(I->getOperand(i), visited);
513
514    I->dump();
515  }
516}
517
518// Dump an instruction and all dependent instructions
519void llvm::dumpInstRec(Value *v) {
520  std::set<Instruction *> visited;
521
522  //BasicBlock *B = getParentBlock(v);
523
524  dumpInstRec(v, &visited);
525}
526
527// Dump the parent for Instruction, block or function
528void llvm::dumpParent(Value *v) {
529  if (Instruction *I = dyn_cast<Instruction>(v)) {
530    I->getParent()->dump();
531    return;
532  }
533
534  if (BasicBlock *B = dyn_cast<BasicBlock>(v)) {
535    B->getParent()->dump();
536    return;
537  }
538
539  if (Function *F = dyn_cast<Function>(v)) {
540    F->getParent()->dump();
541    return;
542  }
543}
544