1//===-- NVPTXUtilities - Utilities -----------------------------*- C++ -*-====//
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 the declaration of the NVVM specific utility functions.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef LLVM_LIB_TARGET_NVPTX_NVPTXUTILITIES_H
14#define LLVM_LIB_TARGET_NVPTX_NVPTXUTILITIES_H
15
16#include "NVPTX.h"
17#include "llvm/ADT/SmallVector.h"
18#include "llvm/ADT/StringExtras.h"
19#include "llvm/CodeGen/ValueTypes.h"
20#include "llvm/IR/CallingConv.h"
21#include "llvm/IR/Function.h"
22#include "llvm/IR/GlobalVariable.h"
23#include "llvm/IR/IntrinsicInst.h"
24#include "llvm/IR/Value.h"
25#include "llvm/Support/Alignment.h"
26#include "llvm/Support/FormatVariadic.h"
27#include <cstdarg>
28#include <string>
29
30namespace llvm {
31
32class DataLayout;
33class TargetMachine;
34
35void clearAnnotationCache(const Module *);
36
37bool isTexture(const Value &);
38bool isSurface(const Value &);
39bool isSampler(const Value &);
40bool isImage(const Value &);
41bool isImageReadOnly(const Value &);
42bool isImageWriteOnly(const Value &);
43bool isImageReadWrite(const Value &);
44bool isManaged(const Value &);
45
46StringRef getTextureName(const Value &);
47StringRef getSurfaceName(const Value &);
48StringRef getSamplerName(const Value &);
49
50SmallVector<unsigned, 3> getMaxNTID(const Function &);
51SmallVector<unsigned, 3> getReqNTID(const Function &);
52SmallVector<unsigned, 3> getClusterDim(const Function &);
53
54std::optional<uint64_t> getOverallMaxNTID(const Function &);
55std::optional<uint64_t> getOverallReqNTID(const Function &);
56std::optional<uint64_t> getOverallClusterRank(const Function &);
57
58std::optional<unsigned> getMaxClusterRank(const Function &);
59std::optional<unsigned> getMinCTASm(const Function &);
60std::optional<unsigned> getMaxNReg(const Function &);
61
62bool hasBlocksAreClusters(const Function &);
63
64inline bool isKernelFunction(const Function &F) {
65 return F.getCallingConv() == CallingConv::PTX_Kernel;
66}
67
68bool isParamGridConstant(const Argument &);
69
70inline MaybeAlign getAlign(const Function &F, unsigned Index) {
71 return F.getAttributes().getAttributes(Index).getStackAlignment();
72}
73
74MaybeAlign getAlign(const CallInst &, unsigned);
75Function *getMaybeBitcastedCallee(const CallBase *CB);
76
77/// Since function arguments are passed via .param space, we may want to
78/// increase their alignment in a way that ensures that we can effectively
79/// vectorize their loads & stores. We can increase alignment only if the
80/// function has internal or private linkage as for other linkage types callers
81/// may already rely on default alignment. To allow using 128-bit vectorized
82/// loads/stores, this function ensures that alignment is 16 or greater.
83Align getFunctionParamOptimizedAlign(const Function *F, Type *ArgTy,
84 const DataLayout &DL);
85
86Align getFunctionArgumentAlignment(const Function *F, Type *Ty, unsigned Idx,
87 const DataLayout &DL);
88
89Align getFunctionByValParamAlign(const Function *F, Type *ArgTy,
90 Align InitialAlign, const DataLayout &DL);
91
92// PTX ABI requires all scalar argument/return values to have
93// bit-size as a power of two of at least 32 bits.
94inline unsigned promoteScalarArgumentSize(unsigned size) {
95 if (size <= 32)
96 return 32;
97 if (size <= 64)
98 return 64;
99 if (size <= 128)
100 return 128;
101 return size;
102}
103
104bool shouldEmitPTXNoReturn(const Value *V, const TargetMachine &TM);
105
106inline bool shouldPassAsArray(Type *Ty) {
107 return Ty->isAggregateType() || Ty->isVectorTy() ||
108 Ty->getScalarSizeInBits() >= 128 || Ty->isHalfTy() || Ty->isBFloatTy();
109}
110
111namespace NVPTX {
112// Returns a list of vector types that we prefer to fit into a single PTX
113// register. NOTE: This must be kept in sync with the register classes
114// defined in NVPTXRegisterInfo.td.
115inline auto packed_types() {
116 static const auto PackedTypes = {MVT::v4i8, MVT::v2f16, MVT::v2bf16,
117 MVT::v2i16, MVT::v2f32, MVT::v2i32};
118 return PackedTypes;
119}
120
121// Checks if the type VT can fit into a single register.
122inline bool isPackedVectorTy(EVT VT) {
123 return any_of(Range: packed_types(), P: equal_to(Arg&: VT));
124}
125
126// Checks if two or more of the type ET can fit into a single register.
127inline bool isPackedElementTy(EVT ET) {
128 return any_of(Range: packed_types(),
129 P: [ET](EVT OVT) { return OVT.getVectorElementType() == ET; });
130}
131
132inline std::string getValidPTXIdentifier(StringRef Name) {
133 std::string ValidName;
134 ValidName.reserve(res_arg: Name.size() + 4);
135 for (char C : Name)
136 // While PTX also allows '%' at the start of identifiers, LLVM will throw a
137 // fatal error for '%' in symbol names in MCSymbol::print. Exclude for now.
138 if (isAlnum(C) || C == '_' || C == '$')
139 ValidName.push_back(c: C);
140 else
141 ValidName.append(l: {'_', '$', '_'});
142
143 return ValidName;
144}
145
146inline std::string OrderingToString(Ordering Order) {
147 switch (Order) {
148 case Ordering::NotAtomic:
149 return "NotAtomic";
150 case Ordering::Relaxed:
151 return "Relaxed";
152 case Ordering::Acquire:
153 return "Acquire";
154 case Ordering::Release:
155 return "Release";
156 case Ordering::AcquireRelease:
157 return "AcquireRelease";
158 case Ordering::SequentiallyConsistent:
159 return "SequentiallyConsistent";
160 case Ordering::Volatile:
161 return "Volatile";
162 case Ordering::RelaxedMMIO:
163 return "RelaxedMMIO";
164 }
165 report_fatal_error(reason: formatv(Fmt: "Unknown NVPTX::Ordering \"{}\".",
166 Vals: static_cast<OrderingUnderlyingType>(Order)));
167}
168
169inline raw_ostream &operator<<(raw_ostream &O, Ordering Order) {
170 O << OrderingToString(Order);
171 return O;
172}
173
174inline std::string ScopeToString(Scope S) {
175 switch (S) {
176 case Scope::Thread:
177 return "Thread";
178 case Scope::System:
179 return "System";
180 case Scope::Block:
181 return "Block";
182 case Scope::Cluster:
183 return "Cluster";
184 case Scope::Device:
185 return "Device";
186 case Scope::DefaultDevice:
187 return "DefaultDevice";
188 }
189 report_fatal_error(reason: formatv(Fmt: "Unknown NVPTX::Scope \"{}\".",
190 Vals: static_cast<ScopeUnderlyingType>(S)));
191}
192
193inline raw_ostream &operator<<(raw_ostream &O, Scope S) {
194 O << ScopeToString(S);
195 return O;
196}
197
198inline std::string AddressSpaceToString(AddressSpace A) {
199 switch (A) {
200 case AddressSpace::Generic:
201 return "generic";
202 case AddressSpace::Global:
203 return "global";
204 case AddressSpace::Const:
205 return "const";
206 case AddressSpace::Shared:
207 return "shared";
208 case AddressSpace::SharedCluster:
209 return "shared::cluster";
210 case AddressSpace::Param:
211 return "param";
212 case AddressSpace::Local:
213 return "local";
214 }
215 report_fatal_error(reason: formatv(Fmt: "Unknown NVPTX::AddressSpace \"{}\".",
216 Vals: static_cast<AddressSpaceUnderlyingType>(A)));
217}
218
219inline raw_ostream &operator<<(raw_ostream &O, AddressSpace A) {
220 O << AddressSpaceToString(A);
221 return O;
222}
223
224} // namespace NVPTX
225} // namespace llvm
226
227#endif
228