xref: /llvm-project/clang/lib/Sema/SemaAMDGPU.cpp (revision a2c3e0c4cb08e9cf26f4a745777295e1eb562e1b)
1ed35a92cSVlad Serebrennikov //===------ SemaAMDGPU.cpp ------- AMDGPU target-specific routines --------===//
2ed35a92cSVlad Serebrennikov //
3ed35a92cSVlad Serebrennikov // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4ed35a92cSVlad Serebrennikov // See https://llvm.org/LICENSE.txt for license information.
5ed35a92cSVlad Serebrennikov // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6ed35a92cSVlad Serebrennikov //
7ed35a92cSVlad Serebrennikov //===----------------------------------------------------------------------===//
8ed35a92cSVlad Serebrennikov //
9ed35a92cSVlad Serebrennikov //  This file implements semantic analysis functions specific to AMDGPU.
10ed35a92cSVlad Serebrennikov //
11ed35a92cSVlad Serebrennikov //===----------------------------------------------------------------------===//
12ed35a92cSVlad Serebrennikov 
13ed35a92cSVlad Serebrennikov #include "clang/Sema/SemaAMDGPU.h"
14ed35a92cSVlad Serebrennikov #include "clang/Basic/DiagnosticSema.h"
15ed35a92cSVlad Serebrennikov #include "clang/Basic/TargetBuiltins.h"
16ed35a92cSVlad Serebrennikov #include "clang/Sema/Ownership.h"
17ed35a92cSVlad Serebrennikov #include "clang/Sema/Sema.h"
18ed35a92cSVlad Serebrennikov #include "llvm/Support/AtomicOrdering.h"
19ed35a92cSVlad Serebrennikov #include <cstdint>
20ed35a92cSVlad Serebrennikov 
21ed35a92cSVlad Serebrennikov namespace clang {
22ed35a92cSVlad Serebrennikov 
23ed35a92cSVlad Serebrennikov SemaAMDGPU::SemaAMDGPU(Sema &S) : SemaBase(S) {}
24ed35a92cSVlad Serebrennikov 
25ed35a92cSVlad Serebrennikov bool SemaAMDGPU::CheckAMDGCNBuiltinFunctionCall(unsigned BuiltinID,
26ed35a92cSVlad Serebrennikov                                                 CallExpr *TheCall) {
27ed35a92cSVlad Serebrennikov   // position of memory order and scope arguments in the builtin
28ed35a92cSVlad Serebrennikov   unsigned OrderIndex, ScopeIndex;
29*a2c3e0c4SMatt Arsenault 
30*a2c3e0c4SMatt Arsenault   const auto *FD = SemaRef.getCurFunctionDecl();
31*a2c3e0c4SMatt Arsenault   assert(FD && "AMDGPU builtins should not be used outside of a function");
32*a2c3e0c4SMatt Arsenault   llvm::StringMap<bool> CallerFeatureMap;
33*a2c3e0c4SMatt Arsenault   getASTContext().getFunctionFeatureMap(CallerFeatureMap, FD);
34*a2c3e0c4SMatt Arsenault   bool HasGFX950Insts =
35*a2c3e0c4SMatt Arsenault       Builtin::evaluateRequiredTargetFeatures("gfx950-insts", CallerFeatureMap);
36*a2c3e0c4SMatt Arsenault 
37ed35a92cSVlad Serebrennikov   switch (BuiltinID) {
38ed35a92cSVlad Serebrennikov   case AMDGPU::BI__builtin_amdgcn_global_load_lds: {
39ed35a92cSVlad Serebrennikov     constexpr const int SizeIdx = 2;
40ed35a92cSVlad Serebrennikov     llvm::APSInt Size;
41ed35a92cSVlad Serebrennikov     Expr *ArgExpr = TheCall->getArg(SizeIdx);
4279393124SHaojian Wu     [[maybe_unused]] ExprResult R =
4379393124SHaojian Wu         SemaRef.VerifyIntegerConstantExpression(ArgExpr, &Size);
44170d45c0SShilei Tian     assert(!R.isInvalid());
45ed35a92cSVlad Serebrennikov     switch (Size.getSExtValue()) {
46ed35a92cSVlad Serebrennikov     case 1:
47ed35a92cSVlad Serebrennikov     case 2:
48ed35a92cSVlad Serebrennikov     case 4:
49ed35a92cSVlad Serebrennikov       return false;
50*a2c3e0c4SMatt Arsenault     case 12:
51*a2c3e0c4SMatt Arsenault     case 16: {
52*a2c3e0c4SMatt Arsenault       if (HasGFX950Insts)
53*a2c3e0c4SMatt Arsenault         return false;
54*a2c3e0c4SMatt Arsenault       [[fallthrough]];
55*a2c3e0c4SMatt Arsenault     }
56ed35a92cSVlad Serebrennikov     default:
57ed35a92cSVlad Serebrennikov       Diag(ArgExpr->getExprLoc(),
58ed35a92cSVlad Serebrennikov            diag::err_amdgcn_global_load_lds_size_invalid_value)
59ed35a92cSVlad Serebrennikov           << ArgExpr->getSourceRange();
60ed35a92cSVlad Serebrennikov       Diag(ArgExpr->getExprLoc(),
61ed35a92cSVlad Serebrennikov            diag::note_amdgcn_global_load_lds_size_valid_value)
62*a2c3e0c4SMatt Arsenault           << HasGFX950Insts << ArgExpr->getSourceRange();
63ed35a92cSVlad Serebrennikov       return true;
64ed35a92cSVlad Serebrennikov     }
65ed35a92cSVlad Serebrennikov   }
66ed35a92cSVlad Serebrennikov   case AMDGPU::BI__builtin_amdgcn_get_fpenv:
67ed35a92cSVlad Serebrennikov   case AMDGPU::BI__builtin_amdgcn_set_fpenv:
68ed35a92cSVlad Serebrennikov     return false;
69ed35a92cSVlad Serebrennikov   case AMDGPU::BI__builtin_amdgcn_atomic_inc32:
70ed35a92cSVlad Serebrennikov   case AMDGPU::BI__builtin_amdgcn_atomic_inc64:
71ed35a92cSVlad Serebrennikov   case AMDGPU::BI__builtin_amdgcn_atomic_dec32:
72ed35a92cSVlad Serebrennikov   case AMDGPU::BI__builtin_amdgcn_atomic_dec64:
73ed35a92cSVlad Serebrennikov     OrderIndex = 2;
74ed35a92cSVlad Serebrennikov     ScopeIndex = 3;
75ed35a92cSVlad Serebrennikov     break;
76ed35a92cSVlad Serebrennikov   case AMDGPU::BI__builtin_amdgcn_fence:
77ed35a92cSVlad Serebrennikov     OrderIndex = 0;
78ed35a92cSVlad Serebrennikov     ScopeIndex = 1;
79ed35a92cSVlad Serebrennikov     break;
80ba1a09daSStanislav Mekhanoshin   case AMDGPU::BI__builtin_amdgcn_mov_dpp:
81ba1a09daSStanislav Mekhanoshin     return checkMovDPPFunctionCall(TheCall, 5, 1);
82ba1a09daSStanislav Mekhanoshin   case AMDGPU::BI__builtin_amdgcn_mov_dpp8:
83ba1a09daSStanislav Mekhanoshin     return checkMovDPPFunctionCall(TheCall, 2, 1);
84622e398dSStanislav Mekhanoshin   case AMDGPU::BI__builtin_amdgcn_update_dpp: {
85ba1a09daSStanislav Mekhanoshin     return checkMovDPPFunctionCall(TheCall, 6, 2);
86622e398dSStanislav Mekhanoshin   }
87ed35a92cSVlad Serebrennikov   default:
88ed35a92cSVlad Serebrennikov     return false;
89ed35a92cSVlad Serebrennikov   }
90ed35a92cSVlad Serebrennikov 
91ed35a92cSVlad Serebrennikov   ExprResult Arg = TheCall->getArg(OrderIndex);
92ed35a92cSVlad Serebrennikov   auto ArgExpr = Arg.get();
93ed35a92cSVlad Serebrennikov   Expr::EvalResult ArgResult;
94ed35a92cSVlad Serebrennikov 
95ed35a92cSVlad Serebrennikov   if (!ArgExpr->EvaluateAsInt(ArgResult, getASTContext()))
96ed35a92cSVlad Serebrennikov     return Diag(ArgExpr->getExprLoc(), diag::err_typecheck_expect_int)
97ed35a92cSVlad Serebrennikov            << ArgExpr->getType();
98ed35a92cSVlad Serebrennikov   auto Ord = ArgResult.Val.getInt().getZExtValue();
99ed35a92cSVlad Serebrennikov 
100ed35a92cSVlad Serebrennikov   // Check validity of memory ordering as per C11 / C++11's memody model.
101ed35a92cSVlad Serebrennikov   // Only fence needs check. Atomic dec/inc allow all memory orders.
102ed35a92cSVlad Serebrennikov   if (!llvm::isValidAtomicOrderingCABI(Ord))
103ed35a92cSVlad Serebrennikov     return Diag(ArgExpr->getBeginLoc(),
104ed35a92cSVlad Serebrennikov                 diag::warn_atomic_op_has_invalid_memory_order)
105ed35a92cSVlad Serebrennikov            << 0 << ArgExpr->getSourceRange();
106ed35a92cSVlad Serebrennikov   switch (static_cast<llvm::AtomicOrderingCABI>(Ord)) {
107ed35a92cSVlad Serebrennikov   case llvm::AtomicOrderingCABI::relaxed:
108ed35a92cSVlad Serebrennikov   case llvm::AtomicOrderingCABI::consume:
109ed35a92cSVlad Serebrennikov     if (BuiltinID == AMDGPU::BI__builtin_amdgcn_fence)
110ed35a92cSVlad Serebrennikov       return Diag(ArgExpr->getBeginLoc(),
111ed35a92cSVlad Serebrennikov                   diag::warn_atomic_op_has_invalid_memory_order)
112ed35a92cSVlad Serebrennikov              << 0 << ArgExpr->getSourceRange();
113ed35a92cSVlad Serebrennikov     break;
114ed35a92cSVlad Serebrennikov   case llvm::AtomicOrderingCABI::acquire:
115ed35a92cSVlad Serebrennikov   case llvm::AtomicOrderingCABI::release:
116ed35a92cSVlad Serebrennikov   case llvm::AtomicOrderingCABI::acq_rel:
117ed35a92cSVlad Serebrennikov   case llvm::AtomicOrderingCABI::seq_cst:
118ed35a92cSVlad Serebrennikov     break;
119ed35a92cSVlad Serebrennikov   }
120ed35a92cSVlad Serebrennikov 
121ed35a92cSVlad Serebrennikov   Arg = TheCall->getArg(ScopeIndex);
122ed35a92cSVlad Serebrennikov   ArgExpr = Arg.get();
123ed35a92cSVlad Serebrennikov   Expr::EvalResult ArgResult1;
124ed35a92cSVlad Serebrennikov   // Check that sync scope is a constant literal
125ed35a92cSVlad Serebrennikov   if (!ArgExpr->EvaluateAsConstantExpr(ArgResult1, getASTContext()))
126ed35a92cSVlad Serebrennikov     return Diag(ArgExpr->getExprLoc(), diag::err_expr_not_string_literal)
127ed35a92cSVlad Serebrennikov            << ArgExpr->getType();
128ed35a92cSVlad Serebrennikov 
129ed35a92cSVlad Serebrennikov   return false;
130ed35a92cSVlad Serebrennikov }
131ed35a92cSVlad Serebrennikov 
132ba1a09daSStanislav Mekhanoshin bool SemaAMDGPU::checkMovDPPFunctionCall(CallExpr *TheCall, unsigned NumArgs,
133ba1a09daSStanislav Mekhanoshin                                          unsigned NumDataArgs) {
134ba1a09daSStanislav Mekhanoshin   assert(NumDataArgs <= 2);
135ba1a09daSStanislav Mekhanoshin   if (SemaRef.checkArgCountRange(TheCall, NumArgs, NumArgs))
136ba1a09daSStanislav Mekhanoshin     return true;
137ba1a09daSStanislav Mekhanoshin   Expr *Args[2];
138ba1a09daSStanislav Mekhanoshin   QualType ArgTys[2];
139ba1a09daSStanislav Mekhanoshin   for (unsigned I = 0; I != NumDataArgs; ++I) {
140ba1a09daSStanislav Mekhanoshin     Args[I] = TheCall->getArg(I);
141ba1a09daSStanislav Mekhanoshin     ArgTys[I] = Args[I]->getType();
142ba1a09daSStanislav Mekhanoshin     // TODO: Vectors can also be supported.
143ba1a09daSStanislav Mekhanoshin     if (!ArgTys[I]->isArithmeticType() || ArgTys[I]->isAnyComplexType()) {
144ba1a09daSStanislav Mekhanoshin       SemaRef.Diag(Args[I]->getBeginLoc(),
145ba1a09daSStanislav Mekhanoshin                    diag::err_typecheck_cond_expect_int_float)
146ba1a09daSStanislav Mekhanoshin           << ArgTys[I] << Args[I]->getSourceRange();
147ba1a09daSStanislav Mekhanoshin       return true;
148ba1a09daSStanislav Mekhanoshin     }
149ba1a09daSStanislav Mekhanoshin   }
150ba1a09daSStanislav Mekhanoshin   if (NumDataArgs < 2)
151ba1a09daSStanislav Mekhanoshin     return false;
152ba1a09daSStanislav Mekhanoshin 
153ba1a09daSStanislav Mekhanoshin   if (getASTContext().hasSameUnqualifiedType(ArgTys[0], ArgTys[1]))
154ba1a09daSStanislav Mekhanoshin     return false;
155ba1a09daSStanislav Mekhanoshin 
156ba1a09daSStanislav Mekhanoshin   if (((ArgTys[0]->isUnsignedIntegerType() &&
157ba1a09daSStanislav Mekhanoshin         ArgTys[1]->isSignedIntegerType()) ||
158ba1a09daSStanislav Mekhanoshin        (ArgTys[0]->isSignedIntegerType() &&
159ba1a09daSStanislav Mekhanoshin         ArgTys[1]->isUnsignedIntegerType())) &&
160ba1a09daSStanislav Mekhanoshin       getASTContext().getTypeSize(ArgTys[0]) ==
161ba1a09daSStanislav Mekhanoshin           getASTContext().getTypeSize(ArgTys[1]))
162ba1a09daSStanislav Mekhanoshin     return false;
163ba1a09daSStanislav Mekhanoshin 
164ba1a09daSStanislav Mekhanoshin   SemaRef.Diag(Args[1]->getBeginLoc(),
165ba1a09daSStanislav Mekhanoshin                diag::err_typecheck_call_different_arg_types)
166ba1a09daSStanislav Mekhanoshin       << ArgTys[0] << ArgTys[1];
167ba1a09daSStanislav Mekhanoshin   return true;
168ba1a09daSStanislav Mekhanoshin }
169ba1a09daSStanislav Mekhanoshin 
170ed35a92cSVlad Serebrennikov static bool
171ed35a92cSVlad Serebrennikov checkAMDGPUFlatWorkGroupSizeArguments(Sema &S, Expr *MinExpr, Expr *MaxExpr,
172ed35a92cSVlad Serebrennikov                                       const AMDGPUFlatWorkGroupSizeAttr &Attr) {
173ed35a92cSVlad Serebrennikov   // Accept template arguments for now as they depend on something else.
174ed35a92cSVlad Serebrennikov   // We'll get to check them when they eventually get instantiated.
175ed35a92cSVlad Serebrennikov   if (MinExpr->isValueDependent() || MaxExpr->isValueDependent())
176ed35a92cSVlad Serebrennikov     return false;
177ed35a92cSVlad Serebrennikov 
178ed35a92cSVlad Serebrennikov   uint32_t Min = 0;
179ed35a92cSVlad Serebrennikov   if (!S.checkUInt32Argument(Attr, MinExpr, Min, 0))
180ed35a92cSVlad Serebrennikov     return true;
181ed35a92cSVlad Serebrennikov 
182ed35a92cSVlad Serebrennikov   uint32_t Max = 0;
183ed35a92cSVlad Serebrennikov   if (!S.checkUInt32Argument(Attr, MaxExpr, Max, 1))
184ed35a92cSVlad Serebrennikov     return true;
185ed35a92cSVlad Serebrennikov 
186ed35a92cSVlad Serebrennikov   if (Min == 0 && Max != 0) {
187ed35a92cSVlad Serebrennikov     S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid)
188ed35a92cSVlad Serebrennikov         << &Attr << 0;
189ed35a92cSVlad Serebrennikov     return true;
190ed35a92cSVlad Serebrennikov   }
191ed35a92cSVlad Serebrennikov   if (Min > Max) {
192ed35a92cSVlad Serebrennikov     S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid)
193ed35a92cSVlad Serebrennikov         << &Attr << 1;
194ed35a92cSVlad Serebrennikov     return true;
195ed35a92cSVlad Serebrennikov   }
196ed35a92cSVlad Serebrennikov 
197ed35a92cSVlad Serebrennikov   return false;
198ed35a92cSVlad Serebrennikov }
199ed35a92cSVlad Serebrennikov 
200ed35a92cSVlad Serebrennikov AMDGPUFlatWorkGroupSizeAttr *
201ed35a92cSVlad Serebrennikov SemaAMDGPU::CreateAMDGPUFlatWorkGroupSizeAttr(const AttributeCommonInfo &CI,
202ed35a92cSVlad Serebrennikov                                               Expr *MinExpr, Expr *MaxExpr) {
203ed35a92cSVlad Serebrennikov   ASTContext &Context = getASTContext();
204ed35a92cSVlad Serebrennikov   AMDGPUFlatWorkGroupSizeAttr TmpAttr(Context, CI, MinExpr, MaxExpr);
205ed35a92cSVlad Serebrennikov 
206ed35a92cSVlad Serebrennikov   if (checkAMDGPUFlatWorkGroupSizeArguments(SemaRef, MinExpr, MaxExpr, TmpAttr))
207ed35a92cSVlad Serebrennikov     return nullptr;
208ed35a92cSVlad Serebrennikov   return ::new (Context)
209ed35a92cSVlad Serebrennikov       AMDGPUFlatWorkGroupSizeAttr(Context, CI, MinExpr, MaxExpr);
210ed35a92cSVlad Serebrennikov }
211ed35a92cSVlad Serebrennikov 
212ed35a92cSVlad Serebrennikov void SemaAMDGPU::addAMDGPUFlatWorkGroupSizeAttr(Decl *D,
213ed35a92cSVlad Serebrennikov                                                 const AttributeCommonInfo &CI,
214ed35a92cSVlad Serebrennikov                                                 Expr *MinExpr, Expr *MaxExpr) {
215ed35a92cSVlad Serebrennikov   if (auto *Attr = CreateAMDGPUFlatWorkGroupSizeAttr(CI, MinExpr, MaxExpr))
216ed35a92cSVlad Serebrennikov     D->addAttr(Attr);
217ed35a92cSVlad Serebrennikov }
218ed35a92cSVlad Serebrennikov 
219ed35a92cSVlad Serebrennikov void SemaAMDGPU::handleAMDGPUFlatWorkGroupSizeAttr(Decl *D,
220ed35a92cSVlad Serebrennikov                                                    const ParsedAttr &AL) {
221ed35a92cSVlad Serebrennikov   Expr *MinExpr = AL.getArgAsExpr(0);
222ed35a92cSVlad Serebrennikov   Expr *MaxExpr = AL.getArgAsExpr(1);
223ed35a92cSVlad Serebrennikov 
224ed35a92cSVlad Serebrennikov   addAMDGPUFlatWorkGroupSizeAttr(D, AL, MinExpr, MaxExpr);
225ed35a92cSVlad Serebrennikov }
226ed35a92cSVlad Serebrennikov 
227ed35a92cSVlad Serebrennikov static bool checkAMDGPUWavesPerEUArguments(Sema &S, Expr *MinExpr,
228ed35a92cSVlad Serebrennikov                                            Expr *MaxExpr,
229ed35a92cSVlad Serebrennikov                                            const AMDGPUWavesPerEUAttr &Attr) {
230ed35a92cSVlad Serebrennikov   if (S.DiagnoseUnexpandedParameterPack(MinExpr) ||
231ed35a92cSVlad Serebrennikov       (MaxExpr && S.DiagnoseUnexpandedParameterPack(MaxExpr)))
232ed35a92cSVlad Serebrennikov     return true;
233ed35a92cSVlad Serebrennikov 
234ed35a92cSVlad Serebrennikov   // Accept template arguments for now as they depend on something else.
235ed35a92cSVlad Serebrennikov   // We'll get to check them when they eventually get instantiated.
236ed35a92cSVlad Serebrennikov   if (MinExpr->isValueDependent() || (MaxExpr && MaxExpr->isValueDependent()))
237ed35a92cSVlad Serebrennikov     return false;
238ed35a92cSVlad Serebrennikov 
239ed35a92cSVlad Serebrennikov   uint32_t Min = 0;
240ed35a92cSVlad Serebrennikov   if (!S.checkUInt32Argument(Attr, MinExpr, Min, 0))
241ed35a92cSVlad Serebrennikov     return true;
242ed35a92cSVlad Serebrennikov 
243ed35a92cSVlad Serebrennikov   uint32_t Max = 0;
244ed35a92cSVlad Serebrennikov   if (MaxExpr && !S.checkUInt32Argument(Attr, MaxExpr, Max, 1))
245ed35a92cSVlad Serebrennikov     return true;
246ed35a92cSVlad Serebrennikov 
247ed35a92cSVlad Serebrennikov   if (Min == 0 && Max != 0) {
248ed35a92cSVlad Serebrennikov     S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid)
249ed35a92cSVlad Serebrennikov         << &Attr << 0;
250ed35a92cSVlad Serebrennikov     return true;
251ed35a92cSVlad Serebrennikov   }
252ed35a92cSVlad Serebrennikov   if (Max != 0 && Min > Max) {
253ed35a92cSVlad Serebrennikov     S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid)
254ed35a92cSVlad Serebrennikov         << &Attr << 1;
255ed35a92cSVlad Serebrennikov     return true;
256ed35a92cSVlad Serebrennikov   }
257ed35a92cSVlad Serebrennikov 
258ed35a92cSVlad Serebrennikov   return false;
259ed35a92cSVlad Serebrennikov }
260ed35a92cSVlad Serebrennikov 
261ed35a92cSVlad Serebrennikov AMDGPUWavesPerEUAttr *
262ed35a92cSVlad Serebrennikov SemaAMDGPU::CreateAMDGPUWavesPerEUAttr(const AttributeCommonInfo &CI,
263ed35a92cSVlad Serebrennikov                                        Expr *MinExpr, Expr *MaxExpr) {
264ed35a92cSVlad Serebrennikov   ASTContext &Context = getASTContext();
265ed35a92cSVlad Serebrennikov   AMDGPUWavesPerEUAttr TmpAttr(Context, CI, MinExpr, MaxExpr);
266ed35a92cSVlad Serebrennikov 
267ed35a92cSVlad Serebrennikov   if (checkAMDGPUWavesPerEUArguments(SemaRef, MinExpr, MaxExpr, TmpAttr))
268ed35a92cSVlad Serebrennikov     return nullptr;
269ed35a92cSVlad Serebrennikov 
270ed35a92cSVlad Serebrennikov   return ::new (Context) AMDGPUWavesPerEUAttr(Context, CI, MinExpr, MaxExpr);
271ed35a92cSVlad Serebrennikov }
272ed35a92cSVlad Serebrennikov 
273ed35a92cSVlad Serebrennikov void SemaAMDGPU::addAMDGPUWavesPerEUAttr(Decl *D, const AttributeCommonInfo &CI,
274ed35a92cSVlad Serebrennikov                                          Expr *MinExpr, Expr *MaxExpr) {
275ed35a92cSVlad Serebrennikov   if (auto *Attr = CreateAMDGPUWavesPerEUAttr(CI, MinExpr, MaxExpr))
276ed35a92cSVlad Serebrennikov     D->addAttr(Attr);
277ed35a92cSVlad Serebrennikov }
278ed35a92cSVlad Serebrennikov 
279ed35a92cSVlad Serebrennikov void SemaAMDGPU::handleAMDGPUWavesPerEUAttr(Decl *D, const ParsedAttr &AL) {
280ed35a92cSVlad Serebrennikov   if (!AL.checkAtLeastNumArgs(SemaRef, 1) || !AL.checkAtMostNumArgs(SemaRef, 2))
281ed35a92cSVlad Serebrennikov     return;
282ed35a92cSVlad Serebrennikov 
283ed35a92cSVlad Serebrennikov   Expr *MinExpr = AL.getArgAsExpr(0);
284ed35a92cSVlad Serebrennikov   Expr *MaxExpr = (AL.getNumArgs() > 1) ? AL.getArgAsExpr(1) : nullptr;
285ed35a92cSVlad Serebrennikov 
286ed35a92cSVlad Serebrennikov   addAMDGPUWavesPerEUAttr(D, AL, MinExpr, MaxExpr);
287ed35a92cSVlad Serebrennikov }
288ed35a92cSVlad Serebrennikov 
289ed35a92cSVlad Serebrennikov void SemaAMDGPU::handleAMDGPUNumSGPRAttr(Decl *D, const ParsedAttr &AL) {
290ed35a92cSVlad Serebrennikov   uint32_t NumSGPR = 0;
291ed35a92cSVlad Serebrennikov   Expr *NumSGPRExpr = AL.getArgAsExpr(0);
292ed35a92cSVlad Serebrennikov   if (!SemaRef.checkUInt32Argument(AL, NumSGPRExpr, NumSGPR))
293ed35a92cSVlad Serebrennikov     return;
294ed35a92cSVlad Serebrennikov 
295ed35a92cSVlad Serebrennikov   D->addAttr(::new (getASTContext())
296ed35a92cSVlad Serebrennikov                  AMDGPUNumSGPRAttr(getASTContext(), AL, NumSGPR));
297ed35a92cSVlad Serebrennikov }
298ed35a92cSVlad Serebrennikov 
299ed35a92cSVlad Serebrennikov void SemaAMDGPU::handleAMDGPUNumVGPRAttr(Decl *D, const ParsedAttr &AL) {
300ed35a92cSVlad Serebrennikov   uint32_t NumVGPR = 0;
301ed35a92cSVlad Serebrennikov   Expr *NumVGPRExpr = AL.getArgAsExpr(0);
302ed35a92cSVlad Serebrennikov   if (!SemaRef.checkUInt32Argument(AL, NumVGPRExpr, NumVGPR))
303ed35a92cSVlad Serebrennikov     return;
304ed35a92cSVlad Serebrennikov 
305ed35a92cSVlad Serebrennikov   D->addAttr(::new (getASTContext())
306ed35a92cSVlad Serebrennikov                  AMDGPUNumVGPRAttr(getASTContext(), AL, NumVGPR));
307ed35a92cSVlad Serebrennikov }
308ed35a92cSVlad Serebrennikov 
309ed35a92cSVlad Serebrennikov static bool
310ed35a92cSVlad Serebrennikov checkAMDGPUMaxNumWorkGroupsArguments(Sema &S, Expr *XExpr, Expr *YExpr,
311ed35a92cSVlad Serebrennikov                                      Expr *ZExpr,
312ed35a92cSVlad Serebrennikov                                      const AMDGPUMaxNumWorkGroupsAttr &Attr) {
313ed35a92cSVlad Serebrennikov   if (S.DiagnoseUnexpandedParameterPack(XExpr) ||
314ed35a92cSVlad Serebrennikov       (YExpr && S.DiagnoseUnexpandedParameterPack(YExpr)) ||
315ed35a92cSVlad Serebrennikov       (ZExpr && S.DiagnoseUnexpandedParameterPack(ZExpr)))
316ed35a92cSVlad Serebrennikov     return true;
317ed35a92cSVlad Serebrennikov 
318ed35a92cSVlad Serebrennikov   // Accept template arguments for now as they depend on something else.
319ed35a92cSVlad Serebrennikov   // We'll get to check them when they eventually get instantiated.
320ed35a92cSVlad Serebrennikov   if (XExpr->isValueDependent() || (YExpr && YExpr->isValueDependent()) ||
321ed35a92cSVlad Serebrennikov       (ZExpr && ZExpr->isValueDependent()))
322ed35a92cSVlad Serebrennikov     return false;
323ed35a92cSVlad Serebrennikov 
324ed35a92cSVlad Serebrennikov   uint32_t NumWG = 0;
325ed35a92cSVlad Serebrennikov   Expr *Exprs[3] = {XExpr, YExpr, ZExpr};
326ed35a92cSVlad Serebrennikov   for (int i = 0; i < 3; i++) {
327ed35a92cSVlad Serebrennikov     if (Exprs[i]) {
328ed35a92cSVlad Serebrennikov       if (!S.checkUInt32Argument(Attr, Exprs[i], NumWG, i,
329ed35a92cSVlad Serebrennikov                                  /*StrictlyUnsigned=*/true))
330ed35a92cSVlad Serebrennikov         return true;
331ed35a92cSVlad Serebrennikov       if (NumWG == 0) {
332ed35a92cSVlad Serebrennikov         S.Diag(Attr.getLoc(), diag::err_attribute_argument_is_zero)
333ed35a92cSVlad Serebrennikov             << &Attr << Exprs[i]->getSourceRange();
334ed35a92cSVlad Serebrennikov         return true;
335ed35a92cSVlad Serebrennikov       }
336ed35a92cSVlad Serebrennikov     }
337ed35a92cSVlad Serebrennikov   }
338ed35a92cSVlad Serebrennikov 
339ed35a92cSVlad Serebrennikov   return false;
340ed35a92cSVlad Serebrennikov }
341ed35a92cSVlad Serebrennikov 
342ed35a92cSVlad Serebrennikov AMDGPUMaxNumWorkGroupsAttr *SemaAMDGPU::CreateAMDGPUMaxNumWorkGroupsAttr(
343ed35a92cSVlad Serebrennikov     const AttributeCommonInfo &CI, Expr *XExpr, Expr *YExpr, Expr *ZExpr) {
344ed35a92cSVlad Serebrennikov   ASTContext &Context = getASTContext();
345ed35a92cSVlad Serebrennikov   AMDGPUMaxNumWorkGroupsAttr TmpAttr(Context, CI, XExpr, YExpr, ZExpr);
346ed35a92cSVlad Serebrennikov 
347ed35a92cSVlad Serebrennikov   if (checkAMDGPUMaxNumWorkGroupsArguments(SemaRef, XExpr, YExpr, ZExpr,
348ed35a92cSVlad Serebrennikov                                            TmpAttr))
349ed35a92cSVlad Serebrennikov     return nullptr;
350ed35a92cSVlad Serebrennikov 
351ed35a92cSVlad Serebrennikov   return ::new (Context)
352ed35a92cSVlad Serebrennikov       AMDGPUMaxNumWorkGroupsAttr(Context, CI, XExpr, YExpr, ZExpr);
353ed35a92cSVlad Serebrennikov }
354ed35a92cSVlad Serebrennikov 
355ed35a92cSVlad Serebrennikov void SemaAMDGPU::addAMDGPUMaxNumWorkGroupsAttr(Decl *D,
356ed35a92cSVlad Serebrennikov                                                const AttributeCommonInfo &CI,
357ed35a92cSVlad Serebrennikov                                                Expr *XExpr, Expr *YExpr,
358ed35a92cSVlad Serebrennikov                                                Expr *ZExpr) {
359ed35a92cSVlad Serebrennikov   if (auto *Attr = CreateAMDGPUMaxNumWorkGroupsAttr(CI, XExpr, YExpr, ZExpr))
360ed35a92cSVlad Serebrennikov     D->addAttr(Attr);
361ed35a92cSVlad Serebrennikov }
362ed35a92cSVlad Serebrennikov 
363ed35a92cSVlad Serebrennikov void SemaAMDGPU::handleAMDGPUMaxNumWorkGroupsAttr(Decl *D,
364ed35a92cSVlad Serebrennikov                                                   const ParsedAttr &AL) {
365ed35a92cSVlad Serebrennikov   Expr *YExpr = (AL.getNumArgs() > 1) ? AL.getArgAsExpr(1) : nullptr;
366ed35a92cSVlad Serebrennikov   Expr *ZExpr = (AL.getNumArgs() > 2) ? AL.getArgAsExpr(2) : nullptr;
367ed35a92cSVlad Serebrennikov   addAMDGPUMaxNumWorkGroupsAttr(D, AL, AL.getArgAsExpr(0), YExpr, ZExpr);
368ed35a92cSVlad Serebrennikov }
369ed35a92cSVlad Serebrennikov 
370ed35a92cSVlad Serebrennikov } // namespace clang
371