clang 24.0.0git
AMDGPU.cpp
Go to the documentation of this file.
1//===---- AMDGPU.cpp - AMDGPU-specific CIR CodeGen ------------------------===//
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 provides AMDGPU-specific CIR CodeGen logic for function attributes.
10//
11//===----------------------------------------------------------------------===//
12
13#include "../CIRGenModule.h"
14#include "../TargetInfo.h"
15
16#include "clang/AST/Attr.h"
17#include "clang/AST/Decl.h"
20#include "llvm/ADT/StringExtras.h"
21#include "llvm/Support/raw_ostream.h"
22
23using namespace clang;
24using namespace clang::CIRGen;
25
26namespace {
27
28/// Handle amdgpu-flat-work-group-size attribute.
29static void
30handleAMDGPUFlatWorkGroupSizeAttr(const FunctionDecl *fd, cir::FuncOp func,
31 CIRGenModule &cgm, CIRGenBuilderTy &builder,
32 bool isOpenCLKernel, bool isHIPKernel,
33 unsigned lbMaxThreads) {
34 const auto *flatWGS = fd->getAttr<AMDGPUFlatWorkGroupSizeAttr>();
35 const auto *reqdWGS =
36 cgm.getLangOpts().OpenCL ? fd->getAttr<ReqdWorkGroupSizeAttr>() : nullptr;
37
38 if (flatWGS || reqdWGS) {
39 unsigned min = 0, max = 0;
40 if (flatWGS) {
41 min = flatWGS->getMin()
42 ->EvaluateKnownConstInt(cgm.getASTContext())
43 .getExtValue();
44 max = flatWGS->getMax()
45 ->EvaluateKnownConstInt(cgm.getASTContext())
46 .getExtValue();
47 }
48 if (reqdWGS && min == 0 && max == 0) {
49 min = max = reqdWGS->getXDim()
50 ->EvaluateKnownConstInt(cgm.getASTContext())
51 .getExtValue() *
52 reqdWGS->getYDim()
53 ->EvaluateKnownConstInt(cgm.getASTContext())
54 .getExtValue() *
55 reqdWGS->getZDim()
56 ->EvaluateKnownConstInt(cgm.getASTContext())
57 .getExtValue();
58 }
59 if (min != 0) {
60 assert(min <= max && "Min must be less than or equal Max");
61 std::string attrVal = llvm::utostr(min) + "," + llvm::utostr(max);
62 func->setAttr(cir::CIRDialect::getAMDGPUFlatWorkGroupSizeAttrName(),
63 builder.getStringAttr(attrVal));
64 } else {
65 assert(max == 0 && "Max must be zero");
66 }
67 } else if (lbMaxThreads > 0) {
68 func->setAttr(cir::CIRDialect::getAMDGPUFlatWorkGroupSizeAttrName(),
69 builder.getStringAttr("1," + llvm::utostr(lbMaxThreads)));
70 } else if (isOpenCLKernel || isHIPKernel) {
71 // By default, restrict the maximum size to a value specified by
72 // --gpu-max-threads-per-block=n or its default value for HIP.
73 const unsigned openCLDefaultMaxWorkGroupSize = 256;
74 const unsigned defaultMaxWorkGroupSize =
75 isOpenCLKernel ? openCLDefaultMaxWorkGroupSize
76 : cgm.getLangOpts().GPUMaxThreadsPerBlock;
77 std::string attrVal =
78 std::string("1,") + llvm::utostr(defaultMaxWorkGroupSize);
79 func->setAttr(cir::CIRDialect::getAMDGPUFlatWorkGroupSizeAttrName(),
80 builder.getStringAttr(attrVal));
81 }
82}
83
84/// Handle amdgpu-waves-per-eu attribute.
85static void handleAMDGPUWavesPerEUAttr(const FunctionDecl *fd, cir::FuncOp func,
86 CIRGenModule &cgm,
87 CIRGenBuilderTy &builder,
88 unsigned lbMinWaves) {
89 const auto *attr = fd->getAttr<AMDGPUWavesPerEUAttr>();
90 if (!attr) {
91 // HIP maps __launch_bounds__ min blocks to min waves per EU.
92 if (lbMinWaves > 0)
93 func->setAttr(cir::CIRDialect::getAMDGPUWavesPerEUAttrName(),
94 builder.getStringAttr(llvm::utostr(lbMinWaves)));
95 return;
96 }
97 unsigned min =
98 attr->getMin()->EvaluateKnownConstInt(cgm.getASTContext()).getExtValue();
99 unsigned max = attr->getMax()
100 ? attr->getMax()
101 ->EvaluateKnownConstInt(cgm.getASTContext())
102 .getExtValue()
103 : 0;
104
105 if (min != 0) {
106 assert((max == 0 || min <= max) && "Min must be less than or equal Max");
107 std::string attrVal = llvm::utostr(min);
108 if (max != 0)
109 attrVal = attrVal + "," + llvm::utostr(max);
110 func->setAttr(cir::CIRDialect::getAMDGPUWavesPerEUAttrName(),
111 builder.getStringAttr(attrVal));
112 } else {
113 assert(max == 0 && "Max must be zero");
114 }
115}
116
117/// Handle amdgpu-num-sgpr attribute.
118static void handleAMDGPUNumSGPRAttr(const FunctionDecl *fd, cir::FuncOp func,
119 CIRGenModule &cgm,
120 CIRGenBuilderTy &builder) {
121 const auto *attr = fd->getAttr<AMDGPUNumSGPRAttr>();
122 if (!attr)
123 return;
124
125 uint32_t numSGPR = attr->getNumSGPR();
126 if (numSGPR != 0) {
127 func->setAttr("cir.amdgpu-num-sgpr",
128 builder.getStringAttr(llvm::utostr(numSGPR)));
129 }
130}
131
132/// Handle amdgpu-num-vgpr attribute.
133static void handleAMDGPUNumVGPRAttr(const FunctionDecl *fd, cir::FuncOp func,
134 CIRGenModule &cgm,
135 CIRGenBuilderTy &builder) {
136 const auto *attr = fd->getAttr<AMDGPUNumVGPRAttr>();
137 if (!attr)
138 return;
139
140 uint32_t numVGPR = attr->getNumVGPR();
141 if (numVGPR != 0) {
142 func->setAttr("cir.amdgpu-num-vgpr",
143 builder.getStringAttr(llvm::utostr(numVGPR)));
144 }
145}
146
147/// Handle amdgpu-max-num-workgroups attribute.
148static void handleAMDGPUMaxNumWorkGroupsAttr(const FunctionDecl *fd,
149 cir::FuncOp func,
150 CIRGenModule &cgm,
151 CIRGenBuilderTy &builder) {
152 const auto *attr = fd->getAttr<AMDGPUMaxNumWorkGroupsAttr>();
153 if (!attr)
154 return;
155 uint32_t x = attr->getMaxNumWorkGroupsX()
156 ->EvaluateKnownConstInt(cgm.getASTContext())
157 .getExtValue();
158 uint32_t y = attr->getMaxNumWorkGroupsY()
159 ? attr->getMaxNumWorkGroupsY()
160 ->EvaluateKnownConstInt(cgm.getASTContext())
161 .getExtValue()
162 : 1;
163 uint32_t z = attr->getMaxNumWorkGroupsZ()
164 ? attr->getMaxNumWorkGroupsZ()
165 ->EvaluateKnownConstInt(cgm.getASTContext())
166 .getExtValue()
167 : 1;
168
169 llvm::SmallString<32> attrVal;
170 llvm::raw_svector_ostream os(attrVal);
171 os << x << ',' << y << ',' << z;
172 func->setAttr("cir.amdgpu-max-num-workgroups",
173 builder.getStringAttr(attrVal.str()));
174}
175
176/// Handle amdgpu-cluster-dims attribute.
177static void handleAMDGPUClusterDimsAttr(const FunctionDecl *fd,
178 cir::FuncOp func, CIRGenModule &cgm,
179 CIRGenBuilderTy &builder,
180 bool isOpenCLKernel) {
181
182 if (const auto *attr = fd->getAttr<CUDAClusterDimsAttr>()) {
183 auto getExprVal = [&](const Expr *e) {
184 return e ? e->EvaluateKnownConstInt(cgm.getASTContext()).getExtValue()
185 : 1;
186 };
187 unsigned x = getExprVal(attr->getX());
188 unsigned y = getExprVal(attr->getY());
189 unsigned z = getExprVal(attr->getZ());
190
191 llvm::SmallString<32> attrVal;
192 llvm::raw_svector_ostream os(attrVal);
193 os << x << ',' << y << ',' << z;
194 func->setAttr("cir.amdgpu-cluster-dims",
195 builder.getStringAttr(attrVal.str()));
196 }
197
198 const TargetInfo &targetInfo = cgm.getASTContext().getTargetInfo();
199 if ((isOpenCLKernel &&
200 targetInfo.hasFeatureEnabled(targetInfo.getTargetOpts().FeatureMap,
201 "clusters")) ||
202 fd->hasAttr<CUDANoClusterAttr>()) {
203 func->setAttr("cir.amdgpu-cluster-dims", builder.getStringAttr("0,0,0"));
204 }
205}
206
207/// Handle amdgpu-ieee attribute.
208static void handleAMDGPUIEEEAttr(cir::FuncOp func, CIRGenModule &cgm,
209 CIRGenBuilderTy &builder) {
210 if (!cgm.getCodeGenOpts().EmitIEEENaNCompliantInsts)
211 func->setAttr("cir.amdgpu-ieee", builder.getStringAttr("false"));
212}
213
214/// Handle amdgpu-expand-waitcnt-profiling attribute.
215static void handleAMDGPUExpandWaitcntProfilingAttr(cir::FuncOp func,
216 CIRGenModule &cgm,
217 CIRGenBuilderTy &builder) {
218 if (cgm.getCodeGenOpts().AMDGPUExpandWaitcntProfiling)
219 func->setAttr("cir.amdgpu-expand-waitcnt-profiling",
220 builder.getStringAttr(""));
221}
222
223} // namespace
224
226 cir::FuncOp func,
227 CIRGenModule &cgm) {
228 if (func.isDeclaration())
229 return;
230
231 CIRGenBuilderTy &builder = cgm.getBuilder();
232
233 const auto *fd = dyn_cast_or_null<FunctionDecl>(decl);
234 if (fd) {
235 const bool isOpenCLKernel =
236 cgm.getLangOpts().OpenCL && fd->hasAttr<DeviceKernelAttr>();
237 const bool isHIPKernel =
238 cgm.getLangOpts().HIP && fd->hasAttr<CUDAGlobalAttr>();
239
240 // Native AMDGPU attributes take precedence over __launch_bounds__.
241 unsigned lbMaxThreads = 0;
242 unsigned lbMinWaves = 0;
243 if (const auto *lb =
244 isHIPKernel ? fd->getAttr<CUDALaunchBoundsAttr>() : nullptr) {
245 lbMaxThreads = lb->getMaxThreads()
246 ->EvaluateKnownConstInt(cgm.getASTContext())
247 .getExtValue();
248 if (const Expr *minBlocks = lb->getMinBlocks())
249 lbMinWaves =
250 minBlocks->EvaluateKnownConstInt(cgm.getASTContext()).getExtValue();
251 }
252
253 handleAMDGPUFlatWorkGroupSizeAttr(fd, func, cgm, builder, isOpenCLKernel,
254 isHIPKernel, lbMaxThreads);
255 handleAMDGPUWavesPerEUAttr(fd, func, cgm, builder, lbMinWaves);
256 handleAMDGPUNumSGPRAttr(fd, func, cgm, builder);
257 handleAMDGPUNumVGPRAttr(fd, func, cgm, builder);
258 handleAMDGPUMaxNumWorkGroupsAttr(fd, func, cgm, builder);
259 handleAMDGPUClusterDimsAttr(fd, func, cgm, builder, isOpenCLKernel);
260 }
261 handleAMDGPUIEEEAttr(func, cgm, builder);
262 handleAMDGPUExpandWaitcntProfilingAttr(func, cgm, builder);
263}
__DEVICE__ int min(int __a, int __b)
__DEVICE__ int max(int __a, int __b)
const TargetInfo & getTargetInfo() const
Definition ASTContext.h:971
This class organizes the cross-function state that is used while generating CIR code.
clang::ASTContext & getASTContext() const
CIRGenBuilderTy & getBuilder()
const clang::CodeGenOptions & getCodeGenOpts() const
const clang::LangOptions & getLangOpts() const
T * getAttr() const
Definition DeclBase.h:582
bool hasAttr() const
Definition DeclBase.h:586
This represents one expression.
Definition Expr.h:114
Represents a function declaration or definition.
Definition Decl.h:2082
Exposes information about the current target.
Definition TargetInfo.h:228
TargetOptions & getTargetOpts() const
Retrieve the target options.
Definition TargetInfo.h:334
virtual bool hasFeatureEnabled(const llvm::StringMap< bool > &Features, StringRef Name) const
Check if target has a given feature enabled.
llvm::StringMap< bool > FeatureMap
The map of which features have been enabled disabled based on the command line.
Defines the clang::TargetInfo interface.
void setAMDGPUTargetFunctionAttributes(const clang::Decl *decl, cir::FuncOp func, CIRGenModule &cgm)
Set AMDGPU-specific function attributes for HIP kernels.
Definition AMDGPU.cpp:225
@ Decl
The l-value was an access to a declared entity or something equivalently strong, like the address of ...
const internal::VariadicAllOfMatcher< Decl > decl
Matches declarations.
Top level wrappers for InstallAPI frontend operations.
nullptr
This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...