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 const auto *flatWGS = fd->getAttr<AMDGPUFlatWorkGroupSizeAttr>();
34 const auto *reqdWGS =
35 cgm.getLangOpts().OpenCL ? fd->getAttr<ReqdWorkGroupSizeAttr>() : nullptr;
36
37 if (flatWGS || reqdWGS) {
38 unsigned min = 0, max = 0;
39 if (flatWGS) {
40 min = flatWGS->getMin()
41 ->EvaluateKnownConstInt(cgm.getASTContext())
42 .getExtValue();
43 max = flatWGS->getMax()
44 ->EvaluateKnownConstInt(cgm.getASTContext())
45 .getExtValue();
46 }
47 if (reqdWGS && min == 0 && max == 0) {
48 min = max = reqdWGS->getXDim()
49 ->EvaluateKnownConstInt(cgm.getASTContext())
50 .getExtValue() *
51 reqdWGS->getYDim()
52 ->EvaluateKnownConstInt(cgm.getASTContext())
53 .getExtValue() *
54 reqdWGS->getZDim()
55 ->EvaluateKnownConstInt(cgm.getASTContext())
56 .getExtValue();
57 }
58 if (min != 0) {
59 assert(min <= max && "Min must be less than or equal Max");
60 std::string attrVal = llvm::utostr(min) + "," + llvm::utostr(max);
61 func->setAttr("cir.amdgpu-flat-work-group-size",
62 builder.getStringAttr(attrVal));
63 } else {
64 assert(max == 0 && "Max must be zero");
65 }
66 } else if (isOpenCLKernel || isHIPKernel) {
67 // By default, restrict the maximum size to a value specified by
68 // --gpu-max-threads-per-block=n or its default value for HIP.
69 const unsigned openCLDefaultMaxWorkGroupSize = 256;
70 const unsigned defaultMaxWorkGroupSize =
71 isOpenCLKernel ? openCLDefaultMaxWorkGroupSize
72 : cgm.getLangOpts().GPUMaxThreadsPerBlock;
73 std::string attrVal =
74 std::string("1,") + llvm::utostr(defaultMaxWorkGroupSize);
75 func->setAttr("cir.amdgpu-flat-work-group-size",
76 builder.getStringAttr(attrVal));
77 }
78}
79
80/// Handle amdgpu-waves-per-eu attribute.
81static void handleAMDGPUWavesPerEUAttr(const FunctionDecl *fd, cir::FuncOp func,
82 CIRGenModule &cgm,
83 CIRGenBuilderTy &builder) {
84 const auto *attr = fd->getAttr<AMDGPUWavesPerEUAttr>();
85 if (!attr)
86 return;
87 unsigned min =
88 attr->getMin()->EvaluateKnownConstInt(cgm.getASTContext()).getExtValue();
89 unsigned max = attr->getMax()
90 ? attr->getMax()
91 ->EvaluateKnownConstInt(cgm.getASTContext())
92 .getExtValue()
93 : 0;
94
95 if (min != 0) {
96 assert((max == 0 || min <= max) && "Min must be less than or equal Max");
97 std::string attrVal = llvm::utostr(min);
98 if (max != 0)
99 attrVal = attrVal + "," + llvm::utostr(max);
100 func->setAttr("cir.amdgpu-waves-per-eu", builder.getStringAttr(attrVal));
101 } else {
102 assert(max == 0 && "Max must be zero");
103 }
104}
105
106/// Handle amdgpu-num-sgpr attribute.
107static void handleAMDGPUNumSGPRAttr(const FunctionDecl *fd, cir::FuncOp func,
108 CIRGenModule &cgm,
109 CIRGenBuilderTy &builder) {
110 const auto *attr = fd->getAttr<AMDGPUNumSGPRAttr>();
111 if (!attr)
112 return;
113
114 uint32_t numSGPR = attr->getNumSGPR();
115 if (numSGPR != 0) {
116 func->setAttr("cir.amdgpu-num-sgpr",
117 builder.getStringAttr(llvm::utostr(numSGPR)));
118 }
119}
120
121/// Handle amdgpu-num-vgpr attribute.
122static void handleAMDGPUNumVGPRAttr(const FunctionDecl *fd, cir::FuncOp func,
123 CIRGenModule &cgm,
124 CIRGenBuilderTy &builder) {
125 const auto *attr = fd->getAttr<AMDGPUNumVGPRAttr>();
126 if (!attr)
127 return;
128
129 uint32_t numVGPR = attr->getNumVGPR();
130 if (numVGPR != 0) {
131 func->setAttr("cir.amdgpu-num-vgpr",
132 builder.getStringAttr(llvm::utostr(numVGPR)));
133 }
134}
135
136/// Handle amdgpu-max-num-workgroups attribute.
137static void handleAMDGPUMaxNumWorkGroupsAttr(const FunctionDecl *fd,
138 cir::FuncOp func,
139 CIRGenModule &cgm,
140 CIRGenBuilderTy &builder) {
141 const auto *attr = fd->getAttr<AMDGPUMaxNumWorkGroupsAttr>();
142 if (!attr)
143 return;
144 uint32_t x = attr->getMaxNumWorkGroupsX()
145 ->EvaluateKnownConstInt(cgm.getASTContext())
146 .getExtValue();
147 uint32_t y = attr->getMaxNumWorkGroupsY()
148 ? attr->getMaxNumWorkGroupsY()
149 ->EvaluateKnownConstInt(cgm.getASTContext())
150 .getExtValue()
151 : 1;
152 uint32_t z = attr->getMaxNumWorkGroupsZ()
153 ? attr->getMaxNumWorkGroupsZ()
154 ->EvaluateKnownConstInt(cgm.getASTContext())
155 .getExtValue()
156 : 1;
157
158 llvm::SmallString<32> attrVal;
159 llvm::raw_svector_ostream os(attrVal);
160 os << x << ',' << y << ',' << z;
161 func->setAttr("cir.amdgpu-max-num-workgroups",
162 builder.getStringAttr(attrVal.str()));
163}
164
165/// Handle amdgpu-cluster-dims attribute.
166static void handleAMDGPUClusterDimsAttr(const FunctionDecl *fd,
167 cir::FuncOp func, CIRGenModule &cgm,
168 CIRGenBuilderTy &builder,
169 bool isOpenCLKernel) {
170
171 if (const auto *attr = fd->getAttr<CUDAClusterDimsAttr>()) {
172 auto getExprVal = [&](const Expr *e) {
173 return e ? e->EvaluateKnownConstInt(cgm.getASTContext()).getExtValue()
174 : 1;
175 };
176 unsigned x = getExprVal(attr->getX());
177 unsigned y = getExprVal(attr->getY());
178 unsigned z = getExprVal(attr->getZ());
179
180 llvm::SmallString<32> attrVal;
181 llvm::raw_svector_ostream os(attrVal);
182 os << x << ',' << y << ',' << z;
183 func->setAttr("cir.amdgpu-cluster-dims",
184 builder.getStringAttr(attrVal.str()));
185 }
186
187 const TargetInfo &targetInfo = cgm.getASTContext().getTargetInfo();
188 if ((isOpenCLKernel &&
189 targetInfo.hasFeatureEnabled(targetInfo.getTargetOpts().FeatureMap,
190 "clusters")) ||
191 fd->hasAttr<CUDANoClusterAttr>()) {
192 func->setAttr("cir.amdgpu-cluster-dims", builder.getStringAttr("0,0,0"));
193 }
194}
195
196/// Handle amdgpu-ieee attribute.
197static void handleAMDGPUIEEEAttr(cir::FuncOp func, CIRGenModule &cgm,
198 CIRGenBuilderTy &builder) {
199 if (!cgm.getCodeGenOpts().EmitIEEENaNCompliantInsts)
200 func->setAttr("cir.amdgpu-ieee", builder.getStringAttr("false"));
201}
202
203/// Handle amdgpu-expand-waitcnt-profiling attribute.
204static void handleAMDGPUExpandWaitcntProfilingAttr(cir::FuncOp func,
205 CIRGenModule &cgm,
206 CIRGenBuilderTy &builder) {
207 if (cgm.getCodeGenOpts().AMDGPUExpandWaitcntProfiling)
208 func->setAttr("cir.amdgpu-expand-waitcnt-profiling",
209 builder.getStringAttr(""));
210}
211
212} // namespace
213
215 cir::FuncOp func,
216 CIRGenModule &cgm) {
217 if (func.isDeclaration())
218 return;
219
220 CIRGenBuilderTy &builder = cgm.getBuilder();
221
222 const auto *fd = dyn_cast_or_null<FunctionDecl>(decl);
223 if (fd) {
224 const bool isOpenCLKernel =
225 cgm.getLangOpts().OpenCL && fd->hasAttr<DeviceKernelAttr>();
226 const bool isHIPKernel =
227 cgm.getLangOpts().HIP && fd->hasAttr<CUDAGlobalAttr>();
228
229 handleAMDGPUFlatWorkGroupSizeAttr(fd, func, cgm, builder, isOpenCLKernel,
230 isHIPKernel);
231 handleAMDGPUWavesPerEUAttr(fd, func, cgm, builder);
232 handleAMDGPUNumSGPRAttr(fd, func, cgm, builder);
233 handleAMDGPUNumVGPRAttr(fd, func, cgm, builder);
234 handleAMDGPUMaxNumWorkGroupsAttr(fd, func, cgm, builder);
235 handleAMDGPUClusterDimsAttr(fd, func, cgm, builder, isOpenCLKernel);
236 }
237 handleAMDGPUIEEEAttr(func, cgm, builder);
238 handleAMDGPUExpandWaitcntProfilingAttr(func, cgm, builder);
239}
__DEVICE__ int min(int __a, int __b)
__DEVICE__ int max(int __a, int __b)
const TargetInfo & getTargetInfo() const
Definition ASTContext.h:975
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:581
bool hasAttr() const
Definition DeclBase.h:585
This represents one expression.
Definition Expr.h:113
Represents a function declaration or definition.
Definition Decl.h:2059
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:214
@ 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',...