clang 20.0.0git
SemaAMDGPU.cpp
Go to the documentation of this file.
1//===------ SemaAMDGPU.cpp ------- AMDGPU target-specific routines --------===//
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 implements semantic analysis functions specific to AMDGPU.
10//
11//===----------------------------------------------------------------------===//
12
17#include "clang/Sema/Sema.h"
18#include "llvm/Support/AtomicOrdering.h"
19#include <cstdint>
20
21namespace clang {
22
24
26 CallExpr *TheCall) {
27 // position of memory order and scope arguments in the builtin
28 unsigned OrderIndex, ScopeIndex;
29
30 const auto *FD = SemaRef.getCurFunctionDecl();
31 assert(FD && "AMDGPU builtins should not be used outside of a function");
32 llvm::StringMap<bool> CallerFeatureMap;
33 getASTContext().getFunctionFeatureMap(CallerFeatureMap, FD);
34 bool HasGFX950Insts =
35 Builtin::evaluateRequiredTargetFeatures("gfx950-insts", CallerFeatureMap);
36
37 switch (BuiltinID) {
38 case AMDGPU::BI__builtin_amdgcn_global_load_lds: {
39 constexpr const int SizeIdx = 2;
40 llvm::APSInt Size;
41 Expr *ArgExpr = TheCall->getArg(SizeIdx);
42 [[maybe_unused]] ExprResult R =
44 assert(!R.isInvalid());
45 switch (Size.getSExtValue()) {
46 case 1:
47 case 2:
48 case 4:
49 return false;
50 case 12:
51 case 16: {
52 if (HasGFX950Insts)
53 return false;
54 [[fallthrough]];
55 }
56 default:
57 Diag(ArgExpr->getExprLoc(),
58 diag::err_amdgcn_global_load_lds_size_invalid_value)
59 << ArgExpr->getSourceRange();
60 Diag(ArgExpr->getExprLoc(),
61 diag::note_amdgcn_global_load_lds_size_valid_value)
62 << HasGFX950Insts << ArgExpr->getSourceRange();
63 return true;
64 }
65 }
66 case AMDGPU::BI__builtin_amdgcn_get_fpenv:
67 case AMDGPU::BI__builtin_amdgcn_set_fpenv:
68 return false;
69 case AMDGPU::BI__builtin_amdgcn_atomic_inc32:
70 case AMDGPU::BI__builtin_amdgcn_atomic_inc64:
71 case AMDGPU::BI__builtin_amdgcn_atomic_dec32:
72 case AMDGPU::BI__builtin_amdgcn_atomic_dec64:
73 OrderIndex = 2;
74 ScopeIndex = 3;
75 break;
76 case AMDGPU::BI__builtin_amdgcn_fence:
77 OrderIndex = 0;
78 ScopeIndex = 1;
79 break;
80 case AMDGPU::BI__builtin_amdgcn_mov_dpp:
81 return checkMovDPPFunctionCall(TheCall, 5, 1);
82 case AMDGPU::BI__builtin_amdgcn_mov_dpp8:
83 return checkMovDPPFunctionCall(TheCall, 2, 1);
84 case AMDGPU::BI__builtin_amdgcn_update_dpp: {
85 return checkMovDPPFunctionCall(TheCall, 6, 2);
86 }
87 default:
88 return false;
89 }
90
91 ExprResult Arg = TheCall->getArg(OrderIndex);
92 auto ArgExpr = Arg.get();
93 Expr::EvalResult ArgResult;
94
95 if (!ArgExpr->EvaluateAsInt(ArgResult, getASTContext()))
96 return Diag(ArgExpr->getExprLoc(), diag::err_typecheck_expect_int)
97 << ArgExpr->getType();
98 auto Ord = ArgResult.Val.getInt().getZExtValue();
99
100 // Check validity of memory ordering as per C11 / C++11's memody model.
101 // Only fence needs check. Atomic dec/inc allow all memory orders.
102 if (!llvm::isValidAtomicOrderingCABI(Ord))
103 return Diag(ArgExpr->getBeginLoc(),
104 diag::warn_atomic_op_has_invalid_memory_order)
105 << 0 << ArgExpr->getSourceRange();
106 switch (static_cast<llvm::AtomicOrderingCABI>(Ord)) {
107 case llvm::AtomicOrderingCABI::relaxed:
108 case llvm::AtomicOrderingCABI::consume:
109 if (BuiltinID == AMDGPU::BI__builtin_amdgcn_fence)
110 return Diag(ArgExpr->getBeginLoc(),
111 diag::warn_atomic_op_has_invalid_memory_order)
112 << 0 << ArgExpr->getSourceRange();
113 break;
114 case llvm::AtomicOrderingCABI::acquire:
115 case llvm::AtomicOrderingCABI::release:
116 case llvm::AtomicOrderingCABI::acq_rel:
117 case llvm::AtomicOrderingCABI::seq_cst:
118 break;
119 }
120
121 Arg = TheCall->getArg(ScopeIndex);
122 ArgExpr = Arg.get();
123 Expr::EvalResult ArgResult1;
124 // Check that sync scope is a constant literal
125 if (!ArgExpr->EvaluateAsConstantExpr(ArgResult1, getASTContext()))
126 return Diag(ArgExpr->getExprLoc(), diag::err_expr_not_string_literal)
127 << ArgExpr->getType();
128
129 return false;
130}
131
132bool SemaAMDGPU::checkMovDPPFunctionCall(CallExpr *TheCall, unsigned NumArgs,
133 unsigned NumDataArgs) {
134 assert(NumDataArgs <= 2);
135 if (SemaRef.checkArgCountRange(TheCall, NumArgs, NumArgs))
136 return true;
137 Expr *Args[2];
138 QualType ArgTys[2];
139 for (unsigned I = 0; I != NumDataArgs; ++I) {
140 Args[I] = TheCall->getArg(I);
141 ArgTys[I] = Args[I]->getType();
142 // TODO: Vectors can also be supported.
143 if (!ArgTys[I]->isArithmeticType() || ArgTys[I]->isAnyComplexType()) {
144 SemaRef.Diag(Args[I]->getBeginLoc(),
145 diag::err_typecheck_cond_expect_int_float)
146 << ArgTys[I] << Args[I]->getSourceRange();
147 return true;
148 }
149 }
150 if (NumDataArgs < 2)
151 return false;
152
153 if (getASTContext().hasSameUnqualifiedType(ArgTys[0], ArgTys[1]))
154 return false;
155
156 if (((ArgTys[0]->isUnsignedIntegerType() &&
157 ArgTys[1]->isSignedIntegerType()) ||
158 (ArgTys[0]->isSignedIntegerType() &&
159 ArgTys[1]->isUnsignedIntegerType())) &&
160 getASTContext().getTypeSize(ArgTys[0]) ==
161 getASTContext().getTypeSize(ArgTys[1]))
162 return false;
163
164 SemaRef.Diag(Args[1]->getBeginLoc(),
165 diag::err_typecheck_call_different_arg_types)
166 << ArgTys[0] << ArgTys[1];
167 return true;
168}
169
170static bool
172 const AMDGPUFlatWorkGroupSizeAttr &Attr) {
173 // Accept template arguments for now as they depend on something else.
174 // We'll get to check them when they eventually get instantiated.
175 if (MinExpr->isValueDependent() || MaxExpr->isValueDependent())
176 return false;
177
178 uint32_t Min = 0;
179 if (!S.checkUInt32Argument(Attr, MinExpr, Min, 0))
180 return true;
181
182 uint32_t Max = 0;
183 if (!S.checkUInt32Argument(Attr, MaxExpr, Max, 1))
184 return true;
185
186 if (Min == 0 && Max != 0) {
187 S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid)
188 << &Attr << 0;
189 return true;
190 }
191 if (Min > Max) {
192 S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid)
193 << &Attr << 1;
194 return true;
195 }
196
197 return false;
198}
199
200AMDGPUFlatWorkGroupSizeAttr *
202 Expr *MinExpr, Expr *MaxExpr) {
203 ASTContext &Context = getASTContext();
204 AMDGPUFlatWorkGroupSizeAttr TmpAttr(Context, CI, MinExpr, MaxExpr);
205
206 if (checkAMDGPUFlatWorkGroupSizeArguments(SemaRef, MinExpr, MaxExpr, TmpAttr))
207 return nullptr;
208 return ::new (Context)
209 AMDGPUFlatWorkGroupSizeAttr(Context, CI, MinExpr, MaxExpr);
210}
211
213 const AttributeCommonInfo &CI,
214 Expr *MinExpr, Expr *MaxExpr) {
215 if (auto *Attr = CreateAMDGPUFlatWorkGroupSizeAttr(CI, MinExpr, MaxExpr))
216 D->addAttr(Attr);
217}
218
220 const ParsedAttr &AL) {
221 Expr *MinExpr = AL.getArgAsExpr(0);
222 Expr *MaxExpr = AL.getArgAsExpr(1);
223
224 addAMDGPUFlatWorkGroupSizeAttr(D, AL, MinExpr, MaxExpr);
225}
226
227static bool checkAMDGPUWavesPerEUArguments(Sema &S, Expr *MinExpr,
228 Expr *MaxExpr,
229 const AMDGPUWavesPerEUAttr &Attr) {
230 if (S.DiagnoseUnexpandedParameterPack(MinExpr) ||
231 (MaxExpr && S.DiagnoseUnexpandedParameterPack(MaxExpr)))
232 return true;
233
234 // Accept template arguments for now as they depend on something else.
235 // We'll get to check them when they eventually get instantiated.
236 if (MinExpr->isValueDependent() || (MaxExpr && MaxExpr->isValueDependent()))
237 return false;
238
239 uint32_t Min = 0;
240 if (!S.checkUInt32Argument(Attr, MinExpr, Min, 0))
241 return true;
242
243 uint32_t Max = 0;
244 if (MaxExpr && !S.checkUInt32Argument(Attr, MaxExpr, Max, 1))
245 return true;
246
247 if (Min == 0 && Max != 0) {
248 S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid)
249 << &Attr << 0;
250 return true;
251 }
252 if (Max != 0 && Min > Max) {
253 S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid)
254 << &Attr << 1;
255 return true;
256 }
257
258 return false;
259}
260
261AMDGPUWavesPerEUAttr *
263 Expr *MinExpr, Expr *MaxExpr) {
264 ASTContext &Context = getASTContext();
265 AMDGPUWavesPerEUAttr TmpAttr(Context, CI, MinExpr, MaxExpr);
266
267 if (checkAMDGPUWavesPerEUArguments(SemaRef, MinExpr, MaxExpr, TmpAttr))
268 return nullptr;
269
270 return ::new (Context) AMDGPUWavesPerEUAttr(Context, CI, MinExpr, MaxExpr);
271}
272
274 Expr *MinExpr, Expr *MaxExpr) {
275 if (auto *Attr = CreateAMDGPUWavesPerEUAttr(CI, MinExpr, MaxExpr))
276 D->addAttr(Attr);
277}
278
281 return;
282
283 Expr *MinExpr = AL.getArgAsExpr(0);
284 Expr *MaxExpr = (AL.getNumArgs() > 1) ? AL.getArgAsExpr(1) : nullptr;
285
286 addAMDGPUWavesPerEUAttr(D, AL, MinExpr, MaxExpr);
287}
288
290 uint32_t NumSGPR = 0;
291 Expr *NumSGPRExpr = AL.getArgAsExpr(0);
292 if (!SemaRef.checkUInt32Argument(AL, NumSGPRExpr, NumSGPR))
293 return;
294
295 D->addAttr(::new (getASTContext())
296 AMDGPUNumSGPRAttr(getASTContext(), AL, NumSGPR));
297}
298
300 uint32_t NumVGPR = 0;
301 Expr *NumVGPRExpr = AL.getArgAsExpr(0);
302 if (!SemaRef.checkUInt32Argument(AL, NumVGPRExpr, NumVGPR))
303 return;
304
305 D->addAttr(::new (getASTContext())
306 AMDGPUNumVGPRAttr(getASTContext(), AL, NumVGPR));
307}
308
309static bool
311 Expr *ZExpr,
312 const AMDGPUMaxNumWorkGroupsAttr &Attr) {
313 if (S.DiagnoseUnexpandedParameterPack(XExpr) ||
314 (YExpr && S.DiagnoseUnexpandedParameterPack(YExpr)) ||
315 (ZExpr && S.DiagnoseUnexpandedParameterPack(ZExpr)))
316 return true;
317
318 // Accept template arguments for now as they depend on something else.
319 // We'll get to check them when they eventually get instantiated.
320 if (XExpr->isValueDependent() || (YExpr && YExpr->isValueDependent()) ||
321 (ZExpr && ZExpr->isValueDependent()))
322 return false;
323
324 uint32_t NumWG = 0;
325 Expr *Exprs[3] = {XExpr, YExpr, ZExpr};
326 for (int i = 0; i < 3; i++) {
327 if (Exprs[i]) {
328 if (!S.checkUInt32Argument(Attr, Exprs[i], NumWG, i,
329 /*StrictlyUnsigned=*/true))
330 return true;
331 if (NumWG == 0) {
332 S.Diag(Attr.getLoc(), diag::err_attribute_argument_is_zero)
333 << &Attr << Exprs[i]->getSourceRange();
334 return true;
335 }
336 }
337 }
338
339 return false;
340}
341
343 const AttributeCommonInfo &CI, Expr *XExpr, Expr *YExpr, Expr *ZExpr) {
344 ASTContext &Context = getASTContext();
345 AMDGPUMaxNumWorkGroupsAttr TmpAttr(Context, CI, XExpr, YExpr, ZExpr);
346
347 if (checkAMDGPUMaxNumWorkGroupsArguments(SemaRef, XExpr, YExpr, ZExpr,
348 TmpAttr))
349 return nullptr;
350
351 return ::new (Context)
352 AMDGPUMaxNumWorkGroupsAttr(Context, CI, XExpr, YExpr, ZExpr);
353}
354
356 const AttributeCommonInfo &CI,
357 Expr *XExpr, Expr *YExpr,
358 Expr *ZExpr) {
359 if (auto *Attr = CreateAMDGPUMaxNumWorkGroupsAttr(CI, XExpr, YExpr, ZExpr))
360 D->addAttr(Attr);
361}
362
364 const ParsedAttr &AL) {
365 Expr *YExpr = (AL.getNumArgs() > 1) ? AL.getArgAsExpr(1) : nullptr;
366 Expr *ZExpr = (AL.getNumArgs() > 2) ? AL.getArgAsExpr(2) : nullptr;
367 addAMDGPUMaxNumWorkGroupsAttr(D, AL, AL.getArgAsExpr(0), YExpr, ZExpr);
368}
369
370} // namespace clang
const Decl * D
This file declares semantic analysis functions specific to AMDGPU.
Enumerates target-specific builtins in their own namespaces within namespace clang.
APSInt & getInt()
Definition: APValue.h:465
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:188
void getFunctionFeatureMap(llvm::StringMap< bool > &FeatureMap, const FunctionDecl *) const
PtrTy get() const
Definition: Ownership.h:170
bool isInvalid() const
Definition: Ownership.h:166
Attr - This represents one attribute.
Definition: Attr.h:43
SourceLocation getLocation() const
Definition: Attr.h:96
SourceLocation getLoc() const
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition: Expr.h:2874
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition: Expr.h:3068
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
This represents one expression.
Definition: Expr.h:110
bool isValueDependent() const
Determines whether the value of this expression depends on.
Definition: Expr.h:175
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
Definition: Expr.cpp:277
QualType getType() const
Definition: Expr.h:142
ParsedAttr - Represents a syntactic attribute.
Definition: ParsedAttr.h:129
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this attribute.
Definition: ParsedAttr.h:386
Expr * getArgAsExpr(unsigned Arg) const
Definition: ParsedAttr.h:398
bool checkAtLeastNumArgs(class Sema &S, unsigned Num) const
Check if the attribute has at least as many args as Num.
Definition: ParsedAttr.cpp:301
bool checkAtMostNumArgs(class Sema &S, unsigned Num) const
Check if the attribute has at most as many args as Num.
Definition: ParsedAttr.cpp:306
A (possibly-)qualified type.
Definition: Type.h:929
void handleAMDGPUMaxNumWorkGroupsAttr(Decl *D, const ParsedAttr &AL)
Definition: SemaAMDGPU.cpp:363
void addAMDGPUFlatWorkGroupSizeAttr(Decl *D, const AttributeCommonInfo &CI, Expr *Min, Expr *Max)
addAMDGPUFlatWorkGroupSizeAttr - Adds an amdgpu_flat_work_group_size attribute to a particular declar...
Definition: SemaAMDGPU.cpp:212
SemaAMDGPU(Sema &S)
Definition: SemaAMDGPU.cpp:23
void handleAMDGPUFlatWorkGroupSizeAttr(Decl *D, const ParsedAttr &AL)
Definition: SemaAMDGPU.cpp:219
void handleAMDGPUNumSGPRAttr(Decl *D, const ParsedAttr &AL)
Definition: SemaAMDGPU.cpp:289
AMDGPUMaxNumWorkGroupsAttr * CreateAMDGPUMaxNumWorkGroupsAttr(const AttributeCommonInfo &CI, Expr *XExpr, Expr *YExpr, Expr *ZExpr)
Create an AMDGPUMaxNumWorkGroupsAttr attribute.
Definition: SemaAMDGPU.cpp:342
AMDGPUWavesPerEUAttr * CreateAMDGPUWavesPerEUAttr(const AttributeCommonInfo &CI, Expr *Min, Expr *Max)
Create an AMDGPUWavesPerEUAttr attribute.
Definition: SemaAMDGPU.cpp:262
void handleAMDGPUNumVGPRAttr(Decl *D, const ParsedAttr &AL)
Definition: SemaAMDGPU.cpp:299
AMDGPUFlatWorkGroupSizeAttr * CreateAMDGPUFlatWorkGroupSizeAttr(const AttributeCommonInfo &CI, Expr *Min, Expr *Max)
Create an AMDGPUWavesPerEUAttr attribute.
Definition: SemaAMDGPU.cpp:201
bool checkMovDPPFunctionCall(CallExpr *TheCall, unsigned NumArgs, unsigned NumDataArgs)
Definition: SemaAMDGPU.cpp:132
void handleAMDGPUWavesPerEUAttr(Decl *D, const ParsedAttr &AL)
Definition: SemaAMDGPU.cpp:279
bool CheckAMDGCNBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall)
Definition: SemaAMDGPU.cpp:25
void addAMDGPUWavesPerEUAttr(Decl *D, const AttributeCommonInfo &CI, Expr *Min, Expr *Max)
addAMDGPUWavePersEUAttr - Adds an amdgpu_waves_per_eu attribute to a particular declaration.
Definition: SemaAMDGPU.cpp:273
void addAMDGPUMaxNumWorkGroupsAttr(Decl *D, const AttributeCommonInfo &CI, Expr *XExpr, Expr *YExpr, Expr *ZExpr)
addAMDGPUMaxNumWorkGroupsAttr - Adds an amdgpu_max_num_work_groups attribute to a particular declarat...
Definition: SemaAMDGPU.cpp:355
SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID, bool DeferHint=false)
Emit a diagnostic.
Definition: SemaBase.cpp:60
ASTContext & getASTContext() const
Definition: SemaBase.cpp:9
Sema & SemaRef
Definition: SemaBase.h:40
Sema - This implements semantic analysis and AST building for C.
Definition: Sema.h:463
ExprResult VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result, VerifyICEDiagnoser &Diagnoser, AllowFoldKind CanFold=NoFold)
VerifyIntegerConstantExpression - Verifies that an expression is an ICE, and reports the appropriate ...
Definition: SemaExpr.cpp:17145
FunctionDecl * getCurFunctionDecl(bool AllowLambda=false) const
Returns a pointer to the innermost enclosing function, or nullptr if the current context is not insid...
Definition: Sema.cpp:1568
bool DiagnoseUnexpandedParameterPack(SourceLocation Loc, TypeSourceInfo *T, UnexpandedParameterPackContext UPPC)
If the given type contains an unexpanded parameter pack, diagnose the error.
bool checkUInt32Argument(const AttrInfo &AI, const Expr *Expr, uint32_t &Val, unsigned Idx=UINT_MAX, bool StrictlyUnsigned=false)
If Expr is a valid integer constant, get the value of the integer expression and return success or fa...
Definition: Sema.h:4416
bool checkArgCountRange(CallExpr *Call, unsigned MinArgCount, unsigned MaxArgCount)
Checks that a call expression's argument count is in the desired range.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition: Stmt.cpp:333
bool evaluateRequiredTargetFeatures(llvm::StringRef RequiredFatures, const llvm::StringMap< bool > &TargetFetureMap)
Returns true if the required target features of a builtin function are enabled.
The JSON file list parser is used to communicate input to InstallAPI.
static bool checkAMDGPUMaxNumWorkGroupsArguments(Sema &S, Expr *XExpr, Expr *YExpr, Expr *ZExpr, const AMDGPUMaxNumWorkGroupsAttr &Attr)
Definition: SemaAMDGPU.cpp:310
static bool checkAMDGPUFlatWorkGroupSizeArguments(Sema &S, Expr *MinExpr, Expr *MaxExpr, const AMDGPUFlatWorkGroupSizeAttr &Attr)
Definition: SemaAMDGPU.cpp:171
static bool checkAMDGPUWavesPerEUArguments(Sema &S, Expr *MinExpr, Expr *MaxExpr, const AMDGPUWavesPerEUAttr &Attr)
Definition: SemaAMDGPU.cpp:227
EvalResult is a struct with detailed info about an evaluated expression.
Definition: Expr.h:642
APValue Val
Val - This is the value the expression can be folded to.
Definition: Expr.h:644