1 //===------ SemaAMDGPU.cpp ------- AMDGPU target-specific routines --------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file implements semantic analysis functions specific to AMDGPU.
11 //===----------------------------------------------------------------------===//
13 #include "clang/Sema/SemaAMDGPU.h"
14 #include "clang/Basic/DiagnosticSema.h"
15 #include "clang/Basic/TargetBuiltins.h"
16 #include "clang/Sema/Ownership.h"
17 #include "clang/Sema/Sema.h"
18 #include "llvm/Support/AtomicOrdering.h"
23 SemaAMDGPU::SemaAMDGPU(Sema
&S
) : SemaBase(S
) {}
25 bool SemaAMDGPU::CheckAMDGCNBuiltinFunctionCall(unsigned BuiltinID
,
27 // position of memory order and scope arguments in the builtin
28 unsigned OrderIndex
, ScopeIndex
;
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
);
35 Builtin::evaluateRequiredTargetFeatures("gfx950-insts", CallerFeatureMap
);
38 case AMDGPU::BI__builtin_amdgcn_global_load_lds
: {
39 constexpr const int SizeIdx
= 2;
41 Expr
*ArgExpr
= TheCall
->getArg(SizeIdx
);
42 [[maybe_unused
]] ExprResult R
=
43 SemaRef
.VerifyIntegerConstantExpression(ArgExpr
, &Size
);
44 assert(!R
.isInvalid());
45 switch (Size
.getSExtValue()) {
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();
66 case AMDGPU::BI__builtin_amdgcn_get_fpenv
:
67 case AMDGPU::BI__builtin_amdgcn_set_fpenv
:
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
:
76 case AMDGPU::BI__builtin_amdgcn_fence
:
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);
91 ExprResult Arg
= TheCall
->getArg(OrderIndex
);
92 auto ArgExpr
= Arg
.get();
93 Expr::EvalResult ArgResult
;
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();
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();
114 case llvm::AtomicOrderingCABI::acquire
:
115 case llvm::AtomicOrderingCABI::release
:
116 case llvm::AtomicOrderingCABI::acq_rel
:
117 case llvm::AtomicOrderingCABI::seq_cst
:
121 Arg
= TheCall
->getArg(ScopeIndex
);
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();
132 bool SemaAMDGPU::checkMovDPPFunctionCall(CallExpr
*TheCall
, unsigned NumArgs
,
133 unsigned NumDataArgs
) {
134 assert(NumDataArgs
<= 2);
135 if (SemaRef
.checkArgCountRange(TheCall
, NumArgs
, NumArgs
))
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();
153 if (getASTContext().hasSameUnqualifiedType(ArgTys
[0], ArgTys
[1]))
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]))
164 SemaRef
.Diag(Args
[1]->getBeginLoc(),
165 diag::err_typecheck_call_different_arg_types
)
166 << ArgTys
[0] << ArgTys
[1];
171 checkAMDGPUFlatWorkGroupSizeArguments(Sema
&S
, Expr
*MinExpr
, Expr
*MaxExpr
,
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())
179 if (!S
.checkUInt32Argument(Attr
, MinExpr
, Min
, 0))
183 if (!S
.checkUInt32Argument(Attr
, MaxExpr
, Max
, 1))
186 if (Min
== 0 && Max
!= 0) {
187 S
.Diag(Attr
.getLocation(), diag::err_attribute_argument_invalid
)
192 S
.Diag(Attr
.getLocation(), diag::err_attribute_argument_invalid
)
200 AMDGPUFlatWorkGroupSizeAttr
*
201 SemaAMDGPU::CreateAMDGPUFlatWorkGroupSizeAttr(const AttributeCommonInfo
&CI
,
202 Expr
*MinExpr
, Expr
*MaxExpr
) {
203 ASTContext
&Context
= getASTContext();
204 AMDGPUFlatWorkGroupSizeAttr
TmpAttr(Context
, CI
, MinExpr
, MaxExpr
);
206 if (checkAMDGPUFlatWorkGroupSizeArguments(SemaRef
, MinExpr
, MaxExpr
, TmpAttr
))
208 return ::new (Context
)
209 AMDGPUFlatWorkGroupSizeAttr(Context
, CI
, MinExpr
, MaxExpr
);
212 void SemaAMDGPU::addAMDGPUFlatWorkGroupSizeAttr(Decl
*D
,
213 const AttributeCommonInfo
&CI
,
214 Expr
*MinExpr
, Expr
*MaxExpr
) {
215 if (auto *Attr
= CreateAMDGPUFlatWorkGroupSizeAttr(CI
, MinExpr
, MaxExpr
))
219 void SemaAMDGPU::handleAMDGPUFlatWorkGroupSizeAttr(Decl
*D
,
220 const ParsedAttr
&AL
) {
221 Expr
*MinExpr
= AL
.getArgAsExpr(0);
222 Expr
*MaxExpr
= AL
.getArgAsExpr(1);
224 addAMDGPUFlatWorkGroupSizeAttr(D
, AL
, MinExpr
, MaxExpr
);
227 static bool checkAMDGPUWavesPerEUArguments(Sema
&S
, Expr
*MinExpr
,
229 const AMDGPUWavesPerEUAttr
&Attr
) {
230 if (S
.DiagnoseUnexpandedParameterPack(MinExpr
) ||
231 (MaxExpr
&& S
.DiagnoseUnexpandedParameterPack(MaxExpr
)))
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()))
240 if (!S
.checkUInt32Argument(Attr
, MinExpr
, Min
, 0))
244 if (MaxExpr
&& !S
.checkUInt32Argument(Attr
, MaxExpr
, Max
, 1))
247 if (Min
== 0 && Max
!= 0) {
248 S
.Diag(Attr
.getLocation(), diag::err_attribute_argument_invalid
)
252 if (Max
!= 0 && Min
> Max
) {
253 S
.Diag(Attr
.getLocation(), diag::err_attribute_argument_invalid
)
261 AMDGPUWavesPerEUAttr
*
262 SemaAMDGPU::CreateAMDGPUWavesPerEUAttr(const AttributeCommonInfo
&CI
,
263 Expr
*MinExpr
, Expr
*MaxExpr
) {
264 ASTContext
&Context
= getASTContext();
265 AMDGPUWavesPerEUAttr
TmpAttr(Context
, CI
, MinExpr
, MaxExpr
);
267 if (checkAMDGPUWavesPerEUArguments(SemaRef
, MinExpr
, MaxExpr
, TmpAttr
))
270 return ::new (Context
) AMDGPUWavesPerEUAttr(Context
, CI
, MinExpr
, MaxExpr
);
273 void SemaAMDGPU::addAMDGPUWavesPerEUAttr(Decl
*D
, const AttributeCommonInfo
&CI
,
274 Expr
*MinExpr
, Expr
*MaxExpr
) {
275 if (auto *Attr
= CreateAMDGPUWavesPerEUAttr(CI
, MinExpr
, MaxExpr
))
279 void SemaAMDGPU::handleAMDGPUWavesPerEUAttr(Decl
*D
, const ParsedAttr
&AL
) {
280 if (!AL
.checkAtLeastNumArgs(SemaRef
, 1) || !AL
.checkAtMostNumArgs(SemaRef
, 2))
283 Expr
*MinExpr
= AL
.getArgAsExpr(0);
284 Expr
*MaxExpr
= (AL
.getNumArgs() > 1) ? AL
.getArgAsExpr(1) : nullptr;
286 addAMDGPUWavesPerEUAttr(D
, AL
, MinExpr
, MaxExpr
);
289 void SemaAMDGPU::handleAMDGPUNumSGPRAttr(Decl
*D
, const ParsedAttr
&AL
) {
290 uint32_t NumSGPR
= 0;
291 Expr
*NumSGPRExpr
= AL
.getArgAsExpr(0);
292 if (!SemaRef
.checkUInt32Argument(AL
, NumSGPRExpr
, NumSGPR
))
295 D
->addAttr(::new (getASTContext())
296 AMDGPUNumSGPRAttr(getASTContext(), AL
, NumSGPR
));
299 void SemaAMDGPU::handleAMDGPUNumVGPRAttr(Decl
*D
, const ParsedAttr
&AL
) {
300 uint32_t NumVGPR
= 0;
301 Expr
*NumVGPRExpr
= AL
.getArgAsExpr(0);
302 if (!SemaRef
.checkUInt32Argument(AL
, NumVGPRExpr
, NumVGPR
))
305 D
->addAttr(::new (getASTContext())
306 AMDGPUNumVGPRAttr(getASTContext(), AL
, NumVGPR
));
310 checkAMDGPUMaxNumWorkGroupsArguments(Sema
&S
, Expr
*XExpr
, Expr
*YExpr
,
312 const AMDGPUMaxNumWorkGroupsAttr
&Attr
) {
313 if (S
.DiagnoseUnexpandedParameterPack(XExpr
) ||
314 (YExpr
&& S
.DiagnoseUnexpandedParameterPack(YExpr
)) ||
315 (ZExpr
&& S
.DiagnoseUnexpandedParameterPack(ZExpr
)))
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()))
325 Expr
*Exprs
[3] = {XExpr
, YExpr
, ZExpr
};
326 for (int i
= 0; i
< 3; i
++) {
328 if (!S
.checkUInt32Argument(Attr
, Exprs
[i
], NumWG
, i
,
329 /*StrictlyUnsigned=*/true))
332 S
.Diag(Attr
.getLoc(), diag::err_attribute_argument_is_zero
)
333 << &Attr
<< Exprs
[i
]->getSourceRange();
342 AMDGPUMaxNumWorkGroupsAttr
*SemaAMDGPU::CreateAMDGPUMaxNumWorkGroupsAttr(
343 const AttributeCommonInfo
&CI
, Expr
*XExpr
, Expr
*YExpr
, Expr
*ZExpr
) {
344 ASTContext
&Context
= getASTContext();
345 AMDGPUMaxNumWorkGroupsAttr
TmpAttr(Context
, CI
, XExpr
, YExpr
, ZExpr
);
347 if (checkAMDGPUMaxNumWorkGroupsArguments(SemaRef
, XExpr
, YExpr
, ZExpr
,
351 return ::new (Context
)
352 AMDGPUMaxNumWorkGroupsAttr(Context
, CI
, XExpr
, YExpr
, ZExpr
);
355 void SemaAMDGPU::addAMDGPUMaxNumWorkGroupsAttr(Decl
*D
,
356 const AttributeCommonInfo
&CI
,
357 Expr
*XExpr
, Expr
*YExpr
,
359 if (auto *Attr
= CreateAMDGPUMaxNumWorkGroupsAttr(CI
, XExpr
, YExpr
, ZExpr
))
363 void SemaAMDGPU::handleAMDGPUMaxNumWorkGroupsAttr(Decl
*D
,
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
);