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