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