Revert " [LoongArch][ISel] Check the number of sign bits in `PatGprGpr_32` (#107432)"
[llvm-project.git] / llvm / lib / Target / NVPTX / NVPTXUtilities.cpp
blob80361744fd5b6f3bfe35243fabefd4d8ebe1bb2c
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
11 //===----------------------------------------------------------------------===//
13 #include "NVPTXUtilities.h"
14 #include "NVPTX.h"
15 #include "NVPTXTargetMachine.h"
16 #include "llvm/IR/Constants.h"
17 #include "llvm/IR/Function.h"
18 #include "llvm/IR/GlobalVariable.h"
19 #include "llvm/IR/InstIterator.h"
20 #include "llvm/IR/Module.h"
21 #include "llvm/IR/Operator.h"
22 #include "llvm/Support/Alignment.h"
23 #include "llvm/Support/Mutex.h"
24 #include <algorithm>
25 #include <cstring>
26 #include <map>
27 #include <mutex>
28 #include <optional>
29 #include <string>
30 #include <vector>
32 namespace llvm {
34 namespace {
35 typedef std::map<std::string, std::vector<unsigned> > key_val_pair_t;
36 typedef std::map<const GlobalValue *, key_val_pair_t> global_val_annot_t;
38 struct AnnotationCache {
39 sys::Mutex Lock;
40 std::map<const Module *, global_val_annot_t> Cache;
43 AnnotationCache &getAnnotationCache() {
44 static AnnotationCache AC;
45 return AC;
47 } // anonymous namespace
49 void clearAnnotationCache(const Module *Mod) {
50 auto &AC = getAnnotationCache();
51 std::lock_guard<sys::Mutex> Guard(AC.Lock);
52 AC.Cache.erase(Mod);
55 static void readIntVecFromMDNode(const MDNode *MetadataNode,
56 std::vector<unsigned> &Vec) {
57 for (unsigned i = 0, e = MetadataNode->getNumOperands(); i != e; ++i) {
58 ConstantInt *Val =
59 mdconst::extract<ConstantInt>(MetadataNode->getOperand(i));
60 Vec.push_back(Val->getZExtValue());
64 static void cacheAnnotationFromMD(const MDNode *MetadataNode,
65 key_val_pair_t &retval) {
66 auto &AC = getAnnotationCache();
67 std::lock_guard<sys::Mutex> Guard(AC.Lock);
68 assert(MetadataNode && "Invalid mdnode for annotation");
69 assert((MetadataNode->getNumOperands() % 2) == 1 &&
70 "Invalid number of operands");
71 // start index = 1, to skip the global variable key
72 // increment = 2, to skip the value for each property-value pairs
73 for (unsigned i = 1, e = MetadataNode->getNumOperands(); i != e; i += 2) {
74 // property
75 const MDString *prop = dyn_cast<MDString>(MetadataNode->getOperand(i));
76 assert(prop && "Annotation property not a string");
77 std::string Key = prop->getString().str();
79 // value
80 if (ConstantInt *Val = mdconst::dyn_extract<ConstantInt>(
81 MetadataNode->getOperand(i + 1))) {
82 retval[Key].push_back(Val->getZExtValue());
83 } else if (MDNode *VecMd =
84 dyn_cast<MDNode>(MetadataNode->getOperand(i + 1))) {
85 // note: only "grid_constant" annotations support vector MDNodes.
86 // assert: there can only exist one unique key value pair of
87 // the form (string key, MDNode node). Operands of such a node
88 // shall always be unsigned ints.
89 if (retval.find(Key) == retval.end()) {
90 readIntVecFromMDNode(VecMd, retval[Key]);
91 continue;
93 } else {
94 llvm_unreachable("Value operand not a constant int or an mdnode");
99 static void cacheAnnotationFromMD(const Module *m, const GlobalValue *gv) {
100 auto &AC = getAnnotationCache();
101 std::lock_guard<sys::Mutex> Guard(AC.Lock);
102 NamedMDNode *NMD = m->getNamedMetadata("nvvm.annotations");
103 if (!NMD)
104 return;
105 key_val_pair_t tmp;
106 for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) {
107 const MDNode *elem = NMD->getOperand(i);
109 GlobalValue *entity =
110 mdconst::dyn_extract_or_null<GlobalValue>(elem->getOperand(0));
111 // entity may be null due to DCE
112 if (!entity)
113 continue;
114 if (entity != gv)
115 continue;
117 // accumulate annotations for entity in tmp
118 cacheAnnotationFromMD(elem, tmp);
121 if (tmp.empty()) // no annotations for this gv
122 return;
124 if (AC.Cache.find(m) != AC.Cache.end())
125 AC.Cache[m][gv] = std::move(tmp);
126 else {
127 global_val_annot_t tmp1;
128 tmp1[gv] = std::move(tmp);
129 AC.Cache[m] = std::move(tmp1);
133 bool findOneNVVMAnnotation(const GlobalValue *gv, const std::string &prop,
134 unsigned &retval) {
135 auto &AC = getAnnotationCache();
136 std::lock_guard<sys::Mutex> Guard(AC.Lock);
137 const Module *m = gv->getParent();
138 if (AC.Cache.find(m) == AC.Cache.end())
139 cacheAnnotationFromMD(m, gv);
140 else if (AC.Cache[m].find(gv) == AC.Cache[m].end())
141 cacheAnnotationFromMD(m, gv);
142 if (AC.Cache[m][gv].find(prop) == AC.Cache[m][gv].end())
143 return false;
144 retval = AC.Cache[m][gv][prop][0];
145 return true;
148 static std::optional<unsigned>
149 findOneNVVMAnnotation(const GlobalValue &GV, const std::string &PropName) {
150 unsigned RetVal;
151 if (findOneNVVMAnnotation(&GV, PropName, RetVal))
152 return RetVal;
153 return std::nullopt;
156 bool findAllNVVMAnnotation(const GlobalValue *gv, const std::string &prop,
157 std::vector<unsigned> &retval) {
158 auto &AC = getAnnotationCache();
159 std::lock_guard<sys::Mutex> Guard(AC.Lock);
160 const Module *m = gv->getParent();
161 if (AC.Cache.find(m) == AC.Cache.end())
162 cacheAnnotationFromMD(m, gv);
163 else if (AC.Cache[m].find(gv) == AC.Cache[m].end())
164 cacheAnnotationFromMD(m, gv);
165 if (AC.Cache[m][gv].find(prop) == AC.Cache[m][gv].end())
166 return false;
167 retval = AC.Cache[m][gv][prop];
168 return true;
171 bool isTexture(const Value &val) {
172 if (const GlobalValue *gv = dyn_cast<GlobalValue>(&val)) {
173 unsigned Annot;
174 if (findOneNVVMAnnotation(gv, "texture", Annot)) {
175 assert((Annot == 1) && "Unexpected annotation on a texture symbol");
176 return true;
179 return false;
182 bool isSurface(const Value &val) {
183 if (const GlobalValue *gv = dyn_cast<GlobalValue>(&val)) {
184 unsigned Annot;
185 if (findOneNVVMAnnotation(gv, "surface", Annot)) {
186 assert((Annot == 1) && "Unexpected annotation on a surface symbol");
187 return true;
190 return false;
193 static bool argHasNVVMAnnotation(const Value &Val,
194 const std::string &Annotation,
195 const bool StartArgIndexAtOne = false) {
196 if (const Argument *Arg = dyn_cast<Argument>(&Val)) {
197 const Function *Func = Arg->getParent();
198 std::vector<unsigned> Annot;
199 if (findAllNVVMAnnotation(Func, Annotation, Annot)) {
200 const unsigned BaseOffset = StartArgIndexAtOne ? 1 : 0;
201 if (is_contained(Annot, BaseOffset + Arg->getArgNo())) {
202 return true;
206 return false;
209 bool isParamGridConstant(const Value &V) {
210 if (const Argument *Arg = dyn_cast<Argument>(&V)) {
211 // "grid_constant" counts argument indices starting from 1
212 if (Arg->hasByValAttr() &&
213 argHasNVVMAnnotation(*Arg, "grid_constant",
214 /*StartArgIndexAtOne*/ true)) {
215 assert(isKernelFunction(*Arg->getParent()) &&
216 "only kernel arguments can be grid_constant");
217 return true;
220 return false;
223 bool isSampler(const Value &val) {
224 const char *AnnotationName = "sampler";
226 if (const GlobalValue *gv = dyn_cast<GlobalValue>(&val)) {
227 unsigned Annot;
228 if (findOneNVVMAnnotation(gv, AnnotationName, Annot)) {
229 assert((Annot == 1) && "Unexpected annotation on a sampler symbol");
230 return true;
233 return argHasNVVMAnnotation(val, AnnotationName);
236 bool isImageReadOnly(const Value &val) {
237 return argHasNVVMAnnotation(val, "rdoimage");
240 bool isImageWriteOnly(const Value &val) {
241 return argHasNVVMAnnotation(val, "wroimage");
244 bool isImageReadWrite(const Value &val) {
245 return argHasNVVMAnnotation(val, "rdwrimage");
248 bool isImage(const Value &val) {
249 return isImageReadOnly(val) || isImageWriteOnly(val) || isImageReadWrite(val);
252 bool isManaged(const Value &val) {
253 if(const GlobalValue *gv = dyn_cast<GlobalValue>(&val)) {
254 unsigned Annot;
255 if (findOneNVVMAnnotation(gv, "managed", Annot)) {
256 assert((Annot == 1) && "Unexpected annotation on a managed symbol");
257 return true;
260 return false;
263 std::string getTextureName(const Value &val) {
264 assert(val.hasName() && "Found texture variable with no name");
265 return std::string(val.getName());
268 std::string getSurfaceName(const Value &val) {
269 assert(val.hasName() && "Found surface variable with no name");
270 return std::string(val.getName());
273 std::string getSamplerName(const Value &val) {
274 assert(val.hasName() && "Found sampler variable with no name");
275 return std::string(val.getName());
278 std::optional<unsigned> getMaxNTIDx(const Function &F) {
279 return findOneNVVMAnnotation(F, "maxntidx");
282 std::optional<unsigned> getMaxNTIDy(const Function &F) {
283 return findOneNVVMAnnotation(F, "maxntidy");
286 std::optional<unsigned> getMaxNTIDz(const Function &F) {
287 return findOneNVVMAnnotation(F, "maxntidz");
290 std::optional<unsigned> getMaxNTID(const Function &F) {
291 // Note: The semantics here are a bit strange. The PTX ISA states the
292 // following (11.4.2. Performance-Tuning Directives: .maxntid):
294 // Note that this directive guarantees that the total number of threads does
295 // not exceed the maximum, but does not guarantee that the limit in any
296 // particular dimension is not exceeded.
297 std::optional<unsigned> MaxNTIDx = getMaxNTIDx(F);
298 std::optional<unsigned> MaxNTIDy = getMaxNTIDy(F);
299 std::optional<unsigned> MaxNTIDz = getMaxNTIDz(F);
300 if (MaxNTIDx || MaxNTIDy || MaxNTIDz)
301 return MaxNTIDx.value_or(1) * MaxNTIDy.value_or(1) * MaxNTIDz.value_or(1);
302 return std::nullopt;
305 bool getMaxClusterRank(const Function &F, unsigned &x) {
306 return findOneNVVMAnnotation(&F, "maxclusterrank", x);
309 std::optional<unsigned> getReqNTIDx(const Function &F) {
310 return findOneNVVMAnnotation(F, "reqntidx");
313 std::optional<unsigned> getReqNTIDy(const Function &F) {
314 return findOneNVVMAnnotation(F, "reqntidy");
317 std::optional<unsigned> getReqNTIDz(const Function &F) {
318 return findOneNVVMAnnotation(F, "reqntidz");
321 std::optional<unsigned> getReqNTID(const Function &F) {
322 // Note: The semantics here are a bit strange. See getMaxNTID.
323 std::optional<unsigned> ReqNTIDx = getReqNTIDx(F);
324 std::optional<unsigned> ReqNTIDy = getReqNTIDy(F);
325 std::optional<unsigned> ReqNTIDz = getReqNTIDz(F);
326 if (ReqNTIDx || ReqNTIDy || ReqNTIDz)
327 return ReqNTIDx.value_or(1) * ReqNTIDy.value_or(1) * ReqNTIDz.value_or(1);
328 return std::nullopt;
331 bool getMinCTASm(const Function &F, unsigned &x) {
332 return findOneNVVMAnnotation(&F, "minctasm", x);
335 bool getMaxNReg(const Function &F, unsigned &x) {
336 return findOneNVVMAnnotation(&F, "maxnreg", x);
339 bool isKernelFunction(const Function &F) {
340 unsigned x = 0;
341 if (!findOneNVVMAnnotation(&F, "kernel", x)) {
342 // There is no NVVM metadata, check the calling convention
343 return F.getCallingConv() == CallingConv::PTX_Kernel;
345 return (x == 1);
348 MaybeAlign getAlign(const Function &F, unsigned Index) {
349 // First check the alignstack metadata
350 if (MaybeAlign StackAlign =
351 F.getAttributes().getAttributes(Index).getStackAlignment())
352 return StackAlign;
354 // If that is missing, check the legacy nvvm metadata
355 std::vector<unsigned> Vs;
356 bool retval = findAllNVVMAnnotation(&F, "align", Vs);
357 if (!retval)
358 return std::nullopt;
359 for (unsigned V : Vs)
360 if ((V >> 16) == Index)
361 return Align(V & 0xFFFF);
363 return std::nullopt;
366 MaybeAlign getAlign(const CallInst &I, unsigned Index) {
367 // First check the alignstack metadata
368 if (MaybeAlign StackAlign =
369 I.getAttributes().getAttributes(Index).getStackAlignment())
370 return StackAlign;
372 // If that is missing, check the legacy nvvm metadata
373 if (MDNode *alignNode = I.getMetadata("callalign")) {
374 for (int i = 0, n = alignNode->getNumOperands(); i < n; i++) {
375 if (const ConstantInt *CI =
376 mdconst::dyn_extract<ConstantInt>(alignNode->getOperand(i))) {
377 unsigned V = CI->getZExtValue();
378 if ((V >> 16) == Index)
379 return Align(V & 0xFFFF);
380 if ((V >> 16) > Index)
381 return std::nullopt;
385 return std::nullopt;
388 Function *getMaybeBitcastedCallee(const CallBase *CB) {
389 return dyn_cast<Function>(CB->getCalledOperand()->stripPointerCasts());
392 bool shouldEmitPTXNoReturn(const Value *V, const TargetMachine &TM) {
393 const auto &ST =
394 *static_cast<const NVPTXTargetMachine &>(TM).getSubtargetImpl();
395 if (!ST.hasNoReturn())
396 return false;
398 assert((isa<Function>(V) || isa<CallInst>(V)) &&
399 "Expect either a call instruction or a function");
401 if (const CallInst *CallI = dyn_cast<CallInst>(V))
402 return CallI->doesNotReturn() &&
403 CallI->getFunctionType()->getReturnType()->isVoidTy();
405 const Function *F = cast<Function>(V);
406 return F->doesNotReturn() &&
407 F->getFunctionType()->getReturnType()->isVoidTy() &&
408 !isKernelFunction(*F);
411 bool Isv2x16VT(EVT VT) {
412 return (VT == MVT::v2f16 || VT == MVT::v2bf16 || VT == MVT::v2i16);
415 } // namespace llvm