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 declarations for PTX-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/StringExtras.h"
18#include "llvm/CodeGen/ValueTypes.h"
19#include "llvm/IR/Function.h"
20#include "llvm/IR/InstrTypes.h"
21#include "llvm/IR/Value.h"
22#include "llvm/Support/Alignment.h"
23#include "llvm/Support/FormatVariadic.h"
24#include <cstdarg>
25#include <string>
26
27namespace llvm {
28
29class DataLayout;
30class MemSDNode;
31
32Function *getMaybeBitcastedCallee(const CallBase *CB);
33
34/// The bit-width of a single element loaded by \p Mem, i.e. the width used for
35/// the ".fromtype" part of the emitted PTX load.
36unsigned getFromTypeWidthForLoad(const MemSDNode *Mem);
37
38/// ABI alignment of \p ArgTy in .param space, capped at the PTX maximum of 128.
39Align getPTXParamTypeAlign(Type *ArgTy, const DataLayout &DL);
40
41/// The .param-space alignment for a byval parameter or call argument: the
42/// (possibly promoted) parameter alignment, raised to the ptxas byval minimum.
43Align getDeviceByValParamAlign(const Function *F, Type *ArgTy, unsigned AttrIdx,
44 const DataLayout &DL);
45Align getDeviceByValParamAlign(const CallBase *CB, Type *ArgTy,
46 unsigned AttrIdx, const DataLayout &DL);
47
48/// Alignment for a function parameter or return value at AttributeList index
49/// \p AttrIdx (FirstArgIndex + argNo, or ReturnIndex). Prefers an explicit
50/// stackalign, else the ABI type alignment, folding in the byval `align`.
51Align getPTXParamAlign(const Function *F, Type *Ty, unsigned AttrIdx,
52 const DataLayout &DL);
53
54/// Alignment for a call-site argument or return value. Prefers an explicit
55/// stackalign on the call, else resolves the direct callee.
56Align getPTXParamAlign(const CallBase *CB, Type *Ty, unsigned AttrIdx,
57 const DataLayout &DL);
58
59// PTX ABI requires all scalar argument/return values to have
60// bit-size as a power of two of at least 32 bits.
61inline unsigned promoteScalarArgumentSize(unsigned size) {
62 if (size <= 32)
63 return 32;
64 if (size <= 64)
65 return 64;
66 if (size <= 128)
67 return 128;
68 return size;
69}
70
71inline bool shouldPassAsArray(Type *Ty) {
72 return Ty->isAggregateType() || Ty->isVectorTy() ||
73 Ty->getScalarSizeInBits() >= 128 || Ty->isHalfTy() || Ty->isBFloatTy();
74}
75
76namespace NVPTX {
77// Returns a list of vector types that we prefer to fit into a single PTX
78// register. NOTE: This must be kept in sync with the register classes
79// defined in NVPTXRegisterInfo.td.
80inline auto packed_types() {
81 static const auto PackedTypes = {MVT::v4i8, MVT::v2f16, MVT::v2bf16,
82 MVT::v2i16, MVT::v2f32, MVT::v2i32};
83 return PackedTypes;
84}
85
86// Checks if the type VT can fit into a single register.
87inline bool isPackedVectorTy(EVT VT) {
88 return any_of(Range: packed_types(), P: equal_to(Arg&: VT));
89}
90
91// Checks if two or more of the type ET can fit into a single register.
92inline bool isPackedElementTy(EVT ET) {
93 return any_of(Range: packed_types(),
94 P: [ET](EVT OVT) { return OVT.getVectorElementType() == ET; });
95}
96
97inline std::string getValidPTXIdentifier(StringRef Name) {
98 std::string ValidName;
99 ValidName.reserve(res_arg: Name.size() + 4);
100 for (char C : Name)
101 // While PTX also allows '%' at the start of identifiers, LLVM will throw a
102 // fatal error for '%' in symbol names in MCSymbol::print. Exclude for now.
103 if (isAlnum(C) || C == '_' || C == '$')
104 ValidName.push_back(c: C);
105 else
106 ValidName.append(l: {'_', '$', '_'});
107
108 return ValidName;
109}
110
111inline std::string OrderingToString(Ordering Order) {
112 switch (Order) {
113 case Ordering::NotAtomic:
114 return "NotAtomic";
115 case Ordering::Relaxed:
116 return "Relaxed";
117 case Ordering::Acquire:
118 return "Acquire";
119 case Ordering::Release:
120 return "Release";
121 case Ordering::AcquireRelease:
122 return "AcquireRelease";
123 case Ordering::SequentiallyConsistent:
124 return "SequentiallyConsistent";
125 case Ordering::Volatile:
126 return "Volatile";
127 case Ordering::RelaxedMMIO:
128 return "RelaxedMMIO";
129 }
130 report_fatal_error(reason: formatv(Fmt: "Unknown NVPTX::Ordering \"{}\".",
131 Vals: static_cast<OrderingUnderlyingType>(Order)));
132}
133
134inline raw_ostream &operator<<(raw_ostream &O, Ordering Order) {
135 O << OrderingToString(Order);
136 return O;
137}
138
139inline std::string ScopeToString(Scope S) {
140 switch (S) {
141 case Scope::Thread:
142 return "Thread";
143 case Scope::System:
144 return "System";
145 case Scope::Block:
146 return "Block";
147 case Scope::Cluster:
148 return "Cluster";
149 case Scope::Device:
150 return "Device";
151 case Scope::DefaultDevice:
152 return "DefaultDevice";
153 }
154 report_fatal_error(reason: formatv(Fmt: "Unknown NVPTX::Scope \"{}\".",
155 Vals: static_cast<ScopeUnderlyingType>(S)));
156}
157
158inline raw_ostream &operator<<(raw_ostream &O, Scope S) {
159 O << ScopeToString(S);
160 return O;
161}
162
163inline const char *addressSpaceToString(AddressSpace A,
164 bool UseParamSubqualifiers = false) {
165 switch (A) {
166 case AddressSpace::Generic:
167 return "generic";
168 case AddressSpace::Global:
169 return "global";
170 case AddressSpace::Const:
171 return "const";
172 case AddressSpace::Shared:
173 return "shared";
174 case AddressSpace::SharedCluster:
175 return "shared::cluster";
176 case AddressSpace::EntryParam:
177 return UseParamSubqualifiers ? "param::entry" : "param";
178 case AddressSpace::DeviceParam:
179 return UseParamSubqualifiers ? "param::func" : "param";
180 case AddressSpace::Local:
181 return "local";
182 }
183 report_fatal_error(reason: formatv(Fmt: "Unknown NVPTX::AddressSpace \"{}\".",
184 Vals: static_cast<AddressSpaceUnderlyingType>(A)));
185}
186
187inline raw_ostream &operator<<(raw_ostream &O, AddressSpace A) {
188 O << addressSpaceToString(A);
189 return O;
190}
191
192} // namespace NVPTX
193} // namespace llvm
194
195#endif
196