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