LLVM 23.0.0git
NVVMProperties.cpp
Go to the documentation of this file.
1//===- NVVMProperties.cpp - NVVM annotation utilities ---------------------===//
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 NVVM attribute and metadata query utilities.
10//
11//===----------------------------------------------------------------------===//
12
13#include "NVVMProperties.h"
14#include "llvm/ADT/ArrayRef.h"
15#include "llvm/ADT/STLExtras.h"
16#include "llvm/ADT/StringRef.h"
17#include "llvm/IR/Argument.h"
18#include "llvm/IR/Constants.h"
19#include "llvm/IR/Function.h"
20#include "llvm/IR/GlobalValue.h"
22#include "llvm/IR/Metadata.h"
23#include "llvm/IR/Module.h"
24#include "llvm/Support/ModRef.h"
25#include "llvm/Support/Mutex.h"
26#include <functional>
27#include <map>
28#include <mutex>
29#include <numeric>
30#include <string>
31#include <vector>
32
33namespace llvm {
34
35namespace {
36using AnnotationValues = std::map<std::string, std::vector<unsigned>>;
37using AnnotationMap = std::map<const GlobalValue *, AnnotationValues>;
38
39struct AnnotationCache {
40 sys::Mutex Lock;
41 std::map<const Module *, AnnotationMap> Cache;
42};
43
44AnnotationCache &getAnnotationCache() {
45 static AnnotationCache AC;
46 return AC;
47}
48} // namespace
49
51 auto &AC = getAnnotationCache();
52 std::lock_guard<sys::Mutex> Guard(AC.Lock);
53 AC.Cache.erase(Mod);
54}
55
56static void cacheAnnotationFromMD(const MDNode *MetadataNode,
57 AnnotationValues &RetVal) {
58 auto &AC = getAnnotationCache();
59 std::lock_guard<sys::Mutex> Guard(AC.Lock);
60 assert(MetadataNode && "Invalid mdnode for annotation");
61 assert((MetadataNode->getNumOperands() % 2) == 1 &&
62 "Invalid number of operands");
63 // start index = 1, to skip the global variable key
64 // increment = 2, to skip the value for each property-value pairs
65 for (unsigned I = 1, E = MetadataNode->getNumOperands(); I != E; I += 2) {
66 const MDString *Prop = dyn_cast<MDString>(MetadataNode->getOperand(I));
67 assert(Prop && "Annotation property not a string");
68 std::string Key = Prop->getString().str();
69
71 MetadataNode->getOperand(I + 1))) {
72 RetVal[Key].push_back(Val->getZExtValue());
73 } else {
74 llvm_unreachable("Value operand not a constant int");
75 }
76 }
77}
78
79static 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
86 AnnotationValues Tmp;
87 for (unsigned I = 0, E = NMD->getNumOperands(); I != E; ++I) {
88 const MDNode *Elem = NMD->getOperand(I);
89 GlobalValue *Entity =
91 // entity may be null due to DCE
92 if (!Entity || Entity != GV)
93 continue;
94
95 cacheAnnotationFromMD(Elem, Tmp);
96 }
97
98 if (Tmp.empty())
99 return;
100
101 AC.Cache[M][GV] = std::move(Tmp);
102}
103
104static std::optional<unsigned> findOneNVVMAnnotation(const GlobalValue *GV,
105 const std::string &Prop) {
106 auto &AC = getAnnotationCache();
107 std::lock_guard<sys::Mutex> Guard(AC.Lock);
108 const Module *M = GV->getParent();
109 auto ACIt = AC.Cache.find(M);
110 if (ACIt == AC.Cache.end())
112 else if (ACIt->second.find(GV) == ACIt->second.end())
114
115 auto &KVP = AC.Cache[M][GV];
116 auto It = KVP.find(Prop);
117 if (It == KVP.end())
118 return std::nullopt;
119 return It->second[0];
120}
121
122static bool findAllNVVMAnnotation(const GlobalValue *GV,
123 const std::string &Prop,
124 std::vector<unsigned> &RetVal) {
125 auto &AC = getAnnotationCache();
126 std::lock_guard<sys::Mutex> Guard(AC.Lock);
127 const Module *M = GV->getParent();
128 auto ACIt = AC.Cache.find(M);
129 if (ACIt == AC.Cache.end())
131 else if (ACIt->second.find(GV) == ACIt->second.end())
133
134 auto &KVP = AC.Cache[M][GV];
135 auto It = KVP.find(Prop);
136 if (It == KVP.end())
137 return false;
138 RetVal = It->second;
139 return true;
140}
141
142static bool globalHasNVVMAnnotation(const Value &V, const std::string &Prop) {
143 if (const auto *GV = dyn_cast<GlobalValue>(&V))
144 if (const auto Annot = findOneNVVMAnnotation(GV, Prop)) {
145 assert((*Annot == 1) && "Unexpected annotation on a symbol");
146 return true;
147 }
148
149 return false;
150}
151
152static bool argHasNVVMAnnotation(const Value &Val,
153 const std::string &Annotation) {
154 if (const auto *Arg = dyn_cast<Argument>(&Val)) {
155 std::vector<unsigned> Annot;
156 if (findAllNVVMAnnotation(Arg->getParent(), Annotation, Annot) &&
157 is_contained(Annot, Arg->getArgNo()))
158 return true;
159 }
160 return false;
161}
162
163static std::optional<unsigned> getFnAttrParsedInt(const Function &F,
164 StringRef Attr) {
165 return F.hasFnAttribute(Attr)
166 ? std::optional(F.getFnAttributeAsParsedInteger(Attr))
167 : std::nullopt;
168}
169
171 StringRef Attr) {
173 auto &Ctx = F.getContext();
174
175 if (F.hasFnAttribute(Attr)) {
176 // We expect the attribute value to be of the form "x[,y[,z]]", where x, y,
177 // and z are unsigned values.
178 StringRef S = F.getFnAttribute(Attr).getValueAsString();
179 for (unsigned I = 0; I < 3 && !S.empty(); I++) {
180 auto [First, Rest] = S.split(",");
181 unsigned IntVal;
182 if (First.trim().getAsInteger(0, IntVal))
183 Ctx.emitError("can't parse integer attribute " + First + " in " + Attr);
184
185 V.push_back(IntVal);
186 S = Rest;
187 }
188 }
189 return V;
190}
191
192static std::optional<uint64_t> getVectorProduct(ArrayRef<unsigned> V) {
193 if (V.empty())
194 return std::nullopt;
195
196 return std::accumulate(V.begin(), V.end(), uint64_t(1),
197 std::multiplies<uint64_t>{});
198}
199
200bool isTexture(const Value &V) { return globalHasNVVMAnnotation(V, "texture"); }
201
202bool isSurface(const Value &V) { return globalHasNVVMAnnotation(V, "surface"); }
203
204bool isSampler(const Value &V) {
205 const char *AnnotationName = "sampler";
206 return globalHasNVVMAnnotation(V, AnnotationName) ||
207 argHasNVVMAnnotation(V, AnnotationName);
208}
209
210bool isImageReadOnly(const Value &V) {
211 return argHasNVVMAnnotation(V, "rdoimage");
212}
213
214bool isImageWriteOnly(const Value &V) {
215 return argHasNVVMAnnotation(V, "wroimage");
216}
217
218bool isImageReadWrite(const Value &V) {
219 return argHasNVVMAnnotation(V, "rdwrimage");
220}
221
222bool isImage(const Value &V) {
224}
225
226bool isManaged(const Value &V) { return globalHasNVVMAnnotation(V, "managed"); }
227
229 return getFnAttrParsedVector(F, "nvvm.maxntid");
230}
231
233 return getFnAttrParsedVector(F, "nvvm.reqntid");
234}
235
237 return getFnAttrParsedVector(F, "nvvm.cluster_dim");
238}
239
240std::optional<uint64_t> getOverallMaxNTID(const Function &F) {
241 // Note: The semantics here are a bit strange. The PTX ISA states the
242 // following (11.4.2. Performance-Tuning Directives: .maxntid):
243 //
244 // Note that this directive guarantees that the total number of threads does
245 // not exceed the maximum, but does not guarantee that the limit in any
246 // particular dimension is not exceeded.
248}
249
250std::optional<uint64_t> getOverallReqNTID(const Function &F) {
251 // Note: The semantics here are a bit strange. See getOverallMaxNTID.
253}
254
255std::optional<uint64_t> getOverallClusterRank(const Function &F) {
256 // maxclusterrank and cluster_dim are mutually exclusive.
257 if (const auto ClusterRank = getMaxClusterRank(F))
258 return ClusterRank;
259
260 // Note: The semantics here are a bit strange. See getOverallMaxNTID.
262}
263
264std::optional<unsigned> getMaxClusterRank(const Function &F) {
265 return getFnAttrParsedInt(F, "nvvm.maxclusterrank");
266}
267
268std::optional<unsigned> getMinCTASm(const Function &F) {
269 return getFnAttrParsedInt(F, "nvvm.minctasm");
270}
271
272std::optional<unsigned> getMaxNReg(const Function &F) {
273 return getFnAttrParsedInt(F, "nvvm.maxnreg");
274}
275
277 return F.hasFnAttribute("nvvm.blocksareclusters");
278}
279
282 "only kernel arguments can be grid_constant");
283
284 if (!Arg.hasByValAttr())
285 return false;
286
287 // Lowering an argument as a grid_constant violates the byval semantics (and
288 // the C++ API) by reusing the same memory location for the argument across
289 // multiple threads. If an argument doesn't read memory and its address is not
290 // captured (its address is not compared with any value), then the tweak of
291 // the C++ API and byval semantics is unobservable by the program and we can
292 // lower the arg as a grid_constant.
293 if (Arg.onlyReadsMemory()) {
294 const auto CI = Arg.getAttributes().getCaptureInfo();
296 return true;
297 }
298
299 // "grid_constant" counts argument indices starting from 1
300 return Arg.hasAttribute("nvvm.grid_constant");
301}
302
303MaybeAlign getAlign(const CallInst &I, unsigned Index) {
304 // First check the alignstack metadata.
305 if (MaybeAlign StackAlign =
306 I.getAttributes().getAttributes(Index).getStackAlignment())
307 return StackAlign;
308
309 // If that is missing, check the legacy nvvm metadata.
310 if (MDNode *AlignNode = I.getMetadata("callalign")) {
311 for (int I = 0, N = AlignNode->getNumOperands(); I < N; I++) {
312 if (const auto *CI =
313 mdconst::dyn_extract<ConstantInt>(AlignNode->getOperand(I))) {
314 unsigned V = CI->getZExtValue();
315 if ((V >> 16) == Index)
316 return Align(V & 0xFFFF);
317 if ((V >> 16) > Index)
318 return std::nullopt;
319 }
320 }
321 }
322 return std::nullopt;
323}
324
325} // namespace llvm
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
Module.h This file contains the declarations for the Module class.
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
This file contains the declarations for metadata subclasses.
This file contains some templates that are useful if you are working with the STL at all.
This class represents an incoming formal argument to a Function.
Definition Argument.h:32
LLVM_ABI bool onlyReadsMemory() const
Return true if this argument has the readonly or readnone attribute.
Definition Function.cpp:308
LLVM_ABI bool hasAttribute(Attribute::AttrKind Kind) const
Check if an argument has a given attribute.
Definition Function.cpp:338
LLVM_ABI bool hasByValAttr() const
Return true if this argument has the byval attribute.
Definition Function.cpp:128
const Function * getParent() const
Definition Argument.h:44
LLVM_ABI AttributeSet getAttributes() const
Definition Function.cpp:350
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
LLVM_ABI CaptureInfo getCaptureInfo() const
This class represents a function call, abstracting a target machine's calling convention.
This is the shared class of boolean and integer constants.
Definition Constants.h:87
Module * getParent()
Get the module that this global value is contained inside of...
Metadata node.
Definition Metadata.h:1080
const MDOperand & getOperand(unsigned I) const
Definition Metadata.h:1444
unsigned getNumOperands() const
Return number of MDNode operands.
Definition Metadata.h:1450
A single uniqued string.
Definition Metadata.h:722
LLVM_ABI StringRef getString() const
Definition Metadata.cpp:632
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:67
A tuple of MDNodes.
Definition Metadata.h:1760
LLVM_ABI MDNode * getOperand(unsigned i) const
LLVM_ABI unsigned getNumOperands() const
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
std::pair< StringRef, StringRef > split(char Separator) const
Split into two substrings around the first occurrence of a separator character.
Definition StringRef.h:730
std::string str() const
str - Get the contents as an std::string.
Definition StringRef.h:222
constexpr bool empty() const
empty - Check if the string is empty.
Definition StringRef.h:140
LLVM Value Representation.
Definition Value.h:75
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
std::enable_if_t< detail::IsValidPointer< X, Y >::value, X * > dyn_extract_or_null(Y &&MD)
Extract a Value from Metadata, if any, allowing null.
Definition Metadata.h:709
std::enable_if_t< detail::IsValidPointer< X, Y >::value, X * > dyn_extract(Y &&MD)
Extract a Value from Metadata, if any.
Definition Metadata.h:696
SmartMutex< false > Mutex
Mutex - A standard, always enforced mutex.
Definition Mutex.h:66
This is an optimization pass for GlobalISel generic memory operations.
Definition Types.h:26
static void cacheAnnotationFromMD(const MDNode *MetadataNode, AnnotationValues &RetVal)
bool isManaged(const Value &V)
std::optional< uint64_t > getOverallClusterRank(const Function &F)
static bool globalHasNVVMAnnotation(const Value &V, const std::string &Prop)
MaybeAlign getAlign(const CallInst &I, unsigned Index)
static std::optional< uint64_t > getVectorProduct(ArrayRef< unsigned > V)
std::optional< unsigned > getMaxNReg(const Function &F)
bool capturesAddress(CaptureComponents CC)
Definition ModRef.h:387
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
bool isImageReadWrite(const Value &V)
bool isImageReadOnly(const Value &V)
static std::optional< unsigned > findOneNVVMAnnotation(const GlobalValue *GV, const std::string &Prop)
std::optional< unsigned > getMinCTASm(const Function &F)
SmallVector< unsigned, 3 > getReqNTID(const Function &F)
bool capturesFullProvenance(CaptureComponents CC)
Definition ModRef.h:396
bool isImage(const Value &V)
bool isSampler(const Value &V)
void clearAnnotationCache(const Module *Mod)
bool isSurface(const Value &V)
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
std::optional< unsigned > getMaxClusterRank(const Function &F)
@ Mod
The access may modify the value stored in memory.
Definition ModRef.h:34
@ First
Helpers to iterate all locations in the MemoryEffectsBase class.
Definition ModRef.h:74
SmallVector< unsigned, 3 > getMaxNTID(const Function &F)
bool isParamGridConstant(const Argument &Arg)
static std::optional< unsigned > getFnAttrParsedInt(const Function &F, StringRef Attr)
std::optional< uint64_t > getOverallReqNTID(const Function &F)
bool isKernelFunction(const Function &F)
bool isTexture(const Value &V)
bool isImageWriteOnly(const Value &V)
static bool findAllNVVMAnnotation(const GlobalValue *GV, const std::string &Prop, std::vector< unsigned > &RetVal)
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition STLExtras.h:1947
std::optional< uint64_t > getOverallMaxNTID(const Function &F)
bool hasBlocksAreClusters(const Function &F)
SmallVector< unsigned, 3 > getClusterDim(const Function &F)
static bool argHasNVVMAnnotation(const Value &Val, const std::string &Annotation)
static SmallVector< unsigned, 3 > getFnAttrParsedVector(const Function &F, StringRef Attr)
#define N
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition Alignment.h:39
This struct is a compact representation of a valid (power of two) or undefined (0) alignment.
Definition Alignment.h:106