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