xref: /freebsd-src/contrib/llvm-project/clang/lib/Sema/SemaARM.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1*0fca6ea1SDimitry Andric //===------ SemaARM.cpp ---------- ARM 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 ARM.
10*0fca6ea1SDimitry Andric //
11*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
12*0fca6ea1SDimitry Andric 
13*0fca6ea1SDimitry Andric #include "clang/Sema/SemaARM.h"
14*0fca6ea1SDimitry Andric #include "clang/Basic/DiagnosticSema.h"
15*0fca6ea1SDimitry Andric #include "clang/Basic/TargetBuiltins.h"
16*0fca6ea1SDimitry Andric #include "clang/Sema/Initialization.h"
17*0fca6ea1SDimitry Andric #include "clang/Sema/ParsedAttr.h"
18*0fca6ea1SDimitry Andric #include "clang/Sema/Sema.h"
19*0fca6ea1SDimitry Andric 
20*0fca6ea1SDimitry Andric namespace clang {
21*0fca6ea1SDimitry Andric 
22*0fca6ea1SDimitry Andric SemaARM::SemaARM(Sema &S) : SemaBase(S) {}
23*0fca6ea1SDimitry Andric 
24*0fca6ea1SDimitry Andric /// BuiltinARMMemoryTaggingCall - Handle calls of memory tagging extensions
25*0fca6ea1SDimitry Andric bool SemaARM::BuiltinARMMemoryTaggingCall(unsigned BuiltinID,
26*0fca6ea1SDimitry Andric                                           CallExpr *TheCall) {
27*0fca6ea1SDimitry Andric   ASTContext &Context = getASTContext();
28*0fca6ea1SDimitry Andric 
29*0fca6ea1SDimitry Andric   if (BuiltinID == AArch64::BI__builtin_arm_irg) {
30*0fca6ea1SDimitry Andric     if (SemaRef.checkArgCount(TheCall, 2))
31*0fca6ea1SDimitry Andric       return true;
32*0fca6ea1SDimitry Andric     Expr *Arg0 = TheCall->getArg(0);
33*0fca6ea1SDimitry Andric     Expr *Arg1 = TheCall->getArg(1);
34*0fca6ea1SDimitry Andric 
35*0fca6ea1SDimitry Andric     ExprResult FirstArg = SemaRef.DefaultFunctionArrayLvalueConversion(Arg0);
36*0fca6ea1SDimitry Andric     if (FirstArg.isInvalid())
37*0fca6ea1SDimitry Andric       return true;
38*0fca6ea1SDimitry Andric     QualType FirstArgType = FirstArg.get()->getType();
39*0fca6ea1SDimitry Andric     if (!FirstArgType->isAnyPointerType())
40*0fca6ea1SDimitry Andric       return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer)
41*0fca6ea1SDimitry Andric              << "first" << FirstArgType << Arg0->getSourceRange();
42*0fca6ea1SDimitry Andric     TheCall->setArg(0, FirstArg.get());
43*0fca6ea1SDimitry Andric 
44*0fca6ea1SDimitry Andric     ExprResult SecArg = SemaRef.DefaultLvalueConversion(Arg1);
45*0fca6ea1SDimitry Andric     if (SecArg.isInvalid())
46*0fca6ea1SDimitry Andric       return true;
47*0fca6ea1SDimitry Andric     QualType SecArgType = SecArg.get()->getType();
48*0fca6ea1SDimitry Andric     if (!SecArgType->isIntegerType())
49*0fca6ea1SDimitry Andric       return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_integer)
50*0fca6ea1SDimitry Andric              << "second" << SecArgType << Arg1->getSourceRange();
51*0fca6ea1SDimitry Andric 
52*0fca6ea1SDimitry Andric     // Derive the return type from the pointer argument.
53*0fca6ea1SDimitry Andric     TheCall->setType(FirstArgType);
54*0fca6ea1SDimitry Andric     return false;
55*0fca6ea1SDimitry Andric   }
56*0fca6ea1SDimitry Andric 
57*0fca6ea1SDimitry Andric   if (BuiltinID == AArch64::BI__builtin_arm_addg) {
58*0fca6ea1SDimitry Andric     if (SemaRef.checkArgCount(TheCall, 2))
59*0fca6ea1SDimitry Andric       return true;
60*0fca6ea1SDimitry Andric 
61*0fca6ea1SDimitry Andric     Expr *Arg0 = TheCall->getArg(0);
62*0fca6ea1SDimitry Andric     ExprResult FirstArg = SemaRef.DefaultFunctionArrayLvalueConversion(Arg0);
63*0fca6ea1SDimitry Andric     if (FirstArg.isInvalid())
64*0fca6ea1SDimitry Andric       return true;
65*0fca6ea1SDimitry Andric     QualType FirstArgType = FirstArg.get()->getType();
66*0fca6ea1SDimitry Andric     if (!FirstArgType->isAnyPointerType())
67*0fca6ea1SDimitry Andric       return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer)
68*0fca6ea1SDimitry Andric              << "first" << FirstArgType << Arg0->getSourceRange();
69*0fca6ea1SDimitry Andric     TheCall->setArg(0, FirstArg.get());
70*0fca6ea1SDimitry Andric 
71*0fca6ea1SDimitry Andric     // Derive the return type from the pointer argument.
72*0fca6ea1SDimitry Andric     TheCall->setType(FirstArgType);
73*0fca6ea1SDimitry Andric 
74*0fca6ea1SDimitry Andric     // Second arg must be an constant in range [0,15]
75*0fca6ea1SDimitry Andric     return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 15);
76*0fca6ea1SDimitry Andric   }
77*0fca6ea1SDimitry Andric 
78*0fca6ea1SDimitry Andric   if (BuiltinID == AArch64::BI__builtin_arm_gmi) {
79*0fca6ea1SDimitry Andric     if (SemaRef.checkArgCount(TheCall, 2))
80*0fca6ea1SDimitry Andric       return true;
81*0fca6ea1SDimitry Andric     Expr *Arg0 = TheCall->getArg(0);
82*0fca6ea1SDimitry Andric     Expr *Arg1 = TheCall->getArg(1);
83*0fca6ea1SDimitry Andric 
84*0fca6ea1SDimitry Andric     ExprResult FirstArg = SemaRef.DefaultFunctionArrayLvalueConversion(Arg0);
85*0fca6ea1SDimitry Andric     if (FirstArg.isInvalid())
86*0fca6ea1SDimitry Andric       return true;
87*0fca6ea1SDimitry Andric     QualType FirstArgType = FirstArg.get()->getType();
88*0fca6ea1SDimitry Andric     if (!FirstArgType->isAnyPointerType())
89*0fca6ea1SDimitry Andric       return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer)
90*0fca6ea1SDimitry Andric              << "first" << FirstArgType << Arg0->getSourceRange();
91*0fca6ea1SDimitry Andric 
92*0fca6ea1SDimitry Andric     QualType SecArgType = Arg1->getType();
93*0fca6ea1SDimitry Andric     if (!SecArgType->isIntegerType())
94*0fca6ea1SDimitry Andric       return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_integer)
95*0fca6ea1SDimitry Andric              << "second" << SecArgType << Arg1->getSourceRange();
96*0fca6ea1SDimitry Andric     TheCall->setType(Context.IntTy);
97*0fca6ea1SDimitry Andric     return false;
98*0fca6ea1SDimitry Andric   }
99*0fca6ea1SDimitry Andric 
100*0fca6ea1SDimitry Andric   if (BuiltinID == AArch64::BI__builtin_arm_ldg ||
101*0fca6ea1SDimitry Andric       BuiltinID == AArch64::BI__builtin_arm_stg) {
102*0fca6ea1SDimitry Andric     if (SemaRef.checkArgCount(TheCall, 1))
103*0fca6ea1SDimitry Andric       return true;
104*0fca6ea1SDimitry Andric     Expr *Arg0 = TheCall->getArg(0);
105*0fca6ea1SDimitry Andric     ExprResult FirstArg = SemaRef.DefaultFunctionArrayLvalueConversion(Arg0);
106*0fca6ea1SDimitry Andric     if (FirstArg.isInvalid())
107*0fca6ea1SDimitry Andric       return true;
108*0fca6ea1SDimitry Andric 
109*0fca6ea1SDimitry Andric     QualType FirstArgType = FirstArg.get()->getType();
110*0fca6ea1SDimitry Andric     if (!FirstArgType->isAnyPointerType())
111*0fca6ea1SDimitry Andric       return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer)
112*0fca6ea1SDimitry Andric              << "first" << FirstArgType << Arg0->getSourceRange();
113*0fca6ea1SDimitry Andric     TheCall->setArg(0, FirstArg.get());
114*0fca6ea1SDimitry Andric 
115*0fca6ea1SDimitry Andric     // Derive the return type from the pointer argument.
116*0fca6ea1SDimitry Andric     if (BuiltinID == AArch64::BI__builtin_arm_ldg)
117*0fca6ea1SDimitry Andric       TheCall->setType(FirstArgType);
118*0fca6ea1SDimitry Andric     return false;
119*0fca6ea1SDimitry Andric   }
120*0fca6ea1SDimitry Andric 
121*0fca6ea1SDimitry Andric   if (BuiltinID == AArch64::BI__builtin_arm_subp) {
122*0fca6ea1SDimitry Andric     Expr *ArgA = TheCall->getArg(0);
123*0fca6ea1SDimitry Andric     Expr *ArgB = TheCall->getArg(1);
124*0fca6ea1SDimitry Andric 
125*0fca6ea1SDimitry Andric     ExprResult ArgExprA = SemaRef.DefaultFunctionArrayLvalueConversion(ArgA);
126*0fca6ea1SDimitry Andric     ExprResult ArgExprB = SemaRef.DefaultFunctionArrayLvalueConversion(ArgB);
127*0fca6ea1SDimitry Andric 
128*0fca6ea1SDimitry Andric     if (ArgExprA.isInvalid() || ArgExprB.isInvalid())
129*0fca6ea1SDimitry Andric       return true;
130*0fca6ea1SDimitry Andric 
131*0fca6ea1SDimitry Andric     QualType ArgTypeA = ArgExprA.get()->getType();
132*0fca6ea1SDimitry Andric     QualType ArgTypeB = ArgExprB.get()->getType();
133*0fca6ea1SDimitry Andric 
134*0fca6ea1SDimitry Andric     auto isNull = [&](Expr *E) -> bool {
135*0fca6ea1SDimitry Andric       return E->isNullPointerConstant(Context,
136*0fca6ea1SDimitry Andric                                       Expr::NPC_ValueDependentIsNotNull);
137*0fca6ea1SDimitry Andric     };
138*0fca6ea1SDimitry Andric 
139*0fca6ea1SDimitry Andric     // argument should be either a pointer or null
140*0fca6ea1SDimitry Andric     if (!ArgTypeA->isAnyPointerType() && !isNull(ArgA))
141*0fca6ea1SDimitry Andric       return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_null_or_pointer)
142*0fca6ea1SDimitry Andric              << "first" << ArgTypeA << ArgA->getSourceRange();
143*0fca6ea1SDimitry Andric 
144*0fca6ea1SDimitry Andric     if (!ArgTypeB->isAnyPointerType() && !isNull(ArgB))
145*0fca6ea1SDimitry Andric       return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_null_or_pointer)
146*0fca6ea1SDimitry Andric              << "second" << ArgTypeB << ArgB->getSourceRange();
147*0fca6ea1SDimitry Andric 
148*0fca6ea1SDimitry Andric     // Ensure Pointee types are compatible
149*0fca6ea1SDimitry Andric     if (ArgTypeA->isAnyPointerType() && !isNull(ArgA) &&
150*0fca6ea1SDimitry Andric         ArgTypeB->isAnyPointerType() && !isNull(ArgB)) {
151*0fca6ea1SDimitry Andric       QualType pointeeA = ArgTypeA->getPointeeType();
152*0fca6ea1SDimitry Andric       QualType pointeeB = ArgTypeB->getPointeeType();
153*0fca6ea1SDimitry Andric       if (!Context.typesAreCompatible(
154*0fca6ea1SDimitry Andric               Context.getCanonicalType(pointeeA).getUnqualifiedType(),
155*0fca6ea1SDimitry Andric               Context.getCanonicalType(pointeeB).getUnqualifiedType())) {
156*0fca6ea1SDimitry Andric         return Diag(TheCall->getBeginLoc(),
157*0fca6ea1SDimitry Andric                     diag::err_typecheck_sub_ptr_compatible)
158*0fca6ea1SDimitry Andric                << ArgTypeA << ArgTypeB << ArgA->getSourceRange()
159*0fca6ea1SDimitry Andric                << ArgB->getSourceRange();
160*0fca6ea1SDimitry Andric       }
161*0fca6ea1SDimitry Andric     }
162*0fca6ea1SDimitry Andric 
163*0fca6ea1SDimitry Andric     // at least one argument should be pointer type
164*0fca6ea1SDimitry Andric     if (!ArgTypeA->isAnyPointerType() && !ArgTypeB->isAnyPointerType())
165*0fca6ea1SDimitry Andric       return Diag(TheCall->getBeginLoc(), diag::err_memtag_any2arg_pointer)
166*0fca6ea1SDimitry Andric              << ArgTypeA << ArgTypeB << ArgA->getSourceRange();
167*0fca6ea1SDimitry Andric 
168*0fca6ea1SDimitry Andric     if (isNull(ArgA)) // adopt type of the other pointer
169*0fca6ea1SDimitry Andric       ArgExprA =
170*0fca6ea1SDimitry Andric           SemaRef.ImpCastExprToType(ArgExprA.get(), ArgTypeB, CK_NullToPointer);
171*0fca6ea1SDimitry Andric 
172*0fca6ea1SDimitry Andric     if (isNull(ArgB))
173*0fca6ea1SDimitry Andric       ArgExprB =
174*0fca6ea1SDimitry Andric           SemaRef.ImpCastExprToType(ArgExprB.get(), ArgTypeA, CK_NullToPointer);
175*0fca6ea1SDimitry Andric 
176*0fca6ea1SDimitry Andric     TheCall->setArg(0, ArgExprA.get());
177*0fca6ea1SDimitry Andric     TheCall->setArg(1, ArgExprB.get());
178*0fca6ea1SDimitry Andric     TheCall->setType(Context.LongLongTy);
179*0fca6ea1SDimitry Andric     return false;
180*0fca6ea1SDimitry Andric   }
181*0fca6ea1SDimitry Andric   assert(false && "Unhandled ARM MTE intrinsic");
182*0fca6ea1SDimitry Andric   return true;
183*0fca6ea1SDimitry Andric }
184*0fca6ea1SDimitry Andric 
185*0fca6ea1SDimitry Andric /// BuiltinARMSpecialReg - Handle a check if argument ArgNum of CallExpr
186*0fca6ea1SDimitry Andric /// TheCall is an ARM/AArch64 special register string literal.
187*0fca6ea1SDimitry Andric bool SemaARM::BuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall,
188*0fca6ea1SDimitry Andric                                    int ArgNum, unsigned ExpectedFieldNum,
189*0fca6ea1SDimitry Andric                                    bool AllowName) {
190*0fca6ea1SDimitry Andric   bool IsARMBuiltin = BuiltinID == ARM::BI__builtin_arm_rsr64 ||
191*0fca6ea1SDimitry Andric                       BuiltinID == ARM::BI__builtin_arm_wsr64 ||
192*0fca6ea1SDimitry Andric                       BuiltinID == ARM::BI__builtin_arm_rsr ||
193*0fca6ea1SDimitry Andric                       BuiltinID == ARM::BI__builtin_arm_rsrp ||
194*0fca6ea1SDimitry Andric                       BuiltinID == ARM::BI__builtin_arm_wsr ||
195*0fca6ea1SDimitry Andric                       BuiltinID == ARM::BI__builtin_arm_wsrp;
196*0fca6ea1SDimitry Andric   bool IsAArch64Builtin = BuiltinID == AArch64::BI__builtin_arm_rsr64 ||
197*0fca6ea1SDimitry Andric                           BuiltinID == AArch64::BI__builtin_arm_wsr64 ||
198*0fca6ea1SDimitry Andric                           BuiltinID == AArch64::BI__builtin_arm_rsr128 ||
199*0fca6ea1SDimitry Andric                           BuiltinID == AArch64::BI__builtin_arm_wsr128 ||
200*0fca6ea1SDimitry Andric                           BuiltinID == AArch64::BI__builtin_arm_rsr ||
201*0fca6ea1SDimitry Andric                           BuiltinID == AArch64::BI__builtin_arm_rsrp ||
202*0fca6ea1SDimitry Andric                           BuiltinID == AArch64::BI__builtin_arm_wsr ||
203*0fca6ea1SDimitry Andric                           BuiltinID == AArch64::BI__builtin_arm_wsrp;
204*0fca6ea1SDimitry Andric   assert((IsARMBuiltin || IsAArch64Builtin) && "Unexpected ARM builtin.");
205*0fca6ea1SDimitry Andric 
206*0fca6ea1SDimitry Andric   // We can't check the value of a dependent argument.
207*0fca6ea1SDimitry Andric   Expr *Arg = TheCall->getArg(ArgNum);
208*0fca6ea1SDimitry Andric   if (Arg->isTypeDependent() || Arg->isValueDependent())
209*0fca6ea1SDimitry Andric     return false;
210*0fca6ea1SDimitry Andric 
211*0fca6ea1SDimitry Andric   // Check if the argument is a string literal.
212*0fca6ea1SDimitry Andric   if (!isa<StringLiteral>(Arg->IgnoreParenImpCasts()))
213*0fca6ea1SDimitry Andric     return Diag(TheCall->getBeginLoc(), diag::err_expr_not_string_literal)
214*0fca6ea1SDimitry Andric            << Arg->getSourceRange();
215*0fca6ea1SDimitry Andric 
216*0fca6ea1SDimitry Andric   // Check the type of special register given.
217*0fca6ea1SDimitry Andric   StringRef Reg = cast<StringLiteral>(Arg->IgnoreParenImpCasts())->getString();
218*0fca6ea1SDimitry Andric   SmallVector<StringRef, 6> Fields;
219*0fca6ea1SDimitry Andric   Reg.split(Fields, ":");
220*0fca6ea1SDimitry Andric 
221*0fca6ea1SDimitry Andric   if (Fields.size() != ExpectedFieldNum && !(AllowName && Fields.size() == 1))
222*0fca6ea1SDimitry Andric     return Diag(TheCall->getBeginLoc(), diag::err_arm_invalid_specialreg)
223*0fca6ea1SDimitry Andric            << Arg->getSourceRange();
224*0fca6ea1SDimitry Andric 
225*0fca6ea1SDimitry Andric   // If the string is the name of a register then we cannot check that it is
226*0fca6ea1SDimitry Andric   // valid here but if the string is of one the forms described in ACLE then we
227*0fca6ea1SDimitry Andric   // can check that the supplied fields are integers and within the valid
228*0fca6ea1SDimitry Andric   // ranges.
229*0fca6ea1SDimitry Andric   if (Fields.size() > 1) {
230*0fca6ea1SDimitry Andric     bool FiveFields = Fields.size() == 5;
231*0fca6ea1SDimitry Andric 
232*0fca6ea1SDimitry Andric     bool ValidString = true;
233*0fca6ea1SDimitry Andric     if (IsARMBuiltin) {
234*0fca6ea1SDimitry Andric       ValidString &= Fields[0].starts_with_insensitive("cp") ||
235*0fca6ea1SDimitry Andric                      Fields[0].starts_with_insensitive("p");
236*0fca6ea1SDimitry Andric       if (ValidString)
237*0fca6ea1SDimitry Andric         Fields[0] = Fields[0].drop_front(
238*0fca6ea1SDimitry Andric             Fields[0].starts_with_insensitive("cp") ? 2 : 1);
239*0fca6ea1SDimitry Andric 
240*0fca6ea1SDimitry Andric       ValidString &= Fields[2].starts_with_insensitive("c");
241*0fca6ea1SDimitry Andric       if (ValidString)
242*0fca6ea1SDimitry Andric         Fields[2] = Fields[2].drop_front(1);
243*0fca6ea1SDimitry Andric 
244*0fca6ea1SDimitry Andric       if (FiveFields) {
245*0fca6ea1SDimitry Andric         ValidString &= Fields[3].starts_with_insensitive("c");
246*0fca6ea1SDimitry Andric         if (ValidString)
247*0fca6ea1SDimitry Andric           Fields[3] = Fields[3].drop_front(1);
248*0fca6ea1SDimitry Andric       }
249*0fca6ea1SDimitry Andric     }
250*0fca6ea1SDimitry Andric 
251*0fca6ea1SDimitry Andric     SmallVector<int, 5> Ranges;
252*0fca6ea1SDimitry Andric     if (FiveFields)
253*0fca6ea1SDimitry Andric       Ranges.append({IsAArch64Builtin ? 1 : 15, 7, 15, 15, 7});
254*0fca6ea1SDimitry Andric     else
255*0fca6ea1SDimitry Andric       Ranges.append({15, 7, 15});
256*0fca6ea1SDimitry Andric 
257*0fca6ea1SDimitry Andric     for (unsigned i = 0; i < Fields.size(); ++i) {
258*0fca6ea1SDimitry Andric       int IntField;
259*0fca6ea1SDimitry Andric       ValidString &= !Fields[i].getAsInteger(10, IntField);
260*0fca6ea1SDimitry Andric       ValidString &= (IntField >= 0 && IntField <= Ranges[i]);
261*0fca6ea1SDimitry Andric     }
262*0fca6ea1SDimitry Andric 
263*0fca6ea1SDimitry Andric     if (!ValidString)
264*0fca6ea1SDimitry Andric       return Diag(TheCall->getBeginLoc(), diag::err_arm_invalid_specialreg)
265*0fca6ea1SDimitry Andric              << Arg->getSourceRange();
266*0fca6ea1SDimitry Andric   } else if (IsAArch64Builtin && Fields.size() == 1) {
267*0fca6ea1SDimitry Andric     // This code validates writes to PSTATE registers.
268*0fca6ea1SDimitry Andric 
269*0fca6ea1SDimitry Andric     // Not a write.
270*0fca6ea1SDimitry Andric     if (TheCall->getNumArgs() != 2)
271*0fca6ea1SDimitry Andric       return false;
272*0fca6ea1SDimitry Andric 
273*0fca6ea1SDimitry Andric     // The 128-bit system register accesses do not touch PSTATE.
274*0fca6ea1SDimitry Andric     if (BuiltinID == AArch64::BI__builtin_arm_rsr128 ||
275*0fca6ea1SDimitry Andric         BuiltinID == AArch64::BI__builtin_arm_wsr128)
276*0fca6ea1SDimitry Andric       return false;
277*0fca6ea1SDimitry Andric 
278*0fca6ea1SDimitry Andric     // These are the named PSTATE accesses using "MSR (immediate)" instructions,
279*0fca6ea1SDimitry Andric     // along with the upper limit on the immediates allowed.
280*0fca6ea1SDimitry Andric     auto MaxLimit = llvm::StringSwitch<std::optional<unsigned>>(Reg)
281*0fca6ea1SDimitry Andric                         .CaseLower("spsel", 15)
282*0fca6ea1SDimitry Andric                         .CaseLower("daifclr", 15)
283*0fca6ea1SDimitry Andric                         .CaseLower("daifset", 15)
284*0fca6ea1SDimitry Andric                         .CaseLower("pan", 15)
285*0fca6ea1SDimitry Andric                         .CaseLower("uao", 15)
286*0fca6ea1SDimitry Andric                         .CaseLower("dit", 15)
287*0fca6ea1SDimitry Andric                         .CaseLower("ssbs", 15)
288*0fca6ea1SDimitry Andric                         .CaseLower("tco", 15)
289*0fca6ea1SDimitry Andric                         .CaseLower("allint", 1)
290*0fca6ea1SDimitry Andric                         .CaseLower("pm", 1)
291*0fca6ea1SDimitry Andric                         .Default(std::nullopt);
292*0fca6ea1SDimitry Andric 
293*0fca6ea1SDimitry Andric     // If this is not a named PSTATE, just continue without validating, as this
294*0fca6ea1SDimitry Andric     // will be lowered to an "MSR (register)" instruction directly
295*0fca6ea1SDimitry Andric     if (!MaxLimit)
296*0fca6ea1SDimitry Andric       return false;
297*0fca6ea1SDimitry Andric 
298*0fca6ea1SDimitry Andric     // Here we only allow constants in the range for that pstate, as required by
299*0fca6ea1SDimitry Andric     // the ACLE.
300*0fca6ea1SDimitry Andric     //
301*0fca6ea1SDimitry Andric     // While clang also accepts the names of system registers in its ACLE
302*0fca6ea1SDimitry Andric     // intrinsics, we prevent this with the PSTATE names used in MSR (immediate)
303*0fca6ea1SDimitry Andric     // as the value written via a register is different to the value used as an
304*0fca6ea1SDimitry Andric     // immediate to have the same effect. e.g., for the instruction `msr tco,
305*0fca6ea1SDimitry Andric     // x0`, it is bit 25 of register x0 that is written into PSTATE.TCO, but
306*0fca6ea1SDimitry Andric     // with `msr tco, #imm`, it is bit 0 of xN that is written into PSTATE.TCO.
307*0fca6ea1SDimitry Andric     //
308*0fca6ea1SDimitry Andric     // If a programmer wants to codegen the MSR (register) form of `msr tco,
309*0fca6ea1SDimitry Andric     // xN`, they can still do so by specifying the register using five
310*0fca6ea1SDimitry Andric     // colon-separated numbers in a string.
311*0fca6ea1SDimitry Andric     return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, *MaxLimit);
312*0fca6ea1SDimitry Andric   }
313*0fca6ea1SDimitry Andric 
314*0fca6ea1SDimitry Andric   return false;
315*0fca6ea1SDimitry Andric }
316*0fca6ea1SDimitry Andric 
317*0fca6ea1SDimitry Andric // Get the valid immediate range for the specified NEON type code.
318*0fca6ea1SDimitry Andric static unsigned RFT(unsigned t, bool shift = false, bool ForceQuad = false) {
319*0fca6ea1SDimitry Andric   NeonTypeFlags Type(t);
320*0fca6ea1SDimitry Andric   int IsQuad = ForceQuad ? true : Type.isQuad();
321*0fca6ea1SDimitry Andric   switch (Type.getEltType()) {
322*0fca6ea1SDimitry Andric   case NeonTypeFlags::Int8:
323*0fca6ea1SDimitry Andric   case NeonTypeFlags::Poly8:
324*0fca6ea1SDimitry Andric     return shift ? 7 : (8 << IsQuad) - 1;
325*0fca6ea1SDimitry Andric   case NeonTypeFlags::Int16:
326*0fca6ea1SDimitry Andric   case NeonTypeFlags::Poly16:
327*0fca6ea1SDimitry Andric     return shift ? 15 : (4 << IsQuad) - 1;
328*0fca6ea1SDimitry Andric   case NeonTypeFlags::Int32:
329*0fca6ea1SDimitry Andric     return shift ? 31 : (2 << IsQuad) - 1;
330*0fca6ea1SDimitry Andric   case NeonTypeFlags::Int64:
331*0fca6ea1SDimitry Andric   case NeonTypeFlags::Poly64:
332*0fca6ea1SDimitry Andric     return shift ? 63 : (1 << IsQuad) - 1;
333*0fca6ea1SDimitry Andric   case NeonTypeFlags::Poly128:
334*0fca6ea1SDimitry Andric     return shift ? 127 : (1 << IsQuad) - 1;
335*0fca6ea1SDimitry Andric   case NeonTypeFlags::Float16:
336*0fca6ea1SDimitry Andric     assert(!shift && "cannot shift float types!");
337*0fca6ea1SDimitry Andric     return (4 << IsQuad) - 1;
338*0fca6ea1SDimitry Andric   case NeonTypeFlags::Float32:
339*0fca6ea1SDimitry Andric     assert(!shift && "cannot shift float types!");
340*0fca6ea1SDimitry Andric     return (2 << IsQuad) - 1;
341*0fca6ea1SDimitry Andric   case NeonTypeFlags::Float64:
342*0fca6ea1SDimitry Andric     assert(!shift && "cannot shift float types!");
343*0fca6ea1SDimitry Andric     return (1 << IsQuad) - 1;
344*0fca6ea1SDimitry Andric   case NeonTypeFlags::BFloat16:
345*0fca6ea1SDimitry Andric     assert(!shift && "cannot shift float types!");
346*0fca6ea1SDimitry Andric     return (4 << IsQuad) - 1;
347*0fca6ea1SDimitry Andric   }
348*0fca6ea1SDimitry Andric   llvm_unreachable("Invalid NeonTypeFlag!");
349*0fca6ea1SDimitry Andric }
350*0fca6ea1SDimitry Andric 
351*0fca6ea1SDimitry Andric /// getNeonEltType - Return the QualType corresponding to the elements of
352*0fca6ea1SDimitry Andric /// the vector type specified by the NeonTypeFlags.  This is used to check
353*0fca6ea1SDimitry Andric /// the pointer arguments for Neon load/store intrinsics.
354*0fca6ea1SDimitry Andric static QualType getNeonEltType(NeonTypeFlags Flags, ASTContext &Context,
355*0fca6ea1SDimitry Andric                                bool IsPolyUnsigned, bool IsInt64Long) {
356*0fca6ea1SDimitry Andric   switch (Flags.getEltType()) {
357*0fca6ea1SDimitry Andric   case NeonTypeFlags::Int8:
358*0fca6ea1SDimitry Andric     return Flags.isUnsigned() ? Context.UnsignedCharTy : Context.SignedCharTy;
359*0fca6ea1SDimitry Andric   case NeonTypeFlags::Int16:
360*0fca6ea1SDimitry Andric     return Flags.isUnsigned() ? Context.UnsignedShortTy : Context.ShortTy;
361*0fca6ea1SDimitry Andric   case NeonTypeFlags::Int32:
362*0fca6ea1SDimitry Andric     return Flags.isUnsigned() ? Context.UnsignedIntTy : Context.IntTy;
363*0fca6ea1SDimitry Andric   case NeonTypeFlags::Int64:
364*0fca6ea1SDimitry Andric     if (IsInt64Long)
365*0fca6ea1SDimitry Andric       return Flags.isUnsigned() ? Context.UnsignedLongTy : Context.LongTy;
366*0fca6ea1SDimitry Andric     else
367*0fca6ea1SDimitry Andric       return Flags.isUnsigned() ? Context.UnsignedLongLongTy
368*0fca6ea1SDimitry Andric                                 : Context.LongLongTy;
369*0fca6ea1SDimitry Andric   case NeonTypeFlags::Poly8:
370*0fca6ea1SDimitry Andric     return IsPolyUnsigned ? Context.UnsignedCharTy : Context.SignedCharTy;
371*0fca6ea1SDimitry Andric   case NeonTypeFlags::Poly16:
372*0fca6ea1SDimitry Andric     return IsPolyUnsigned ? Context.UnsignedShortTy : Context.ShortTy;
373*0fca6ea1SDimitry Andric   case NeonTypeFlags::Poly64:
374*0fca6ea1SDimitry Andric     if (IsInt64Long)
375*0fca6ea1SDimitry Andric       return Context.UnsignedLongTy;
376*0fca6ea1SDimitry Andric     else
377*0fca6ea1SDimitry Andric       return Context.UnsignedLongLongTy;
378*0fca6ea1SDimitry Andric   case NeonTypeFlags::Poly128:
379*0fca6ea1SDimitry Andric     break;
380*0fca6ea1SDimitry Andric   case NeonTypeFlags::Float16:
381*0fca6ea1SDimitry Andric     return Context.HalfTy;
382*0fca6ea1SDimitry Andric   case NeonTypeFlags::Float32:
383*0fca6ea1SDimitry Andric     return Context.FloatTy;
384*0fca6ea1SDimitry Andric   case NeonTypeFlags::Float64:
385*0fca6ea1SDimitry Andric     return Context.DoubleTy;
386*0fca6ea1SDimitry Andric   case NeonTypeFlags::BFloat16:
387*0fca6ea1SDimitry Andric     return Context.BFloat16Ty;
388*0fca6ea1SDimitry Andric   }
389*0fca6ea1SDimitry Andric   llvm_unreachable("Invalid NeonTypeFlag!");
390*0fca6ea1SDimitry Andric }
391*0fca6ea1SDimitry Andric 
392*0fca6ea1SDimitry Andric enum ArmSMEState : unsigned {
393*0fca6ea1SDimitry Andric   ArmNoState = 0,
394*0fca6ea1SDimitry Andric 
395*0fca6ea1SDimitry Andric   ArmInZA = 0b01,
396*0fca6ea1SDimitry Andric   ArmOutZA = 0b10,
397*0fca6ea1SDimitry Andric   ArmInOutZA = 0b11,
398*0fca6ea1SDimitry Andric   ArmZAMask = 0b11,
399*0fca6ea1SDimitry Andric 
400*0fca6ea1SDimitry Andric   ArmInZT0 = 0b01 << 2,
401*0fca6ea1SDimitry Andric   ArmOutZT0 = 0b10 << 2,
402*0fca6ea1SDimitry Andric   ArmInOutZT0 = 0b11 << 2,
403*0fca6ea1SDimitry Andric   ArmZT0Mask = 0b11 << 2
404*0fca6ea1SDimitry Andric };
405*0fca6ea1SDimitry Andric 
406*0fca6ea1SDimitry Andric bool SemaARM::ParseSVEImmChecks(
407*0fca6ea1SDimitry Andric     CallExpr *TheCall, SmallVector<std::tuple<int, int, int>, 3> &ImmChecks) {
408*0fca6ea1SDimitry Andric   // Perform all the immediate checks for this builtin call.
409*0fca6ea1SDimitry Andric   bool HasError = false;
410*0fca6ea1SDimitry Andric   for (auto &I : ImmChecks) {
411*0fca6ea1SDimitry Andric     int ArgNum, CheckTy, ElementSizeInBits;
412*0fca6ea1SDimitry Andric     std::tie(ArgNum, CheckTy, ElementSizeInBits) = I;
413*0fca6ea1SDimitry Andric 
414*0fca6ea1SDimitry Andric     typedef bool (*OptionSetCheckFnTy)(int64_t Value);
415*0fca6ea1SDimitry Andric 
416*0fca6ea1SDimitry Andric     // Function that checks whether the operand (ArgNum) is an immediate
417*0fca6ea1SDimitry Andric     // that is one of the predefined values.
418*0fca6ea1SDimitry Andric     auto CheckImmediateInSet = [&](OptionSetCheckFnTy CheckImm,
419*0fca6ea1SDimitry Andric                                    int ErrDiag) -> bool {
420*0fca6ea1SDimitry Andric       // We can't check the value of a dependent argument.
421*0fca6ea1SDimitry Andric       Expr *Arg = TheCall->getArg(ArgNum);
422*0fca6ea1SDimitry Andric       if (Arg->isTypeDependent() || Arg->isValueDependent())
423*0fca6ea1SDimitry Andric         return false;
424*0fca6ea1SDimitry Andric 
425*0fca6ea1SDimitry Andric       // Check constant-ness first.
426*0fca6ea1SDimitry Andric       llvm::APSInt Imm;
427*0fca6ea1SDimitry Andric       if (SemaRef.BuiltinConstantArg(TheCall, ArgNum, Imm))
428*0fca6ea1SDimitry Andric         return true;
429*0fca6ea1SDimitry Andric 
430*0fca6ea1SDimitry Andric       if (!CheckImm(Imm.getSExtValue()))
431*0fca6ea1SDimitry Andric         return Diag(TheCall->getBeginLoc(), ErrDiag) << Arg->getSourceRange();
432*0fca6ea1SDimitry Andric       return false;
433*0fca6ea1SDimitry Andric     };
434*0fca6ea1SDimitry Andric 
435*0fca6ea1SDimitry Andric     switch ((SVETypeFlags::ImmCheckType)CheckTy) {
436*0fca6ea1SDimitry Andric     case SVETypeFlags::ImmCheck0_31:
437*0fca6ea1SDimitry Andric       if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, 31))
438*0fca6ea1SDimitry Andric         HasError = true;
439*0fca6ea1SDimitry Andric       break;
440*0fca6ea1SDimitry Andric     case SVETypeFlags::ImmCheck0_13:
441*0fca6ea1SDimitry Andric       if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, 13))
442*0fca6ea1SDimitry Andric         HasError = true;
443*0fca6ea1SDimitry Andric       break;
444*0fca6ea1SDimitry Andric     case SVETypeFlags::ImmCheck1_16:
445*0fca6ea1SDimitry Andric       if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 1, 16))
446*0fca6ea1SDimitry Andric         HasError = true;
447*0fca6ea1SDimitry Andric       break;
448*0fca6ea1SDimitry Andric     case SVETypeFlags::ImmCheck0_7:
449*0fca6ea1SDimitry Andric       if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, 7))
450*0fca6ea1SDimitry Andric         HasError = true;
451*0fca6ea1SDimitry Andric       break;
452*0fca6ea1SDimitry Andric     case SVETypeFlags::ImmCheck1_1:
453*0fca6ea1SDimitry Andric       if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 1, 1))
454*0fca6ea1SDimitry Andric         HasError = true;
455*0fca6ea1SDimitry Andric       break;
456*0fca6ea1SDimitry Andric     case SVETypeFlags::ImmCheck1_3:
457*0fca6ea1SDimitry Andric       if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 1, 3))
458*0fca6ea1SDimitry Andric         HasError = true;
459*0fca6ea1SDimitry Andric       break;
460*0fca6ea1SDimitry Andric     case SVETypeFlags::ImmCheck1_7:
461*0fca6ea1SDimitry Andric       if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 1, 7))
462*0fca6ea1SDimitry Andric         HasError = true;
463*0fca6ea1SDimitry Andric       break;
464*0fca6ea1SDimitry Andric     case SVETypeFlags::ImmCheckExtract:
465*0fca6ea1SDimitry Andric       if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0,
466*0fca6ea1SDimitry Andric                                           (2048 / ElementSizeInBits) - 1))
467*0fca6ea1SDimitry Andric         HasError = true;
468*0fca6ea1SDimitry Andric       break;
469*0fca6ea1SDimitry Andric     case SVETypeFlags::ImmCheckShiftRight:
470*0fca6ea1SDimitry Andric       if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 1,
471*0fca6ea1SDimitry Andric                                           ElementSizeInBits))
472*0fca6ea1SDimitry Andric         HasError = true;
473*0fca6ea1SDimitry Andric       break;
474*0fca6ea1SDimitry Andric     case SVETypeFlags::ImmCheckShiftRightNarrow:
475*0fca6ea1SDimitry Andric       if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 1,
476*0fca6ea1SDimitry Andric                                           ElementSizeInBits / 2))
477*0fca6ea1SDimitry Andric         HasError = true;
478*0fca6ea1SDimitry Andric       break;
479*0fca6ea1SDimitry Andric     case SVETypeFlags::ImmCheckShiftLeft:
480*0fca6ea1SDimitry Andric       if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0,
481*0fca6ea1SDimitry Andric                                           ElementSizeInBits - 1))
482*0fca6ea1SDimitry Andric         HasError = true;
483*0fca6ea1SDimitry Andric       break;
484*0fca6ea1SDimitry Andric     case SVETypeFlags::ImmCheckLaneIndex:
485*0fca6ea1SDimitry Andric       if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0,
486*0fca6ea1SDimitry Andric                                           (128 / (1 * ElementSizeInBits)) - 1))
487*0fca6ea1SDimitry Andric         HasError = true;
488*0fca6ea1SDimitry Andric       break;
489*0fca6ea1SDimitry Andric     case SVETypeFlags::ImmCheckLaneIndexCompRotate:
490*0fca6ea1SDimitry Andric       if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0,
491*0fca6ea1SDimitry Andric                                           (128 / (2 * ElementSizeInBits)) - 1))
492*0fca6ea1SDimitry Andric         HasError = true;
493*0fca6ea1SDimitry Andric       break;
494*0fca6ea1SDimitry Andric     case SVETypeFlags::ImmCheckLaneIndexDot:
495*0fca6ea1SDimitry Andric       if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0,
496*0fca6ea1SDimitry Andric                                           (128 / (4 * ElementSizeInBits)) - 1))
497*0fca6ea1SDimitry Andric         HasError = true;
498*0fca6ea1SDimitry Andric       break;
499*0fca6ea1SDimitry Andric     case SVETypeFlags::ImmCheckComplexRot90_270:
500*0fca6ea1SDimitry Andric       if (CheckImmediateInSet([](int64_t V) { return V == 90 || V == 270; },
501*0fca6ea1SDimitry Andric                               diag::err_rotation_argument_to_cadd))
502*0fca6ea1SDimitry Andric         HasError = true;
503*0fca6ea1SDimitry Andric       break;
504*0fca6ea1SDimitry Andric     case SVETypeFlags::ImmCheckComplexRotAll90:
505*0fca6ea1SDimitry Andric       if (CheckImmediateInSet(
506*0fca6ea1SDimitry Andric               [](int64_t V) {
507*0fca6ea1SDimitry Andric                 return V == 0 || V == 90 || V == 180 || V == 270;
508*0fca6ea1SDimitry Andric               },
509*0fca6ea1SDimitry Andric               diag::err_rotation_argument_to_cmla))
510*0fca6ea1SDimitry Andric         HasError = true;
511*0fca6ea1SDimitry Andric       break;
512*0fca6ea1SDimitry Andric     case SVETypeFlags::ImmCheck0_1:
513*0fca6ea1SDimitry Andric       if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, 1))
514*0fca6ea1SDimitry Andric         HasError = true;
515*0fca6ea1SDimitry Andric       break;
516*0fca6ea1SDimitry Andric     case SVETypeFlags::ImmCheck0_2:
517*0fca6ea1SDimitry Andric       if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, 2))
518*0fca6ea1SDimitry Andric         HasError = true;
519*0fca6ea1SDimitry Andric       break;
520*0fca6ea1SDimitry Andric     case SVETypeFlags::ImmCheck0_3:
521*0fca6ea1SDimitry Andric       if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, 3))
522*0fca6ea1SDimitry Andric         HasError = true;
523*0fca6ea1SDimitry Andric       break;
524*0fca6ea1SDimitry Andric     case SVETypeFlags::ImmCheck0_0:
525*0fca6ea1SDimitry Andric       if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, 0))
526*0fca6ea1SDimitry Andric         HasError = true;
527*0fca6ea1SDimitry Andric       break;
528*0fca6ea1SDimitry Andric     case SVETypeFlags::ImmCheck0_15:
529*0fca6ea1SDimitry Andric       if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, 15))
530*0fca6ea1SDimitry Andric         HasError = true;
531*0fca6ea1SDimitry Andric       break;
532*0fca6ea1SDimitry Andric     case SVETypeFlags::ImmCheck0_255:
533*0fca6ea1SDimitry Andric       if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, 255))
534*0fca6ea1SDimitry Andric         HasError = true;
535*0fca6ea1SDimitry Andric       break;
536*0fca6ea1SDimitry Andric     case SVETypeFlags::ImmCheck2_4_Mul2:
537*0fca6ea1SDimitry Andric       if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 2, 4) ||
538*0fca6ea1SDimitry Andric           SemaRef.BuiltinConstantArgMultiple(TheCall, ArgNum, 2))
539*0fca6ea1SDimitry Andric         HasError = true;
540*0fca6ea1SDimitry Andric       break;
541*0fca6ea1SDimitry Andric     }
542*0fca6ea1SDimitry Andric   }
543*0fca6ea1SDimitry Andric 
544*0fca6ea1SDimitry Andric   return HasError;
545*0fca6ea1SDimitry Andric }
546*0fca6ea1SDimitry Andric 
547*0fca6ea1SDimitry Andric SemaARM::ArmStreamingType getArmStreamingFnType(const FunctionDecl *FD) {
548*0fca6ea1SDimitry Andric   if (FD->hasAttr<ArmLocallyStreamingAttr>())
549*0fca6ea1SDimitry Andric     return SemaARM::ArmStreaming;
550*0fca6ea1SDimitry Andric   if (const Type *Ty = FD->getType().getTypePtrOrNull()) {
551*0fca6ea1SDimitry Andric     if (const auto *FPT = Ty->getAs<FunctionProtoType>()) {
552*0fca6ea1SDimitry Andric       if (FPT->getAArch64SMEAttributes() &
553*0fca6ea1SDimitry Andric           FunctionType::SME_PStateSMEnabledMask)
554*0fca6ea1SDimitry Andric         return SemaARM::ArmStreaming;
555*0fca6ea1SDimitry Andric       if (FPT->getAArch64SMEAttributes() &
556*0fca6ea1SDimitry Andric           FunctionType::SME_PStateSMCompatibleMask)
557*0fca6ea1SDimitry Andric         return SemaARM::ArmStreamingCompatible;
558*0fca6ea1SDimitry Andric     }
559*0fca6ea1SDimitry Andric   }
560*0fca6ea1SDimitry Andric   return SemaARM::ArmNonStreaming;
561*0fca6ea1SDimitry Andric }
562*0fca6ea1SDimitry Andric 
563*0fca6ea1SDimitry Andric static bool checkArmStreamingBuiltin(Sema &S, CallExpr *TheCall,
564*0fca6ea1SDimitry Andric                                      const FunctionDecl *FD,
565*0fca6ea1SDimitry Andric                                      SemaARM::ArmStreamingType BuiltinType,
566*0fca6ea1SDimitry Andric                                      unsigned BuiltinID) {
567*0fca6ea1SDimitry Andric   SemaARM::ArmStreamingType FnType = getArmStreamingFnType(FD);
568*0fca6ea1SDimitry Andric 
569*0fca6ea1SDimitry Andric   // Check if the intrinsic is available in the right mode, i.e.
570*0fca6ea1SDimitry Andric   // * When compiling for SME only, the caller must be in streaming mode.
571*0fca6ea1SDimitry Andric   // * When compiling for SVE only, the caller must be in non-streaming mode.
572*0fca6ea1SDimitry Andric   // * When compiling for both SVE and SME, the caller can be in either mode.
573*0fca6ea1SDimitry Andric   if (BuiltinType == SemaARM::VerifyRuntimeMode) {
574*0fca6ea1SDimitry Andric     auto DisableFeatures = [](llvm::StringMap<bool> &Map, StringRef S) {
575*0fca6ea1SDimitry Andric       for (StringRef K : Map.keys())
576*0fca6ea1SDimitry Andric         if (K.starts_with(S))
577*0fca6ea1SDimitry Andric           Map[K] = false;
578*0fca6ea1SDimitry Andric     };
579*0fca6ea1SDimitry Andric 
580*0fca6ea1SDimitry Andric     llvm::StringMap<bool> CallerFeatureMapWithoutSVE;
581*0fca6ea1SDimitry Andric     S.Context.getFunctionFeatureMap(CallerFeatureMapWithoutSVE, FD);
582*0fca6ea1SDimitry Andric     DisableFeatures(CallerFeatureMapWithoutSVE, "sve");
583*0fca6ea1SDimitry Andric 
584*0fca6ea1SDimitry Andric     // Avoid emitting diagnostics for a function that can never compile.
585*0fca6ea1SDimitry Andric     if (FnType == SemaARM::ArmStreaming && !CallerFeatureMapWithoutSVE["sme"])
586*0fca6ea1SDimitry Andric       return false;
587*0fca6ea1SDimitry Andric 
588*0fca6ea1SDimitry Andric     llvm::StringMap<bool> CallerFeatureMapWithoutSME;
589*0fca6ea1SDimitry Andric     S.Context.getFunctionFeatureMap(CallerFeatureMapWithoutSME, FD);
590*0fca6ea1SDimitry Andric     DisableFeatures(CallerFeatureMapWithoutSME, "sme");
591*0fca6ea1SDimitry Andric 
592*0fca6ea1SDimitry Andric     // We know the builtin requires either some combination of SVE flags, or
593*0fca6ea1SDimitry Andric     // some combination of SME flags, but we need to figure out which part
594*0fca6ea1SDimitry Andric     // of the required features is satisfied by the target features.
595*0fca6ea1SDimitry Andric     //
596*0fca6ea1SDimitry Andric     // For a builtin with target guard 'sve2p1|sme2', if we compile with
597*0fca6ea1SDimitry Andric     // '+sve2p1,+sme', then we know that it satisfies the 'sve2p1' part if we
598*0fca6ea1SDimitry Andric     // evaluate the features for '+sve2p1,+sme,+nosme'.
599*0fca6ea1SDimitry Andric     //
600*0fca6ea1SDimitry Andric     // Similarly, if we compile with '+sve2,+sme2', then we know it satisfies
601*0fca6ea1SDimitry Andric     // the 'sme2' part if we evaluate the features for '+sve2,+sme2,+nosve'.
602*0fca6ea1SDimitry Andric     StringRef BuiltinTargetGuards(
603*0fca6ea1SDimitry Andric         S.Context.BuiltinInfo.getRequiredFeatures(BuiltinID));
604*0fca6ea1SDimitry Andric     bool SatisfiesSVE = Builtin::evaluateRequiredTargetFeatures(
605*0fca6ea1SDimitry Andric         BuiltinTargetGuards, CallerFeatureMapWithoutSME);
606*0fca6ea1SDimitry Andric     bool SatisfiesSME = Builtin::evaluateRequiredTargetFeatures(
607*0fca6ea1SDimitry Andric         BuiltinTargetGuards, CallerFeatureMapWithoutSVE);
608*0fca6ea1SDimitry Andric 
609*0fca6ea1SDimitry Andric     if ((SatisfiesSVE && SatisfiesSME) ||
610*0fca6ea1SDimitry Andric         (SatisfiesSVE && FnType == SemaARM::ArmStreamingCompatible))
611*0fca6ea1SDimitry Andric       return false;
612*0fca6ea1SDimitry Andric     else if (SatisfiesSVE)
613*0fca6ea1SDimitry Andric       BuiltinType = SemaARM::ArmNonStreaming;
614*0fca6ea1SDimitry Andric     else if (SatisfiesSME)
615*0fca6ea1SDimitry Andric       BuiltinType = SemaARM::ArmStreaming;
616*0fca6ea1SDimitry Andric     else
617*0fca6ea1SDimitry Andric       // This should be diagnosed by CodeGen
618*0fca6ea1SDimitry Andric       return false;
619*0fca6ea1SDimitry Andric   }
620*0fca6ea1SDimitry Andric 
621*0fca6ea1SDimitry Andric   if (FnType != SemaARM::ArmNonStreaming &&
622*0fca6ea1SDimitry Andric       BuiltinType == SemaARM::ArmNonStreaming)
623*0fca6ea1SDimitry Andric     S.Diag(TheCall->getBeginLoc(), diag::err_attribute_arm_sm_incompat_builtin)
624*0fca6ea1SDimitry Andric         << TheCall->getSourceRange() << "non-streaming";
625*0fca6ea1SDimitry Andric   else if (FnType != SemaARM::ArmStreaming &&
626*0fca6ea1SDimitry Andric            BuiltinType == SemaARM::ArmStreaming)
627*0fca6ea1SDimitry Andric     S.Diag(TheCall->getBeginLoc(), diag::err_attribute_arm_sm_incompat_builtin)
628*0fca6ea1SDimitry Andric         << TheCall->getSourceRange() << "streaming";
629*0fca6ea1SDimitry Andric   else
630*0fca6ea1SDimitry Andric     return false;
631*0fca6ea1SDimitry Andric 
632*0fca6ea1SDimitry Andric   return true;
633*0fca6ea1SDimitry Andric }
634*0fca6ea1SDimitry Andric 
635*0fca6ea1SDimitry Andric static bool hasArmZAState(const FunctionDecl *FD) {
636*0fca6ea1SDimitry Andric   const auto *T = FD->getType()->getAs<FunctionProtoType>();
637*0fca6ea1SDimitry Andric   return (T && FunctionType::getArmZAState(T->getAArch64SMEAttributes()) !=
638*0fca6ea1SDimitry Andric                    FunctionType::ARM_None) ||
639*0fca6ea1SDimitry Andric          (FD->hasAttr<ArmNewAttr>() && FD->getAttr<ArmNewAttr>()->isNewZA());
640*0fca6ea1SDimitry Andric }
641*0fca6ea1SDimitry Andric 
642*0fca6ea1SDimitry Andric static bool hasArmZT0State(const FunctionDecl *FD) {
643*0fca6ea1SDimitry Andric   const auto *T = FD->getType()->getAs<FunctionProtoType>();
644*0fca6ea1SDimitry Andric   return (T && FunctionType::getArmZT0State(T->getAArch64SMEAttributes()) !=
645*0fca6ea1SDimitry Andric                    FunctionType::ARM_None) ||
646*0fca6ea1SDimitry Andric          (FD->hasAttr<ArmNewAttr>() && FD->getAttr<ArmNewAttr>()->isNewZT0());
647*0fca6ea1SDimitry Andric }
648*0fca6ea1SDimitry Andric 
649*0fca6ea1SDimitry Andric static ArmSMEState getSMEState(unsigned BuiltinID) {
650*0fca6ea1SDimitry Andric   switch (BuiltinID) {
651*0fca6ea1SDimitry Andric   default:
652*0fca6ea1SDimitry Andric     return ArmNoState;
653*0fca6ea1SDimitry Andric #define GET_SME_BUILTIN_GET_STATE
654*0fca6ea1SDimitry Andric #include "clang/Basic/arm_sme_builtins_za_state.inc"
655*0fca6ea1SDimitry Andric #undef GET_SME_BUILTIN_GET_STATE
656*0fca6ea1SDimitry Andric   }
657*0fca6ea1SDimitry Andric }
658*0fca6ea1SDimitry Andric 
659*0fca6ea1SDimitry Andric bool SemaARM::CheckSMEBuiltinFunctionCall(unsigned BuiltinID,
660*0fca6ea1SDimitry Andric                                           CallExpr *TheCall) {
661*0fca6ea1SDimitry Andric   if (const FunctionDecl *FD = SemaRef.getCurFunctionDecl()) {
662*0fca6ea1SDimitry Andric     std::optional<ArmStreamingType> BuiltinType;
663*0fca6ea1SDimitry Andric 
664*0fca6ea1SDimitry Andric     switch (BuiltinID) {
665*0fca6ea1SDimitry Andric #define GET_SME_STREAMING_ATTRS
666*0fca6ea1SDimitry Andric #include "clang/Basic/arm_sme_streaming_attrs.inc"
667*0fca6ea1SDimitry Andric #undef GET_SME_STREAMING_ATTRS
668*0fca6ea1SDimitry Andric     }
669*0fca6ea1SDimitry Andric 
670*0fca6ea1SDimitry Andric     if (BuiltinType &&
671*0fca6ea1SDimitry Andric         checkArmStreamingBuiltin(SemaRef, TheCall, FD, *BuiltinType, BuiltinID))
672*0fca6ea1SDimitry Andric       return true;
673*0fca6ea1SDimitry Andric 
674*0fca6ea1SDimitry Andric     if ((getSMEState(BuiltinID) & ArmZAMask) && !hasArmZAState(FD))
675*0fca6ea1SDimitry Andric       Diag(TheCall->getBeginLoc(),
676*0fca6ea1SDimitry Andric            diag::warn_attribute_arm_za_builtin_no_za_state)
677*0fca6ea1SDimitry Andric           << TheCall->getSourceRange();
678*0fca6ea1SDimitry Andric 
679*0fca6ea1SDimitry Andric     if ((getSMEState(BuiltinID) & ArmZT0Mask) && !hasArmZT0State(FD))
680*0fca6ea1SDimitry Andric       Diag(TheCall->getBeginLoc(),
681*0fca6ea1SDimitry Andric            diag::warn_attribute_arm_zt0_builtin_no_zt0_state)
682*0fca6ea1SDimitry Andric           << TheCall->getSourceRange();
683*0fca6ea1SDimitry Andric   }
684*0fca6ea1SDimitry Andric 
685*0fca6ea1SDimitry Andric   // Range check SME intrinsics that take immediate values.
686*0fca6ea1SDimitry Andric   SmallVector<std::tuple<int, int, int>, 3> ImmChecks;
687*0fca6ea1SDimitry Andric 
688*0fca6ea1SDimitry Andric   switch (BuiltinID) {
689*0fca6ea1SDimitry Andric   default:
690*0fca6ea1SDimitry Andric     return false;
691*0fca6ea1SDimitry Andric #define GET_SME_IMMEDIATE_CHECK
692*0fca6ea1SDimitry Andric #include "clang/Basic/arm_sme_sema_rangechecks.inc"
693*0fca6ea1SDimitry Andric #undef GET_SME_IMMEDIATE_CHECK
694*0fca6ea1SDimitry Andric   }
695*0fca6ea1SDimitry Andric 
696*0fca6ea1SDimitry Andric   return ParseSVEImmChecks(TheCall, ImmChecks);
697*0fca6ea1SDimitry Andric }
698*0fca6ea1SDimitry Andric 
699*0fca6ea1SDimitry Andric bool SemaARM::CheckSVEBuiltinFunctionCall(unsigned BuiltinID,
700*0fca6ea1SDimitry Andric                                           CallExpr *TheCall) {
701*0fca6ea1SDimitry Andric   if (const FunctionDecl *FD = SemaRef.getCurFunctionDecl()) {
702*0fca6ea1SDimitry Andric     std::optional<ArmStreamingType> BuiltinType;
703*0fca6ea1SDimitry Andric 
704*0fca6ea1SDimitry Andric     switch (BuiltinID) {
705*0fca6ea1SDimitry Andric #define GET_SVE_STREAMING_ATTRS
706*0fca6ea1SDimitry Andric #include "clang/Basic/arm_sve_streaming_attrs.inc"
707*0fca6ea1SDimitry Andric #undef GET_SVE_STREAMING_ATTRS
708*0fca6ea1SDimitry Andric     }
709*0fca6ea1SDimitry Andric     if (BuiltinType &&
710*0fca6ea1SDimitry Andric         checkArmStreamingBuiltin(SemaRef, TheCall, FD, *BuiltinType, BuiltinID))
711*0fca6ea1SDimitry Andric       return true;
712*0fca6ea1SDimitry Andric   }
713*0fca6ea1SDimitry Andric   // Range check SVE intrinsics that take immediate values.
714*0fca6ea1SDimitry Andric   SmallVector<std::tuple<int, int, int>, 3> ImmChecks;
715*0fca6ea1SDimitry Andric 
716*0fca6ea1SDimitry Andric   switch (BuiltinID) {
717*0fca6ea1SDimitry Andric   default:
718*0fca6ea1SDimitry Andric     return false;
719*0fca6ea1SDimitry Andric #define GET_SVE_IMMEDIATE_CHECK
720*0fca6ea1SDimitry Andric #include "clang/Basic/arm_sve_sema_rangechecks.inc"
721*0fca6ea1SDimitry Andric #undef GET_SVE_IMMEDIATE_CHECK
722*0fca6ea1SDimitry Andric   }
723*0fca6ea1SDimitry Andric 
724*0fca6ea1SDimitry Andric   return ParseSVEImmChecks(TheCall, ImmChecks);
725*0fca6ea1SDimitry Andric }
726*0fca6ea1SDimitry Andric 
727*0fca6ea1SDimitry Andric bool SemaARM::CheckNeonBuiltinFunctionCall(const TargetInfo &TI,
728*0fca6ea1SDimitry Andric                                            unsigned BuiltinID,
729*0fca6ea1SDimitry Andric                                            CallExpr *TheCall) {
730*0fca6ea1SDimitry Andric   if (const FunctionDecl *FD = SemaRef.getCurFunctionDecl()) {
731*0fca6ea1SDimitry Andric 
732*0fca6ea1SDimitry Andric     switch (BuiltinID) {
733*0fca6ea1SDimitry Andric     default:
734*0fca6ea1SDimitry Andric       break;
735*0fca6ea1SDimitry Andric #define GET_NEON_BUILTINS
736*0fca6ea1SDimitry Andric #define TARGET_BUILTIN(id, ...) case NEON::BI##id:
737*0fca6ea1SDimitry Andric #define BUILTIN(id, ...) case NEON::BI##id:
738*0fca6ea1SDimitry Andric #include "clang/Basic/arm_neon.inc"
739*0fca6ea1SDimitry Andric       if (checkArmStreamingBuiltin(SemaRef, TheCall, FD, ArmNonStreaming,
740*0fca6ea1SDimitry Andric                                    BuiltinID))
741*0fca6ea1SDimitry Andric         return true;
742*0fca6ea1SDimitry Andric       break;
743*0fca6ea1SDimitry Andric #undef TARGET_BUILTIN
744*0fca6ea1SDimitry Andric #undef BUILTIN
745*0fca6ea1SDimitry Andric #undef GET_NEON_BUILTINS
746*0fca6ea1SDimitry Andric     }
747*0fca6ea1SDimitry Andric   }
748*0fca6ea1SDimitry Andric 
749*0fca6ea1SDimitry Andric   llvm::APSInt Result;
750*0fca6ea1SDimitry Andric   uint64_t mask = 0;
751*0fca6ea1SDimitry Andric   unsigned TV = 0;
752*0fca6ea1SDimitry Andric   int PtrArgNum = -1;
753*0fca6ea1SDimitry Andric   bool HasConstPtr = false;
754*0fca6ea1SDimitry Andric   switch (BuiltinID) {
755*0fca6ea1SDimitry Andric #define GET_NEON_OVERLOAD_CHECK
756*0fca6ea1SDimitry Andric #include "clang/Basic/arm_fp16.inc"
757*0fca6ea1SDimitry Andric #include "clang/Basic/arm_neon.inc"
758*0fca6ea1SDimitry Andric #undef GET_NEON_OVERLOAD_CHECK
759*0fca6ea1SDimitry Andric   }
760*0fca6ea1SDimitry Andric 
761*0fca6ea1SDimitry Andric   // For NEON intrinsics which are overloaded on vector element type, validate
762*0fca6ea1SDimitry Andric   // the immediate which specifies which variant to emit.
763*0fca6ea1SDimitry Andric   unsigned ImmArg = TheCall->getNumArgs() - 1;
764*0fca6ea1SDimitry Andric   if (mask) {
765*0fca6ea1SDimitry Andric     if (SemaRef.BuiltinConstantArg(TheCall, ImmArg, Result))
766*0fca6ea1SDimitry Andric       return true;
767*0fca6ea1SDimitry Andric 
768*0fca6ea1SDimitry Andric     TV = Result.getLimitedValue(64);
769*0fca6ea1SDimitry Andric     if ((TV > 63) || (mask & (1ULL << TV)) == 0)
770*0fca6ea1SDimitry Andric       return Diag(TheCall->getBeginLoc(), diag::err_invalid_neon_type_code)
771*0fca6ea1SDimitry Andric              << TheCall->getArg(ImmArg)->getSourceRange();
772*0fca6ea1SDimitry Andric   }
773*0fca6ea1SDimitry Andric 
774*0fca6ea1SDimitry Andric   if (PtrArgNum >= 0) {
775*0fca6ea1SDimitry Andric     // Check that pointer arguments have the specified type.
776*0fca6ea1SDimitry Andric     Expr *Arg = TheCall->getArg(PtrArgNum);
777*0fca6ea1SDimitry Andric     if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg))
778*0fca6ea1SDimitry Andric       Arg = ICE->getSubExpr();
779*0fca6ea1SDimitry Andric     ExprResult RHS = SemaRef.DefaultFunctionArrayLvalueConversion(Arg);
780*0fca6ea1SDimitry Andric     QualType RHSTy = RHS.get()->getType();
781*0fca6ea1SDimitry Andric 
782*0fca6ea1SDimitry Andric     llvm::Triple::ArchType Arch = TI.getTriple().getArch();
783*0fca6ea1SDimitry Andric     bool IsPolyUnsigned = Arch == llvm::Triple::aarch64 ||
784*0fca6ea1SDimitry Andric                           Arch == llvm::Triple::aarch64_32 ||
785*0fca6ea1SDimitry Andric                           Arch == llvm::Triple::aarch64_be;
786*0fca6ea1SDimitry Andric     bool IsInt64Long = TI.getInt64Type() == TargetInfo::SignedLong;
787*0fca6ea1SDimitry Andric     QualType EltTy = getNeonEltType(NeonTypeFlags(TV), getASTContext(),
788*0fca6ea1SDimitry Andric                                     IsPolyUnsigned, IsInt64Long);
789*0fca6ea1SDimitry Andric     if (HasConstPtr)
790*0fca6ea1SDimitry Andric       EltTy = EltTy.withConst();
791*0fca6ea1SDimitry Andric     QualType LHSTy = getASTContext().getPointerType(EltTy);
792*0fca6ea1SDimitry Andric     Sema::AssignConvertType ConvTy;
793*0fca6ea1SDimitry Andric     ConvTy = SemaRef.CheckSingleAssignmentConstraints(LHSTy, RHS);
794*0fca6ea1SDimitry Andric     if (RHS.isInvalid())
795*0fca6ea1SDimitry Andric       return true;
796*0fca6ea1SDimitry Andric     if (SemaRef.DiagnoseAssignmentResult(ConvTy, Arg->getBeginLoc(), LHSTy,
797*0fca6ea1SDimitry Andric                                          RHSTy, RHS.get(), Sema::AA_Assigning))
798*0fca6ea1SDimitry Andric       return true;
799*0fca6ea1SDimitry Andric   }
800*0fca6ea1SDimitry Andric 
801*0fca6ea1SDimitry Andric   // For NEON intrinsics which take an immediate value as part of the
802*0fca6ea1SDimitry Andric   // instruction, range check them here.
803*0fca6ea1SDimitry Andric   unsigned i = 0, l = 0, u = 0;
804*0fca6ea1SDimitry Andric   switch (BuiltinID) {
805*0fca6ea1SDimitry Andric   default:
806*0fca6ea1SDimitry Andric     return false;
807*0fca6ea1SDimitry Andric #define GET_NEON_IMMEDIATE_CHECK
808*0fca6ea1SDimitry Andric #include "clang/Basic/arm_fp16.inc"
809*0fca6ea1SDimitry Andric #include "clang/Basic/arm_neon.inc"
810*0fca6ea1SDimitry Andric #undef GET_NEON_IMMEDIATE_CHECK
811*0fca6ea1SDimitry Andric   }
812*0fca6ea1SDimitry Andric 
813*0fca6ea1SDimitry Andric   return SemaRef.BuiltinConstantArgRange(TheCall, i, l, u + l);
814*0fca6ea1SDimitry Andric }
815*0fca6ea1SDimitry Andric 
816*0fca6ea1SDimitry Andric bool SemaARM::CheckMVEBuiltinFunctionCall(unsigned BuiltinID,
817*0fca6ea1SDimitry Andric                                           CallExpr *TheCall) {
818*0fca6ea1SDimitry Andric   switch (BuiltinID) {
819*0fca6ea1SDimitry Andric   default:
820*0fca6ea1SDimitry Andric     return false;
821*0fca6ea1SDimitry Andric #include "clang/Basic/arm_mve_builtin_sema.inc"
822*0fca6ea1SDimitry Andric   }
823*0fca6ea1SDimitry Andric }
824*0fca6ea1SDimitry Andric 
825*0fca6ea1SDimitry Andric bool SemaARM::CheckCDEBuiltinFunctionCall(const TargetInfo &TI,
826*0fca6ea1SDimitry Andric                                           unsigned BuiltinID,
827*0fca6ea1SDimitry Andric                                           CallExpr *TheCall) {
828*0fca6ea1SDimitry Andric   bool Err = false;
829*0fca6ea1SDimitry Andric   switch (BuiltinID) {
830*0fca6ea1SDimitry Andric   default:
831*0fca6ea1SDimitry Andric     return false;
832*0fca6ea1SDimitry Andric #include "clang/Basic/arm_cde_builtin_sema.inc"
833*0fca6ea1SDimitry Andric   }
834*0fca6ea1SDimitry Andric 
835*0fca6ea1SDimitry Andric   if (Err)
836*0fca6ea1SDimitry Andric     return true;
837*0fca6ea1SDimitry Andric 
838*0fca6ea1SDimitry Andric   return CheckARMCoprocessorImmediate(TI, TheCall->getArg(0), /*WantCDE*/ true);
839*0fca6ea1SDimitry Andric }
840*0fca6ea1SDimitry Andric 
841*0fca6ea1SDimitry Andric bool SemaARM::CheckARMCoprocessorImmediate(const TargetInfo &TI,
842*0fca6ea1SDimitry Andric                                            const Expr *CoprocArg,
843*0fca6ea1SDimitry Andric                                            bool WantCDE) {
844*0fca6ea1SDimitry Andric   ASTContext &Context = getASTContext();
845*0fca6ea1SDimitry Andric   if (SemaRef.isConstantEvaluatedContext())
846*0fca6ea1SDimitry Andric     return false;
847*0fca6ea1SDimitry Andric 
848*0fca6ea1SDimitry Andric   // We can't check the value of a dependent argument.
849*0fca6ea1SDimitry Andric   if (CoprocArg->isTypeDependent() || CoprocArg->isValueDependent())
850*0fca6ea1SDimitry Andric     return false;
851*0fca6ea1SDimitry Andric 
852*0fca6ea1SDimitry Andric   llvm::APSInt CoprocNoAP = *CoprocArg->getIntegerConstantExpr(Context);
853*0fca6ea1SDimitry Andric   int64_t CoprocNo = CoprocNoAP.getExtValue();
854*0fca6ea1SDimitry Andric   assert(CoprocNo >= 0 && "Coprocessor immediate must be non-negative");
855*0fca6ea1SDimitry Andric 
856*0fca6ea1SDimitry Andric   uint32_t CDECoprocMask = TI.getARMCDECoprocMask();
857*0fca6ea1SDimitry Andric   bool IsCDECoproc = CoprocNo <= 7 && (CDECoprocMask & (1 << CoprocNo));
858*0fca6ea1SDimitry Andric 
859*0fca6ea1SDimitry Andric   if (IsCDECoproc != WantCDE)
860*0fca6ea1SDimitry Andric     return Diag(CoprocArg->getBeginLoc(), diag::err_arm_invalid_coproc)
861*0fca6ea1SDimitry Andric            << (int)CoprocNo << (int)WantCDE << CoprocArg->getSourceRange();
862*0fca6ea1SDimitry Andric 
863*0fca6ea1SDimitry Andric   return false;
864*0fca6ea1SDimitry Andric }
865*0fca6ea1SDimitry Andric 
866*0fca6ea1SDimitry Andric bool SemaARM::CheckARMBuiltinExclusiveCall(unsigned BuiltinID,
867*0fca6ea1SDimitry Andric                                            CallExpr *TheCall,
868*0fca6ea1SDimitry Andric                                            unsigned MaxWidth) {
869*0fca6ea1SDimitry Andric   assert((BuiltinID == ARM::BI__builtin_arm_ldrex ||
870*0fca6ea1SDimitry Andric           BuiltinID == ARM::BI__builtin_arm_ldaex ||
871*0fca6ea1SDimitry Andric           BuiltinID == ARM::BI__builtin_arm_strex ||
872*0fca6ea1SDimitry Andric           BuiltinID == ARM::BI__builtin_arm_stlex ||
873*0fca6ea1SDimitry Andric           BuiltinID == AArch64::BI__builtin_arm_ldrex ||
874*0fca6ea1SDimitry Andric           BuiltinID == AArch64::BI__builtin_arm_ldaex ||
875*0fca6ea1SDimitry Andric           BuiltinID == AArch64::BI__builtin_arm_strex ||
876*0fca6ea1SDimitry Andric           BuiltinID == AArch64::BI__builtin_arm_stlex) &&
877*0fca6ea1SDimitry Andric          "unexpected ARM builtin");
878*0fca6ea1SDimitry Andric   bool IsLdrex = BuiltinID == ARM::BI__builtin_arm_ldrex ||
879*0fca6ea1SDimitry Andric                  BuiltinID == ARM::BI__builtin_arm_ldaex ||
880*0fca6ea1SDimitry Andric                  BuiltinID == AArch64::BI__builtin_arm_ldrex ||
881*0fca6ea1SDimitry Andric                  BuiltinID == AArch64::BI__builtin_arm_ldaex;
882*0fca6ea1SDimitry Andric 
883*0fca6ea1SDimitry Andric   ASTContext &Context = getASTContext();
884*0fca6ea1SDimitry Andric   DeclRefExpr *DRE =
885*0fca6ea1SDimitry Andric       cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts());
886*0fca6ea1SDimitry Andric 
887*0fca6ea1SDimitry Andric   // Ensure that we have the proper number of arguments.
888*0fca6ea1SDimitry Andric   if (SemaRef.checkArgCount(TheCall, IsLdrex ? 1 : 2))
889*0fca6ea1SDimitry Andric     return true;
890*0fca6ea1SDimitry Andric 
891*0fca6ea1SDimitry Andric   // Inspect the pointer argument of the atomic builtin.  This should always be
892*0fca6ea1SDimitry Andric   // a pointer type, whose element is an integral scalar or pointer type.
893*0fca6ea1SDimitry Andric   // Because it is a pointer type, we don't have to worry about any implicit
894*0fca6ea1SDimitry Andric   // casts here.
895*0fca6ea1SDimitry Andric   Expr *PointerArg = TheCall->getArg(IsLdrex ? 0 : 1);
896*0fca6ea1SDimitry Andric   ExprResult PointerArgRes =
897*0fca6ea1SDimitry Andric       SemaRef.DefaultFunctionArrayLvalueConversion(PointerArg);
898*0fca6ea1SDimitry Andric   if (PointerArgRes.isInvalid())
899*0fca6ea1SDimitry Andric     return true;
900*0fca6ea1SDimitry Andric   PointerArg = PointerArgRes.get();
901*0fca6ea1SDimitry Andric 
902*0fca6ea1SDimitry Andric   const PointerType *pointerType = PointerArg->getType()->getAs<PointerType>();
903*0fca6ea1SDimitry Andric   if (!pointerType) {
904*0fca6ea1SDimitry Andric     Diag(DRE->getBeginLoc(), diag::err_atomic_builtin_must_be_pointer)
905*0fca6ea1SDimitry Andric         << PointerArg->getType() << 0 << PointerArg->getSourceRange();
906*0fca6ea1SDimitry Andric     return true;
907*0fca6ea1SDimitry Andric   }
908*0fca6ea1SDimitry Andric 
909*0fca6ea1SDimitry Andric   // ldrex takes a "const volatile T*" and strex takes a "volatile T*". Our next
910*0fca6ea1SDimitry Andric   // task is to insert the appropriate casts into the AST. First work out just
911*0fca6ea1SDimitry Andric   // what the appropriate type is.
912*0fca6ea1SDimitry Andric   QualType ValType = pointerType->getPointeeType();
913*0fca6ea1SDimitry Andric   QualType AddrType = ValType.getUnqualifiedType().withVolatile();
914*0fca6ea1SDimitry Andric   if (IsLdrex)
915*0fca6ea1SDimitry Andric     AddrType.addConst();
916*0fca6ea1SDimitry Andric 
917*0fca6ea1SDimitry Andric   // Issue a warning if the cast is dodgy.
918*0fca6ea1SDimitry Andric   CastKind CastNeeded = CK_NoOp;
919*0fca6ea1SDimitry Andric   if (!AddrType.isAtLeastAsQualifiedAs(ValType)) {
920*0fca6ea1SDimitry Andric     CastNeeded = CK_BitCast;
921*0fca6ea1SDimitry Andric     Diag(DRE->getBeginLoc(), diag::ext_typecheck_convert_discards_qualifiers)
922*0fca6ea1SDimitry Andric         << PointerArg->getType() << Context.getPointerType(AddrType)
923*0fca6ea1SDimitry Andric         << Sema::AA_Passing << PointerArg->getSourceRange();
924*0fca6ea1SDimitry Andric   }
925*0fca6ea1SDimitry Andric 
926*0fca6ea1SDimitry Andric   // Finally, do the cast and replace the argument with the corrected version.
927*0fca6ea1SDimitry Andric   AddrType = Context.getPointerType(AddrType);
928*0fca6ea1SDimitry Andric   PointerArgRes = SemaRef.ImpCastExprToType(PointerArg, AddrType, CastNeeded);
929*0fca6ea1SDimitry Andric   if (PointerArgRes.isInvalid())
930*0fca6ea1SDimitry Andric     return true;
931*0fca6ea1SDimitry Andric   PointerArg = PointerArgRes.get();
932*0fca6ea1SDimitry Andric 
933*0fca6ea1SDimitry Andric   TheCall->setArg(IsLdrex ? 0 : 1, PointerArg);
934*0fca6ea1SDimitry Andric 
935*0fca6ea1SDimitry Andric   // In general, we allow ints, floats and pointers to be loaded and stored.
936*0fca6ea1SDimitry Andric   if (!ValType->isIntegerType() && !ValType->isAnyPointerType() &&
937*0fca6ea1SDimitry Andric       !ValType->isBlockPointerType() && !ValType->isFloatingType()) {
938*0fca6ea1SDimitry Andric     Diag(DRE->getBeginLoc(), diag::err_atomic_builtin_must_be_pointer_intfltptr)
939*0fca6ea1SDimitry Andric         << PointerArg->getType() << 0 << PointerArg->getSourceRange();
940*0fca6ea1SDimitry Andric     return true;
941*0fca6ea1SDimitry Andric   }
942*0fca6ea1SDimitry Andric 
943*0fca6ea1SDimitry Andric   // But ARM doesn't have instructions to deal with 128-bit versions.
944*0fca6ea1SDimitry Andric   if (Context.getTypeSize(ValType) > MaxWidth) {
945*0fca6ea1SDimitry Andric     assert(MaxWidth == 64 && "Diagnostic unexpectedly inaccurate");
946*0fca6ea1SDimitry Andric     Diag(DRE->getBeginLoc(), diag::err_atomic_exclusive_builtin_pointer_size)
947*0fca6ea1SDimitry Andric         << PointerArg->getType() << PointerArg->getSourceRange();
948*0fca6ea1SDimitry Andric     return true;
949*0fca6ea1SDimitry Andric   }
950*0fca6ea1SDimitry Andric 
951*0fca6ea1SDimitry Andric   switch (ValType.getObjCLifetime()) {
952*0fca6ea1SDimitry Andric   case Qualifiers::OCL_None:
953*0fca6ea1SDimitry Andric   case Qualifiers::OCL_ExplicitNone:
954*0fca6ea1SDimitry Andric     // okay
955*0fca6ea1SDimitry Andric     break;
956*0fca6ea1SDimitry Andric 
957*0fca6ea1SDimitry Andric   case Qualifiers::OCL_Weak:
958*0fca6ea1SDimitry Andric   case Qualifiers::OCL_Strong:
959*0fca6ea1SDimitry Andric   case Qualifiers::OCL_Autoreleasing:
960*0fca6ea1SDimitry Andric     Diag(DRE->getBeginLoc(), diag::err_arc_atomic_ownership)
961*0fca6ea1SDimitry Andric         << ValType << PointerArg->getSourceRange();
962*0fca6ea1SDimitry Andric     return true;
963*0fca6ea1SDimitry Andric   }
964*0fca6ea1SDimitry Andric 
965*0fca6ea1SDimitry Andric   if (IsLdrex) {
966*0fca6ea1SDimitry Andric     TheCall->setType(ValType);
967*0fca6ea1SDimitry Andric     return false;
968*0fca6ea1SDimitry Andric   }
969*0fca6ea1SDimitry Andric 
970*0fca6ea1SDimitry Andric   // Initialize the argument to be stored.
971*0fca6ea1SDimitry Andric   ExprResult ValArg = TheCall->getArg(0);
972*0fca6ea1SDimitry Andric   InitializedEntity Entity = InitializedEntity::InitializeParameter(
973*0fca6ea1SDimitry Andric       Context, ValType, /*consume*/ false);
974*0fca6ea1SDimitry Andric   ValArg = SemaRef.PerformCopyInitialization(Entity, SourceLocation(), ValArg);
975*0fca6ea1SDimitry Andric   if (ValArg.isInvalid())
976*0fca6ea1SDimitry Andric     return true;
977*0fca6ea1SDimitry Andric   TheCall->setArg(0, ValArg.get());
978*0fca6ea1SDimitry Andric 
979*0fca6ea1SDimitry Andric   // __builtin_arm_strex always returns an int. It's marked as such in the .def,
980*0fca6ea1SDimitry Andric   // but the custom checker bypasses all default analysis.
981*0fca6ea1SDimitry Andric   TheCall->setType(Context.IntTy);
982*0fca6ea1SDimitry Andric   return false;
983*0fca6ea1SDimitry Andric }
984*0fca6ea1SDimitry Andric 
985*0fca6ea1SDimitry Andric bool SemaARM::CheckARMBuiltinFunctionCall(const TargetInfo &TI,
986*0fca6ea1SDimitry Andric                                           unsigned BuiltinID,
987*0fca6ea1SDimitry Andric                                           CallExpr *TheCall) {
988*0fca6ea1SDimitry Andric   if (BuiltinID == ARM::BI__builtin_arm_ldrex ||
989*0fca6ea1SDimitry Andric       BuiltinID == ARM::BI__builtin_arm_ldaex ||
990*0fca6ea1SDimitry Andric       BuiltinID == ARM::BI__builtin_arm_strex ||
991*0fca6ea1SDimitry Andric       BuiltinID == ARM::BI__builtin_arm_stlex) {
992*0fca6ea1SDimitry Andric     return CheckARMBuiltinExclusiveCall(BuiltinID, TheCall, 64);
993*0fca6ea1SDimitry Andric   }
994*0fca6ea1SDimitry Andric 
995*0fca6ea1SDimitry Andric   if (BuiltinID == ARM::BI__builtin_arm_prefetch) {
996*0fca6ea1SDimitry Andric     return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 1) ||
997*0fca6ea1SDimitry Andric            SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 1);
998*0fca6ea1SDimitry Andric   }
999*0fca6ea1SDimitry Andric 
1000*0fca6ea1SDimitry Andric   if (BuiltinID == ARM::BI__builtin_arm_rsr64 ||
1001*0fca6ea1SDimitry Andric       BuiltinID == ARM::BI__builtin_arm_wsr64)
1002*0fca6ea1SDimitry Andric     return BuiltinARMSpecialReg(BuiltinID, TheCall, 0, 3, false);
1003*0fca6ea1SDimitry Andric 
1004*0fca6ea1SDimitry Andric   if (BuiltinID == ARM::BI__builtin_arm_rsr ||
1005*0fca6ea1SDimitry Andric       BuiltinID == ARM::BI__builtin_arm_rsrp ||
1006*0fca6ea1SDimitry Andric       BuiltinID == ARM::BI__builtin_arm_wsr ||
1007*0fca6ea1SDimitry Andric       BuiltinID == ARM::BI__builtin_arm_wsrp)
1008*0fca6ea1SDimitry Andric     return BuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true);
1009*0fca6ea1SDimitry Andric 
1010*0fca6ea1SDimitry Andric   if (CheckNeonBuiltinFunctionCall(TI, BuiltinID, TheCall))
1011*0fca6ea1SDimitry Andric     return true;
1012*0fca6ea1SDimitry Andric   if (CheckMVEBuiltinFunctionCall(BuiltinID, TheCall))
1013*0fca6ea1SDimitry Andric     return true;
1014*0fca6ea1SDimitry Andric   if (CheckCDEBuiltinFunctionCall(TI, BuiltinID, TheCall))
1015*0fca6ea1SDimitry Andric     return true;
1016*0fca6ea1SDimitry Andric 
1017*0fca6ea1SDimitry Andric   // For intrinsics which take an immediate value as part of the instruction,
1018*0fca6ea1SDimitry Andric   // range check them here.
1019*0fca6ea1SDimitry Andric   // FIXME: VFP Intrinsics should error if VFP not present.
1020*0fca6ea1SDimitry Andric   switch (BuiltinID) {
1021*0fca6ea1SDimitry Andric   default:
1022*0fca6ea1SDimitry Andric     return false;
1023*0fca6ea1SDimitry Andric   case ARM::BI__builtin_arm_ssat:
1024*0fca6ea1SDimitry Andric     return SemaRef.BuiltinConstantArgRange(TheCall, 1, 1, 32);
1025*0fca6ea1SDimitry Andric   case ARM::BI__builtin_arm_usat:
1026*0fca6ea1SDimitry Andric     return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 31);
1027*0fca6ea1SDimitry Andric   case ARM::BI__builtin_arm_ssat16:
1028*0fca6ea1SDimitry Andric     return SemaRef.BuiltinConstantArgRange(TheCall, 1, 1, 16);
1029*0fca6ea1SDimitry Andric   case ARM::BI__builtin_arm_usat16:
1030*0fca6ea1SDimitry Andric     return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 15);
1031*0fca6ea1SDimitry Andric   case ARM::BI__builtin_arm_vcvtr_f:
1032*0fca6ea1SDimitry Andric   case ARM::BI__builtin_arm_vcvtr_d:
1033*0fca6ea1SDimitry Andric     return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 1);
1034*0fca6ea1SDimitry Andric   case ARM::BI__builtin_arm_dmb:
1035*0fca6ea1SDimitry Andric   case ARM::BI__builtin_arm_dsb:
1036*0fca6ea1SDimitry Andric   case ARM::BI__builtin_arm_isb:
1037*0fca6ea1SDimitry Andric   case ARM::BI__builtin_arm_dbg:
1038*0fca6ea1SDimitry Andric     return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 15);
1039*0fca6ea1SDimitry Andric   case ARM::BI__builtin_arm_cdp:
1040*0fca6ea1SDimitry Andric   case ARM::BI__builtin_arm_cdp2:
1041*0fca6ea1SDimitry Andric   case ARM::BI__builtin_arm_mcr:
1042*0fca6ea1SDimitry Andric   case ARM::BI__builtin_arm_mcr2:
1043*0fca6ea1SDimitry Andric   case ARM::BI__builtin_arm_mrc:
1044*0fca6ea1SDimitry Andric   case ARM::BI__builtin_arm_mrc2:
1045*0fca6ea1SDimitry Andric   case ARM::BI__builtin_arm_mcrr:
1046*0fca6ea1SDimitry Andric   case ARM::BI__builtin_arm_mcrr2:
1047*0fca6ea1SDimitry Andric   case ARM::BI__builtin_arm_mrrc:
1048*0fca6ea1SDimitry Andric   case ARM::BI__builtin_arm_mrrc2:
1049*0fca6ea1SDimitry Andric   case ARM::BI__builtin_arm_ldc:
1050*0fca6ea1SDimitry Andric   case ARM::BI__builtin_arm_ldcl:
1051*0fca6ea1SDimitry Andric   case ARM::BI__builtin_arm_ldc2:
1052*0fca6ea1SDimitry Andric   case ARM::BI__builtin_arm_ldc2l:
1053*0fca6ea1SDimitry Andric   case ARM::BI__builtin_arm_stc:
1054*0fca6ea1SDimitry Andric   case ARM::BI__builtin_arm_stcl:
1055*0fca6ea1SDimitry Andric   case ARM::BI__builtin_arm_stc2:
1056*0fca6ea1SDimitry Andric   case ARM::BI__builtin_arm_stc2l:
1057*0fca6ea1SDimitry Andric     return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 15) ||
1058*0fca6ea1SDimitry Andric            CheckARMCoprocessorImmediate(TI, TheCall->getArg(0),
1059*0fca6ea1SDimitry Andric                                         /*WantCDE*/ false);
1060*0fca6ea1SDimitry Andric   }
1061*0fca6ea1SDimitry Andric }
1062*0fca6ea1SDimitry Andric 
1063*0fca6ea1SDimitry Andric bool SemaARM::CheckAArch64BuiltinFunctionCall(const TargetInfo &TI,
1064*0fca6ea1SDimitry Andric                                               unsigned BuiltinID,
1065*0fca6ea1SDimitry Andric                                               CallExpr *TheCall) {
1066*0fca6ea1SDimitry Andric   if (BuiltinID == AArch64::BI__builtin_arm_ldrex ||
1067*0fca6ea1SDimitry Andric       BuiltinID == AArch64::BI__builtin_arm_ldaex ||
1068*0fca6ea1SDimitry Andric       BuiltinID == AArch64::BI__builtin_arm_strex ||
1069*0fca6ea1SDimitry Andric       BuiltinID == AArch64::BI__builtin_arm_stlex) {
1070*0fca6ea1SDimitry Andric     return CheckARMBuiltinExclusiveCall(BuiltinID, TheCall, 128);
1071*0fca6ea1SDimitry Andric   }
1072*0fca6ea1SDimitry Andric 
1073*0fca6ea1SDimitry Andric   if (BuiltinID == AArch64::BI__builtin_arm_prefetch) {
1074*0fca6ea1SDimitry Andric     return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 1) ||
1075*0fca6ea1SDimitry Andric            SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 3) ||
1076*0fca6ea1SDimitry Andric            SemaRef.BuiltinConstantArgRange(TheCall, 3, 0, 1) ||
1077*0fca6ea1SDimitry Andric            SemaRef.BuiltinConstantArgRange(TheCall, 4, 0, 1);
1078*0fca6ea1SDimitry Andric   }
1079*0fca6ea1SDimitry Andric 
1080*0fca6ea1SDimitry Andric   if (BuiltinID == AArch64::BI__builtin_arm_rsr64 ||
1081*0fca6ea1SDimitry Andric       BuiltinID == AArch64::BI__builtin_arm_wsr64 ||
1082*0fca6ea1SDimitry Andric       BuiltinID == AArch64::BI__builtin_arm_rsr128 ||
1083*0fca6ea1SDimitry Andric       BuiltinID == AArch64::BI__builtin_arm_wsr128)
1084*0fca6ea1SDimitry Andric     return BuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true);
1085*0fca6ea1SDimitry Andric 
1086*0fca6ea1SDimitry Andric   // Memory Tagging Extensions (MTE) Intrinsics
1087*0fca6ea1SDimitry Andric   if (BuiltinID == AArch64::BI__builtin_arm_irg ||
1088*0fca6ea1SDimitry Andric       BuiltinID == AArch64::BI__builtin_arm_addg ||
1089*0fca6ea1SDimitry Andric       BuiltinID == AArch64::BI__builtin_arm_gmi ||
1090*0fca6ea1SDimitry Andric       BuiltinID == AArch64::BI__builtin_arm_ldg ||
1091*0fca6ea1SDimitry Andric       BuiltinID == AArch64::BI__builtin_arm_stg ||
1092*0fca6ea1SDimitry Andric       BuiltinID == AArch64::BI__builtin_arm_subp) {
1093*0fca6ea1SDimitry Andric     return BuiltinARMMemoryTaggingCall(BuiltinID, TheCall);
1094*0fca6ea1SDimitry Andric   }
1095*0fca6ea1SDimitry Andric 
1096*0fca6ea1SDimitry Andric   if (BuiltinID == AArch64::BI__builtin_arm_rsr ||
1097*0fca6ea1SDimitry Andric       BuiltinID == AArch64::BI__builtin_arm_rsrp ||
1098*0fca6ea1SDimitry Andric       BuiltinID == AArch64::BI__builtin_arm_wsr ||
1099*0fca6ea1SDimitry Andric       BuiltinID == AArch64::BI__builtin_arm_wsrp)
1100*0fca6ea1SDimitry Andric     return BuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true);
1101*0fca6ea1SDimitry Andric 
1102*0fca6ea1SDimitry Andric   // Only check the valid encoding range. Any constant in this range would be
1103*0fca6ea1SDimitry Andric   // converted to a register of the form S1_2_C3_C4_5. Let the hardware throw
1104*0fca6ea1SDimitry Andric   // an exception for incorrect registers. This matches MSVC behavior.
1105*0fca6ea1SDimitry Andric   if (BuiltinID == AArch64::BI_ReadStatusReg ||
1106*0fca6ea1SDimitry Andric       BuiltinID == AArch64::BI_WriteStatusReg)
1107*0fca6ea1SDimitry Andric     return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 0x7fff);
1108*0fca6ea1SDimitry Andric 
1109*0fca6ea1SDimitry Andric   if (BuiltinID == AArch64::BI__getReg)
1110*0fca6ea1SDimitry Andric     return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 31);
1111*0fca6ea1SDimitry Andric 
1112*0fca6ea1SDimitry Andric   if (BuiltinID == AArch64::BI__break)
1113*0fca6ea1SDimitry Andric     return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 0xffff);
1114*0fca6ea1SDimitry Andric 
1115*0fca6ea1SDimitry Andric   if (BuiltinID == AArch64::BI__hlt)
1116*0fca6ea1SDimitry Andric     return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 0xffff);
1117*0fca6ea1SDimitry Andric 
1118*0fca6ea1SDimitry Andric   if (CheckNeonBuiltinFunctionCall(TI, BuiltinID, TheCall))
1119*0fca6ea1SDimitry Andric     return true;
1120*0fca6ea1SDimitry Andric 
1121*0fca6ea1SDimitry Andric   if (CheckSVEBuiltinFunctionCall(BuiltinID, TheCall))
1122*0fca6ea1SDimitry Andric     return true;
1123*0fca6ea1SDimitry Andric 
1124*0fca6ea1SDimitry Andric   if (CheckSMEBuiltinFunctionCall(BuiltinID, TheCall))
1125*0fca6ea1SDimitry Andric     return true;
1126*0fca6ea1SDimitry Andric 
1127*0fca6ea1SDimitry Andric   // For intrinsics which take an immediate value as part of the instruction,
1128*0fca6ea1SDimitry Andric   // range check them here.
1129*0fca6ea1SDimitry Andric   unsigned i = 0, l = 0, u = 0;
1130*0fca6ea1SDimitry Andric   switch (BuiltinID) {
1131*0fca6ea1SDimitry Andric   default: return false;
1132*0fca6ea1SDimitry Andric   case AArch64::BI__builtin_arm_dmb:
1133*0fca6ea1SDimitry Andric   case AArch64::BI__builtin_arm_dsb:
1134*0fca6ea1SDimitry Andric   case AArch64::BI__builtin_arm_isb: l = 0; u = 15; break;
1135*0fca6ea1SDimitry Andric   case AArch64::BI__builtin_arm_tcancel: l = 0; u = 65535; break;
1136*0fca6ea1SDimitry Andric   }
1137*0fca6ea1SDimitry Andric 
1138*0fca6ea1SDimitry Andric   return SemaRef.BuiltinConstantArgRange(TheCall, i, l, u + l);
1139*0fca6ea1SDimitry Andric }
1140*0fca6ea1SDimitry Andric 
1141*0fca6ea1SDimitry Andric namespace {
1142*0fca6ea1SDimitry Andric struct IntrinToName {
1143*0fca6ea1SDimitry Andric   uint32_t Id;
1144*0fca6ea1SDimitry Andric   int32_t FullName;
1145*0fca6ea1SDimitry Andric   int32_t ShortName;
1146*0fca6ea1SDimitry Andric };
1147*0fca6ea1SDimitry Andric } // unnamed namespace
1148*0fca6ea1SDimitry Andric 
1149*0fca6ea1SDimitry Andric static bool BuiltinAliasValid(unsigned BuiltinID, StringRef AliasName,
1150*0fca6ea1SDimitry Andric                               ArrayRef<IntrinToName> Map,
1151*0fca6ea1SDimitry Andric                               const char *IntrinNames) {
1152*0fca6ea1SDimitry Andric   AliasName.consume_front("__arm_");
1153*0fca6ea1SDimitry Andric   const IntrinToName *It =
1154*0fca6ea1SDimitry Andric       llvm::lower_bound(Map, BuiltinID, [](const IntrinToName &L, unsigned Id) {
1155*0fca6ea1SDimitry Andric         return L.Id < Id;
1156*0fca6ea1SDimitry Andric       });
1157*0fca6ea1SDimitry Andric   if (It == Map.end() || It->Id != BuiltinID)
1158*0fca6ea1SDimitry Andric     return false;
1159*0fca6ea1SDimitry Andric   StringRef FullName(&IntrinNames[It->FullName]);
1160*0fca6ea1SDimitry Andric   if (AliasName == FullName)
1161*0fca6ea1SDimitry Andric     return true;
1162*0fca6ea1SDimitry Andric   if (It->ShortName == -1)
1163*0fca6ea1SDimitry Andric     return false;
1164*0fca6ea1SDimitry Andric   StringRef ShortName(&IntrinNames[It->ShortName]);
1165*0fca6ea1SDimitry Andric   return AliasName == ShortName;
1166*0fca6ea1SDimitry Andric }
1167*0fca6ea1SDimitry Andric 
1168*0fca6ea1SDimitry Andric bool SemaARM::MveAliasValid(unsigned BuiltinID, StringRef AliasName) {
1169*0fca6ea1SDimitry Andric #include "clang/Basic/arm_mve_builtin_aliases.inc"
1170*0fca6ea1SDimitry Andric   // The included file defines:
1171*0fca6ea1SDimitry Andric   // - ArrayRef<IntrinToName> Map
1172*0fca6ea1SDimitry Andric   // - const char IntrinNames[]
1173*0fca6ea1SDimitry Andric   return BuiltinAliasValid(BuiltinID, AliasName, Map, IntrinNames);
1174*0fca6ea1SDimitry Andric }
1175*0fca6ea1SDimitry Andric 
1176*0fca6ea1SDimitry Andric bool SemaARM::CdeAliasValid(unsigned BuiltinID, StringRef AliasName) {
1177*0fca6ea1SDimitry Andric #include "clang/Basic/arm_cde_builtin_aliases.inc"
1178*0fca6ea1SDimitry Andric   return BuiltinAliasValid(BuiltinID, AliasName, Map, IntrinNames);
1179*0fca6ea1SDimitry Andric }
1180*0fca6ea1SDimitry Andric 
1181*0fca6ea1SDimitry Andric bool SemaARM::SveAliasValid(unsigned BuiltinID, StringRef AliasName) {
1182*0fca6ea1SDimitry Andric   if (getASTContext().BuiltinInfo.isAuxBuiltinID(BuiltinID))
1183*0fca6ea1SDimitry Andric     BuiltinID = getASTContext().BuiltinInfo.getAuxBuiltinID(BuiltinID);
1184*0fca6ea1SDimitry Andric   return BuiltinID >= AArch64::FirstSVEBuiltin &&
1185*0fca6ea1SDimitry Andric          BuiltinID <= AArch64::LastSVEBuiltin;
1186*0fca6ea1SDimitry Andric }
1187*0fca6ea1SDimitry Andric 
1188*0fca6ea1SDimitry Andric bool SemaARM::SmeAliasValid(unsigned BuiltinID, StringRef AliasName) {
1189*0fca6ea1SDimitry Andric   if (getASTContext().BuiltinInfo.isAuxBuiltinID(BuiltinID))
1190*0fca6ea1SDimitry Andric     BuiltinID = getASTContext().BuiltinInfo.getAuxBuiltinID(BuiltinID);
1191*0fca6ea1SDimitry Andric   return BuiltinID >= AArch64::FirstSMEBuiltin &&
1192*0fca6ea1SDimitry Andric          BuiltinID <= AArch64::LastSMEBuiltin;
1193*0fca6ea1SDimitry Andric }
1194*0fca6ea1SDimitry Andric 
1195*0fca6ea1SDimitry Andric void SemaARM::handleBuiltinAliasAttr(Decl *D, const ParsedAttr &AL) {
1196*0fca6ea1SDimitry Andric   ASTContext &Context = getASTContext();
1197*0fca6ea1SDimitry Andric   if (!AL.isArgIdent(0)) {
1198*0fca6ea1SDimitry Andric     Diag(AL.getLoc(), diag::err_attribute_argument_n_type)
1199*0fca6ea1SDimitry Andric         << AL << 1 << AANT_ArgumentIdentifier;
1200*0fca6ea1SDimitry Andric     return;
1201*0fca6ea1SDimitry Andric   }
1202*0fca6ea1SDimitry Andric 
1203*0fca6ea1SDimitry Andric   IdentifierInfo *Ident = AL.getArgAsIdent(0)->Ident;
1204*0fca6ea1SDimitry Andric   unsigned BuiltinID = Ident->getBuiltinID();
1205*0fca6ea1SDimitry Andric   StringRef AliasName = cast<FunctionDecl>(D)->getIdentifier()->getName();
1206*0fca6ea1SDimitry Andric 
1207*0fca6ea1SDimitry Andric   bool IsAArch64 = Context.getTargetInfo().getTriple().isAArch64();
1208*0fca6ea1SDimitry Andric   if ((IsAArch64 && !SveAliasValid(BuiltinID, AliasName) &&
1209*0fca6ea1SDimitry Andric        !SmeAliasValid(BuiltinID, AliasName)) ||
1210*0fca6ea1SDimitry Andric       (!IsAArch64 && !MveAliasValid(BuiltinID, AliasName) &&
1211*0fca6ea1SDimitry Andric        !CdeAliasValid(BuiltinID, AliasName))) {
1212*0fca6ea1SDimitry Andric     Diag(AL.getLoc(), diag::err_attribute_arm_builtin_alias);
1213*0fca6ea1SDimitry Andric     return;
1214*0fca6ea1SDimitry Andric   }
1215*0fca6ea1SDimitry Andric 
1216*0fca6ea1SDimitry Andric   D->addAttr(::new (Context) ArmBuiltinAliasAttr(Context, AL, Ident));
1217*0fca6ea1SDimitry Andric }
1218*0fca6ea1SDimitry Andric 
1219*0fca6ea1SDimitry Andric static bool checkNewAttrMutualExclusion(
1220*0fca6ea1SDimitry Andric     Sema &S, const ParsedAttr &AL, const FunctionProtoType *FPT,
1221*0fca6ea1SDimitry Andric     FunctionType::ArmStateValue CurrentState, StringRef StateName) {
1222*0fca6ea1SDimitry Andric   auto CheckForIncompatibleAttr =
1223*0fca6ea1SDimitry Andric       [&](FunctionType::ArmStateValue IncompatibleState,
1224*0fca6ea1SDimitry Andric           StringRef IncompatibleStateName) {
1225*0fca6ea1SDimitry Andric         if (CurrentState == IncompatibleState) {
1226*0fca6ea1SDimitry Andric           S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible)
1227*0fca6ea1SDimitry Andric               << (std::string("'__arm_new(\"") + StateName.str() + "\")'")
1228*0fca6ea1SDimitry Andric               << (std::string("'") + IncompatibleStateName.str() + "(\"" +
1229*0fca6ea1SDimitry Andric                   StateName.str() + "\")'")
1230*0fca6ea1SDimitry Andric               << true;
1231*0fca6ea1SDimitry Andric           AL.setInvalid();
1232*0fca6ea1SDimitry Andric         }
1233*0fca6ea1SDimitry Andric       };
1234*0fca6ea1SDimitry Andric 
1235*0fca6ea1SDimitry Andric   CheckForIncompatibleAttr(FunctionType::ARM_In, "__arm_in");
1236*0fca6ea1SDimitry Andric   CheckForIncompatibleAttr(FunctionType::ARM_Out, "__arm_out");
1237*0fca6ea1SDimitry Andric   CheckForIncompatibleAttr(FunctionType::ARM_InOut, "__arm_inout");
1238*0fca6ea1SDimitry Andric   CheckForIncompatibleAttr(FunctionType::ARM_Preserves, "__arm_preserves");
1239*0fca6ea1SDimitry Andric   return AL.isInvalid();
1240*0fca6ea1SDimitry Andric }
1241*0fca6ea1SDimitry Andric 
1242*0fca6ea1SDimitry Andric void SemaARM::handleNewAttr(Decl *D, const ParsedAttr &AL) {
1243*0fca6ea1SDimitry Andric   if (!AL.getNumArgs()) {
1244*0fca6ea1SDimitry Andric     Diag(AL.getLoc(), diag::err_missing_arm_state) << AL;
1245*0fca6ea1SDimitry Andric     AL.setInvalid();
1246*0fca6ea1SDimitry Andric     return;
1247*0fca6ea1SDimitry Andric   }
1248*0fca6ea1SDimitry Andric 
1249*0fca6ea1SDimitry Andric   std::vector<StringRef> NewState;
1250*0fca6ea1SDimitry Andric   if (const auto *ExistingAttr = D->getAttr<ArmNewAttr>()) {
1251*0fca6ea1SDimitry Andric     for (StringRef S : ExistingAttr->newArgs())
1252*0fca6ea1SDimitry Andric       NewState.push_back(S);
1253*0fca6ea1SDimitry Andric   }
1254*0fca6ea1SDimitry Andric 
1255*0fca6ea1SDimitry Andric   bool HasZA = false;
1256*0fca6ea1SDimitry Andric   bool HasZT0 = false;
1257*0fca6ea1SDimitry Andric   for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) {
1258*0fca6ea1SDimitry Andric     StringRef StateName;
1259*0fca6ea1SDimitry Andric     SourceLocation LiteralLoc;
1260*0fca6ea1SDimitry Andric     if (!SemaRef.checkStringLiteralArgumentAttr(AL, I, StateName, &LiteralLoc))
1261*0fca6ea1SDimitry Andric       return;
1262*0fca6ea1SDimitry Andric 
1263*0fca6ea1SDimitry Andric     if (StateName == "za")
1264*0fca6ea1SDimitry Andric       HasZA = true;
1265*0fca6ea1SDimitry Andric     else if (StateName == "zt0")
1266*0fca6ea1SDimitry Andric       HasZT0 = true;
1267*0fca6ea1SDimitry Andric     else {
1268*0fca6ea1SDimitry Andric       Diag(LiteralLoc, diag::err_unknown_arm_state) << StateName;
1269*0fca6ea1SDimitry Andric       AL.setInvalid();
1270*0fca6ea1SDimitry Andric       return;
1271*0fca6ea1SDimitry Andric     }
1272*0fca6ea1SDimitry Andric 
1273*0fca6ea1SDimitry Andric     if (!llvm::is_contained(NewState, StateName)) // Avoid adding duplicates.
1274*0fca6ea1SDimitry Andric       NewState.push_back(StateName);
1275*0fca6ea1SDimitry Andric   }
1276*0fca6ea1SDimitry Andric 
1277*0fca6ea1SDimitry Andric   if (auto *FPT = dyn_cast<FunctionProtoType>(D->getFunctionType())) {
1278*0fca6ea1SDimitry Andric     FunctionType::ArmStateValue ZAState =
1279*0fca6ea1SDimitry Andric         FunctionType::getArmZAState(FPT->getAArch64SMEAttributes());
1280*0fca6ea1SDimitry Andric     if (HasZA && ZAState != FunctionType::ARM_None &&
1281*0fca6ea1SDimitry Andric         checkNewAttrMutualExclusion(SemaRef, AL, FPT, ZAState, "za"))
1282*0fca6ea1SDimitry Andric       return;
1283*0fca6ea1SDimitry Andric     FunctionType::ArmStateValue ZT0State =
1284*0fca6ea1SDimitry Andric         FunctionType::getArmZT0State(FPT->getAArch64SMEAttributes());
1285*0fca6ea1SDimitry Andric     if (HasZT0 && ZT0State != FunctionType::ARM_None &&
1286*0fca6ea1SDimitry Andric         checkNewAttrMutualExclusion(SemaRef, AL, FPT, ZT0State, "zt0"))
1287*0fca6ea1SDimitry Andric       return;
1288*0fca6ea1SDimitry Andric   }
1289*0fca6ea1SDimitry Andric 
1290*0fca6ea1SDimitry Andric   D->dropAttr<ArmNewAttr>();
1291*0fca6ea1SDimitry Andric   D->addAttr(::new (getASTContext()) ArmNewAttr(
1292*0fca6ea1SDimitry Andric       getASTContext(), AL, NewState.data(), NewState.size()));
1293*0fca6ea1SDimitry Andric }
1294*0fca6ea1SDimitry Andric 
1295*0fca6ea1SDimitry Andric void SemaARM::handleCmseNSEntryAttr(Decl *D, const ParsedAttr &AL) {
1296*0fca6ea1SDimitry Andric   if (getLangOpts().CPlusPlus && !D->getDeclContext()->isExternCContext()) {
1297*0fca6ea1SDimitry Andric     Diag(AL.getLoc(), diag::err_attribute_not_clinkage) << AL;
1298*0fca6ea1SDimitry Andric     return;
1299*0fca6ea1SDimitry Andric   }
1300*0fca6ea1SDimitry Andric 
1301*0fca6ea1SDimitry Andric   const auto *FD = cast<FunctionDecl>(D);
1302*0fca6ea1SDimitry Andric   if (!FD->isExternallyVisible()) {
1303*0fca6ea1SDimitry Andric     Diag(AL.getLoc(), diag::warn_attribute_cmse_entry_static);
1304*0fca6ea1SDimitry Andric     return;
1305*0fca6ea1SDimitry Andric   }
1306*0fca6ea1SDimitry Andric 
1307*0fca6ea1SDimitry Andric   D->addAttr(::new (getASTContext()) CmseNSEntryAttr(getASTContext(), AL));
1308*0fca6ea1SDimitry Andric }
1309*0fca6ea1SDimitry Andric 
1310*0fca6ea1SDimitry Andric void SemaARM::handleInterruptAttr(Decl *D, const ParsedAttr &AL) {
1311*0fca6ea1SDimitry Andric   // Check the attribute arguments.
1312*0fca6ea1SDimitry Andric   if (AL.getNumArgs() > 1) {
1313*0fca6ea1SDimitry Andric     Diag(AL.getLoc(), diag::err_attribute_too_many_arguments) << AL << 1;
1314*0fca6ea1SDimitry Andric     return;
1315*0fca6ea1SDimitry Andric   }
1316*0fca6ea1SDimitry Andric 
1317*0fca6ea1SDimitry Andric   StringRef Str;
1318*0fca6ea1SDimitry Andric   SourceLocation ArgLoc;
1319*0fca6ea1SDimitry Andric 
1320*0fca6ea1SDimitry Andric   if (AL.getNumArgs() == 0)
1321*0fca6ea1SDimitry Andric     Str = "";
1322*0fca6ea1SDimitry Andric   else if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
1323*0fca6ea1SDimitry Andric     return;
1324*0fca6ea1SDimitry Andric 
1325*0fca6ea1SDimitry Andric   ARMInterruptAttr::InterruptType Kind;
1326*0fca6ea1SDimitry Andric   if (!ARMInterruptAttr::ConvertStrToInterruptType(Str, Kind)) {
1327*0fca6ea1SDimitry Andric     Diag(AL.getLoc(), diag::warn_attribute_type_not_supported)
1328*0fca6ea1SDimitry Andric         << AL << Str << ArgLoc;
1329*0fca6ea1SDimitry Andric     return;
1330*0fca6ea1SDimitry Andric   }
1331*0fca6ea1SDimitry Andric 
1332*0fca6ea1SDimitry Andric   const TargetInfo &TI = getASTContext().getTargetInfo();
1333*0fca6ea1SDimitry Andric   if (TI.hasFeature("vfp"))
1334*0fca6ea1SDimitry Andric     Diag(D->getLocation(), diag::warn_arm_interrupt_vfp_clobber);
1335*0fca6ea1SDimitry Andric 
1336*0fca6ea1SDimitry Andric   D->addAttr(::new (getASTContext())
1337*0fca6ea1SDimitry Andric                  ARMInterruptAttr(getASTContext(), AL, Kind));
1338*0fca6ea1SDimitry Andric }
1339*0fca6ea1SDimitry Andric 
1340*0fca6ea1SDimitry Andric } // namespace clang
1341