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