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/Mutex.h"
33 typedef std::map
<std::string
, std::vector
<unsigned> > key_val_pair_t
;
34 typedef std::map
<const GlobalValue
*, key_val_pair_t
> global_val_annot_t
;
36 struct AnnotationCache
{
38 std::map
<const Module
*, global_val_annot_t
> Cache
;
41 AnnotationCache
&getAnnotationCache() {
42 static AnnotationCache AC
;
45 } // anonymous namespace
47 void clearAnnotationCache(const Module
*Mod
) {
48 auto &AC
= getAnnotationCache();
49 std::lock_guard
<sys::Mutex
> Guard(AC
.Lock
);
53 static void cacheAnnotationFromMD(const MDNode
*md
, key_val_pair_t
&retval
) {
54 auto &AC
= getAnnotationCache();
55 std::lock_guard
<sys::Mutex
> Guard(AC
.Lock
);
56 assert(md
&& "Invalid mdnode for annotation");
57 assert((md
->getNumOperands() % 2) == 1 && "Invalid number of operands");
58 // start index = 1, to skip the global variable key
59 // increment = 2, to skip the value for each property-value pairs
60 for (unsigned i
= 1, e
= md
->getNumOperands(); i
!= e
; i
+= 2) {
62 const MDString
*prop
= dyn_cast
<MDString
>(md
->getOperand(i
));
63 assert(prop
&& "Annotation property not a string");
66 ConstantInt
*Val
= mdconst::dyn_extract
<ConstantInt
>(md
->getOperand(i
+ 1));
67 assert(Val
&& "Value operand not a constant int");
69 std::string keyname
= prop
->getString().str();
70 if (retval
.find(keyname
) != retval
.end())
71 retval
[keyname
].push_back(Val
->getZExtValue());
73 std::vector
<unsigned> tmp
;
74 tmp
.push_back(Val
->getZExtValue());
75 retval
[keyname
] = tmp
;
80 static void cacheAnnotationFromMD(const Module
*m
, const GlobalValue
*gv
) {
81 auto &AC
= getAnnotationCache();
82 std::lock_guard
<sys::Mutex
> Guard(AC
.Lock
);
83 NamedMDNode
*NMD
= m
->getNamedMetadata("nvvm.annotations");
87 for (unsigned i
= 0, e
= NMD
->getNumOperands(); i
!= e
; ++i
) {
88 const MDNode
*elem
= NMD
->getOperand(i
);
91 mdconst::dyn_extract_or_null
<GlobalValue
>(elem
->getOperand(0));
92 // entity may be null due to DCE
98 // accumulate annotations for entity in tmp
99 cacheAnnotationFromMD(elem
, tmp
);
102 if (tmp
.empty()) // no annotations for this gv
105 if (AC
.Cache
.find(m
) != AC
.Cache
.end())
106 AC
.Cache
[m
][gv
] = std::move(tmp
);
108 global_val_annot_t tmp1
;
109 tmp1
[gv
] = std::move(tmp
);
110 AC
.Cache
[m
] = std::move(tmp1
);
114 bool findOneNVVMAnnotation(const GlobalValue
*gv
, const std::string
&prop
,
116 auto &AC
= getAnnotationCache();
117 std::lock_guard
<sys::Mutex
> Guard(AC
.Lock
);
118 const Module
*m
= gv
->getParent();
119 if (AC
.Cache
.find(m
) == AC
.Cache
.end())
120 cacheAnnotationFromMD(m
, gv
);
121 else if (AC
.Cache
[m
].find(gv
) == AC
.Cache
[m
].end())
122 cacheAnnotationFromMD(m
, gv
);
123 if (AC
.Cache
[m
][gv
].find(prop
) == AC
.Cache
[m
][gv
].end())
125 retval
= AC
.Cache
[m
][gv
][prop
][0];
129 bool findAllNVVMAnnotation(const GlobalValue
*gv
, const std::string
&prop
,
130 std::vector
<unsigned> &retval
) {
131 auto &AC
= getAnnotationCache();
132 std::lock_guard
<sys::Mutex
> Guard(AC
.Lock
);
133 const Module
*m
= gv
->getParent();
134 if (AC
.Cache
.find(m
) == AC
.Cache
.end())
135 cacheAnnotationFromMD(m
, gv
);
136 else if (AC
.Cache
[m
].find(gv
) == AC
.Cache
[m
].end())
137 cacheAnnotationFromMD(m
, gv
);
138 if (AC
.Cache
[m
][gv
].find(prop
) == AC
.Cache
[m
][gv
].end())
140 retval
= AC
.Cache
[m
][gv
][prop
];
144 bool isTexture(const Value
&val
) {
145 if (const GlobalValue
*gv
= dyn_cast
<GlobalValue
>(&val
)) {
147 if (findOneNVVMAnnotation(gv
, "texture", annot
)) {
148 assert((annot
== 1) && "Unexpected annotation on a texture symbol");
155 bool isSurface(const Value
&val
) {
156 if (const GlobalValue
*gv
= dyn_cast
<GlobalValue
>(&val
)) {
158 if (findOneNVVMAnnotation(gv
, "surface", annot
)) {
159 assert((annot
== 1) && "Unexpected annotation on a surface symbol");
166 bool isSampler(const Value
&val
) {
167 const char *AnnotationName
= "sampler";
169 if (const GlobalValue
*gv
= dyn_cast
<GlobalValue
>(&val
)) {
171 if (findOneNVVMAnnotation(gv
, AnnotationName
, annot
)) {
172 assert((annot
== 1) && "Unexpected annotation on a sampler symbol");
176 if (const Argument
*arg
= dyn_cast
<Argument
>(&val
)) {
177 const Function
*func
= arg
->getParent();
178 std::vector
<unsigned> annot
;
179 if (findAllNVVMAnnotation(func
, AnnotationName
, annot
)) {
180 if (is_contained(annot
, arg
->getArgNo()))
187 bool isImageReadOnly(const Value
&val
) {
188 if (const Argument
*arg
= dyn_cast
<Argument
>(&val
)) {
189 const Function
*func
= arg
->getParent();
190 std::vector
<unsigned> annot
;
191 if (findAllNVVMAnnotation(func
, "rdoimage", annot
)) {
192 if (is_contained(annot
, arg
->getArgNo()))
199 bool isImageWriteOnly(const Value
&val
) {
200 if (const Argument
*arg
= dyn_cast
<Argument
>(&val
)) {
201 const Function
*func
= arg
->getParent();
202 std::vector
<unsigned> annot
;
203 if (findAllNVVMAnnotation(func
, "wroimage", annot
)) {
204 if (is_contained(annot
, arg
->getArgNo()))
211 bool isImageReadWrite(const Value
&val
) {
212 if (const Argument
*arg
= dyn_cast
<Argument
>(&val
)) {
213 const Function
*func
= arg
->getParent();
214 std::vector
<unsigned> annot
;
215 if (findAllNVVMAnnotation(func
, "rdwrimage", annot
)) {
216 if (is_contained(annot
, arg
->getArgNo()))
223 bool isImage(const Value
&val
) {
224 return isImageReadOnly(val
) || isImageWriteOnly(val
) || isImageReadWrite(val
);
227 bool isManaged(const Value
&val
) {
228 if(const GlobalValue
*gv
= dyn_cast
<GlobalValue
>(&val
)) {
230 if (findOneNVVMAnnotation(gv
, "managed", annot
)) {
231 assert((annot
== 1) && "Unexpected annotation on a managed symbol");
238 std::string
getTextureName(const Value
&val
) {
239 assert(val
.hasName() && "Found texture variable with no name");
240 return std::string(val
.getName());
243 std::string
getSurfaceName(const Value
&val
) {
244 assert(val
.hasName() && "Found surface variable with no name");
245 return std::string(val
.getName());
248 std::string
getSamplerName(const Value
&val
) {
249 assert(val
.hasName() && "Found sampler variable with no name");
250 return std::string(val
.getName());
253 bool getMaxNTIDx(const Function
&F
, unsigned &x
) {
254 return findOneNVVMAnnotation(&F
, "maxntidx", x
);
257 bool getMaxNTIDy(const Function
&F
, unsigned &y
) {
258 return findOneNVVMAnnotation(&F
, "maxntidy", y
);
261 bool getMaxNTIDz(const Function
&F
, unsigned &z
) {
262 return findOneNVVMAnnotation(&F
, "maxntidz", z
);
265 bool getMaxClusterRank(const Function
&F
, unsigned &x
) {
266 return findOneNVVMAnnotation(&F
, "maxclusterrank", x
);
269 bool getReqNTIDx(const Function
&F
, unsigned &x
) {
270 return findOneNVVMAnnotation(&F
, "reqntidx", x
);
273 bool getReqNTIDy(const Function
&F
, unsigned &y
) {
274 return findOneNVVMAnnotation(&F
, "reqntidy", y
);
277 bool getReqNTIDz(const Function
&F
, unsigned &z
) {
278 return findOneNVVMAnnotation(&F
, "reqntidz", z
);
281 bool getMinCTASm(const Function
&F
, unsigned &x
) {
282 return findOneNVVMAnnotation(&F
, "minctasm", x
);
285 bool getMaxNReg(const Function
&F
, unsigned &x
) {
286 return findOneNVVMAnnotation(&F
, "maxnreg", x
);
289 bool isKernelFunction(const Function
&F
) {
291 bool retval
= findOneNVVMAnnotation(&F
, "kernel", x
);
293 // There is no NVVM metadata, check the calling convention
294 return F
.getCallingConv() == CallingConv::PTX_Kernel
;
299 bool getAlign(const Function
&F
, unsigned index
, unsigned &align
) {
300 std::vector
<unsigned> Vs
;
301 bool retval
= findAllNVVMAnnotation(&F
, "align", Vs
);
304 for (unsigned v
: Vs
) {
305 if ((v
>> 16) == index
) {
313 bool getAlign(const CallInst
&I
, unsigned index
, unsigned &align
) {
314 if (MDNode
*alignNode
= I
.getMetadata("callalign")) {
315 for (int i
= 0, n
= alignNode
->getNumOperands(); i
< n
; i
++) {
316 if (const ConstantInt
*CI
=
317 mdconst::dyn_extract
<ConstantInt
>(alignNode
->getOperand(i
))) {
318 unsigned v
= CI
->getZExtValue();
319 if ((v
>> 16) == index
) {
323 if ((v
>> 16) > index
) {
332 Function
*getMaybeBitcastedCallee(const CallBase
*CB
) {
333 return dyn_cast
<Function
>(CB
->getCalledOperand()->stripPointerCasts());
336 bool shouldEmitPTXNoReturn(const Value
*V
, const TargetMachine
&TM
) {
338 *static_cast<const NVPTXTargetMachine
&>(TM
).getSubtargetImpl();
339 if (!ST
.hasNoReturn())
342 assert((isa
<Function
>(V
) || isa
<CallInst
>(V
)) &&
343 "Expect either a call instruction or a function");
345 if (const CallInst
*CallI
= dyn_cast
<CallInst
>(V
))
346 return CallI
->doesNotReturn() &&
347 CallI
->getFunctionType()->getReturnType()->isVoidTy();
349 const Function
*F
= cast
<Function
>(V
);
350 return F
->doesNotReturn() &&
351 F
->getFunctionType()->getReturnType()->isVoidTy() &&
352 !isKernelFunction(*F
);
355 bool Isv2x16VT(EVT VT
) {
356 return (VT
== MVT::v2f16
|| VT
== MVT::v2bf16
|| VT
== MVT::v2i16
);