xref: /llvm-project/clang/lib/Sema/SemaARM.cpp (revision a7f4044bd01919df2bf2204d203ee0378e2e9fb2)
1ed35a92cSVlad Serebrennikov //===------ SemaARM.cpp ---------- ARM target-specific routines -----------===//
2ed35a92cSVlad Serebrennikov //
3ed35a92cSVlad Serebrennikov // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4ed35a92cSVlad Serebrennikov // See https://llvm.org/LICENSE.txt for license information.
5ed35a92cSVlad Serebrennikov // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6ed35a92cSVlad Serebrennikov //
7ed35a92cSVlad Serebrennikov //===----------------------------------------------------------------------===//
8ed35a92cSVlad Serebrennikov //
9ed35a92cSVlad Serebrennikov //  This file implements semantic analysis functions specific to ARM.
10ed35a92cSVlad Serebrennikov //
11ed35a92cSVlad Serebrennikov //===----------------------------------------------------------------------===//
12ed35a92cSVlad Serebrennikov 
13ed35a92cSVlad Serebrennikov #include "clang/Sema/SemaARM.h"
14ed35a92cSVlad Serebrennikov #include "clang/Basic/DiagnosticSema.h"
15ed35a92cSVlad Serebrennikov #include "clang/Basic/TargetBuiltins.h"
1627d37ee4SVlad Serebrennikov #include "clang/Basic/TargetInfo.h"
17ed35a92cSVlad Serebrennikov #include "clang/Sema/Initialization.h"
186b755b0cSVlad Serebrennikov #include "clang/Sema/ParsedAttr.h"
19ed35a92cSVlad Serebrennikov #include "clang/Sema/Sema.h"
20ed35a92cSVlad Serebrennikov 
21ed35a92cSVlad Serebrennikov namespace clang {
22ed35a92cSVlad Serebrennikov 
23ed35a92cSVlad Serebrennikov SemaARM::SemaARM(Sema &S) : SemaBase(S) {}
24ed35a92cSVlad Serebrennikov 
25ed35a92cSVlad Serebrennikov /// BuiltinARMMemoryTaggingCall - Handle calls of memory tagging extensions
26ed35a92cSVlad Serebrennikov bool SemaARM::BuiltinARMMemoryTaggingCall(unsigned BuiltinID,
27ed35a92cSVlad Serebrennikov                                           CallExpr *TheCall) {
28ed35a92cSVlad Serebrennikov   ASTContext &Context = getASTContext();
29ed35a92cSVlad Serebrennikov 
30ed35a92cSVlad Serebrennikov   if (BuiltinID == AArch64::BI__builtin_arm_irg) {
31ed35a92cSVlad Serebrennikov     if (SemaRef.checkArgCount(TheCall, 2))
32ed35a92cSVlad Serebrennikov       return true;
33ed35a92cSVlad Serebrennikov     Expr *Arg0 = TheCall->getArg(0);
34ed35a92cSVlad Serebrennikov     Expr *Arg1 = TheCall->getArg(1);
35ed35a92cSVlad Serebrennikov 
36ed35a92cSVlad Serebrennikov     ExprResult FirstArg = SemaRef.DefaultFunctionArrayLvalueConversion(Arg0);
37ed35a92cSVlad Serebrennikov     if (FirstArg.isInvalid())
38ed35a92cSVlad Serebrennikov       return true;
39ed35a92cSVlad Serebrennikov     QualType FirstArgType = FirstArg.get()->getType();
40ed35a92cSVlad Serebrennikov     if (!FirstArgType->isAnyPointerType())
41ed35a92cSVlad Serebrennikov       return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer)
42ed35a92cSVlad Serebrennikov              << "first" << FirstArgType << Arg0->getSourceRange();
43ed35a92cSVlad Serebrennikov     TheCall->setArg(0, FirstArg.get());
44ed35a92cSVlad Serebrennikov 
45ed35a92cSVlad Serebrennikov     ExprResult SecArg = SemaRef.DefaultLvalueConversion(Arg1);
46ed35a92cSVlad Serebrennikov     if (SecArg.isInvalid())
47ed35a92cSVlad Serebrennikov       return true;
48ed35a92cSVlad Serebrennikov     QualType SecArgType = SecArg.get()->getType();
49ed35a92cSVlad Serebrennikov     if (!SecArgType->isIntegerType())
50ed35a92cSVlad Serebrennikov       return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_integer)
51ed35a92cSVlad Serebrennikov              << "second" << SecArgType << Arg1->getSourceRange();
52ed35a92cSVlad Serebrennikov 
53ed35a92cSVlad Serebrennikov     // Derive the return type from the pointer argument.
54ed35a92cSVlad Serebrennikov     TheCall->setType(FirstArgType);
55ed35a92cSVlad Serebrennikov     return false;
56ed35a92cSVlad Serebrennikov   }
57ed35a92cSVlad Serebrennikov 
58ed35a92cSVlad Serebrennikov   if (BuiltinID == AArch64::BI__builtin_arm_addg) {
59ed35a92cSVlad Serebrennikov     if (SemaRef.checkArgCount(TheCall, 2))
60ed35a92cSVlad Serebrennikov       return true;
61ed35a92cSVlad Serebrennikov 
62ed35a92cSVlad Serebrennikov     Expr *Arg0 = TheCall->getArg(0);
63ed35a92cSVlad Serebrennikov     ExprResult FirstArg = SemaRef.DefaultFunctionArrayLvalueConversion(Arg0);
64ed35a92cSVlad Serebrennikov     if (FirstArg.isInvalid())
65ed35a92cSVlad Serebrennikov       return true;
66ed35a92cSVlad Serebrennikov     QualType FirstArgType = FirstArg.get()->getType();
67ed35a92cSVlad Serebrennikov     if (!FirstArgType->isAnyPointerType())
68ed35a92cSVlad Serebrennikov       return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer)
69ed35a92cSVlad Serebrennikov              << "first" << FirstArgType << Arg0->getSourceRange();
70ed35a92cSVlad Serebrennikov     TheCall->setArg(0, FirstArg.get());
71ed35a92cSVlad Serebrennikov 
72ed35a92cSVlad Serebrennikov     // Derive the return type from the pointer argument.
73ed35a92cSVlad Serebrennikov     TheCall->setType(FirstArgType);
74ed35a92cSVlad Serebrennikov 
75ed35a92cSVlad Serebrennikov     // Second arg must be an constant in range [0,15]
76ed35a92cSVlad Serebrennikov     return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 15);
77ed35a92cSVlad Serebrennikov   }
78ed35a92cSVlad Serebrennikov 
79ed35a92cSVlad Serebrennikov   if (BuiltinID == AArch64::BI__builtin_arm_gmi) {
80ed35a92cSVlad Serebrennikov     if (SemaRef.checkArgCount(TheCall, 2))
81ed35a92cSVlad Serebrennikov       return true;
82ed35a92cSVlad Serebrennikov     Expr *Arg0 = TheCall->getArg(0);
83ed35a92cSVlad Serebrennikov     Expr *Arg1 = TheCall->getArg(1);
84ed35a92cSVlad Serebrennikov 
85ed35a92cSVlad Serebrennikov     ExprResult FirstArg = SemaRef.DefaultFunctionArrayLvalueConversion(Arg0);
86ed35a92cSVlad Serebrennikov     if (FirstArg.isInvalid())
87ed35a92cSVlad Serebrennikov       return true;
88ed35a92cSVlad Serebrennikov     QualType FirstArgType = FirstArg.get()->getType();
89ed35a92cSVlad Serebrennikov     if (!FirstArgType->isAnyPointerType())
90ed35a92cSVlad Serebrennikov       return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer)
91ed35a92cSVlad Serebrennikov              << "first" << FirstArgType << Arg0->getSourceRange();
92ed35a92cSVlad Serebrennikov 
93ed35a92cSVlad Serebrennikov     QualType SecArgType = Arg1->getType();
94ed35a92cSVlad Serebrennikov     if (!SecArgType->isIntegerType())
95ed35a92cSVlad Serebrennikov       return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_integer)
96ed35a92cSVlad Serebrennikov              << "second" << SecArgType << Arg1->getSourceRange();
97ed35a92cSVlad Serebrennikov     TheCall->setType(Context.IntTy);
98ed35a92cSVlad Serebrennikov     return false;
99ed35a92cSVlad Serebrennikov   }
100ed35a92cSVlad Serebrennikov 
101ed35a92cSVlad Serebrennikov   if (BuiltinID == AArch64::BI__builtin_arm_ldg ||
102ed35a92cSVlad Serebrennikov       BuiltinID == AArch64::BI__builtin_arm_stg) {
103ed35a92cSVlad Serebrennikov     if (SemaRef.checkArgCount(TheCall, 1))
104ed35a92cSVlad Serebrennikov       return true;
105ed35a92cSVlad Serebrennikov     Expr *Arg0 = TheCall->getArg(0);
106ed35a92cSVlad Serebrennikov     ExprResult FirstArg = SemaRef.DefaultFunctionArrayLvalueConversion(Arg0);
107ed35a92cSVlad Serebrennikov     if (FirstArg.isInvalid())
108ed35a92cSVlad Serebrennikov       return true;
109ed35a92cSVlad Serebrennikov 
110ed35a92cSVlad Serebrennikov     QualType FirstArgType = FirstArg.get()->getType();
111ed35a92cSVlad Serebrennikov     if (!FirstArgType->isAnyPointerType())
112ed35a92cSVlad Serebrennikov       return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer)
113ed35a92cSVlad Serebrennikov              << "first" << FirstArgType << Arg0->getSourceRange();
114ed35a92cSVlad Serebrennikov     TheCall->setArg(0, FirstArg.get());
115ed35a92cSVlad Serebrennikov 
116ed35a92cSVlad Serebrennikov     // Derive the return type from the pointer argument.
117ed35a92cSVlad Serebrennikov     if (BuiltinID == AArch64::BI__builtin_arm_ldg)
118ed35a92cSVlad Serebrennikov       TheCall->setType(FirstArgType);
119ed35a92cSVlad Serebrennikov     return false;
120ed35a92cSVlad Serebrennikov   }
121ed35a92cSVlad Serebrennikov 
122ed35a92cSVlad Serebrennikov   if (BuiltinID == AArch64::BI__builtin_arm_subp) {
123ed35a92cSVlad Serebrennikov     Expr *ArgA = TheCall->getArg(0);
124ed35a92cSVlad Serebrennikov     Expr *ArgB = TheCall->getArg(1);
125ed35a92cSVlad Serebrennikov 
126ed35a92cSVlad Serebrennikov     ExprResult ArgExprA = SemaRef.DefaultFunctionArrayLvalueConversion(ArgA);
127ed35a92cSVlad Serebrennikov     ExprResult ArgExprB = SemaRef.DefaultFunctionArrayLvalueConversion(ArgB);
128ed35a92cSVlad Serebrennikov 
129ed35a92cSVlad Serebrennikov     if (ArgExprA.isInvalid() || ArgExprB.isInvalid())
130ed35a92cSVlad Serebrennikov       return true;
131ed35a92cSVlad Serebrennikov 
132ed35a92cSVlad Serebrennikov     QualType ArgTypeA = ArgExprA.get()->getType();
133ed35a92cSVlad Serebrennikov     QualType ArgTypeB = ArgExprB.get()->getType();
134ed35a92cSVlad Serebrennikov 
135ed35a92cSVlad Serebrennikov     auto isNull = [&](Expr *E) -> bool {
136ed35a92cSVlad Serebrennikov       return E->isNullPointerConstant(Context,
137ed35a92cSVlad Serebrennikov                                       Expr::NPC_ValueDependentIsNotNull);
138ed35a92cSVlad Serebrennikov     };
139ed35a92cSVlad Serebrennikov 
140ed35a92cSVlad Serebrennikov     // argument should be either a pointer or null
141ed35a92cSVlad Serebrennikov     if (!ArgTypeA->isAnyPointerType() && !isNull(ArgA))
142ed35a92cSVlad Serebrennikov       return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_null_or_pointer)
143ed35a92cSVlad Serebrennikov              << "first" << ArgTypeA << ArgA->getSourceRange();
144ed35a92cSVlad Serebrennikov 
145ed35a92cSVlad Serebrennikov     if (!ArgTypeB->isAnyPointerType() && !isNull(ArgB))
146ed35a92cSVlad Serebrennikov       return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_null_or_pointer)
147ed35a92cSVlad Serebrennikov              << "second" << ArgTypeB << ArgB->getSourceRange();
148ed35a92cSVlad Serebrennikov 
149ed35a92cSVlad Serebrennikov     // Ensure Pointee types are compatible
150ed35a92cSVlad Serebrennikov     if (ArgTypeA->isAnyPointerType() && !isNull(ArgA) &&
151ed35a92cSVlad Serebrennikov         ArgTypeB->isAnyPointerType() && !isNull(ArgB)) {
152ed35a92cSVlad Serebrennikov       QualType pointeeA = ArgTypeA->getPointeeType();
153ed35a92cSVlad Serebrennikov       QualType pointeeB = ArgTypeB->getPointeeType();
154ed35a92cSVlad Serebrennikov       if (!Context.typesAreCompatible(
155ed35a92cSVlad Serebrennikov               Context.getCanonicalType(pointeeA).getUnqualifiedType(),
156ed35a92cSVlad Serebrennikov               Context.getCanonicalType(pointeeB).getUnqualifiedType())) {
157ed35a92cSVlad Serebrennikov         return Diag(TheCall->getBeginLoc(),
158ed35a92cSVlad Serebrennikov                     diag::err_typecheck_sub_ptr_compatible)
159ed35a92cSVlad Serebrennikov                << ArgTypeA << ArgTypeB << ArgA->getSourceRange()
160ed35a92cSVlad Serebrennikov                << ArgB->getSourceRange();
161ed35a92cSVlad Serebrennikov       }
162ed35a92cSVlad Serebrennikov     }
163ed35a92cSVlad Serebrennikov 
164ed35a92cSVlad Serebrennikov     // at least one argument should be pointer type
165ed35a92cSVlad Serebrennikov     if (!ArgTypeA->isAnyPointerType() && !ArgTypeB->isAnyPointerType())
166ed35a92cSVlad Serebrennikov       return Diag(TheCall->getBeginLoc(), diag::err_memtag_any2arg_pointer)
167ed35a92cSVlad Serebrennikov              << ArgTypeA << ArgTypeB << ArgA->getSourceRange();
168ed35a92cSVlad Serebrennikov 
169ed35a92cSVlad Serebrennikov     if (isNull(ArgA)) // adopt type of the other pointer
170ed35a92cSVlad Serebrennikov       ArgExprA =
171ed35a92cSVlad Serebrennikov           SemaRef.ImpCastExprToType(ArgExprA.get(), ArgTypeB, CK_NullToPointer);
172ed35a92cSVlad Serebrennikov 
173ed35a92cSVlad Serebrennikov     if (isNull(ArgB))
174ed35a92cSVlad Serebrennikov       ArgExprB =
175ed35a92cSVlad Serebrennikov           SemaRef.ImpCastExprToType(ArgExprB.get(), ArgTypeA, CK_NullToPointer);
176ed35a92cSVlad Serebrennikov 
177ed35a92cSVlad Serebrennikov     TheCall->setArg(0, ArgExprA.get());
178ed35a92cSVlad Serebrennikov     TheCall->setArg(1, ArgExprB.get());
179ed35a92cSVlad Serebrennikov     TheCall->setType(Context.LongLongTy);
180ed35a92cSVlad Serebrennikov     return false;
181ed35a92cSVlad Serebrennikov   }
182ed35a92cSVlad Serebrennikov   assert(false && "Unhandled ARM MTE intrinsic");
183ed35a92cSVlad Serebrennikov   return true;
184ed35a92cSVlad Serebrennikov }
185ed35a92cSVlad Serebrennikov 
186ed35a92cSVlad Serebrennikov /// BuiltinARMSpecialReg - Handle a check if argument ArgNum of CallExpr
187ed35a92cSVlad Serebrennikov /// TheCall is an ARM/AArch64 special register string literal.
188ed35a92cSVlad Serebrennikov bool SemaARM::BuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall,
189ed35a92cSVlad Serebrennikov                                    int ArgNum, unsigned ExpectedFieldNum,
190ed35a92cSVlad Serebrennikov                                    bool AllowName) {
191ed35a92cSVlad Serebrennikov   bool IsARMBuiltin = BuiltinID == ARM::BI__builtin_arm_rsr64 ||
192ed35a92cSVlad Serebrennikov                       BuiltinID == ARM::BI__builtin_arm_wsr64 ||
193ed35a92cSVlad Serebrennikov                       BuiltinID == ARM::BI__builtin_arm_rsr ||
194ed35a92cSVlad Serebrennikov                       BuiltinID == ARM::BI__builtin_arm_rsrp ||
195ed35a92cSVlad Serebrennikov                       BuiltinID == ARM::BI__builtin_arm_wsr ||
196ed35a92cSVlad Serebrennikov                       BuiltinID == ARM::BI__builtin_arm_wsrp;
197ed35a92cSVlad Serebrennikov   bool IsAArch64Builtin = BuiltinID == AArch64::BI__builtin_arm_rsr64 ||
198ed35a92cSVlad Serebrennikov                           BuiltinID == AArch64::BI__builtin_arm_wsr64 ||
199ed35a92cSVlad Serebrennikov                           BuiltinID == AArch64::BI__builtin_arm_rsr128 ||
200ed35a92cSVlad Serebrennikov                           BuiltinID == AArch64::BI__builtin_arm_wsr128 ||
201ed35a92cSVlad Serebrennikov                           BuiltinID == AArch64::BI__builtin_arm_rsr ||
202ed35a92cSVlad Serebrennikov                           BuiltinID == AArch64::BI__builtin_arm_rsrp ||
203ed35a92cSVlad Serebrennikov                           BuiltinID == AArch64::BI__builtin_arm_wsr ||
204ed35a92cSVlad Serebrennikov                           BuiltinID == AArch64::BI__builtin_arm_wsrp;
205ed35a92cSVlad Serebrennikov   assert((IsARMBuiltin || IsAArch64Builtin) && "Unexpected ARM builtin.");
206ed35a92cSVlad Serebrennikov 
207ed35a92cSVlad Serebrennikov   // We can't check the value of a dependent argument.
208ed35a92cSVlad Serebrennikov   Expr *Arg = TheCall->getArg(ArgNum);
209ed35a92cSVlad Serebrennikov   if (Arg->isTypeDependent() || Arg->isValueDependent())
210ed35a92cSVlad Serebrennikov     return false;
211ed35a92cSVlad Serebrennikov 
212ed35a92cSVlad Serebrennikov   // Check if the argument is a string literal.
213ed35a92cSVlad Serebrennikov   if (!isa<StringLiteral>(Arg->IgnoreParenImpCasts()))
214ed35a92cSVlad Serebrennikov     return Diag(TheCall->getBeginLoc(), diag::err_expr_not_string_literal)
215ed35a92cSVlad Serebrennikov            << Arg->getSourceRange();
216ed35a92cSVlad Serebrennikov 
217ed35a92cSVlad Serebrennikov   // Check the type of special register given.
218ed35a92cSVlad Serebrennikov   StringRef Reg = cast<StringLiteral>(Arg->IgnoreParenImpCasts())->getString();
219ed35a92cSVlad Serebrennikov   SmallVector<StringRef, 6> Fields;
220ed35a92cSVlad Serebrennikov   Reg.split(Fields, ":");
221ed35a92cSVlad Serebrennikov 
222ed35a92cSVlad Serebrennikov   if (Fields.size() != ExpectedFieldNum && !(AllowName && Fields.size() == 1))
223ed35a92cSVlad Serebrennikov     return Diag(TheCall->getBeginLoc(), diag::err_arm_invalid_specialreg)
224ed35a92cSVlad Serebrennikov            << Arg->getSourceRange();
225ed35a92cSVlad Serebrennikov 
226ed35a92cSVlad Serebrennikov   // If the string is the name of a register then we cannot check that it is
227ed35a92cSVlad Serebrennikov   // valid here but if the string is of one the forms described in ACLE then we
228ed35a92cSVlad Serebrennikov   // can check that the supplied fields are integers and within the valid
229ed35a92cSVlad Serebrennikov   // ranges.
230ed35a92cSVlad Serebrennikov   if (Fields.size() > 1) {
231ed35a92cSVlad Serebrennikov     bool FiveFields = Fields.size() == 5;
232ed35a92cSVlad Serebrennikov 
233ed35a92cSVlad Serebrennikov     bool ValidString = true;
234ed35a92cSVlad Serebrennikov     if (IsARMBuiltin) {
235ed35a92cSVlad Serebrennikov       ValidString &= Fields[0].starts_with_insensitive("cp") ||
236ed35a92cSVlad Serebrennikov                      Fields[0].starts_with_insensitive("p");
237ed35a92cSVlad Serebrennikov       if (ValidString)
238ed35a92cSVlad Serebrennikov         Fields[0] = Fields[0].drop_front(
239ed35a92cSVlad Serebrennikov             Fields[0].starts_with_insensitive("cp") ? 2 : 1);
240ed35a92cSVlad Serebrennikov 
241ed35a92cSVlad Serebrennikov       ValidString &= Fields[2].starts_with_insensitive("c");
242ed35a92cSVlad Serebrennikov       if (ValidString)
243ed35a92cSVlad Serebrennikov         Fields[2] = Fields[2].drop_front(1);
244ed35a92cSVlad Serebrennikov 
245ed35a92cSVlad Serebrennikov       if (FiveFields) {
246ed35a92cSVlad Serebrennikov         ValidString &= Fields[3].starts_with_insensitive("c");
247ed35a92cSVlad Serebrennikov         if (ValidString)
248ed35a92cSVlad Serebrennikov           Fields[3] = Fields[3].drop_front(1);
249ed35a92cSVlad Serebrennikov       }
250ed35a92cSVlad Serebrennikov     }
251ed35a92cSVlad Serebrennikov 
252ed35a92cSVlad Serebrennikov     SmallVector<int, 5> Ranges;
253ed35a92cSVlad Serebrennikov     if (FiveFields)
254ed35a92cSVlad Serebrennikov       Ranges.append({IsAArch64Builtin ? 1 : 15, 7, 15, 15, 7});
255ed35a92cSVlad Serebrennikov     else
256ed35a92cSVlad Serebrennikov       Ranges.append({15, 7, 15});
257ed35a92cSVlad Serebrennikov 
258ed35a92cSVlad Serebrennikov     for (unsigned i = 0; i < Fields.size(); ++i) {
259ed35a92cSVlad Serebrennikov       int IntField;
260ed35a92cSVlad Serebrennikov       ValidString &= !Fields[i].getAsInteger(10, IntField);
261ed35a92cSVlad Serebrennikov       ValidString &= (IntField >= 0 && IntField <= Ranges[i]);
262ed35a92cSVlad Serebrennikov     }
263ed35a92cSVlad Serebrennikov 
264ed35a92cSVlad Serebrennikov     if (!ValidString)
265ed35a92cSVlad Serebrennikov       return Diag(TheCall->getBeginLoc(), diag::err_arm_invalid_specialreg)
266ed35a92cSVlad Serebrennikov              << Arg->getSourceRange();
267ed35a92cSVlad Serebrennikov   } else if (IsAArch64Builtin && Fields.size() == 1) {
268ed35a92cSVlad Serebrennikov     // This code validates writes to PSTATE registers.
269ed35a92cSVlad Serebrennikov 
270ed35a92cSVlad Serebrennikov     // Not a write.
271ed35a92cSVlad Serebrennikov     if (TheCall->getNumArgs() != 2)
272ed35a92cSVlad Serebrennikov       return false;
273ed35a92cSVlad Serebrennikov 
274ed35a92cSVlad Serebrennikov     // The 128-bit system register accesses do not touch PSTATE.
275ed35a92cSVlad Serebrennikov     if (BuiltinID == AArch64::BI__builtin_arm_rsr128 ||
276ed35a92cSVlad Serebrennikov         BuiltinID == AArch64::BI__builtin_arm_wsr128)
277ed35a92cSVlad Serebrennikov       return false;
278ed35a92cSVlad Serebrennikov 
279ed35a92cSVlad Serebrennikov     // These are the named PSTATE accesses using "MSR (immediate)" instructions,
280ed35a92cSVlad Serebrennikov     // along with the upper limit on the immediates allowed.
281ed35a92cSVlad Serebrennikov     auto MaxLimit = llvm::StringSwitch<std::optional<unsigned>>(Reg)
282ed35a92cSVlad Serebrennikov                         .CaseLower("spsel", 15)
283ed35a92cSVlad Serebrennikov                         .CaseLower("daifclr", 15)
284ed35a92cSVlad Serebrennikov                         .CaseLower("daifset", 15)
285ed35a92cSVlad Serebrennikov                         .CaseLower("pan", 15)
286ed35a92cSVlad Serebrennikov                         .CaseLower("uao", 15)
287ed35a92cSVlad Serebrennikov                         .CaseLower("dit", 15)
288ed35a92cSVlad Serebrennikov                         .CaseLower("ssbs", 15)
289ed35a92cSVlad Serebrennikov                         .CaseLower("tco", 15)
290ed35a92cSVlad Serebrennikov                         .CaseLower("allint", 1)
291ed35a92cSVlad Serebrennikov                         .CaseLower("pm", 1)
292ed35a92cSVlad Serebrennikov                         .Default(std::nullopt);
293ed35a92cSVlad Serebrennikov 
294ed35a92cSVlad Serebrennikov     // If this is not a named PSTATE, just continue without validating, as this
295ed35a92cSVlad Serebrennikov     // will be lowered to an "MSR (register)" instruction directly
296ed35a92cSVlad Serebrennikov     if (!MaxLimit)
297ed35a92cSVlad Serebrennikov       return false;
298ed35a92cSVlad Serebrennikov 
299ed35a92cSVlad Serebrennikov     // Here we only allow constants in the range for that pstate, as required by
300ed35a92cSVlad Serebrennikov     // the ACLE.
301ed35a92cSVlad Serebrennikov     //
302ed35a92cSVlad Serebrennikov     // While clang also accepts the names of system registers in its ACLE
303ed35a92cSVlad Serebrennikov     // intrinsics, we prevent this with the PSTATE names used in MSR (immediate)
304ed35a92cSVlad Serebrennikov     // as the value written via a register is different to the value used as an
305ed35a92cSVlad Serebrennikov     // immediate to have the same effect. e.g., for the instruction `msr tco,
306ed35a92cSVlad Serebrennikov     // x0`, it is bit 25 of register x0 that is written into PSTATE.TCO, but
307ed35a92cSVlad Serebrennikov     // with `msr tco, #imm`, it is bit 0 of xN that is written into PSTATE.TCO.
308ed35a92cSVlad Serebrennikov     //
309ed35a92cSVlad Serebrennikov     // If a programmer wants to codegen the MSR (register) form of `msr tco,
310ed35a92cSVlad Serebrennikov     // xN`, they can still do so by specifying the register using five
311ed35a92cSVlad Serebrennikov     // colon-separated numbers in a string.
312ed35a92cSVlad Serebrennikov     return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, *MaxLimit);
313ed35a92cSVlad Serebrennikov   }
314ed35a92cSVlad Serebrennikov 
315ed35a92cSVlad Serebrennikov   return false;
316ed35a92cSVlad Serebrennikov }
317ed35a92cSVlad Serebrennikov 
318ed35a92cSVlad Serebrennikov /// getNeonEltType - Return the QualType corresponding to the elements of
319ed35a92cSVlad Serebrennikov /// the vector type specified by the NeonTypeFlags.  This is used to check
320ed35a92cSVlad Serebrennikov /// the pointer arguments for Neon load/store intrinsics.
321ed35a92cSVlad Serebrennikov static QualType getNeonEltType(NeonTypeFlags Flags, ASTContext &Context,
322ed35a92cSVlad Serebrennikov                                bool IsPolyUnsigned, bool IsInt64Long) {
323ed35a92cSVlad Serebrennikov   switch (Flags.getEltType()) {
324ed35a92cSVlad Serebrennikov   case NeonTypeFlags::Int8:
325ed35a92cSVlad Serebrennikov     return Flags.isUnsigned() ? Context.UnsignedCharTy : Context.SignedCharTy;
326ed35a92cSVlad Serebrennikov   case NeonTypeFlags::Int16:
327ed35a92cSVlad Serebrennikov     return Flags.isUnsigned() ? Context.UnsignedShortTy : Context.ShortTy;
328ed35a92cSVlad Serebrennikov   case NeonTypeFlags::Int32:
329ed35a92cSVlad Serebrennikov     return Flags.isUnsigned() ? Context.UnsignedIntTy : Context.IntTy;
330ed35a92cSVlad Serebrennikov   case NeonTypeFlags::Int64:
331ed35a92cSVlad Serebrennikov     if (IsInt64Long)
332ed35a92cSVlad Serebrennikov       return Flags.isUnsigned() ? Context.UnsignedLongTy : Context.LongTy;
333ed35a92cSVlad Serebrennikov     else
334ed35a92cSVlad Serebrennikov       return Flags.isUnsigned() ? Context.UnsignedLongLongTy
335ed35a92cSVlad Serebrennikov                                 : Context.LongLongTy;
336ed35a92cSVlad Serebrennikov   case NeonTypeFlags::Poly8:
337ed35a92cSVlad Serebrennikov     return IsPolyUnsigned ? Context.UnsignedCharTy : Context.SignedCharTy;
338ed35a92cSVlad Serebrennikov   case NeonTypeFlags::Poly16:
339ed35a92cSVlad Serebrennikov     return IsPolyUnsigned ? Context.UnsignedShortTy : Context.ShortTy;
340ed35a92cSVlad Serebrennikov   case NeonTypeFlags::Poly64:
341ed35a92cSVlad Serebrennikov     if (IsInt64Long)
342ed35a92cSVlad Serebrennikov       return Context.UnsignedLongTy;
343ed35a92cSVlad Serebrennikov     else
344ed35a92cSVlad Serebrennikov       return Context.UnsignedLongLongTy;
345ed35a92cSVlad Serebrennikov   case NeonTypeFlags::Poly128:
346ed35a92cSVlad Serebrennikov     break;
347ed35a92cSVlad Serebrennikov   case NeonTypeFlags::Float16:
348ed35a92cSVlad Serebrennikov     return Context.HalfTy;
349ed35a92cSVlad Serebrennikov   case NeonTypeFlags::Float32:
350ed35a92cSVlad Serebrennikov     return Context.FloatTy;
351ed35a92cSVlad Serebrennikov   case NeonTypeFlags::Float64:
352ed35a92cSVlad Serebrennikov     return Context.DoubleTy;
353ed35a92cSVlad Serebrennikov   case NeonTypeFlags::BFloat16:
354ed35a92cSVlad Serebrennikov     return Context.BFloat16Ty;
355*87103a01SMomchil Velikov   case NeonTypeFlags::MFloat8:
356*87103a01SMomchil Velikov     return Context.MFloat8Ty;
357ed35a92cSVlad Serebrennikov   }
358ed35a92cSVlad Serebrennikov   llvm_unreachable("Invalid NeonTypeFlag!");
359ed35a92cSVlad Serebrennikov }
360ed35a92cSVlad Serebrennikov 
361ed35a92cSVlad Serebrennikov enum ArmSMEState : unsigned {
362ed35a92cSVlad Serebrennikov   ArmNoState = 0,
363ed35a92cSVlad Serebrennikov 
364ed35a92cSVlad Serebrennikov   ArmInZA = 0b01,
365ed35a92cSVlad Serebrennikov   ArmOutZA = 0b10,
366ed35a92cSVlad Serebrennikov   ArmInOutZA = 0b11,
367ed35a92cSVlad Serebrennikov   ArmZAMask = 0b11,
368ed35a92cSVlad Serebrennikov 
369ed35a92cSVlad Serebrennikov   ArmInZT0 = 0b01 << 2,
370ed35a92cSVlad Serebrennikov   ArmOutZT0 = 0b10 << 2,
371ed35a92cSVlad Serebrennikov   ArmInOutZT0 = 0b11 << 2,
372ed35a92cSVlad Serebrennikov   ArmZT0Mask = 0b11 << 2
373ed35a92cSVlad Serebrennikov };
374ed35a92cSVlad Serebrennikov 
3751f70fcefSSpencerAbson bool SemaARM::CheckImmediateArg(CallExpr *TheCall, unsigned CheckTy,
3761f70fcefSSpencerAbson                                 unsigned ArgIdx, unsigned EltBitWidth,
377a3744f06SSpencer Abson                                 unsigned ContainerBitWidth) {
3781f70fcefSSpencerAbson   // Function that checks whether the operand (ArgIdx) is an immediate
3791f70fcefSSpencerAbson   // that is one of a given set of values.
3801f70fcefSSpencerAbson   auto CheckImmediateInSet = [&](std::initializer_list<int64_t> Set,
381ed35a92cSVlad Serebrennikov                                  int ErrDiag) -> bool {
382ed35a92cSVlad Serebrennikov     // We can't check the value of a dependent argument.
3831f70fcefSSpencerAbson     Expr *Arg = TheCall->getArg(ArgIdx);
384ed35a92cSVlad Serebrennikov     if (Arg->isTypeDependent() || Arg->isValueDependent())
385ed35a92cSVlad Serebrennikov       return false;
386ed35a92cSVlad Serebrennikov 
387ed35a92cSVlad Serebrennikov     // Check constant-ness first.
388ed35a92cSVlad Serebrennikov     llvm::APSInt Imm;
3891f70fcefSSpencerAbson     if (SemaRef.BuiltinConstantArg(TheCall, ArgIdx, Imm))
390ed35a92cSVlad Serebrennikov       return true;
391ed35a92cSVlad Serebrennikov 
3921f70fcefSSpencerAbson     if (std::find(Set.begin(), Set.end(), Imm.getSExtValue()) == Set.end())
393ed35a92cSVlad Serebrennikov       return Diag(TheCall->getBeginLoc(), ErrDiag) << Arg->getSourceRange();
394ed35a92cSVlad Serebrennikov     return false;
395ed35a92cSVlad Serebrennikov   };
396ed35a92cSVlad Serebrennikov 
3971f70fcefSSpencerAbson   switch ((ImmCheckType)CheckTy) {
3981f70fcefSSpencerAbson   case ImmCheckType::ImmCheck0_31:
3991f70fcefSSpencerAbson     if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 0, 31))
4001f70fcefSSpencerAbson       return true;
401ed35a92cSVlad Serebrennikov     break;
4021f70fcefSSpencerAbson   case ImmCheckType::ImmCheck0_13:
4031f70fcefSSpencerAbson     if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 0, 13))
4041f70fcefSSpencerAbson       return true;
405ed35a92cSVlad Serebrennikov     break;
4061f70fcefSSpencerAbson   case ImmCheckType::ImmCheck0_63:
4071f70fcefSSpencerAbson     if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 0, 63))
4081f70fcefSSpencerAbson       return true;
409ed35a92cSVlad Serebrennikov     break;
4101f70fcefSSpencerAbson   case ImmCheckType::ImmCheck1_16:
4111f70fcefSSpencerAbson     if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 1, 16))
4121f70fcefSSpencerAbson       return true;
413ed35a92cSVlad Serebrennikov     break;
4141f70fcefSSpencerAbson   case ImmCheckType::ImmCheck0_7:
4151f70fcefSSpencerAbson     if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 0, 7))
4161f70fcefSSpencerAbson       return true;
417ed35a92cSVlad Serebrennikov     break;
4181f70fcefSSpencerAbson   case ImmCheckType::ImmCheck1_1:
4191f70fcefSSpencerAbson     if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 1, 1))
4201f70fcefSSpencerAbson       return true;
421ed35a92cSVlad Serebrennikov     break;
4221f70fcefSSpencerAbson   case ImmCheckType::ImmCheck1_3:
4231f70fcefSSpencerAbson     if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 1, 3))
4241f70fcefSSpencerAbson       return true;
425ed35a92cSVlad Serebrennikov     break;
4261f70fcefSSpencerAbson   case ImmCheckType::ImmCheck1_7:
4271f70fcefSSpencerAbson     if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 1, 7))
4281f70fcefSSpencerAbson       return true;
429ed35a92cSVlad Serebrennikov     break;
4301f70fcefSSpencerAbson   case ImmCheckType::ImmCheckExtract:
4311f70fcefSSpencerAbson     if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 0,
4321f70fcefSSpencerAbson                                         (2048 / EltBitWidth) - 1))
4331f70fcefSSpencerAbson       return true;
434ed35a92cSVlad Serebrennikov     break;
4351f70fcefSSpencerAbson   case ImmCheckType::ImmCheckCvt:
4361f70fcefSSpencerAbson   case ImmCheckType::ImmCheckShiftRight:
4371f70fcefSSpencerAbson     if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 1, EltBitWidth))
4381f70fcefSSpencerAbson       return true;
439ed35a92cSVlad Serebrennikov     break;
4401f70fcefSSpencerAbson   case ImmCheckType::ImmCheckShiftRightNarrow:
4411f70fcefSSpencerAbson     if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 1, EltBitWidth / 2))
4421f70fcefSSpencerAbson       return true;
443ed35a92cSVlad Serebrennikov     break;
4441f70fcefSSpencerAbson   case ImmCheckType::ImmCheckShiftLeft:
4451f70fcefSSpencerAbson     if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 0, EltBitWidth - 1))
4461f70fcefSSpencerAbson       return true;
447ed35a92cSVlad Serebrennikov     break;
4481f70fcefSSpencerAbson   case ImmCheckType::ImmCheckLaneIndex:
4491f70fcefSSpencerAbson     if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 0,
450a3744f06SSpencer Abson                                         (ContainerBitWidth / EltBitWidth) - 1))
4511f70fcefSSpencerAbson       return true;
452ed35a92cSVlad Serebrennikov     break;
4531f70fcefSSpencerAbson   case ImmCheckType::ImmCheckLaneIndexCompRotate:
454a3744f06SSpencer Abson     if (SemaRef.BuiltinConstantArgRange(
455a3744f06SSpencer Abson             TheCall, ArgIdx, 0, (ContainerBitWidth / (2 * EltBitWidth)) - 1))
4561f70fcefSSpencerAbson       return true;
457ed35a92cSVlad Serebrennikov     break;
4581f70fcefSSpencerAbson   case ImmCheckType::ImmCheckLaneIndexDot:
459a3744f06SSpencer Abson     if (SemaRef.BuiltinConstantArgRange(
460a3744f06SSpencer Abson             TheCall, ArgIdx, 0, (ContainerBitWidth / (4 * EltBitWidth)) - 1))
4611f70fcefSSpencerAbson       return true;
462ed35a92cSVlad Serebrennikov     break;
4631f70fcefSSpencerAbson   case ImmCheckType::ImmCheckComplexRot90_270:
4641f70fcefSSpencerAbson     if (CheckImmediateInSet({90, 270}, diag::err_rotation_argument_to_cadd))
4651f70fcefSSpencerAbson       return true;
4661f70fcefSSpencerAbson     break;
4671f70fcefSSpencerAbson   case ImmCheckType::ImmCheckComplexRotAll90:
4681f70fcefSSpencerAbson     if (CheckImmediateInSet({0, 90, 180, 270},
469ed35a92cSVlad Serebrennikov                             diag::err_rotation_argument_to_cmla))
4701f70fcefSSpencerAbson       return true;
471ed35a92cSVlad Serebrennikov     break;
4721f70fcefSSpencerAbson   case ImmCheckType::ImmCheck0_1:
4731f70fcefSSpencerAbson     if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 0, 1))
4741f70fcefSSpencerAbson       return true;
475ed35a92cSVlad Serebrennikov     break;
4761f70fcefSSpencerAbson   case ImmCheckType::ImmCheck0_2:
4771f70fcefSSpencerAbson     if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 0, 2))
4781f70fcefSSpencerAbson       return true;
479ed35a92cSVlad Serebrennikov     break;
4801f70fcefSSpencerAbson   case ImmCheckType::ImmCheck0_3:
4811f70fcefSSpencerAbson     if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 0, 3))
4821f70fcefSSpencerAbson       return true;
483ed35a92cSVlad Serebrennikov     break;
4841f70fcefSSpencerAbson   case ImmCheckType::ImmCheck0_0:
4851f70fcefSSpencerAbson     if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 0, 0))
4861f70fcefSSpencerAbson       return true;
487ed35a92cSVlad Serebrennikov     break;
4881f70fcefSSpencerAbson   case ImmCheckType::ImmCheck0_15:
4891f70fcefSSpencerAbson     if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 0, 15))
4901f70fcefSSpencerAbson       return true;
491ed35a92cSVlad Serebrennikov     break;
4921f70fcefSSpencerAbson   case ImmCheckType::ImmCheck0_255:
4931f70fcefSSpencerAbson     if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 0, 255))
4941f70fcefSSpencerAbson       return true;
495ed35a92cSVlad Serebrennikov     break;
4961f70fcefSSpencerAbson   case ImmCheckType::ImmCheck1_32:
4971f70fcefSSpencerAbson     if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 1, 32))
4981f70fcefSSpencerAbson       return true;
4991f70fcefSSpencerAbson     break;
5001f70fcefSSpencerAbson   case ImmCheckType::ImmCheck1_64:
5011f70fcefSSpencerAbson     if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 1, 64))
5021f70fcefSSpencerAbson       return true;
5031f70fcefSSpencerAbson     break;
5041f70fcefSSpencerAbson   case ImmCheckType::ImmCheck2_4_Mul2:
5051f70fcefSSpencerAbson     if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 2, 4) ||
5061f70fcefSSpencerAbson         SemaRef.BuiltinConstantArgMultiple(TheCall, ArgIdx, 2))
5071f70fcefSSpencerAbson       return true;
5081f70fcefSSpencerAbson     break;
509ed35a92cSVlad Serebrennikov   }
5101f70fcefSSpencerAbson   return false;
5111f70fcefSSpencerAbson }
5121f70fcefSSpencerAbson 
5131f70fcefSSpencerAbson bool SemaARM::PerformNeonImmChecks(
5141f70fcefSSpencerAbson     CallExpr *TheCall,
5151f70fcefSSpencerAbson     SmallVectorImpl<std::tuple<int, int, int, int>> &ImmChecks,
5161f70fcefSSpencerAbson     int OverloadType) {
5171f70fcefSSpencerAbson   bool HasError = false;
5181f70fcefSSpencerAbson 
5191f70fcefSSpencerAbson   for (const auto &I : ImmChecks) {
520a3744f06SSpencer Abson     auto [ArgIdx, CheckTy, ElementBitWidth, VecBitWidth] = I;
5211f70fcefSSpencerAbson 
5221f70fcefSSpencerAbson     if (OverloadType >= 0)
523a3744f06SSpencer Abson       ElementBitWidth = NeonTypeFlags(OverloadType).getEltSizeInBits();
5241f70fcefSSpencerAbson 
525a3744f06SSpencer Abson     HasError |= CheckImmediateArg(TheCall, CheckTy, ArgIdx, ElementBitWidth,
526a3744f06SSpencer Abson                                   VecBitWidth);
5271f70fcefSSpencerAbson   }
5281f70fcefSSpencerAbson 
5291f70fcefSSpencerAbson   return HasError;
5301f70fcefSSpencerAbson }
5311f70fcefSSpencerAbson 
5321f70fcefSSpencerAbson bool SemaARM::PerformSVEImmChecks(
5331f70fcefSSpencerAbson     CallExpr *TheCall, SmallVectorImpl<std::tuple<int, int, int>> &ImmChecks) {
5341f70fcefSSpencerAbson   bool HasError = false;
5351f70fcefSSpencerAbson 
5361f70fcefSSpencerAbson   for (const auto &I : ImmChecks) {
537a3744f06SSpencer Abson     auto [ArgIdx, CheckTy, ElementBitWidth] = I;
5381f70fcefSSpencerAbson     HasError |=
539a3744f06SSpencer Abson         CheckImmediateArg(TheCall, CheckTy, ArgIdx, ElementBitWidth, 128);
540ed35a92cSVlad Serebrennikov   }
541ed35a92cSVlad Serebrennikov 
542ed35a92cSVlad Serebrennikov   return HasError;
543ed35a92cSVlad Serebrennikov }
544ed35a92cSVlad Serebrennikov 
545ed35a92cSVlad Serebrennikov SemaARM::ArmStreamingType getArmStreamingFnType(const FunctionDecl *FD) {
546ed35a92cSVlad Serebrennikov   if (FD->hasAttr<ArmLocallyStreamingAttr>())
547ed35a92cSVlad Serebrennikov     return SemaARM::ArmStreaming;
548ed35a92cSVlad Serebrennikov   if (const Type *Ty = FD->getType().getTypePtrOrNull()) {
549ed35a92cSVlad Serebrennikov     if (const auto *FPT = Ty->getAs<FunctionProtoType>()) {
550ed35a92cSVlad Serebrennikov       if (FPT->getAArch64SMEAttributes() &
551ed35a92cSVlad Serebrennikov           FunctionType::SME_PStateSMEnabledMask)
552ed35a92cSVlad Serebrennikov         return SemaARM::ArmStreaming;
553ed35a92cSVlad Serebrennikov       if (FPT->getAArch64SMEAttributes() &
554ed35a92cSVlad Serebrennikov           FunctionType::SME_PStateSMCompatibleMask)
555ed35a92cSVlad Serebrennikov         return SemaARM::ArmStreamingCompatible;
556ed35a92cSVlad Serebrennikov     }
557ed35a92cSVlad Serebrennikov   }
558ed35a92cSVlad Serebrennikov   return SemaARM::ArmNonStreaming;
559ed35a92cSVlad Serebrennikov }
560ed35a92cSVlad Serebrennikov 
5611644a31aSSander de Smalen static bool checkArmStreamingBuiltin(Sema &S, CallExpr *TheCall,
562ed35a92cSVlad Serebrennikov                                      const FunctionDecl *FD,
5631644a31aSSander de Smalen                                      SemaARM::ArmStreamingType BuiltinType,
5641644a31aSSander de Smalen                                      unsigned BuiltinID) {
565ed35a92cSVlad Serebrennikov   SemaARM::ArmStreamingType FnType = getArmStreamingFnType(FD);
5661644a31aSSander de Smalen 
5671644a31aSSander de Smalen   // Check if the intrinsic is available in the right mode, i.e.
5681644a31aSSander de Smalen   // * When compiling for SME only, the caller must be in streaming mode.
5691644a31aSSander de Smalen   // * When compiling for SVE only, the caller must be in non-streaming mode.
5701644a31aSSander de Smalen   // * When compiling for both SVE and SME, the caller can be in either mode.
5711644a31aSSander de Smalen   if (BuiltinType == SemaARM::VerifyRuntimeMode) {
5721644a31aSSander de Smalen     llvm::StringMap<bool> CallerFeatureMapWithoutSVE;
5731644a31aSSander de Smalen     S.Context.getFunctionFeatureMap(CallerFeatureMapWithoutSVE, FD);
574f22e6d59SSander de Smalen     CallerFeatureMapWithoutSVE["sve"] = false;
5751644a31aSSander de Smalen 
5761644a31aSSander de Smalen     // Avoid emitting diagnostics for a function that can never compile.
5771644a31aSSander de Smalen     if (FnType == SemaARM::ArmStreaming && !CallerFeatureMapWithoutSVE["sme"])
5781644a31aSSander de Smalen       return false;
5791644a31aSSander de Smalen 
5801644a31aSSander de Smalen     llvm::StringMap<bool> CallerFeatureMapWithoutSME;
5811644a31aSSander de Smalen     S.Context.getFunctionFeatureMap(CallerFeatureMapWithoutSME, FD);
582f22e6d59SSander de Smalen     CallerFeatureMapWithoutSME["sme"] = false;
5831644a31aSSander de Smalen 
5841644a31aSSander de Smalen     // We know the builtin requires either some combination of SVE flags, or
5851644a31aSSander de Smalen     // some combination of SME flags, but we need to figure out which part
5861644a31aSSander de Smalen     // of the required features is satisfied by the target features.
5871644a31aSSander de Smalen     //
5881644a31aSSander de Smalen     // For a builtin with target guard 'sve2p1|sme2', if we compile with
5891644a31aSSander de Smalen     // '+sve2p1,+sme', then we know that it satisfies the 'sve2p1' part if we
5901644a31aSSander de Smalen     // evaluate the features for '+sve2p1,+sme,+nosme'.
5911644a31aSSander de Smalen     //
5921644a31aSSander de Smalen     // Similarly, if we compile with '+sve2,+sme2', then we know it satisfies
5931644a31aSSander de Smalen     // the 'sme2' part if we evaluate the features for '+sve2,+sme2,+nosve'.
5941644a31aSSander de Smalen     StringRef BuiltinTargetGuards(
5951644a31aSSander de Smalen         S.Context.BuiltinInfo.getRequiredFeatures(BuiltinID));
5961644a31aSSander de Smalen     bool SatisfiesSVE = Builtin::evaluateRequiredTargetFeatures(
5971644a31aSSander de Smalen         BuiltinTargetGuards, CallerFeatureMapWithoutSME);
5981644a31aSSander de Smalen     bool SatisfiesSME = Builtin::evaluateRequiredTargetFeatures(
5991644a31aSSander de Smalen         BuiltinTargetGuards, CallerFeatureMapWithoutSVE);
6001644a31aSSander de Smalen 
6011644a31aSSander de Smalen     if ((SatisfiesSVE && SatisfiesSME) ||
6021644a31aSSander de Smalen         (SatisfiesSVE && FnType == SemaARM::ArmStreamingCompatible))
6031644a31aSSander de Smalen       return false;
6041644a31aSSander de Smalen     else if (SatisfiesSVE)
6051644a31aSSander de Smalen       BuiltinType = SemaARM::ArmNonStreaming;
6061644a31aSSander de Smalen     else if (SatisfiesSME)
607ed35a92cSVlad Serebrennikov       BuiltinType = SemaARM::ArmStreaming;
6081644a31aSSander de Smalen     else
6091644a31aSSander de Smalen       // This should be diagnosed by CodeGen
6101644a31aSSander de Smalen       return false;
611ed35a92cSVlad Serebrennikov   }
612ed35a92cSVlad Serebrennikov 
6131644a31aSSander de Smalen   if (FnType != SemaARM::ArmNonStreaming &&
614ed35a92cSVlad Serebrennikov       BuiltinType == SemaARM::ArmNonStreaming)
6151644a31aSSander de Smalen     S.Diag(TheCall->getBeginLoc(), diag::err_attribute_arm_sm_incompat_builtin)
616ed35a92cSVlad Serebrennikov         << TheCall->getSourceRange() << "non-streaming";
6171644a31aSSander de Smalen   else if (FnType != SemaARM::ArmStreaming &&
6181644a31aSSander de Smalen            BuiltinType == SemaARM::ArmStreaming)
6191644a31aSSander de Smalen     S.Diag(TheCall->getBeginLoc(), diag::err_attribute_arm_sm_incompat_builtin)
6201644a31aSSander de Smalen         << TheCall->getSourceRange() << "streaming";
6211644a31aSSander de Smalen   else
6221644a31aSSander de Smalen     return false;
6231644a31aSSander de Smalen 
6241644a31aSSander de Smalen   return true;
625ed35a92cSVlad Serebrennikov }
626ed35a92cSVlad Serebrennikov 
627ed35a92cSVlad Serebrennikov static ArmSMEState getSMEState(unsigned BuiltinID) {
628ed35a92cSVlad Serebrennikov   switch (BuiltinID) {
629ed35a92cSVlad Serebrennikov   default:
630ed35a92cSVlad Serebrennikov     return ArmNoState;
631ed35a92cSVlad Serebrennikov #define GET_SME_BUILTIN_GET_STATE
632ed35a92cSVlad Serebrennikov #include "clang/Basic/arm_sme_builtins_za_state.inc"
633ed35a92cSVlad Serebrennikov #undef GET_SME_BUILTIN_GET_STATE
634ed35a92cSVlad Serebrennikov   }
635ed35a92cSVlad Serebrennikov }
636ed35a92cSVlad Serebrennikov 
637ed35a92cSVlad Serebrennikov bool SemaARM::CheckSMEBuiltinFunctionCall(unsigned BuiltinID,
638ed35a92cSVlad Serebrennikov                                           CallExpr *TheCall) {
639ed35a92cSVlad Serebrennikov   if (const FunctionDecl *FD = SemaRef.getCurFunctionDecl()) {
640ed35a92cSVlad Serebrennikov     std::optional<ArmStreamingType> BuiltinType;
641ed35a92cSVlad Serebrennikov 
642ed35a92cSVlad Serebrennikov     switch (BuiltinID) {
643ed35a92cSVlad Serebrennikov #define GET_SME_STREAMING_ATTRS
644ed35a92cSVlad Serebrennikov #include "clang/Basic/arm_sme_streaming_attrs.inc"
645ed35a92cSVlad Serebrennikov #undef GET_SME_STREAMING_ATTRS
646ed35a92cSVlad Serebrennikov     }
647ed35a92cSVlad Serebrennikov 
6481644a31aSSander de Smalen     if (BuiltinType &&
6491644a31aSSander de Smalen         checkArmStreamingBuiltin(SemaRef, TheCall, FD, *BuiltinType, BuiltinID))
6501644a31aSSander de Smalen       return true;
651ed35a92cSVlad Serebrennikov 
652ed35a92cSVlad Serebrennikov     if ((getSMEState(BuiltinID) & ArmZAMask) && !hasArmZAState(FD))
653ed35a92cSVlad Serebrennikov       Diag(TheCall->getBeginLoc(),
654ed35a92cSVlad Serebrennikov            diag::warn_attribute_arm_za_builtin_no_za_state)
655ed35a92cSVlad Serebrennikov           << TheCall->getSourceRange();
656ed35a92cSVlad Serebrennikov 
657ed35a92cSVlad Serebrennikov     if ((getSMEState(BuiltinID) & ArmZT0Mask) && !hasArmZT0State(FD))
658ed35a92cSVlad Serebrennikov       Diag(TheCall->getBeginLoc(),
659ed35a92cSVlad Serebrennikov            diag::warn_attribute_arm_zt0_builtin_no_zt0_state)
660ed35a92cSVlad Serebrennikov           << TheCall->getSourceRange();
661ed35a92cSVlad Serebrennikov   }
662ed35a92cSVlad Serebrennikov 
663ed35a92cSVlad Serebrennikov   // Range check SME intrinsics that take immediate values.
664ed35a92cSVlad Serebrennikov   SmallVector<std::tuple<int, int, int>, 3> ImmChecks;
665ed35a92cSVlad Serebrennikov 
666ed35a92cSVlad Serebrennikov   switch (BuiltinID) {
667ed35a92cSVlad Serebrennikov   default:
668ed35a92cSVlad Serebrennikov     return false;
669ed35a92cSVlad Serebrennikov #define GET_SME_IMMEDIATE_CHECK
670ed35a92cSVlad Serebrennikov #include "clang/Basic/arm_sme_sema_rangechecks.inc"
671ed35a92cSVlad Serebrennikov #undef GET_SME_IMMEDIATE_CHECK
672ed35a92cSVlad Serebrennikov   }
673ed35a92cSVlad Serebrennikov 
6741f70fcefSSpencerAbson   return PerformSVEImmChecks(TheCall, ImmChecks);
675ed35a92cSVlad Serebrennikov }
676ed35a92cSVlad Serebrennikov 
677ed35a92cSVlad Serebrennikov bool SemaARM::CheckSVEBuiltinFunctionCall(unsigned BuiltinID,
678ed35a92cSVlad Serebrennikov                                           CallExpr *TheCall) {
679ed35a92cSVlad Serebrennikov   if (const FunctionDecl *FD = SemaRef.getCurFunctionDecl()) {
680ed35a92cSVlad Serebrennikov     std::optional<ArmStreamingType> BuiltinType;
681ed35a92cSVlad Serebrennikov 
682ed35a92cSVlad Serebrennikov     switch (BuiltinID) {
683ed35a92cSVlad Serebrennikov #define GET_SVE_STREAMING_ATTRS
684ed35a92cSVlad Serebrennikov #include "clang/Basic/arm_sve_streaming_attrs.inc"
685ed35a92cSVlad Serebrennikov #undef GET_SVE_STREAMING_ATTRS
686ed35a92cSVlad Serebrennikov     }
6871644a31aSSander de Smalen     if (BuiltinType &&
6881644a31aSSander de Smalen         checkArmStreamingBuiltin(SemaRef, TheCall, FD, *BuiltinType, BuiltinID))
6891644a31aSSander de Smalen       return true;
690ed35a92cSVlad Serebrennikov   }
691ed35a92cSVlad Serebrennikov   // Range check SVE intrinsics that take immediate values.
692ed35a92cSVlad Serebrennikov   SmallVector<std::tuple<int, int, int>, 3> ImmChecks;
693ed35a92cSVlad Serebrennikov 
694ed35a92cSVlad Serebrennikov   switch (BuiltinID) {
695ed35a92cSVlad Serebrennikov   default:
696ed35a92cSVlad Serebrennikov     return false;
697ed35a92cSVlad Serebrennikov #define GET_SVE_IMMEDIATE_CHECK
698ed35a92cSVlad Serebrennikov #include "clang/Basic/arm_sve_sema_rangechecks.inc"
699ed35a92cSVlad Serebrennikov #undef GET_SVE_IMMEDIATE_CHECK
700ed35a92cSVlad Serebrennikov   }
701ed35a92cSVlad Serebrennikov 
7021f70fcefSSpencerAbson   return PerformSVEImmChecks(TheCall, ImmChecks);
703ed35a92cSVlad Serebrennikov }
704ed35a92cSVlad Serebrennikov 
705ed35a92cSVlad Serebrennikov bool SemaARM::CheckNeonBuiltinFunctionCall(const TargetInfo &TI,
706ed35a92cSVlad Serebrennikov                                            unsigned BuiltinID,
707ed35a92cSVlad Serebrennikov                                            CallExpr *TheCall) {
708ed35a92cSVlad Serebrennikov   if (const FunctionDecl *FD = SemaRef.getCurFunctionDecl()) {
709ed35a92cSVlad Serebrennikov 
710ed35a92cSVlad Serebrennikov     switch (BuiltinID) {
711ed35a92cSVlad Serebrennikov     default:
712ed35a92cSVlad Serebrennikov       break;
713ed35a92cSVlad Serebrennikov #define GET_NEON_BUILTINS
714ed35a92cSVlad Serebrennikov #define TARGET_BUILTIN(id, ...) case NEON::BI##id:
715ed35a92cSVlad Serebrennikov #define BUILTIN(id, ...) case NEON::BI##id:
716ed35a92cSVlad Serebrennikov #include "clang/Basic/arm_neon.inc"
7171644a31aSSander de Smalen       if (checkArmStreamingBuiltin(SemaRef, TheCall, FD, ArmNonStreaming,
7181644a31aSSander de Smalen                                    BuiltinID))
7191644a31aSSander de Smalen         return true;
720ed35a92cSVlad Serebrennikov       break;
721ed35a92cSVlad Serebrennikov #undef TARGET_BUILTIN
722ed35a92cSVlad Serebrennikov #undef BUILTIN
723ed35a92cSVlad Serebrennikov #undef GET_NEON_BUILTINS
724ed35a92cSVlad Serebrennikov     }
725ed35a92cSVlad Serebrennikov   }
726ed35a92cSVlad Serebrennikov 
727ed35a92cSVlad Serebrennikov   llvm::APSInt Result;
728ed35a92cSVlad Serebrennikov   uint64_t mask = 0;
7291f70fcefSSpencerAbson   int TV = -1;
730ed35a92cSVlad Serebrennikov   int PtrArgNum = -1;
731ed35a92cSVlad Serebrennikov   bool HasConstPtr = false;
732ed35a92cSVlad Serebrennikov   switch (BuiltinID) {
733ed35a92cSVlad Serebrennikov #define GET_NEON_OVERLOAD_CHECK
734ed35a92cSVlad Serebrennikov #include "clang/Basic/arm_fp16.inc"
735ed35a92cSVlad Serebrennikov #include "clang/Basic/arm_neon.inc"
736ed35a92cSVlad Serebrennikov #undef GET_NEON_OVERLOAD_CHECK
737ed35a92cSVlad Serebrennikov   }
738ed35a92cSVlad Serebrennikov 
739ed35a92cSVlad Serebrennikov   // For NEON intrinsics which are overloaded on vector element type, validate
740ed35a92cSVlad Serebrennikov   // the immediate which specifies which variant to emit.
741ed35a92cSVlad Serebrennikov   unsigned ImmArg = TheCall->getNumArgs() - 1;
742ed35a92cSVlad Serebrennikov   if (mask) {
743ed35a92cSVlad Serebrennikov     if (SemaRef.BuiltinConstantArg(TheCall, ImmArg, Result))
744ed35a92cSVlad Serebrennikov       return true;
745ed35a92cSVlad Serebrennikov 
746ed35a92cSVlad Serebrennikov     TV = Result.getLimitedValue(64);
747ed35a92cSVlad Serebrennikov     if ((TV > 63) || (mask & (1ULL << TV)) == 0)
748ed35a92cSVlad Serebrennikov       return Diag(TheCall->getBeginLoc(), diag::err_invalid_neon_type_code)
749ed35a92cSVlad Serebrennikov              << TheCall->getArg(ImmArg)->getSourceRange();
750ed35a92cSVlad Serebrennikov   }
751ed35a92cSVlad Serebrennikov 
752ed35a92cSVlad Serebrennikov   if (PtrArgNum >= 0) {
753ed35a92cSVlad Serebrennikov     // Check that pointer arguments have the specified type.
754ed35a92cSVlad Serebrennikov     Expr *Arg = TheCall->getArg(PtrArgNum);
755ed35a92cSVlad Serebrennikov     if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg))
756ed35a92cSVlad Serebrennikov       Arg = ICE->getSubExpr();
757ed35a92cSVlad Serebrennikov     ExprResult RHS = SemaRef.DefaultFunctionArrayLvalueConversion(Arg);
758ed35a92cSVlad Serebrennikov     QualType RHSTy = RHS.get()->getType();
759ed35a92cSVlad Serebrennikov 
760ed35a92cSVlad Serebrennikov     llvm::Triple::ArchType Arch = TI.getTriple().getArch();
761ed35a92cSVlad Serebrennikov     bool IsPolyUnsigned = Arch == llvm::Triple::aarch64 ||
762ed35a92cSVlad Serebrennikov                           Arch == llvm::Triple::aarch64_32 ||
763ed35a92cSVlad Serebrennikov                           Arch == llvm::Triple::aarch64_be;
764ed35a92cSVlad Serebrennikov     bool IsInt64Long = TI.getInt64Type() == TargetInfo::SignedLong;
765ed35a92cSVlad Serebrennikov     QualType EltTy = getNeonEltType(NeonTypeFlags(TV), getASTContext(),
766ed35a92cSVlad Serebrennikov                                     IsPolyUnsigned, IsInt64Long);
767ed35a92cSVlad Serebrennikov     if (HasConstPtr)
768ed35a92cSVlad Serebrennikov       EltTy = EltTy.withConst();
769ed35a92cSVlad Serebrennikov     QualType LHSTy = getASTContext().getPointerType(EltTy);
770ed35a92cSVlad Serebrennikov     Sema::AssignConvertType ConvTy;
771ed35a92cSVlad Serebrennikov     ConvTy = SemaRef.CheckSingleAssignmentConstraints(LHSTy, RHS);
772ed35a92cSVlad Serebrennikov     if (RHS.isInvalid())
773ed35a92cSVlad Serebrennikov       return true;
774ed35a92cSVlad Serebrennikov     if (SemaRef.DiagnoseAssignmentResult(ConvTy, Arg->getBeginLoc(), LHSTy,
775ff04c5b2SDan Liew                                          RHSTy, RHS.get(),
776ff04c5b2SDan Liew                                          AssignmentAction::Assigning))
777ed35a92cSVlad Serebrennikov       return true;
778ed35a92cSVlad Serebrennikov   }
779ed35a92cSVlad Serebrennikov 
780ed35a92cSVlad Serebrennikov   // For NEON intrinsics which take an immediate value as part of the
781ed35a92cSVlad Serebrennikov   // instruction, range check them here.
7821f70fcefSSpencerAbson   SmallVector<std::tuple<int, int, int, int>, 2> ImmChecks;
783ed35a92cSVlad Serebrennikov   switch (BuiltinID) {
784ed35a92cSVlad Serebrennikov   default:
785ed35a92cSVlad Serebrennikov     return false;
786ed35a92cSVlad Serebrennikov #define GET_NEON_IMMEDIATE_CHECK
787ed35a92cSVlad Serebrennikov #include "clang/Basic/arm_fp16.inc"
788ed35a92cSVlad Serebrennikov #include "clang/Basic/arm_neon.inc"
789ed35a92cSVlad Serebrennikov #undef GET_NEON_IMMEDIATE_CHECK
790ed35a92cSVlad Serebrennikov   }
791ed35a92cSVlad Serebrennikov 
7921f70fcefSSpencerAbson   return PerformNeonImmChecks(TheCall, ImmChecks, TV);
793ed35a92cSVlad Serebrennikov }
794ed35a92cSVlad Serebrennikov 
795ed35a92cSVlad Serebrennikov bool SemaARM::CheckMVEBuiltinFunctionCall(unsigned BuiltinID,
796ed35a92cSVlad Serebrennikov                                           CallExpr *TheCall) {
797ed35a92cSVlad Serebrennikov   switch (BuiltinID) {
798ed35a92cSVlad Serebrennikov   default:
799ed35a92cSVlad Serebrennikov     return false;
800ed35a92cSVlad Serebrennikov #include "clang/Basic/arm_mve_builtin_sema.inc"
801ed35a92cSVlad Serebrennikov   }
802ed35a92cSVlad Serebrennikov }
803ed35a92cSVlad Serebrennikov 
804ed35a92cSVlad Serebrennikov bool SemaARM::CheckCDEBuiltinFunctionCall(const TargetInfo &TI,
805ed35a92cSVlad Serebrennikov                                           unsigned BuiltinID,
806ed35a92cSVlad Serebrennikov                                           CallExpr *TheCall) {
807ed35a92cSVlad Serebrennikov   bool Err = false;
808ed35a92cSVlad Serebrennikov   switch (BuiltinID) {
809ed35a92cSVlad Serebrennikov   default:
810ed35a92cSVlad Serebrennikov     return false;
811ed35a92cSVlad Serebrennikov #include "clang/Basic/arm_cde_builtin_sema.inc"
812ed35a92cSVlad Serebrennikov   }
813ed35a92cSVlad Serebrennikov 
814ed35a92cSVlad Serebrennikov   if (Err)
815ed35a92cSVlad Serebrennikov     return true;
816ed35a92cSVlad Serebrennikov 
817ed35a92cSVlad Serebrennikov   return CheckARMCoprocessorImmediate(TI, TheCall->getArg(0), /*WantCDE*/ true);
818ed35a92cSVlad Serebrennikov }
819ed35a92cSVlad Serebrennikov 
820ed35a92cSVlad Serebrennikov bool SemaARM::CheckARMCoprocessorImmediate(const TargetInfo &TI,
821ed35a92cSVlad Serebrennikov                                            const Expr *CoprocArg,
822ed35a92cSVlad Serebrennikov                                            bool WantCDE) {
823ed35a92cSVlad Serebrennikov   ASTContext &Context = getASTContext();
824ed35a92cSVlad Serebrennikov   if (SemaRef.isConstantEvaluatedContext())
825ed35a92cSVlad Serebrennikov     return false;
826ed35a92cSVlad Serebrennikov 
827ed35a92cSVlad Serebrennikov   // We can't check the value of a dependent argument.
828ed35a92cSVlad Serebrennikov   if (CoprocArg->isTypeDependent() || CoprocArg->isValueDependent())
829ed35a92cSVlad Serebrennikov     return false;
830ed35a92cSVlad Serebrennikov 
831ed35a92cSVlad Serebrennikov   llvm::APSInt CoprocNoAP = *CoprocArg->getIntegerConstantExpr(Context);
832ed35a92cSVlad Serebrennikov   int64_t CoprocNo = CoprocNoAP.getExtValue();
833ed35a92cSVlad Serebrennikov   assert(CoprocNo >= 0 && "Coprocessor immediate must be non-negative");
834ed35a92cSVlad Serebrennikov 
835ed35a92cSVlad Serebrennikov   uint32_t CDECoprocMask = TI.getARMCDECoprocMask();
836ed35a92cSVlad Serebrennikov   bool IsCDECoproc = CoprocNo <= 7 && (CDECoprocMask & (1 << CoprocNo));
837ed35a92cSVlad Serebrennikov 
838ed35a92cSVlad Serebrennikov   if (IsCDECoproc != WantCDE)
839ed35a92cSVlad Serebrennikov     return Diag(CoprocArg->getBeginLoc(), diag::err_arm_invalid_coproc)
840ed35a92cSVlad Serebrennikov            << (int)CoprocNo << (int)WantCDE << CoprocArg->getSourceRange();
841ed35a92cSVlad Serebrennikov 
842ed35a92cSVlad Serebrennikov   return false;
843ed35a92cSVlad Serebrennikov }
844ed35a92cSVlad Serebrennikov 
845ed35a92cSVlad Serebrennikov bool SemaARM::CheckARMBuiltinExclusiveCall(unsigned BuiltinID,
846ed35a92cSVlad Serebrennikov                                            CallExpr *TheCall,
847ed35a92cSVlad Serebrennikov                                            unsigned MaxWidth) {
848ed35a92cSVlad Serebrennikov   assert((BuiltinID == ARM::BI__builtin_arm_ldrex ||
849ed35a92cSVlad Serebrennikov           BuiltinID == ARM::BI__builtin_arm_ldaex ||
850ed35a92cSVlad Serebrennikov           BuiltinID == ARM::BI__builtin_arm_strex ||
851ed35a92cSVlad Serebrennikov           BuiltinID == ARM::BI__builtin_arm_stlex ||
852ed35a92cSVlad Serebrennikov           BuiltinID == AArch64::BI__builtin_arm_ldrex ||
853ed35a92cSVlad Serebrennikov           BuiltinID == AArch64::BI__builtin_arm_ldaex ||
854ed35a92cSVlad Serebrennikov           BuiltinID == AArch64::BI__builtin_arm_strex ||
855ed35a92cSVlad Serebrennikov           BuiltinID == AArch64::BI__builtin_arm_stlex) &&
856ed35a92cSVlad Serebrennikov          "unexpected ARM builtin");
857ed35a92cSVlad Serebrennikov   bool IsLdrex = BuiltinID == ARM::BI__builtin_arm_ldrex ||
858ed35a92cSVlad Serebrennikov                  BuiltinID == ARM::BI__builtin_arm_ldaex ||
859ed35a92cSVlad Serebrennikov                  BuiltinID == AArch64::BI__builtin_arm_ldrex ||
860ed35a92cSVlad Serebrennikov                  BuiltinID == AArch64::BI__builtin_arm_ldaex;
861ed35a92cSVlad Serebrennikov 
862ed35a92cSVlad Serebrennikov   ASTContext &Context = getASTContext();
863ed35a92cSVlad Serebrennikov   DeclRefExpr *DRE =
864ed35a92cSVlad Serebrennikov       cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts());
865ed35a92cSVlad Serebrennikov 
866ed35a92cSVlad Serebrennikov   // Ensure that we have the proper number of arguments.
867ed35a92cSVlad Serebrennikov   if (SemaRef.checkArgCount(TheCall, IsLdrex ? 1 : 2))
868ed35a92cSVlad Serebrennikov     return true;
869ed35a92cSVlad Serebrennikov 
870ed35a92cSVlad Serebrennikov   // Inspect the pointer argument of the atomic builtin.  This should always be
871ed35a92cSVlad Serebrennikov   // a pointer type, whose element is an integral scalar or pointer type.
872ed35a92cSVlad Serebrennikov   // Because it is a pointer type, we don't have to worry about any implicit
873ed35a92cSVlad Serebrennikov   // casts here.
874ed35a92cSVlad Serebrennikov   Expr *PointerArg = TheCall->getArg(IsLdrex ? 0 : 1);
875ed35a92cSVlad Serebrennikov   ExprResult PointerArgRes =
876ed35a92cSVlad Serebrennikov       SemaRef.DefaultFunctionArrayLvalueConversion(PointerArg);
877ed35a92cSVlad Serebrennikov   if (PointerArgRes.isInvalid())
878ed35a92cSVlad Serebrennikov     return true;
879ed35a92cSVlad Serebrennikov   PointerArg = PointerArgRes.get();
880ed35a92cSVlad Serebrennikov 
881ed35a92cSVlad Serebrennikov   const PointerType *pointerType = PointerArg->getType()->getAs<PointerType>();
882ed35a92cSVlad Serebrennikov   if (!pointerType) {
883ed35a92cSVlad Serebrennikov     Diag(DRE->getBeginLoc(), diag::err_atomic_builtin_must_be_pointer)
884ed35a92cSVlad Serebrennikov         << PointerArg->getType() << 0 << PointerArg->getSourceRange();
885ed35a92cSVlad Serebrennikov     return true;
886ed35a92cSVlad Serebrennikov   }
887ed35a92cSVlad Serebrennikov 
888ed35a92cSVlad Serebrennikov   // ldrex takes a "const volatile T*" and strex takes a "volatile T*". Our next
889ed35a92cSVlad Serebrennikov   // task is to insert the appropriate casts into the AST. First work out just
890ed35a92cSVlad Serebrennikov   // what the appropriate type is.
891ed35a92cSVlad Serebrennikov   QualType ValType = pointerType->getPointeeType();
892ed35a92cSVlad Serebrennikov   QualType AddrType = ValType.getUnqualifiedType().withVolatile();
893ed35a92cSVlad Serebrennikov   if (IsLdrex)
894ed35a92cSVlad Serebrennikov     AddrType.addConst();
895ed35a92cSVlad Serebrennikov 
896ed35a92cSVlad Serebrennikov   // Issue a warning if the cast is dodgy.
897ed35a92cSVlad Serebrennikov   CastKind CastNeeded = CK_NoOp;
898b9d678d2SJoseph Huber   if (!AddrType.isAtLeastAsQualifiedAs(ValType, getASTContext())) {
899ed35a92cSVlad Serebrennikov     CastNeeded = CK_BitCast;
900ed35a92cSVlad Serebrennikov     Diag(DRE->getBeginLoc(), diag::ext_typecheck_convert_discards_qualifiers)
901ed35a92cSVlad Serebrennikov         << PointerArg->getType() << Context.getPointerType(AddrType)
902ff04c5b2SDan Liew         << AssignmentAction::Passing << PointerArg->getSourceRange();
903ed35a92cSVlad Serebrennikov   }
904ed35a92cSVlad Serebrennikov 
905ed35a92cSVlad Serebrennikov   // Finally, do the cast and replace the argument with the corrected version.
906ed35a92cSVlad Serebrennikov   AddrType = Context.getPointerType(AddrType);
907ed35a92cSVlad Serebrennikov   PointerArgRes = SemaRef.ImpCastExprToType(PointerArg, AddrType, CastNeeded);
908ed35a92cSVlad Serebrennikov   if (PointerArgRes.isInvalid())
909ed35a92cSVlad Serebrennikov     return true;
910ed35a92cSVlad Serebrennikov   PointerArg = PointerArgRes.get();
911ed35a92cSVlad Serebrennikov 
912ed35a92cSVlad Serebrennikov   TheCall->setArg(IsLdrex ? 0 : 1, PointerArg);
913ed35a92cSVlad Serebrennikov 
914ed35a92cSVlad Serebrennikov   // In general, we allow ints, floats and pointers to be loaded and stored.
915ed35a92cSVlad Serebrennikov   if (!ValType->isIntegerType() && !ValType->isAnyPointerType() &&
916ed35a92cSVlad Serebrennikov       !ValType->isBlockPointerType() && !ValType->isFloatingType()) {
917ed35a92cSVlad Serebrennikov     Diag(DRE->getBeginLoc(), diag::err_atomic_builtin_must_be_pointer_intfltptr)
918ed35a92cSVlad Serebrennikov         << PointerArg->getType() << 0 << PointerArg->getSourceRange();
919ed35a92cSVlad Serebrennikov     return true;
920ed35a92cSVlad Serebrennikov   }
921ed35a92cSVlad Serebrennikov 
922ed35a92cSVlad Serebrennikov   // But ARM doesn't have instructions to deal with 128-bit versions.
923ed35a92cSVlad Serebrennikov   if (Context.getTypeSize(ValType) > MaxWidth) {
924ed35a92cSVlad Serebrennikov     assert(MaxWidth == 64 && "Diagnostic unexpectedly inaccurate");
925ed35a92cSVlad Serebrennikov     Diag(DRE->getBeginLoc(), diag::err_atomic_exclusive_builtin_pointer_size)
926ed35a92cSVlad Serebrennikov         << PointerArg->getType() << PointerArg->getSourceRange();
927ed35a92cSVlad Serebrennikov     return true;
928ed35a92cSVlad Serebrennikov   }
929ed35a92cSVlad Serebrennikov 
930ed35a92cSVlad Serebrennikov   switch (ValType.getObjCLifetime()) {
931ed35a92cSVlad Serebrennikov   case Qualifiers::OCL_None:
932ed35a92cSVlad Serebrennikov   case Qualifiers::OCL_ExplicitNone:
933ed35a92cSVlad Serebrennikov     // okay
934ed35a92cSVlad Serebrennikov     break;
935ed35a92cSVlad Serebrennikov 
936ed35a92cSVlad Serebrennikov   case Qualifiers::OCL_Weak:
937ed35a92cSVlad Serebrennikov   case Qualifiers::OCL_Strong:
938ed35a92cSVlad Serebrennikov   case Qualifiers::OCL_Autoreleasing:
939ed35a92cSVlad Serebrennikov     Diag(DRE->getBeginLoc(), diag::err_arc_atomic_ownership)
940ed35a92cSVlad Serebrennikov         << ValType << PointerArg->getSourceRange();
941ed35a92cSVlad Serebrennikov     return true;
942ed35a92cSVlad Serebrennikov   }
943ed35a92cSVlad Serebrennikov 
944ed35a92cSVlad Serebrennikov   if (IsLdrex) {
945ed35a92cSVlad Serebrennikov     TheCall->setType(ValType);
946ed35a92cSVlad Serebrennikov     return false;
947ed35a92cSVlad Serebrennikov   }
948ed35a92cSVlad Serebrennikov 
949ed35a92cSVlad Serebrennikov   // Initialize the argument to be stored.
950ed35a92cSVlad Serebrennikov   ExprResult ValArg = TheCall->getArg(0);
951ed35a92cSVlad Serebrennikov   InitializedEntity Entity = InitializedEntity::InitializeParameter(
952ed35a92cSVlad Serebrennikov       Context, ValType, /*consume*/ false);
953ed35a92cSVlad Serebrennikov   ValArg = SemaRef.PerformCopyInitialization(Entity, SourceLocation(), ValArg);
954ed35a92cSVlad Serebrennikov   if (ValArg.isInvalid())
955ed35a92cSVlad Serebrennikov     return true;
956ed35a92cSVlad Serebrennikov   TheCall->setArg(0, ValArg.get());
957ed35a92cSVlad Serebrennikov 
958ed35a92cSVlad Serebrennikov   // __builtin_arm_strex always returns an int. It's marked as such in the .def,
959ed35a92cSVlad Serebrennikov   // but the custom checker bypasses all default analysis.
960ed35a92cSVlad Serebrennikov   TheCall->setType(Context.IntTy);
961ed35a92cSVlad Serebrennikov   return false;
962ed35a92cSVlad Serebrennikov }
963ed35a92cSVlad Serebrennikov 
964ed35a92cSVlad Serebrennikov bool SemaARM::CheckARMBuiltinFunctionCall(const TargetInfo &TI,
965ed35a92cSVlad Serebrennikov                                           unsigned BuiltinID,
966ed35a92cSVlad Serebrennikov                                           CallExpr *TheCall) {
967ed35a92cSVlad Serebrennikov   if (BuiltinID == ARM::BI__builtin_arm_ldrex ||
968ed35a92cSVlad Serebrennikov       BuiltinID == ARM::BI__builtin_arm_ldaex ||
969ed35a92cSVlad Serebrennikov       BuiltinID == ARM::BI__builtin_arm_strex ||
970ed35a92cSVlad Serebrennikov       BuiltinID == ARM::BI__builtin_arm_stlex) {
971ed35a92cSVlad Serebrennikov     return CheckARMBuiltinExclusiveCall(BuiltinID, TheCall, 64);
972ed35a92cSVlad Serebrennikov   }
973ed35a92cSVlad Serebrennikov 
974ed35a92cSVlad Serebrennikov   if (BuiltinID == ARM::BI__builtin_arm_prefetch) {
975ed35a92cSVlad Serebrennikov     return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 1) ||
976ed35a92cSVlad Serebrennikov            SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 1);
977ed35a92cSVlad Serebrennikov   }
978ed35a92cSVlad Serebrennikov 
979ed35a92cSVlad Serebrennikov   if (BuiltinID == ARM::BI__builtin_arm_rsr64 ||
980ed35a92cSVlad Serebrennikov       BuiltinID == ARM::BI__builtin_arm_wsr64)
981ed35a92cSVlad Serebrennikov     return BuiltinARMSpecialReg(BuiltinID, TheCall, 0, 3, false);
982ed35a92cSVlad Serebrennikov 
983ed35a92cSVlad Serebrennikov   if (BuiltinID == ARM::BI__builtin_arm_rsr ||
984ed35a92cSVlad Serebrennikov       BuiltinID == ARM::BI__builtin_arm_rsrp ||
985ed35a92cSVlad Serebrennikov       BuiltinID == ARM::BI__builtin_arm_wsr ||
986ed35a92cSVlad Serebrennikov       BuiltinID == ARM::BI__builtin_arm_wsrp)
987ed35a92cSVlad Serebrennikov     return BuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true);
988ed35a92cSVlad Serebrennikov 
989ed35a92cSVlad Serebrennikov   if (CheckNeonBuiltinFunctionCall(TI, BuiltinID, TheCall))
990ed35a92cSVlad Serebrennikov     return true;
991ed35a92cSVlad Serebrennikov   if (CheckMVEBuiltinFunctionCall(BuiltinID, TheCall))
992ed35a92cSVlad Serebrennikov     return true;
993ed35a92cSVlad Serebrennikov   if (CheckCDEBuiltinFunctionCall(TI, BuiltinID, TheCall))
994ed35a92cSVlad Serebrennikov     return true;
995ed35a92cSVlad Serebrennikov 
996ed35a92cSVlad Serebrennikov   // For intrinsics which take an immediate value as part of the instruction,
997ed35a92cSVlad Serebrennikov   // range check them here.
998ed35a92cSVlad Serebrennikov   // FIXME: VFP Intrinsics should error if VFP not present.
999ed35a92cSVlad Serebrennikov   switch (BuiltinID) {
1000ed35a92cSVlad Serebrennikov   default:
1001ed35a92cSVlad Serebrennikov     return false;
1002ed35a92cSVlad Serebrennikov   case ARM::BI__builtin_arm_ssat:
1003ed35a92cSVlad Serebrennikov     return SemaRef.BuiltinConstantArgRange(TheCall, 1, 1, 32);
1004ed35a92cSVlad Serebrennikov   case ARM::BI__builtin_arm_usat:
1005ed35a92cSVlad Serebrennikov     return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 31);
1006ed35a92cSVlad Serebrennikov   case ARM::BI__builtin_arm_ssat16:
1007ed35a92cSVlad Serebrennikov     return SemaRef.BuiltinConstantArgRange(TheCall, 1, 1, 16);
1008ed35a92cSVlad Serebrennikov   case ARM::BI__builtin_arm_usat16:
1009ed35a92cSVlad Serebrennikov     return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 15);
1010ed35a92cSVlad Serebrennikov   case ARM::BI__builtin_arm_vcvtr_f:
1011ed35a92cSVlad Serebrennikov   case ARM::BI__builtin_arm_vcvtr_d:
1012ed35a92cSVlad Serebrennikov     return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 1);
1013ed35a92cSVlad Serebrennikov   case ARM::BI__builtin_arm_dmb:
1014ed35a92cSVlad Serebrennikov   case ARM::BI__builtin_arm_dsb:
1015ed35a92cSVlad Serebrennikov   case ARM::BI__builtin_arm_isb:
1016ed35a92cSVlad Serebrennikov   case ARM::BI__builtin_arm_dbg:
1017ed35a92cSVlad Serebrennikov     return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 15);
1018ed35a92cSVlad Serebrennikov   case ARM::BI__builtin_arm_cdp:
1019ed35a92cSVlad Serebrennikov   case ARM::BI__builtin_arm_cdp2:
1020ed35a92cSVlad Serebrennikov   case ARM::BI__builtin_arm_mcr:
1021ed35a92cSVlad Serebrennikov   case ARM::BI__builtin_arm_mcr2:
1022ed35a92cSVlad Serebrennikov   case ARM::BI__builtin_arm_mrc:
1023ed35a92cSVlad Serebrennikov   case ARM::BI__builtin_arm_mrc2:
1024ed35a92cSVlad Serebrennikov   case ARM::BI__builtin_arm_mcrr:
1025ed35a92cSVlad Serebrennikov   case ARM::BI__builtin_arm_mcrr2:
1026ed35a92cSVlad Serebrennikov   case ARM::BI__builtin_arm_mrrc:
1027ed35a92cSVlad Serebrennikov   case ARM::BI__builtin_arm_mrrc2:
1028ed35a92cSVlad Serebrennikov   case ARM::BI__builtin_arm_ldc:
1029ed35a92cSVlad Serebrennikov   case ARM::BI__builtin_arm_ldcl:
1030ed35a92cSVlad Serebrennikov   case ARM::BI__builtin_arm_ldc2:
1031ed35a92cSVlad Serebrennikov   case ARM::BI__builtin_arm_ldc2l:
1032ed35a92cSVlad Serebrennikov   case ARM::BI__builtin_arm_stc:
1033ed35a92cSVlad Serebrennikov   case ARM::BI__builtin_arm_stcl:
1034ed35a92cSVlad Serebrennikov   case ARM::BI__builtin_arm_stc2:
1035ed35a92cSVlad Serebrennikov   case ARM::BI__builtin_arm_stc2l:
1036ed35a92cSVlad Serebrennikov     return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 15) ||
1037ed35a92cSVlad Serebrennikov            CheckARMCoprocessorImmediate(TI, TheCall->getArg(0),
1038ed35a92cSVlad Serebrennikov                                         /*WantCDE*/ false);
1039ed35a92cSVlad Serebrennikov   }
1040ed35a92cSVlad Serebrennikov }
1041ed35a92cSVlad Serebrennikov 
1042ed35a92cSVlad Serebrennikov bool SemaARM::CheckAArch64BuiltinFunctionCall(const TargetInfo &TI,
1043ed35a92cSVlad Serebrennikov                                               unsigned BuiltinID,
1044ed35a92cSVlad Serebrennikov                                               CallExpr *TheCall) {
1045ed35a92cSVlad Serebrennikov   if (BuiltinID == AArch64::BI__builtin_arm_ldrex ||
1046ed35a92cSVlad Serebrennikov       BuiltinID == AArch64::BI__builtin_arm_ldaex ||
1047ed35a92cSVlad Serebrennikov       BuiltinID == AArch64::BI__builtin_arm_strex ||
1048ed35a92cSVlad Serebrennikov       BuiltinID == AArch64::BI__builtin_arm_stlex) {
1049ed35a92cSVlad Serebrennikov     return CheckARMBuiltinExclusiveCall(BuiltinID, TheCall, 128);
1050ed35a92cSVlad Serebrennikov   }
1051ed35a92cSVlad Serebrennikov 
1052ed35a92cSVlad Serebrennikov   if (BuiltinID == AArch64::BI__builtin_arm_prefetch) {
1053ed35a92cSVlad Serebrennikov     return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 1) ||
1054ed35a92cSVlad Serebrennikov            SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 3) ||
1055ed35a92cSVlad Serebrennikov            SemaRef.BuiltinConstantArgRange(TheCall, 3, 0, 1) ||
1056ed35a92cSVlad Serebrennikov            SemaRef.BuiltinConstantArgRange(TheCall, 4, 0, 1);
1057ed35a92cSVlad Serebrennikov   }
1058ed35a92cSVlad Serebrennikov 
1059ed35a92cSVlad Serebrennikov   if (BuiltinID == AArch64::BI__builtin_arm_rsr64 ||
1060ed35a92cSVlad Serebrennikov       BuiltinID == AArch64::BI__builtin_arm_wsr64 ||
1061ed35a92cSVlad Serebrennikov       BuiltinID == AArch64::BI__builtin_arm_rsr128 ||
1062ed35a92cSVlad Serebrennikov       BuiltinID == AArch64::BI__builtin_arm_wsr128)
1063ed35a92cSVlad Serebrennikov     return BuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true);
1064ed35a92cSVlad Serebrennikov 
1065ed35a92cSVlad Serebrennikov   // Memory Tagging Extensions (MTE) Intrinsics
1066ed35a92cSVlad Serebrennikov   if (BuiltinID == AArch64::BI__builtin_arm_irg ||
1067ed35a92cSVlad Serebrennikov       BuiltinID == AArch64::BI__builtin_arm_addg ||
1068ed35a92cSVlad Serebrennikov       BuiltinID == AArch64::BI__builtin_arm_gmi ||
1069ed35a92cSVlad Serebrennikov       BuiltinID == AArch64::BI__builtin_arm_ldg ||
1070ed35a92cSVlad Serebrennikov       BuiltinID == AArch64::BI__builtin_arm_stg ||
1071ed35a92cSVlad Serebrennikov       BuiltinID == AArch64::BI__builtin_arm_subp) {
1072ed35a92cSVlad Serebrennikov     return BuiltinARMMemoryTaggingCall(BuiltinID, TheCall);
1073ed35a92cSVlad Serebrennikov   }
1074ed35a92cSVlad Serebrennikov 
1075ed35a92cSVlad Serebrennikov   if (BuiltinID == AArch64::BI__builtin_arm_rsr ||
1076ed35a92cSVlad Serebrennikov       BuiltinID == AArch64::BI__builtin_arm_rsrp ||
1077ed35a92cSVlad Serebrennikov       BuiltinID == AArch64::BI__builtin_arm_wsr ||
1078ed35a92cSVlad Serebrennikov       BuiltinID == AArch64::BI__builtin_arm_wsrp)
1079ed35a92cSVlad Serebrennikov     return BuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true);
1080ed35a92cSVlad Serebrennikov 
1081ed35a92cSVlad Serebrennikov   // Only check the valid encoding range. Any constant in this range would be
1082ed35a92cSVlad Serebrennikov   // converted to a register of the form S1_2_C3_C4_5. Let the hardware throw
1083ed35a92cSVlad Serebrennikov   // an exception for incorrect registers. This matches MSVC behavior.
1084ed35a92cSVlad Serebrennikov   if (BuiltinID == AArch64::BI_ReadStatusReg ||
1085ed35a92cSVlad Serebrennikov       BuiltinID == AArch64::BI_WriteStatusReg)
1086ed35a92cSVlad Serebrennikov     return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 0x7fff);
1087ed35a92cSVlad Serebrennikov 
1088ed35a92cSVlad Serebrennikov   if (BuiltinID == AArch64::BI__getReg)
1089ed35a92cSVlad Serebrennikov     return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 31);
1090ed35a92cSVlad Serebrennikov 
1091ed35a92cSVlad Serebrennikov   if (BuiltinID == AArch64::BI__break)
1092ed35a92cSVlad Serebrennikov     return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 0xffff);
1093ed35a92cSVlad Serebrennikov 
1094ae7ab043SAmy Huang   if (BuiltinID == AArch64::BI__hlt)
1095ae7ab043SAmy Huang     return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 0xffff);
1096ae7ab043SAmy Huang 
1097ed35a92cSVlad Serebrennikov   if (CheckNeonBuiltinFunctionCall(TI, BuiltinID, TheCall))
1098ed35a92cSVlad Serebrennikov     return true;
1099ed35a92cSVlad Serebrennikov 
1100ed35a92cSVlad Serebrennikov   if (CheckSVEBuiltinFunctionCall(BuiltinID, TheCall))
1101ed35a92cSVlad Serebrennikov     return true;
1102ed35a92cSVlad Serebrennikov 
1103ed35a92cSVlad Serebrennikov   if (CheckSMEBuiltinFunctionCall(BuiltinID, TheCall))
1104ed35a92cSVlad Serebrennikov     return true;
1105ed35a92cSVlad Serebrennikov 
1106ed35a92cSVlad Serebrennikov   // For intrinsics which take an immediate value as part of the instruction,
1107ed35a92cSVlad Serebrennikov   // range check them here.
1108ed35a92cSVlad Serebrennikov   unsigned i = 0, l = 0, u = 0;
1109ed35a92cSVlad Serebrennikov   switch (BuiltinID) {
1110ed35a92cSVlad Serebrennikov   default: return false;
1111ed35a92cSVlad Serebrennikov   case AArch64::BI__builtin_arm_dmb:
1112ed35a92cSVlad Serebrennikov   case AArch64::BI__builtin_arm_dsb:
1113ed35a92cSVlad Serebrennikov   case AArch64::BI__builtin_arm_isb: l = 0; u = 15; break;
1114ed35a92cSVlad Serebrennikov   case AArch64::BI__builtin_arm_tcancel: l = 0; u = 65535; break;
1115ed35a92cSVlad Serebrennikov   }
1116ed35a92cSVlad Serebrennikov 
1117ed35a92cSVlad Serebrennikov   return SemaRef.BuiltinConstantArgRange(TheCall, i, l, u + l);
1118ed35a92cSVlad Serebrennikov }
1119ed35a92cSVlad Serebrennikov 
11206b755b0cSVlad Serebrennikov namespace {
11216b755b0cSVlad Serebrennikov struct IntrinToName {
11226b755b0cSVlad Serebrennikov   uint32_t Id;
11236b755b0cSVlad Serebrennikov   int32_t FullName;
11246b755b0cSVlad Serebrennikov   int32_t ShortName;
11256b755b0cSVlad Serebrennikov };
11266b755b0cSVlad Serebrennikov } // unnamed namespace
11276b755b0cSVlad Serebrennikov 
11286b755b0cSVlad Serebrennikov static bool BuiltinAliasValid(unsigned BuiltinID, StringRef AliasName,
11296b755b0cSVlad Serebrennikov                               ArrayRef<IntrinToName> Map,
11306b755b0cSVlad Serebrennikov                               const char *IntrinNames) {
11316b755b0cSVlad Serebrennikov   AliasName.consume_front("__arm_");
11326b755b0cSVlad Serebrennikov   const IntrinToName *It =
11336b755b0cSVlad Serebrennikov       llvm::lower_bound(Map, BuiltinID, [](const IntrinToName &L, unsigned Id) {
11346b755b0cSVlad Serebrennikov         return L.Id < Id;
11356b755b0cSVlad Serebrennikov       });
11366b755b0cSVlad Serebrennikov   if (It == Map.end() || It->Id != BuiltinID)
11376b755b0cSVlad Serebrennikov     return false;
11386b755b0cSVlad Serebrennikov   StringRef FullName(&IntrinNames[It->FullName]);
11396b755b0cSVlad Serebrennikov   if (AliasName == FullName)
11406b755b0cSVlad Serebrennikov     return true;
11416b755b0cSVlad Serebrennikov   if (It->ShortName == -1)
11426b755b0cSVlad Serebrennikov     return false;
11436b755b0cSVlad Serebrennikov   StringRef ShortName(&IntrinNames[It->ShortName]);
11446b755b0cSVlad Serebrennikov   return AliasName == ShortName;
11456b755b0cSVlad Serebrennikov }
11466b755b0cSVlad Serebrennikov 
11476b755b0cSVlad Serebrennikov bool SemaARM::MveAliasValid(unsigned BuiltinID, StringRef AliasName) {
11486b755b0cSVlad Serebrennikov #include "clang/Basic/arm_mve_builtin_aliases.inc"
11496b755b0cSVlad Serebrennikov   // The included file defines:
11506b755b0cSVlad Serebrennikov   // - ArrayRef<IntrinToName> Map
11516b755b0cSVlad Serebrennikov   // - const char IntrinNames[]
11526b755b0cSVlad Serebrennikov   return BuiltinAliasValid(BuiltinID, AliasName, Map, IntrinNames);
11536b755b0cSVlad Serebrennikov }
11546b755b0cSVlad Serebrennikov 
11556b755b0cSVlad Serebrennikov bool SemaARM::CdeAliasValid(unsigned BuiltinID, StringRef AliasName) {
11566b755b0cSVlad Serebrennikov #include "clang/Basic/arm_cde_builtin_aliases.inc"
11576b755b0cSVlad Serebrennikov   return BuiltinAliasValid(BuiltinID, AliasName, Map, IntrinNames);
11586b755b0cSVlad Serebrennikov }
11596b755b0cSVlad Serebrennikov 
11606b755b0cSVlad Serebrennikov bool SemaARM::SveAliasValid(unsigned BuiltinID, StringRef AliasName) {
11616b755b0cSVlad Serebrennikov   if (getASTContext().BuiltinInfo.isAuxBuiltinID(BuiltinID))
11626b755b0cSVlad Serebrennikov     BuiltinID = getASTContext().BuiltinInfo.getAuxBuiltinID(BuiltinID);
11636b755b0cSVlad Serebrennikov   return BuiltinID >= AArch64::FirstSVEBuiltin &&
11646b755b0cSVlad Serebrennikov          BuiltinID <= AArch64::LastSVEBuiltin;
11656b755b0cSVlad Serebrennikov }
11666b755b0cSVlad Serebrennikov 
11676b755b0cSVlad Serebrennikov bool SemaARM::SmeAliasValid(unsigned BuiltinID, StringRef AliasName) {
11686b755b0cSVlad Serebrennikov   if (getASTContext().BuiltinInfo.isAuxBuiltinID(BuiltinID))
11696b755b0cSVlad Serebrennikov     BuiltinID = getASTContext().BuiltinInfo.getAuxBuiltinID(BuiltinID);
11706b755b0cSVlad Serebrennikov   return BuiltinID >= AArch64::FirstSMEBuiltin &&
11716b755b0cSVlad Serebrennikov          BuiltinID <= AArch64::LastSMEBuiltin;
11726b755b0cSVlad Serebrennikov }
11736b755b0cSVlad Serebrennikov 
11746b755b0cSVlad Serebrennikov void SemaARM::handleBuiltinAliasAttr(Decl *D, const ParsedAttr &AL) {
11756b755b0cSVlad Serebrennikov   ASTContext &Context = getASTContext();
11766b755b0cSVlad Serebrennikov   if (!AL.isArgIdent(0)) {
11776b755b0cSVlad Serebrennikov     Diag(AL.getLoc(), diag::err_attribute_argument_n_type)
11786b755b0cSVlad Serebrennikov         << AL << 1 << AANT_ArgumentIdentifier;
11796b755b0cSVlad Serebrennikov     return;
11806b755b0cSVlad Serebrennikov   }
11816b755b0cSVlad Serebrennikov 
11826b755b0cSVlad Serebrennikov   IdentifierInfo *Ident = AL.getArgAsIdent(0)->Ident;
11836b755b0cSVlad Serebrennikov   unsigned BuiltinID = Ident->getBuiltinID();
11846b755b0cSVlad Serebrennikov   StringRef AliasName = cast<FunctionDecl>(D)->getIdentifier()->getName();
11856b755b0cSVlad Serebrennikov 
11866b755b0cSVlad Serebrennikov   bool IsAArch64 = Context.getTargetInfo().getTriple().isAArch64();
11876b755b0cSVlad Serebrennikov   if ((IsAArch64 && !SveAliasValid(BuiltinID, AliasName) &&
11886b755b0cSVlad Serebrennikov        !SmeAliasValid(BuiltinID, AliasName)) ||
11896b755b0cSVlad Serebrennikov       (!IsAArch64 && !MveAliasValid(BuiltinID, AliasName) &&
11906b755b0cSVlad Serebrennikov        !CdeAliasValid(BuiltinID, AliasName))) {
11916b755b0cSVlad Serebrennikov     Diag(AL.getLoc(), diag::err_attribute_arm_builtin_alias);
11926b755b0cSVlad Serebrennikov     return;
11936b755b0cSVlad Serebrennikov   }
11946b755b0cSVlad Serebrennikov 
11956b755b0cSVlad Serebrennikov   D->addAttr(::new (Context) ArmBuiltinAliasAttr(Context, AL, Ident));
11966b755b0cSVlad Serebrennikov }
11976b755b0cSVlad Serebrennikov 
11986b755b0cSVlad Serebrennikov static bool checkNewAttrMutualExclusion(
11996b755b0cSVlad Serebrennikov     Sema &S, const ParsedAttr &AL, const FunctionProtoType *FPT,
12006b755b0cSVlad Serebrennikov     FunctionType::ArmStateValue CurrentState, StringRef StateName) {
12016b755b0cSVlad Serebrennikov   auto CheckForIncompatibleAttr =
12026b755b0cSVlad Serebrennikov       [&](FunctionType::ArmStateValue IncompatibleState,
12036b755b0cSVlad Serebrennikov           StringRef IncompatibleStateName) {
12046b755b0cSVlad Serebrennikov         if (CurrentState == IncompatibleState) {
12056b755b0cSVlad Serebrennikov           S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible)
12066b755b0cSVlad Serebrennikov               << (std::string("'__arm_new(\"") + StateName.str() + "\")'")
12076b755b0cSVlad Serebrennikov               << (std::string("'") + IncompatibleStateName.str() + "(\"" +
12086b755b0cSVlad Serebrennikov                   StateName.str() + "\")'")
12096b755b0cSVlad Serebrennikov               << true;
12106b755b0cSVlad Serebrennikov           AL.setInvalid();
12116b755b0cSVlad Serebrennikov         }
12126b755b0cSVlad Serebrennikov       };
12136b755b0cSVlad Serebrennikov 
12146b755b0cSVlad Serebrennikov   CheckForIncompatibleAttr(FunctionType::ARM_In, "__arm_in");
12156b755b0cSVlad Serebrennikov   CheckForIncompatibleAttr(FunctionType::ARM_Out, "__arm_out");
12166b755b0cSVlad Serebrennikov   CheckForIncompatibleAttr(FunctionType::ARM_InOut, "__arm_inout");
12176b755b0cSVlad Serebrennikov   CheckForIncompatibleAttr(FunctionType::ARM_Preserves, "__arm_preserves");
12186b755b0cSVlad Serebrennikov   return AL.isInvalid();
12196b755b0cSVlad Serebrennikov }
12206b755b0cSVlad Serebrennikov 
12216b755b0cSVlad Serebrennikov void SemaARM::handleNewAttr(Decl *D, const ParsedAttr &AL) {
12226b755b0cSVlad Serebrennikov   if (!AL.getNumArgs()) {
12236b755b0cSVlad Serebrennikov     Diag(AL.getLoc(), diag::err_missing_arm_state) << AL;
12246b755b0cSVlad Serebrennikov     AL.setInvalid();
12256b755b0cSVlad Serebrennikov     return;
12266b755b0cSVlad Serebrennikov   }
12276b755b0cSVlad Serebrennikov 
12286b755b0cSVlad Serebrennikov   std::vector<StringRef> NewState;
12296b755b0cSVlad Serebrennikov   if (const auto *ExistingAttr = D->getAttr<ArmNewAttr>()) {
12306b755b0cSVlad Serebrennikov     for (StringRef S : ExistingAttr->newArgs())
12316b755b0cSVlad Serebrennikov       NewState.push_back(S);
12326b755b0cSVlad Serebrennikov   }
12336b755b0cSVlad Serebrennikov 
12346b755b0cSVlad Serebrennikov   bool HasZA = false;
12356b755b0cSVlad Serebrennikov   bool HasZT0 = false;
12366b755b0cSVlad Serebrennikov   for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) {
12376b755b0cSVlad Serebrennikov     StringRef StateName;
12386b755b0cSVlad Serebrennikov     SourceLocation LiteralLoc;
12396b755b0cSVlad Serebrennikov     if (!SemaRef.checkStringLiteralArgumentAttr(AL, I, StateName, &LiteralLoc))
12406b755b0cSVlad Serebrennikov       return;
12416b755b0cSVlad Serebrennikov 
12426b755b0cSVlad Serebrennikov     if (StateName == "za")
12436b755b0cSVlad Serebrennikov       HasZA = true;
12446b755b0cSVlad Serebrennikov     else if (StateName == "zt0")
12456b755b0cSVlad Serebrennikov       HasZT0 = true;
12466b755b0cSVlad Serebrennikov     else {
12476b755b0cSVlad Serebrennikov       Diag(LiteralLoc, diag::err_unknown_arm_state) << StateName;
12486b755b0cSVlad Serebrennikov       AL.setInvalid();
12496b755b0cSVlad Serebrennikov       return;
12506b755b0cSVlad Serebrennikov     }
12516b755b0cSVlad Serebrennikov 
12526b755b0cSVlad Serebrennikov     if (!llvm::is_contained(NewState, StateName)) // Avoid adding duplicates.
12536b755b0cSVlad Serebrennikov       NewState.push_back(StateName);
12546b755b0cSVlad Serebrennikov   }
12556b755b0cSVlad Serebrennikov 
12566b755b0cSVlad Serebrennikov   if (auto *FPT = dyn_cast<FunctionProtoType>(D->getFunctionType())) {
12576b755b0cSVlad Serebrennikov     FunctionType::ArmStateValue ZAState =
12586b755b0cSVlad Serebrennikov         FunctionType::getArmZAState(FPT->getAArch64SMEAttributes());
12596b755b0cSVlad Serebrennikov     if (HasZA && ZAState != FunctionType::ARM_None &&
12606b755b0cSVlad Serebrennikov         checkNewAttrMutualExclusion(SemaRef, AL, FPT, ZAState, "za"))
12616b755b0cSVlad Serebrennikov       return;
12626b755b0cSVlad Serebrennikov     FunctionType::ArmStateValue ZT0State =
12636b755b0cSVlad Serebrennikov         FunctionType::getArmZT0State(FPT->getAArch64SMEAttributes());
12646b755b0cSVlad Serebrennikov     if (HasZT0 && ZT0State != FunctionType::ARM_None &&
12656b755b0cSVlad Serebrennikov         checkNewAttrMutualExclusion(SemaRef, AL, FPT, ZT0State, "zt0"))
12666b755b0cSVlad Serebrennikov       return;
12676b755b0cSVlad Serebrennikov   }
12686b755b0cSVlad Serebrennikov 
12696b755b0cSVlad Serebrennikov   D->dropAttr<ArmNewAttr>();
12706b755b0cSVlad Serebrennikov   D->addAttr(::new (getASTContext()) ArmNewAttr(
12716b755b0cSVlad Serebrennikov       getASTContext(), AL, NewState.data(), NewState.size()));
12726b755b0cSVlad Serebrennikov }
12736b755b0cSVlad Serebrennikov 
12746b755b0cSVlad Serebrennikov void SemaARM::handleCmseNSEntryAttr(Decl *D, const ParsedAttr &AL) {
12756b755b0cSVlad Serebrennikov   if (getLangOpts().CPlusPlus && !D->getDeclContext()->isExternCContext()) {
12766b755b0cSVlad Serebrennikov     Diag(AL.getLoc(), diag::err_attribute_not_clinkage) << AL;
12776b755b0cSVlad Serebrennikov     return;
12786b755b0cSVlad Serebrennikov   }
12796b755b0cSVlad Serebrennikov 
12806b755b0cSVlad Serebrennikov   const auto *FD = cast<FunctionDecl>(D);
12816b755b0cSVlad Serebrennikov   if (!FD->isExternallyVisible()) {
12826b755b0cSVlad Serebrennikov     Diag(AL.getLoc(), diag::warn_attribute_cmse_entry_static);
12836b755b0cSVlad Serebrennikov     return;
12846b755b0cSVlad Serebrennikov   }
12856b755b0cSVlad Serebrennikov 
12866b755b0cSVlad Serebrennikov   D->addAttr(::new (getASTContext()) CmseNSEntryAttr(getASTContext(), AL));
12876b755b0cSVlad Serebrennikov }
12886b755b0cSVlad Serebrennikov 
12896b755b0cSVlad Serebrennikov void SemaARM::handleInterruptAttr(Decl *D, const ParsedAttr &AL) {
12906b755b0cSVlad Serebrennikov   // Check the attribute arguments.
12916b755b0cSVlad Serebrennikov   if (AL.getNumArgs() > 1) {
12926b755b0cSVlad Serebrennikov     Diag(AL.getLoc(), diag::err_attribute_too_many_arguments) << AL << 1;
12936b755b0cSVlad Serebrennikov     return;
12946b755b0cSVlad Serebrennikov   }
12956b755b0cSVlad Serebrennikov 
12966b755b0cSVlad Serebrennikov   StringRef Str;
12976b755b0cSVlad Serebrennikov   SourceLocation ArgLoc;
12986b755b0cSVlad Serebrennikov 
12996b755b0cSVlad Serebrennikov   if (AL.getNumArgs() == 0)
13006b755b0cSVlad Serebrennikov     Str = "";
13016b755b0cSVlad Serebrennikov   else if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
13026b755b0cSVlad Serebrennikov     return;
13036b755b0cSVlad Serebrennikov 
13046b755b0cSVlad Serebrennikov   ARMInterruptAttr::InterruptType Kind;
13056b755b0cSVlad Serebrennikov   if (!ARMInterruptAttr::ConvertStrToInterruptType(Str, Kind)) {
13066b755b0cSVlad Serebrennikov     Diag(AL.getLoc(), diag::warn_attribute_type_not_supported)
13076b755b0cSVlad Serebrennikov         << AL << Str << ArgLoc;
13086b755b0cSVlad Serebrennikov     return;
13096b755b0cSVlad Serebrennikov   }
13106b755b0cSVlad Serebrennikov 
1311588a6d7dSChris Copeland   const TargetInfo &TI = getASTContext().getTargetInfo();
1312588a6d7dSChris Copeland   if (TI.hasFeature("vfp"))
1313588a6d7dSChris Copeland     Diag(D->getLocation(), diag::warn_arm_interrupt_vfp_clobber);
1314588a6d7dSChris Copeland 
13156b755b0cSVlad Serebrennikov   D->addAttr(::new (getASTContext())
13166b755b0cSVlad Serebrennikov                  ARMInterruptAttr(getASTContext(), AL, Kind));
13176b755b0cSVlad Serebrennikov }
13186b755b0cSVlad Serebrennikov 
13194e32271eSKerry McLaughlin // Check if the function definition uses any AArch64 SME features without
13204e32271eSKerry McLaughlin // having the '+sme' feature enabled and warn user if sme locally streaming
13214e32271eSKerry McLaughlin // function returns or uses arguments with VL-based types.
13224e32271eSKerry McLaughlin void SemaARM::CheckSMEFunctionDefAttributes(const FunctionDecl *FD) {
13234e32271eSKerry McLaughlin   const auto *Attr = FD->getAttr<ArmNewAttr>();
13244e32271eSKerry McLaughlin   bool UsesSM = FD->hasAttr<ArmLocallyStreamingAttr>();
13254e32271eSKerry McLaughlin   bool UsesZA = Attr && Attr->isNewZA();
13264e32271eSKerry McLaughlin   bool UsesZT0 = Attr && Attr->isNewZT0();
13274e32271eSKerry McLaughlin 
1328b4ce29abSSander de Smalen   if (UsesZA || UsesZT0) {
1329b4ce29abSSander de Smalen     if (const auto *FPT = FD->getType()->getAs<FunctionProtoType>()) {
1330b4ce29abSSander de Smalen       FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
1331b4ce29abSSander de Smalen       if (EPI.AArch64SMEAttributes & FunctionType::SME_AgnosticZAStateMask)
1332b4ce29abSSander de Smalen         Diag(FD->getLocation(), diag::err_sme_unsupported_agnostic_new);
1333b4ce29abSSander de Smalen     }
1334b4ce29abSSander de Smalen   }
1335b4ce29abSSander de Smalen 
13364e32271eSKerry McLaughlin   if (FD->hasAttr<ArmLocallyStreamingAttr>()) {
13374e32271eSKerry McLaughlin     if (FD->getReturnType()->isSizelessVectorType())
13384e32271eSKerry McLaughlin       Diag(FD->getLocation(),
13394e32271eSKerry McLaughlin            diag::warn_sme_locally_streaming_has_vl_args_returns)
13404e32271eSKerry McLaughlin           << /*IsArg=*/false;
13414e32271eSKerry McLaughlin     if (llvm::any_of(FD->parameters(), [](ParmVarDecl *P) {
13424e32271eSKerry McLaughlin           return P->getOriginalType()->isSizelessVectorType();
13434e32271eSKerry McLaughlin         }))
13444e32271eSKerry McLaughlin       Diag(FD->getLocation(),
13454e32271eSKerry McLaughlin            diag::warn_sme_locally_streaming_has_vl_args_returns)
13464e32271eSKerry McLaughlin           << /*IsArg=*/true;
13474e32271eSKerry McLaughlin   }
13484e32271eSKerry McLaughlin   if (const auto *FPT = FD->getType()->getAs<FunctionProtoType>()) {
13494e32271eSKerry McLaughlin     FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
13504e32271eSKerry McLaughlin     UsesSM |= EPI.AArch64SMEAttributes & FunctionType::SME_PStateSMEnabledMask;
13514e32271eSKerry McLaughlin     UsesZA |= FunctionType::getArmZAState(EPI.AArch64SMEAttributes) !=
13524e32271eSKerry McLaughlin               FunctionType::ARM_None;
13534e32271eSKerry McLaughlin     UsesZT0 |= FunctionType::getArmZT0State(EPI.AArch64SMEAttributes) !=
13544e32271eSKerry McLaughlin                FunctionType::ARM_None;
13554e32271eSKerry McLaughlin   }
13564e32271eSKerry McLaughlin 
13574e32271eSKerry McLaughlin   ASTContext &Context = getASTContext();
13584e32271eSKerry McLaughlin   if (UsesSM || UsesZA) {
13594e32271eSKerry McLaughlin     llvm::StringMap<bool> FeatureMap;
13604e32271eSKerry McLaughlin     Context.getFunctionFeatureMap(FeatureMap, FD);
13614e32271eSKerry McLaughlin     if (!FeatureMap.contains("sme")) {
13624e32271eSKerry McLaughlin       if (UsesSM)
13634e32271eSKerry McLaughlin         Diag(FD->getLocation(),
13644e32271eSKerry McLaughlin              diag::err_sme_definition_using_sm_in_non_sme_target);
13654e32271eSKerry McLaughlin       else
13664e32271eSKerry McLaughlin         Diag(FD->getLocation(),
13674e32271eSKerry McLaughlin              diag::err_sme_definition_using_za_in_non_sme_target);
13684e32271eSKerry McLaughlin     }
13694e32271eSKerry McLaughlin   }
13704e32271eSKerry McLaughlin   if (UsesZT0) {
13714e32271eSKerry McLaughlin     llvm::StringMap<bool> FeatureMap;
13724e32271eSKerry McLaughlin     Context.getFunctionFeatureMap(FeatureMap, FD);
13734e32271eSKerry McLaughlin     if (!FeatureMap.contains("sme2")) {
13744e32271eSKerry McLaughlin       Diag(FD->getLocation(),
13754e32271eSKerry McLaughlin            diag::err_sme_definition_using_zt0_in_non_sme2_target);
13764e32271eSKerry McLaughlin     }
13774e32271eSKerry McLaughlin   }
13784e32271eSKerry McLaughlin }
13794e32271eSKerry McLaughlin 
1380ed35a92cSVlad Serebrennikov } // namespace clang
1381