1 //===- NVPTXUtilities.cpp - Utility Functions -----------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file contains miscellaneous utility functions
11 //===----------------------------------------------------------------------===//
13 #include "NVPTXUtilities.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"
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
{
40 std::map
<const Module
*, global_val_annot_t
> Cache
;
43 AnnotationCache
&getAnnotationCache() {
44 static AnnotationCache AC
;
47 } // anonymous namespace
49 void clearAnnotationCache(const Module
*Mod
) {
50 auto &AC
= getAnnotationCache();
51 std::lock_guard
<sys::Mutex
> Guard(AC
.Lock
);
55 static void readIntVecFromMDNode(const MDNode
*MetadataNode
,
56 std::vector
<unsigned> &Vec
) {
57 for (unsigned i
= 0, e
= MetadataNode
->getNumOperands(); i
!= e
; ++i
) {
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) {
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();
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
]);
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");
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
117 // accumulate annotations for entity in tmp
118 cacheAnnotationFromMD(elem
, tmp
);
121 if (tmp
.empty()) // no annotations for this gv
124 if (AC
.Cache
.find(m
) != AC
.Cache
.end())
125 AC
.Cache
[m
][gv
] = std::move(tmp
);
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
,
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())
144 retval
= AC
.Cache
[m
][gv
][prop
][0];
148 static std::optional
<unsigned>
149 findOneNVVMAnnotation(const GlobalValue
&GV
, const std::string
&PropName
) {
151 if (findOneNVVMAnnotation(&GV
, PropName
, RetVal
))
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())
167 retval
= AC
.Cache
[m
][gv
][prop
];
171 bool isTexture(const Value
&val
) {
172 if (const GlobalValue
*gv
= dyn_cast
<GlobalValue
>(&val
)) {
174 if (findOneNVVMAnnotation(gv
, "texture", Annot
)) {
175 assert((Annot
== 1) && "Unexpected annotation on a texture symbol");
182 bool isSurface(const Value
&val
) {
183 if (const GlobalValue
*gv
= dyn_cast
<GlobalValue
>(&val
)) {
185 if (findOneNVVMAnnotation(gv
, "surface", Annot
)) {
186 assert((Annot
== 1) && "Unexpected annotation on a surface symbol");
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())) {
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");
223 bool isSampler(const Value
&val
) {
224 const char *AnnotationName
= "sampler";
226 if (const GlobalValue
*gv
= dyn_cast
<GlobalValue
>(&val
)) {
228 if (findOneNVVMAnnotation(gv
, AnnotationName
, Annot
)) {
229 assert((Annot
== 1) && "Unexpected annotation on a sampler symbol");
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
)) {
255 if (findOneNVVMAnnotation(gv
, "managed", Annot
)) {
256 assert((Annot
== 1) && "Unexpected annotation on a managed symbol");
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);
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);
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
) {
341 if (!findOneNVVMAnnotation(&F
, "kernel", x
)) {
342 // There is no NVVM metadata, check the calling convention
343 return F
.getCallingConv() == CallingConv::PTX_Kernel
;
348 MaybeAlign
getAlign(const Function
&F
, unsigned Index
) {
349 // First check the alignstack metadata
350 if (MaybeAlign StackAlign
=
351 F
.getAttributes().getAttributes(Index
).getStackAlignment())
354 // If that is missing, check the legacy nvvm metadata
355 std::vector
<unsigned> Vs
;
356 bool retval
= findAllNVVMAnnotation(&F
, "align", Vs
);
359 for (unsigned V
: Vs
)
360 if ((V
>> 16) == Index
)
361 return Align(V
& 0xFFFF);
366 MaybeAlign
getAlign(const CallInst
&I
, unsigned Index
) {
367 // First check the alignstack metadata
368 if (MaybeAlign StackAlign
=
369 I
.getAttributes().getAttributes(Index
).getStackAlignment())
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
)
388 Function
*getMaybeBitcastedCallee(const CallBase
*CB
) {
389 return dyn_cast
<Function
>(CB
->getCalledOperand()->stripPointerCasts());
392 bool shouldEmitPTXNoReturn(const Value
*V
, const TargetMachine
&TM
) {
394 *static_cast<const NVPTXTargetMachine
&>(TM
).getSubtargetImpl();
395 if (!ST
.hasNoReturn())
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
);