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#include "llvm/Support/AArch64MemoryHints.h"
21
22namespace clang {
23
24SemaARM::SemaARM(Sema &S) : SemaBase(S) {}
25
26/// BuiltinARMMemoryTaggingCall - Handle calls of memory tagging extensions
27bool SemaARM::BuiltinARMMemoryTaggingCall(unsigned BuiltinID,
28 CallExpr *TheCall) {
29 ASTContext &Context = getASTContext();
30
31 if (BuiltinID == AArch64::BI__builtin_arm_irg) {
32 if (SemaRef.checkArgCount(Call: TheCall, DesiredArgCount: 2))
33 return true;
34 Expr *Arg0 = TheCall->getArg(Arg: 0);
35 Expr *Arg1 = TheCall->getArg(Arg: 1);
36
37 ExprResult FirstArg = SemaRef.DefaultFunctionArrayLvalueConversion(E: Arg0);
38 if (FirstArg.isInvalid())
39 return true;
40 QualType FirstArgType = FirstArg.get()->getType();
41 if (!FirstArgType->isAnyPointerType())
42 return Diag(Loc: TheCall->getBeginLoc(), DiagID: diag::err_memtag_arg_must_be_pointer)
43 << "first" << FirstArgType << Arg0->getSourceRange();
44 TheCall->setArg(Arg: 0, ArgExpr: FirstArg.get());
45
46 InitializedEntity Entity = InitializedEntity::InitializeParameter(
47 Context, Type: Context.getIntTypeForBitwidth(DestWidth: 64, /*Signed=*/false),
48 /*Consumed=*/false);
49 ExprResult SecArg =
50 SemaRef.PerformCopyInitialization(Entity,
51 /*EqualLoc=*/SourceLocation(), Init: Arg1);
52 if (SecArg.isInvalid())
53 return true;
54 TheCall->setArg(Arg: 1, ArgExpr: SecArg.get());
55
56 // Derive the return type from the pointer argument.
57 TheCall->setType(FirstArgType);
58 return false;
59 }
60
61 if (BuiltinID == AArch64::BI__builtin_arm_addg) {
62 if (SemaRef.checkArgCount(Call: TheCall, DesiredArgCount: 2))
63 return true;
64
65 Expr *Arg0 = TheCall->getArg(Arg: 0);
66 ExprResult FirstArg = SemaRef.DefaultFunctionArrayLvalueConversion(E: Arg0);
67 if (FirstArg.isInvalid())
68 return true;
69 QualType FirstArgType = FirstArg.get()->getType();
70 if (!FirstArgType->isAnyPointerType())
71 return Diag(Loc: TheCall->getBeginLoc(), DiagID: diag::err_memtag_arg_must_be_pointer)
72 << "first" << FirstArgType << Arg0->getSourceRange();
73 TheCall->setArg(Arg: 0, ArgExpr: FirstArg.get());
74
75 // Derive the return type from the pointer argument.
76 TheCall->setType(FirstArgType);
77
78 // Second arg must be an constant in range [0,15]
79 return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 1, Low: 0, High: 15);
80 }
81
82 if (BuiltinID == AArch64::BI__builtin_arm_gmi) {
83 if (SemaRef.checkArgCount(Call: TheCall, DesiredArgCount: 2))
84 return true;
85 Expr *Arg0 = TheCall->getArg(Arg: 0);
86 Expr *Arg1 = TheCall->getArg(Arg: 1);
87
88 ExprResult FirstArg = SemaRef.DefaultFunctionArrayLvalueConversion(E: Arg0);
89 if (FirstArg.isInvalid())
90 return true;
91 QualType FirstArgType = FirstArg.get()->getType();
92 if (!FirstArgType->isAnyPointerType())
93 return Diag(Loc: TheCall->getBeginLoc(), DiagID: diag::err_memtag_arg_must_be_pointer)
94 << "first" << FirstArgType << Arg0->getSourceRange();
95 TheCall->setArg(Arg: 0, ArgExpr: FirstArg.get());
96
97 InitializedEntity Entity = InitializedEntity::InitializeParameter(
98 Context, Type: Context.getIntTypeForBitwidth(DestWidth: 64, /*Signed=*/false),
99 /*Consumed=*/false);
100 ExprResult SecArg =
101 SemaRef.PerformCopyInitialization(Entity,
102 /*EqualLoc=*/SourceLocation(), Init: Arg1);
103 if (SecArg.isInvalid())
104 return true;
105 TheCall->setArg(Arg: 1, ArgExpr: SecArg.get());
106
107 return false;
108 }
109
110 if (BuiltinID == AArch64::BI__builtin_arm_ldg ||
111 BuiltinID == AArch64::BI__builtin_arm_stg) {
112 if (SemaRef.checkArgCount(Call: TheCall, DesiredArgCount: 1))
113 return true;
114 Expr *Arg0 = TheCall->getArg(Arg: 0);
115 ExprResult FirstArg = SemaRef.DefaultFunctionArrayLvalueConversion(E: Arg0);
116 if (FirstArg.isInvalid())
117 return true;
118
119 QualType FirstArgType = FirstArg.get()->getType();
120 if (!FirstArgType->isAnyPointerType())
121 return Diag(Loc: TheCall->getBeginLoc(), DiagID: diag::err_memtag_arg_must_be_pointer)
122 << "first" << FirstArgType << Arg0->getSourceRange();
123 TheCall->setArg(Arg: 0, ArgExpr: FirstArg.get());
124
125 // Derive the return type from the pointer argument.
126 if (BuiltinID == AArch64::BI__builtin_arm_ldg)
127 TheCall->setType(FirstArgType);
128 return false;
129 }
130
131 if (BuiltinID == AArch64::BI__builtin_arm_subp) {
132 Expr *ArgA = TheCall->getArg(Arg: 0);
133 Expr *ArgB = TheCall->getArg(Arg: 1);
134
135 ExprResult ArgExprA = SemaRef.DefaultFunctionArrayLvalueConversion(E: ArgA);
136 ExprResult ArgExprB = SemaRef.DefaultFunctionArrayLvalueConversion(E: ArgB);
137
138 if (ArgExprA.isInvalid() || ArgExprB.isInvalid())
139 return true;
140
141 QualType ArgTypeA = ArgExprA.get()->getType();
142 QualType ArgTypeB = ArgExprB.get()->getType();
143
144 auto isNull = [&](Expr *E) -> bool {
145 return E->isNullPointerConstant(Ctx&: Context,
146 NPC: Expr::NPC_ValueDependentIsNotNull);
147 };
148
149 // argument should be either a pointer or null
150 if (!ArgTypeA->isAnyPointerType() && !isNull(ArgA))
151 return Diag(Loc: TheCall->getBeginLoc(), DiagID: diag::err_memtag_arg_null_or_pointer)
152 << "first" << ArgTypeA << ArgA->getSourceRange();
153
154 if (!ArgTypeB->isAnyPointerType() && !isNull(ArgB))
155 return Diag(Loc: TheCall->getBeginLoc(), DiagID: diag::err_memtag_arg_null_or_pointer)
156 << "second" << ArgTypeB << ArgB->getSourceRange();
157
158 // Ensure Pointee types are compatible
159 if (ArgTypeA->isAnyPointerType() && !isNull(ArgA) &&
160 ArgTypeB->isAnyPointerType() && !isNull(ArgB)) {
161 QualType pointeeA = ArgTypeA->getPointeeType();
162 QualType pointeeB = ArgTypeB->getPointeeType();
163 if (!Context.typesAreCompatible(
164 T1: Context.getCanonicalType(T: pointeeA).getUnqualifiedType(),
165 T2: Context.getCanonicalType(T: pointeeB).getUnqualifiedType())) {
166 return Diag(Loc: TheCall->getBeginLoc(),
167 DiagID: diag::err_typecheck_sub_ptr_compatible)
168 << ArgTypeA << ArgTypeB << ArgA->getSourceRange()
169 << ArgB->getSourceRange();
170 }
171 }
172
173 // at least one argument should be pointer type
174 if (!ArgTypeA->isAnyPointerType() && !ArgTypeB->isAnyPointerType())
175 return Diag(Loc: TheCall->getBeginLoc(), DiagID: diag::err_memtag_any2arg_pointer)
176 << ArgTypeA << ArgTypeB << ArgA->getSourceRange();
177
178 if (isNull(ArgA)) // adopt type of the other pointer
179 ArgExprA =
180 SemaRef.ImpCastExprToType(E: ArgExprA.get(), Type: ArgTypeB, CK: CK_NullToPointer);
181
182 if (isNull(ArgB))
183 ArgExprB =
184 SemaRef.ImpCastExprToType(E: ArgExprB.get(), Type: ArgTypeA, CK: CK_NullToPointer);
185
186 TheCall->setArg(Arg: 0, ArgExpr: ArgExprA.get());
187 TheCall->setArg(Arg: 1, ArgExpr: ArgExprB.get());
188 return false;
189 }
190 assert(false && "Unhandled ARM MTE intrinsic");
191 return true;
192}
193
194/// BuiltinARMSpecialReg - Handle a check if argument ArgNum of CallExpr
195/// TheCall is an ARM/AArch64 special register string literal.
196bool SemaARM::BuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall,
197 int ArgNum, unsigned ExpectedFieldNum,
198 bool AllowName) {
199 bool IsARMBuiltin = BuiltinID == ARM::BI__builtin_arm_rsr64 ||
200 BuiltinID == ARM::BI__builtin_arm_wsr64 ||
201 BuiltinID == ARM::BI__builtin_arm_rsr ||
202 BuiltinID == ARM::BI__builtin_arm_rsrp ||
203 BuiltinID == ARM::BI__builtin_arm_wsr ||
204 BuiltinID == ARM::BI__builtin_arm_wsrp;
205 bool IsAArch64Builtin = BuiltinID == AArch64::BI__builtin_arm_rsr64 ||
206 BuiltinID == AArch64::BI__builtin_arm_wsr64 ||
207 BuiltinID == AArch64::BI__builtin_arm_rsr128 ||
208 BuiltinID == AArch64::BI__builtin_arm_wsr128 ||
209 BuiltinID == AArch64::BI__builtin_arm_rsr ||
210 BuiltinID == AArch64::BI__builtin_arm_rsrp ||
211 BuiltinID == AArch64::BI__builtin_arm_wsr ||
212 BuiltinID == AArch64::BI__builtin_arm_wsrp;
213 assert((IsARMBuiltin || IsAArch64Builtin) && "Unexpected ARM builtin.");
214
215 // We can't check the value of a dependent argument.
216 Expr *Arg = TheCall->getArg(Arg: ArgNum);
217 if (Arg->isTypeDependent() || Arg->isValueDependent())
218 return false;
219
220 // Check if the argument is a string literal.
221 if (!isa<StringLiteral>(Val: Arg->IgnoreParenImpCasts()))
222 return Diag(Loc: TheCall->getBeginLoc(), DiagID: diag::err_expr_not_string_literal)
223 << Arg->getSourceRange();
224
225 // Check the type of special register given.
226 StringRef Reg = cast<StringLiteral>(Val: Arg->IgnoreParenImpCasts())->getString();
227 SmallVector<StringRef, 6> Fields;
228 Reg.split(A&: Fields, Separator: ":");
229
230 if (Fields.size() != ExpectedFieldNum && !(AllowName && Fields.size() == 1))
231 return Diag(Loc: TheCall->getBeginLoc(), DiagID: diag::err_arm_invalid_specialreg)
232 << Arg->getSourceRange();
233
234 // If the string is the name of a register then we cannot check that it is
235 // valid here but if the string is of one the forms described in ACLE then we
236 // can check that the supplied fields are integers and within the valid
237 // ranges.
238 if (Fields.size() > 1) {
239 bool FiveFields = Fields.size() == 5;
240
241 bool ValidString = true;
242 if (IsARMBuiltin) {
243 ValidString &= Fields[0].starts_with_insensitive(Prefix: "cp") ||
244 Fields[0].starts_with_insensitive(Prefix: "p");
245 if (ValidString)
246 Fields[0] = Fields[0].drop_front(
247 N: Fields[0].starts_with_insensitive(Prefix: "cp") ? 2 : 1);
248
249 ValidString &= Fields[2].starts_with_insensitive(Prefix: "c");
250 if (ValidString)
251 Fields[2] = Fields[2].drop_front(N: 1);
252
253 if (FiveFields) {
254 ValidString &= Fields[3].starts_with_insensitive(Prefix: "c");
255 if (ValidString)
256 Fields[3] = Fields[3].drop_front(N: 1);
257 }
258 }
259
260 SmallVector<int, 5> FieldBitWidths;
261 if (FiveFields)
262 FieldBitWidths.append(IL: {IsAArch64Builtin ? 2 : 4, 3, 4, 4, 3});
263 else
264 FieldBitWidths.append(IL: {4, 3, 4});
265
266 for (unsigned i = 0; i < Fields.size(); ++i) {
267 int IntField;
268 ValidString &= !Fields[i].getAsInteger(Radix: 10, Result&: IntField);
269 ValidString &= (IntField >= 0 && IntField < (1 << FieldBitWidths[i]));
270 }
271
272 if (!ValidString)
273 return Diag(Loc: TheCall->getBeginLoc(), DiagID: diag::err_arm_invalid_specialreg)
274 << Arg->getSourceRange();
275 } else if (IsAArch64Builtin && Fields.size() == 1) {
276 // This code validates writes to PSTATE registers.
277
278 // Not a write.
279 if (TheCall->getNumArgs() != 2)
280 return false;
281
282 // The 128-bit system register accesses do not touch PSTATE.
283 if (BuiltinID == AArch64::BI__builtin_arm_rsr128 ||
284 BuiltinID == AArch64::BI__builtin_arm_wsr128)
285 return false;
286
287 // These are the named PSTATE accesses using "MSR (immediate)" instructions,
288 // along with the upper limit on the immediates allowed.
289 auto MaxLimit = llvm::StringSwitch<std::optional<unsigned>>(Reg)
290 .CaseLower(S: "spsel", Value: 15)
291 .CaseLower(S: "daifclr", Value: 15)
292 .CaseLower(S: "daifset", Value: 15)
293 .CaseLower(S: "pan", Value: 15)
294 .CaseLower(S: "uao", Value: 15)
295 .CaseLower(S: "dit", Value: 15)
296 .CaseLower(S: "ssbs", Value: 15)
297 .CaseLower(S: "tco", Value: 15)
298 .CaseLower(S: "allint", Value: 1)
299 .CaseLower(S: "pm", Value: 1)
300 .Default(Value: std::nullopt);
301
302 // If this is not a named PSTATE, just continue without validating, as this
303 // will be lowered to an "MSR (register)" instruction directly
304 if (!MaxLimit)
305 return false;
306
307 // Here we only allow constants in the range for that pstate, as required by
308 // the ACLE.
309 //
310 // While clang also accepts the names of system registers in its ACLE
311 // intrinsics, we prevent this with the PSTATE names used in MSR (immediate)
312 // as the value written via a register is different to the value used as an
313 // immediate to have the same effect. e.g., for the instruction `msr tco,
314 // x0`, it is bit 25 of register x0 that is written into PSTATE.TCO, but
315 // with `msr tco, #imm`, it is bit 0 of xN that is written into PSTATE.TCO.
316 //
317 // If a programmer wants to codegen the MSR (register) form of `msr tco,
318 // xN`, they can still do so by specifying the register using five
319 // colon-separated numbers in a string.
320 return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 1, Low: 0, High: *MaxLimit);
321 }
322
323 return false;
324}
325
326bool SemaARM::BuiltinARMAtomicHintCall(unsigned BuiltinID, CallExpr *TheCall) {
327 if (SemaRef.checkArgCount(Call: TheCall, DesiredArgCount: 4))
328 return true;
329
330 bool IsStore = BuiltinID == AArch64::BI__builtin_arm_atomic_store_with_hint;
331 ASTContext &Context = getASTContext();
332
333 // Arg 0 should be the pointer type. The pointee type must be a
334 // scalar integral type of 8, 16, 32 or 64 bits. Stores also support
335 // floating-point types.
336 auto PtrArgRes =
337 SemaRef.DefaultFunctionArrayLvalueConversion(E: TheCall->getArg(Arg: 0));
338 if (PtrArgRes.isInvalid())
339 return true;
340 auto *PtrArg = PtrArgRes.get();
341 auto *PtrTy = PtrArg->getType()->getAs<PointerType>();
342 if (!PtrTy)
343 return Diag(Loc: TheCall->getBeginLoc(),
344 DiagID: diag::err_atomic_hint_builtin_must_be_pointer)
345 << PtrArg->getType() << IsStore << PtrArg->getSourceRange();
346 TheCall->setArg(Arg: 0, ArgExpr: PtrArg);
347
348 QualType PtrQT = Context.getCanonicalType(T: PtrTy->getPointeeType());
349 if (PtrQT.isConstQualified())
350 return Diag(Loc: TheCall->getBeginLoc(),
351 DiagID: diag::err_atomic_op_needs_non_const_pointer)
352 << PtrQT << PtrArg->getSourceRange();
353
354 PtrQT = PtrQT.getUnqualifiedType();
355 if (!PtrQT->isIntegralType(Ctx: Context) &&
356 !(IsStore && (PtrQT->isFloatingType() || PtrQT->isMFloat8Type())))
357 return Diag(Loc: TheCall->getBeginLoc(),
358 DiagID: IsStore ? diag::err_atomic_op_needs_atomic_int_or_fp
359 : diag::err_atomic_op_needs_atomic_int)
360 << 0 << PtrQT << PtrArg->getSourceRange();
361
362 if (PtrQT->isBitIntType())
363 return Diag(Loc: TheCall->getBeginLoc(),
364 DiagID: diag::err_atomic_builtin_bit_int_prohibit)
365 << PtrQT << PtrArg->getSourceRange();
366
367 unsigned TySize = Context.getTypeSize(T: PtrQT);
368 if (TySize != 8 && TySize != 16 && TySize != 32 && TySize != 64)
369 return Diag(Loc: TheCall->getBeginLoc(), DiagID: diag::err_atomic_op_hint_data_size)
370 << IsStore << PtrArg->getSourceRange();
371
372 if (!IsStore)
373 TheCall->setType(PtrQT);
374
375 // Arg 1 is the data operand. The type must match the pointee
376 // type found above.
377 auto DataArgRes =
378 SemaRef.DefaultFunctionArrayLvalueConversion(E: TheCall->getArg(Arg: 1));
379 if (DataArgRes.isInvalid())
380 return true;
381 auto *DataArg = DataArgRes.get();
382 QualType DataQT =
383 Context.getCanonicalType(T: DataArg->getType()).getUnqualifiedType();
384 TheCall->setArg(Arg: 1, ArgExpr: DataArg);
385
386 if (PtrQT != DataQT)
387 return Diag(Loc: TheCall->getBeginLoc(),
388 DiagID: diag::err_typecheck_call_different_arg_types)
389 << PtrQT << DataQT;
390
391 // Arg 2 is the memory order. Stores only allow relaxed, release or seq_cst.
392 auto MemOrdArg =
393 SemaRef.DefaultFunctionArrayLvalueConversion(E: TheCall->getArg(Arg: 2));
394 if (MemOrdArg.isInvalid())
395 return true;
396 auto *MemOrd = MemOrdArg.get();
397 if (SemaRef.convertArgumentToType(Value&: MemOrd, Ty: Context.IntTy))
398 return true;
399 TheCall->setArg(Arg: 2, ArgExpr: MemOrd);
400
401 if (!MemOrd->isValueDependent()) {
402 std::optional<llvm::APSInt> MemOrdAP =
403 MemOrd->getIntegerConstantExpr(Ctx: Context);
404 if (!MemOrdAP)
405 return Diag(Loc: TheCall->getBeginLoc(),
406 DiagID: diag::err_atomic_hint_has_invalid_memory_order)
407 << MemOrd->getType() << MemOrd->getSourceRange();
408
409 unsigned Ordering = MemOrdAP->getZExtValue();
410 if (!llvm::isValidAtomicOrderingCABI(I: Ordering))
411 return Diag(Loc: TheCall->getBeginLoc(),
412 DiagID: diag::err_atomic_hint_has_invalid_memory_order)
413 << *MemOrdAP << MemOrd->getSourceRange();
414
415 auto AtomicOrdering = static_cast<llvm::AtomicOrderingCABI>(Ordering);
416 if (IsStore && AtomicOrdering != llvm::AtomicOrderingCABI::relaxed &&
417 AtomicOrdering != llvm::AtomicOrderingCABI::release &&
418 AtomicOrdering != llvm::AtomicOrderingCABI::seq_cst)
419 return Diag(Loc: TheCall->getBeginLoc(),
420 DiagID: diag::err_atomic_hint_has_invalid_memory_order)
421 << *MemOrdAP << MemOrd->getSourceRange();
422 }
423
424 // Arg 3 is the hint type. Only values represented by AArch64MemoryHint
425 // are valid. Fetch operations only allow HINT_SHUH and HINT_SHUH_PH.
426 auto HintArg =
427 SemaRef.DefaultFunctionArrayLvalueConversion(E: TheCall->getArg(Arg: 3));
428 if (HintArg.isInvalid())
429 return true;
430 auto Hint = HintArg.get();
431 if (SemaRef.convertArgumentToType(Value&: Hint, Ty: Context.IntTy))
432 return true;
433 TheCall->setArg(Arg: 3, ArgExpr: Hint);
434
435 if (!Hint->isValueDependent()) {
436 std::optional<llvm::APSInt> HintAP = Hint->getIntegerConstantExpr(Ctx: Context);
437 if (!HintAP)
438 return Diag(Loc: TheCall->getBeginLoc(),
439 DiagID: diag::err_atomic_hint_has_invalid_hint_type)
440 << Hint->getType() << Hint->getSourceRange();
441
442 auto MemoryHint = llvm::toAArch64MemoryHint(I: HintAP->getZExtValue());
443 if (MemoryHint == llvm::AArch64MemoryHint::NONE ||
444 (!IsStore && MemoryHint != llvm::AArch64MemoryHint::SHUH &&
445 MemoryHint != llvm::AArch64MemoryHint::SHUH_PH)) {
446 Diag(Loc: TheCall->getBeginLoc(), DiagID: diag::warn_atomic_hint_has_invalid_hint_type)
447 << *HintAP << Hint->getSourceRange();
448 return false;
449 }
450 }
451 return false;
452}
453
454/// getNeonEltType - Return the QualType corresponding to the elements of
455/// the vector type specified by the NeonTypeFlags. This is used to check
456/// the pointer arguments for Neon load/store intrinsics.
457static QualType getNeonEltType(NeonTypeFlags Flags, ASTContext &Context,
458 bool IsPolyUnsigned, bool IsInt64Long) {
459 switch (Flags.getEltType()) {
460 case NeonTypeFlags::Int8:
461 return Flags.isUnsigned() ? Context.UnsignedCharTy : Context.SignedCharTy;
462 case NeonTypeFlags::Int16:
463 return Flags.isUnsigned() ? Context.UnsignedShortTy : Context.ShortTy;
464 case NeonTypeFlags::Int32:
465 return Flags.isUnsigned() ? Context.UnsignedIntTy : Context.IntTy;
466 case NeonTypeFlags::Int64:
467 if (IsInt64Long)
468 return Flags.isUnsigned() ? Context.UnsignedLongTy : Context.LongTy;
469 else
470 return Flags.isUnsigned() ? Context.UnsignedLongLongTy
471 : Context.LongLongTy;
472 case NeonTypeFlags::Poly8:
473 return IsPolyUnsigned ? Context.UnsignedCharTy : Context.SignedCharTy;
474 case NeonTypeFlags::Poly16:
475 return IsPolyUnsigned ? Context.UnsignedShortTy : Context.ShortTy;
476 case NeonTypeFlags::Poly64:
477 if (IsInt64Long)
478 return Context.UnsignedLongTy;
479 else
480 return Context.UnsignedLongLongTy;
481 case NeonTypeFlags::Poly128:
482 break;
483 case NeonTypeFlags::Float16:
484 return Context.HalfTy;
485 case NeonTypeFlags::Float32:
486 return Context.FloatTy;
487 case NeonTypeFlags::Float64:
488 return Context.DoubleTy;
489 case NeonTypeFlags::BFloat16:
490 return Context.BFloat16Ty;
491 case NeonTypeFlags::MFloat8:
492 return Context.MFloat8Ty;
493 }
494 llvm_unreachable("Invalid NeonTypeFlag!");
495}
496
497enum ArmSMEState : unsigned {
498 ArmNoState = 0,
499
500 ArmInZA = 0b01,
501 ArmOutZA = 0b10,
502 ArmInOutZA = 0b11,
503 ArmZAMask = 0b11,
504
505 ArmInZT0 = 0b01 << 2,
506 ArmOutZT0 = 0b10 << 2,
507 ArmInOutZT0 = 0b11 << 2,
508 ArmZT0Mask = 0b11 << 2
509};
510
511bool SemaARM::CheckImmediateArg(CallExpr *TheCall, unsigned CheckTy,
512 unsigned ArgIdx, unsigned EltBitWidth,
513 unsigned ContainerBitWidth) {
514 // Function that checks whether the operand (ArgIdx) is an immediate
515 // that is one of a given set of values.
516 auto CheckImmediateInSet = [&](std::initializer_list<int64_t> Set,
517 int ErrDiag) -> bool {
518 // We can't check the value of a dependent argument.
519 Expr *Arg = TheCall->getArg(Arg: ArgIdx);
520 if (Arg->isTypeDependent() || Arg->isValueDependent())
521 return false;
522
523 // Check constant-ness first.
524 llvm::APSInt Imm;
525 if (SemaRef.BuiltinConstantArg(TheCall, ArgNum: ArgIdx, Result&: Imm))
526 return true;
527
528 if (!llvm::is_contained(Set, Element: Imm.getSExtValue()))
529 return Diag(Loc: TheCall->getBeginLoc(), DiagID: ErrDiag) << Arg->getSourceRange();
530 return false;
531 };
532
533 switch ((ImmCheckType)CheckTy) {
534 case ImmCheckType::ImmCheck0_31:
535 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: ArgIdx, Low: 0, High: 31))
536 return true;
537 break;
538 case ImmCheckType::ImmCheck0_13:
539 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: ArgIdx, Low: 0, High: 13))
540 return true;
541 break;
542 case ImmCheckType::ImmCheck0_63:
543 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: ArgIdx, Low: 0, High: 63))
544 return true;
545 break;
546 case ImmCheckType::ImmCheck1_16:
547 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: ArgIdx, Low: 1, High: 16))
548 return true;
549 break;
550 case ImmCheckType::ImmCheck0_7:
551 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: ArgIdx, Low: 0, High: 7))
552 return true;
553 break;
554 case ImmCheckType::ImmCheck1_1:
555 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: ArgIdx, Low: 1, High: 1))
556 return true;
557 break;
558 case ImmCheckType::ImmCheck1_3:
559 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: ArgIdx, Low: 1, High: 3))
560 return true;
561 break;
562 case ImmCheckType::ImmCheck1_7:
563 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: ArgIdx, Low: 1, High: 7))
564 return true;
565 break;
566 case ImmCheckType::ImmCheckExtract:
567 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: ArgIdx, Low: 0,
568 High: (2048 / EltBitWidth) - 1))
569 return true;
570 break;
571 case ImmCheckType::ImmCheckCvt:
572 case ImmCheckType::ImmCheckShiftRight:
573 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: ArgIdx, Low: 1, High: EltBitWidth))
574 return true;
575 break;
576 case ImmCheckType::ImmCheckShiftRightNarrow:
577 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: ArgIdx, Low: 1, High: EltBitWidth / 2))
578 return true;
579 break;
580 case ImmCheckType::ImmCheckShiftLeft:
581 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: ArgIdx, Low: 0, High: EltBitWidth - 1))
582 return true;
583 break;
584 case ImmCheckType::ImmCheckShiftLeftLong:
585 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: ArgIdx, Low: 0, High: (EltBitWidth / 2)))
586 return true;
587 break;
588 case ImmCheckType::ImmCheckLaneIndex:
589 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: ArgIdx, Low: 0,
590 High: (ContainerBitWidth / EltBitWidth) - 1))
591 return true;
592 break;
593 case ImmCheckType::ImmCheckLaneIndexCompRotate:
594 if (SemaRef.BuiltinConstantArgRange(
595 TheCall, ArgNum: ArgIdx, Low: 0, High: (ContainerBitWidth / (2 * EltBitWidth)) - 1))
596 return true;
597 break;
598 case ImmCheckType::ImmCheckLaneIndexDot:
599 if (SemaRef.BuiltinConstantArgRange(
600 TheCall, ArgNum: ArgIdx, Low: 0, High: (ContainerBitWidth / (4 * EltBitWidth)) - 1))
601 return true;
602 break;
603 case ImmCheckType::ImmCheckComplexRot90_270:
604 if (CheckImmediateInSet({90, 270}, diag::err_rotation_argument_to_cadd))
605 return true;
606 break;
607 case ImmCheckType::ImmCheckComplexRotAll90:
608 if (CheckImmediateInSet({0, 90, 180, 270},
609 diag::err_rotation_argument_to_cmla))
610 return true;
611 break;
612 case ImmCheckType::ImmCheck0_1:
613 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: ArgIdx, Low: 0, High: 1))
614 return true;
615 break;
616 case ImmCheckType::ImmCheck0_2:
617 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: ArgIdx, Low: 0, High: 2))
618 return true;
619 break;
620 case ImmCheckType::ImmCheck0_3:
621 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: ArgIdx, Low: 0, High: 3))
622 return true;
623 break;
624 case ImmCheckType::ImmCheck0_0:
625 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: ArgIdx, Low: 0, High: 0))
626 return true;
627 break;
628 case ImmCheckType::ImmCheck0_15:
629 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: ArgIdx, Low: 0, High: 15))
630 return true;
631 break;
632 case ImmCheckType::ImmCheck0_255:
633 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: ArgIdx, Low: 0, High: 255))
634 return true;
635 break;
636 case ImmCheckType::ImmCheck1_32:
637 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: ArgIdx, Low: 1, High: 32))
638 return true;
639 break;
640 case ImmCheckType::ImmCheck1_64:
641 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: ArgIdx, Low: 1, High: 64))
642 return true;
643 break;
644 case ImmCheckType::ImmCheck2_4_Mul2:
645 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: ArgIdx, Low: 2, High: 4) ||
646 SemaRef.BuiltinConstantArgMultiple(TheCall, ArgNum: ArgIdx, Multiple: 2))
647 return true;
648 break;
649 }
650 return false;
651}
652
653bool SemaARM::PerformNeonImmChecks(
654 CallExpr *TheCall,
655 SmallVectorImpl<std::tuple<int, int, int, int>> &ImmChecks,
656 int OverloadType) {
657 bool HasError = false;
658
659 for (const auto &I : ImmChecks) {
660 auto [ArgIdx, CheckTy, ElementBitWidth, VecBitWidth] = I;
661
662 if (OverloadType >= 0)
663 ElementBitWidth = NeonTypeFlags(OverloadType).getEltSizeInBits();
664
665 HasError |= CheckImmediateArg(TheCall, CheckTy, ArgIdx, EltBitWidth: ElementBitWidth,
666 ContainerBitWidth: VecBitWidth);
667 }
668
669 return HasError;
670}
671
672bool SemaARM::PerformSVEImmChecks(
673 CallExpr *TheCall, SmallVectorImpl<std::tuple<int, int, int>> &ImmChecks) {
674 bool HasError = false;
675
676 for (const auto &I : ImmChecks) {
677 auto [ArgIdx, CheckTy, ElementBitWidth] = I;
678 HasError |=
679 CheckImmediateArg(TheCall, CheckTy, ArgIdx, EltBitWidth: ElementBitWidth, ContainerBitWidth: 128);
680 }
681
682 return HasError;
683}
684
685SemaARM::ArmStreamingType getArmStreamingFnType(const FunctionDecl *FD) {
686 if (FD->hasAttr<ArmLocallyStreamingAttr>())
687 return SemaARM::ArmStreaming;
688 if (const Type *Ty = FD->getType().getTypePtrOrNull()) {
689 if (const auto *FPT = Ty->getAs<FunctionProtoType>()) {
690 if (FPT->getAArch64SMEAttributes() &
691 FunctionType::SME_PStateSMEnabledMask)
692 return SemaARM::ArmStreaming;
693 if (FPT->getAArch64SMEAttributes() &
694 FunctionType::SME_PStateSMCompatibleMask)
695 return SemaARM::ArmStreamingCompatible;
696 }
697 }
698 return SemaARM::ArmNonStreaming;
699}
700
701static bool checkArmStreamingBuiltin(Sema &S, CallExpr *TheCall,
702 const FunctionDecl *FD,
703 SemaARM::ArmStreamingType BuiltinType,
704 unsigned BuiltinID) {
705 SemaARM::ArmStreamingType FnType = getArmStreamingFnType(FD);
706
707 // Check if the intrinsic is available in the right mode, i.e.
708 // * When compiling for SME only, the caller must be in streaming mode.
709 // * When compiling for SVE only, the caller must be in non-streaming mode.
710 // * When compiling for both SVE and SME, the caller can be in either mode.
711 if (BuiltinType == SemaARM::VerifyRuntimeMode) {
712 llvm::StringMap<bool> CallerFeatures;
713 S.Context.getFunctionFeatureMap(FeatureMap&: CallerFeatures, FD);
714
715 // Avoid emitting diagnostics for a function that can never compile.
716 if (FnType == SemaARM::ArmStreaming && !CallerFeatures["sme"])
717 return false;
718
719 const auto FindTopLevelPipe = [](const char *S) {
720 unsigned Depth = 0;
721 unsigned I = 0, E = strlen(s: S);
722 for (; I < E; ++I) {
723 if (S[I] == '|' && Depth == 0)
724 break;
725 if (S[I] == '(')
726 ++Depth;
727 else if (S[I] == ')')
728 --Depth;
729 }
730 return I;
731 };
732
733 const char *RequiredFeatures =
734 S.Context.BuiltinInfo.getRequiredFeatures(ID: BuiltinID);
735 unsigned PipeIdx = FindTopLevelPipe(RequiredFeatures);
736 assert(PipeIdx != 0 && PipeIdx != strlen(RequiredFeatures) &&
737 "Expected feature string of the form 'SVE-EXPR|SME-EXPR'");
738 StringRef NonStreamingBuiltinGuard = StringRef(RequiredFeatures, PipeIdx);
739 StringRef StreamingBuiltinGuard = StringRef(RequiredFeatures + PipeIdx + 1);
740
741 bool SatisfiesSVE = Builtin::evaluateRequiredTargetFeatures(
742 RequiredFatures: NonStreamingBuiltinGuard, TargetFetureMap: CallerFeatures);
743 bool SatisfiesSME = Builtin::evaluateRequiredTargetFeatures(
744 RequiredFatures: StreamingBuiltinGuard, TargetFetureMap: CallerFeatures);
745
746 if (SatisfiesSVE && SatisfiesSME)
747 // Function type is irrelevant for streaming-agnostic builtins.
748 return false;
749 else if (SatisfiesSVE)
750 BuiltinType = SemaARM::ArmNonStreaming;
751 else if (SatisfiesSME)
752 BuiltinType = SemaARM::ArmStreaming;
753 else
754 // This should be diagnosed by CodeGen
755 return false;
756 }
757
758 if (FnType != SemaARM::ArmNonStreaming &&
759 BuiltinType == SemaARM::ArmNonStreaming)
760 S.Diag(Loc: TheCall->getBeginLoc(), DiagID: diag::err_attribute_arm_sm_incompat_builtin)
761 << TheCall->getSourceRange() << "non-streaming";
762 else if (FnType != SemaARM::ArmStreaming &&
763 BuiltinType == SemaARM::ArmStreaming)
764 S.Diag(Loc: TheCall->getBeginLoc(), DiagID: diag::err_attribute_arm_sm_incompat_builtin)
765 << TheCall->getSourceRange() << "streaming";
766 else
767 return false;
768
769 return true;
770}
771
772static ArmSMEState getSMEState(unsigned BuiltinID) {
773 switch (BuiltinID) {
774 default:
775 return ArmNoState;
776#define GET_SME_BUILTIN_GET_STATE
777#include "clang/Basic/arm_sme_builtins_za_state.inc"
778#undef GET_SME_BUILTIN_GET_STATE
779 }
780}
781
782bool SemaARM::CheckSMEBuiltinFunctionCall(unsigned BuiltinID,
783 CallExpr *TheCall) {
784 if (const FunctionDecl *FD =
785 SemaRef.getCurFunctionDecl(/*AllowLambda=*/true)) {
786 std::optional<ArmStreamingType> BuiltinType;
787
788 switch (BuiltinID) {
789#define GET_SME_STREAMING_ATTRS
790#include "clang/Basic/arm_sme_streaming_attrs.inc"
791#undef GET_SME_STREAMING_ATTRS
792 }
793
794 if (BuiltinType &&
795 checkArmStreamingBuiltin(S&: SemaRef, TheCall, FD, BuiltinType: *BuiltinType, BuiltinID))
796 return true;
797
798 if ((getSMEState(BuiltinID) & ArmZAMask) && !hasArmZAState(FD)) {
799 Diag(Loc: TheCall->getBeginLoc(),
800 DiagID: diag::err_attribute_arm_za_builtin_no_za_state)
801 << TheCall->getSourceRange();
802 return true;
803 }
804
805 if ((getSMEState(BuiltinID) & ArmZT0Mask) && !hasArmZT0State(FD)) {
806 Diag(Loc: TheCall->getBeginLoc(),
807 DiagID: diag::err_attribute_arm_zt0_builtin_no_zt0_state)
808 << TheCall->getSourceRange();
809 return true;
810 }
811 }
812
813 // Range check SME intrinsics that take immediate values.
814 SmallVector<std::tuple<int, int, int>, 3> ImmChecks;
815
816 switch (BuiltinID) {
817 default:
818 return false;
819#define GET_SME_IMMEDIATE_CHECK
820#include "clang/Basic/arm_sme_sema_rangechecks.inc"
821#undef GET_SME_IMMEDIATE_CHECK
822 }
823
824 return PerformSVEImmChecks(TheCall, ImmChecks);
825}
826
827bool SemaARM::CheckSVEBuiltinFunctionCall(unsigned BuiltinID,
828 CallExpr *TheCall) {
829 if (const FunctionDecl *FD =
830 SemaRef.getCurFunctionDecl(/*AllowLambda=*/true)) {
831 std::optional<ArmStreamingType> BuiltinType;
832
833 switch (BuiltinID) {
834#define GET_SVE_STREAMING_ATTRS
835#include "clang/Basic/arm_sve_streaming_attrs.inc"
836#undef GET_SVE_STREAMING_ATTRS
837 }
838 if (BuiltinType &&
839 checkArmStreamingBuiltin(S&: SemaRef, TheCall, FD, BuiltinType: *BuiltinType, BuiltinID))
840 return true;
841 }
842 // Range check SVE intrinsics that take immediate values.
843 SmallVector<std::tuple<int, int, int>, 3> ImmChecks;
844
845 switch (BuiltinID) {
846 default:
847 return false;
848#define GET_SVE_IMMEDIATE_CHECK
849#include "clang/Basic/arm_sve_sema_rangechecks.inc"
850#undef GET_SVE_IMMEDIATE_CHECK
851 }
852
853 return PerformSVEImmChecks(TheCall, ImmChecks);
854}
855
856bool SemaARM::CheckNeonBuiltinFunctionCall(const TargetInfo &TI,
857 unsigned BuiltinID,
858 CallExpr *TheCall) {
859 if (const FunctionDecl *FD =
860 SemaRef.getCurFunctionDecl(/*AllowLambda=*/true)) {
861 std::optional<ArmStreamingType> BuiltinType;
862
863 switch (BuiltinID) {
864 default:
865 break;
866#define GET_NEON_STREAMING_COMPAT_FLAG
867#include "clang/Basic/arm_neon.inc"
868#undef GET_NEON_STREAMING_COMPAT_FLAG
869 }
870 if (BuiltinType &&
871 checkArmStreamingBuiltin(S&: SemaRef, TheCall, FD, BuiltinType: *BuiltinType, BuiltinID))
872 return true;
873 }
874
875 llvm::APSInt Result;
876 uint64_t mask = 0;
877 int TV = -1;
878 int PtrArgNum = -1;
879 bool HasConstPtr = false;
880 switch (BuiltinID) {
881#define GET_NEON_OVERLOAD_CHECK
882#include "clang/Basic/arm_fp16.inc"
883#include "clang/Basic/arm_neon.inc"
884#undef GET_NEON_OVERLOAD_CHECK
885 }
886
887 // For NEON intrinsics which are overloaded on vector element type, validate
888 // the immediate which specifies which variant to emit.
889 if (mask) {
890 unsigned ImmArg = TheCall->getNumArgs() - 1;
891 if (SemaRef.BuiltinConstantArg(TheCall, ArgNum: ImmArg, Result))
892 return true;
893
894 // FIXME: This is effectively dead code. Change the logic above so that the
895 // following check is actually run.
896 TV = Result.getLimitedValue(Limit: 64);
897 if ((TV > 63) || (mask & (1ULL << TV)) == 0)
898 return Diag(Loc: TheCall->getBeginLoc(), DiagID: diag::err_invalid_neon_type_code)
899 << TheCall->getArg(Arg: ImmArg)->getSourceRange();
900 }
901
902 if (PtrArgNum >= 0) {
903 // Check that pointer arguments have the specified type.
904 Expr *Arg = TheCall->getArg(Arg: PtrArgNum);
905 if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Val: Arg))
906 Arg = ICE->getSubExpr();
907 ExprResult RHS = SemaRef.DefaultFunctionArrayLvalueConversion(E: Arg);
908 QualType RHSTy = RHS.get()->getType();
909
910 llvm::Triple::ArchType Arch = TI.getTriple().getArch();
911 bool IsPolyUnsigned = Arch == llvm::Triple::aarch64 ||
912 Arch == llvm::Triple::aarch64_32 ||
913 Arch == llvm::Triple::aarch64_be;
914 bool IsInt64Long = TI.getInt64Type() == TargetInfo::SignedLong;
915 QualType EltTy = getNeonEltType(Flags: NeonTypeFlags(TV), Context&: getASTContext(),
916 IsPolyUnsigned, IsInt64Long);
917 if (HasConstPtr)
918 EltTy = EltTy.withConst();
919 QualType LHSTy = getASTContext().getPointerType(T: EltTy);
920 AssignConvertType ConvTy;
921 ConvTy = SemaRef.CheckSingleAssignmentConstraints(LHSType: LHSTy, RHS);
922 if (RHS.isInvalid())
923 return true;
924 if (SemaRef.DiagnoseAssignmentResult(ConvTy, Loc: Arg->getBeginLoc(), DstType: LHSTy,
925 SrcType: RHSTy, SrcExpr: RHS.get(),
926 Action: AssignmentAction::Assigning))
927 return true;
928 }
929
930 // For NEON intrinsics which take an immediate value as part of the
931 // instruction, range check them here.
932 SmallVector<std::tuple<int, int, int, int>, 2> ImmChecks;
933 switch (BuiltinID) {
934 default:
935 return false;
936#define GET_NEON_IMMEDIATE_CHECK
937#include "clang/Basic/arm_fp16.inc"
938#include "clang/Basic/arm_neon.inc"
939#undef GET_NEON_IMMEDIATE_CHECK
940 }
941
942 return PerformNeonImmChecks(TheCall, ImmChecks, OverloadType: TV);
943}
944
945bool SemaARM::CheckMVEBuiltinFunctionCall(unsigned BuiltinID,
946 CallExpr *TheCall) {
947 switch (BuiltinID) {
948 default:
949 return false;
950#include "clang/Basic/arm_mve_builtin_sema.inc"
951 }
952}
953
954bool SemaARM::CheckCDEBuiltinFunctionCall(const TargetInfo &TI,
955 unsigned BuiltinID,
956 CallExpr *TheCall) {
957 bool Err = false;
958 switch (BuiltinID) {
959 default:
960 return false;
961#include "clang/Basic/arm_cde_builtin_sema.inc"
962 }
963
964 if (Err)
965 return true;
966
967 return CheckARMCoprocessorImmediate(TI, CoprocArg: TheCall->getArg(Arg: 0), /*WantCDE*/ true);
968}
969
970bool SemaARM::CheckARMCoprocessorImmediate(const TargetInfo &TI,
971 const Expr *CoprocArg,
972 bool WantCDE) {
973 ASTContext &Context = getASTContext();
974 if (SemaRef.isConstantEvaluatedContext())
975 return false;
976
977 // We can't check the value of a dependent argument.
978 if (CoprocArg->isTypeDependent() || CoprocArg->isValueDependent())
979 return false;
980
981 llvm::APSInt CoprocNoAP = *CoprocArg->getIntegerConstantExpr(Ctx: Context);
982 int64_t CoprocNo = CoprocNoAP.getExtValue();
983 assert(CoprocNo >= 0 && "Coprocessor immediate must be non-negative");
984
985 uint32_t CDECoprocMask = TI.getARMCDECoprocMask();
986 bool IsCDECoproc = CoprocNo <= 7 && (CDECoprocMask & (1 << CoprocNo));
987
988 if (IsCDECoproc != WantCDE)
989 return Diag(Loc: CoprocArg->getBeginLoc(), DiagID: diag::err_arm_invalid_coproc)
990 << (int)CoprocNo << (int)WantCDE << CoprocArg->getSourceRange();
991
992 return false;
993}
994
995bool SemaARM::CheckARMBuiltinExclusiveCall(const TargetInfo &TI,
996 unsigned BuiltinID,
997 CallExpr *TheCall) {
998 assert((BuiltinID == ARM::BI__builtin_arm_ldrex ||
999 BuiltinID == ARM::BI__builtin_arm_ldrexd ||
1000 BuiltinID == ARM::BI__builtin_arm_ldaex ||
1001 BuiltinID == ARM::BI__builtin_arm_strex ||
1002 BuiltinID == ARM::BI__builtin_arm_strexd ||
1003 BuiltinID == ARM::BI__builtin_arm_stlex ||
1004 BuiltinID == AArch64::BI__builtin_arm_ldrex ||
1005 BuiltinID == AArch64::BI__builtin_arm_ldaex ||
1006 BuiltinID == AArch64::BI__builtin_arm_strex ||
1007 BuiltinID == AArch64::BI__builtin_arm_stlex) &&
1008 "unexpected ARM builtin");
1009 bool IsLdrex = BuiltinID == ARM::BI__builtin_arm_ldrex ||
1010 BuiltinID == ARM::BI__builtin_arm_ldrexd ||
1011 BuiltinID == ARM::BI__builtin_arm_ldaex ||
1012 BuiltinID == AArch64::BI__builtin_arm_ldrex ||
1013 BuiltinID == AArch64::BI__builtin_arm_ldaex;
1014 bool IsDoubleWord = BuiltinID == ARM::BI__builtin_arm_ldrexd ||
1015 BuiltinID == ARM::BI__builtin_arm_strexd;
1016
1017 ASTContext &Context = getASTContext();
1018 DeclRefExpr *DRE =
1019 cast<DeclRefExpr>(Val: TheCall->getCallee()->IgnoreParenCasts());
1020
1021 // Ensure that we have the proper number of arguments.
1022 if (SemaRef.checkArgCount(Call: TheCall, DesiredArgCount: IsLdrex ? 1 : 2))
1023 return true;
1024
1025 // Inspect the pointer argument of the atomic builtin. This should always be
1026 // a pointer type, whose element is an integral scalar or pointer type.
1027 // Because it is a pointer type, we don't have to worry about any implicit
1028 // casts here.
1029 Expr *PointerArg = TheCall->getArg(Arg: IsLdrex ? 0 : 1);
1030 ExprResult PointerArgRes =
1031 SemaRef.DefaultFunctionArrayLvalueConversion(E: PointerArg);
1032 if (PointerArgRes.isInvalid())
1033 return true;
1034 PointerArg = PointerArgRes.get();
1035
1036 const PointerType *pointerType = PointerArg->getType()->getAs<PointerType>();
1037 if (!pointerType) {
1038 Diag(Loc: DRE->getBeginLoc(), DiagID: diag::err_atomic_builtin_must_be_pointer)
1039 << PointerArg->getType() << 0 << PointerArg->getSourceRange();
1040 return true;
1041 }
1042
1043 // ldrex takes a "const volatile T*" and strex takes a "volatile T*". Our next
1044 // task is to insert the appropriate casts into the AST. First work out just
1045 // what the appropriate type is.
1046 QualType ValType = pointerType->getPointeeType();
1047 QualType AddrType = ValType.getUnqualifiedType().withVolatile();
1048 if (IsLdrex)
1049 AddrType.addConst();
1050
1051 // Issue a warning if the cast is dodgy.
1052 CastKind CastNeeded = CK_NoOp;
1053 if (!AddrType.isAtLeastAsQualifiedAs(other: ValType, Ctx: getASTContext())) {
1054 CastNeeded = CK_BitCast;
1055 Diag(Loc: DRE->getBeginLoc(), DiagID: diag::ext_typecheck_convert_discards_qualifiers)
1056 << PointerArg->getType() << Context.getPointerType(T: AddrType)
1057 << AssignmentAction::Passing << PointerArg->getSourceRange();
1058 }
1059
1060 // Finally, do the cast and replace the argument with the corrected version.
1061 AddrType = Context.getPointerType(T: AddrType);
1062 PointerArgRes = SemaRef.ImpCastExprToType(E: PointerArg, Type: AddrType, CK: CastNeeded);
1063 if (PointerArgRes.isInvalid())
1064 return true;
1065 PointerArg = PointerArgRes.get();
1066
1067 TheCall->setArg(Arg: IsLdrex ? 0 : 1, ArgExpr: PointerArg);
1068
1069 // In general, we allow ints, floats and pointers to be loaded and stored.
1070 if (!ValType->isIntegerType() && !ValType->isAnyPointerType() &&
1071 !ValType->isBlockPointerType() && !ValType->isFloatingType()) {
1072 Diag(Loc: DRE->getBeginLoc(), DiagID: diag::err_atomic_builtin_must_be_pointer_intfltptr)
1073 << PointerArg->getType() << 0 << PointerArg->getSourceRange();
1074 return true;
1075 }
1076
1077 // Check whether the size of the type can be handled atomically on this
1078 // target.
1079 if (!TI.getTriple().isAArch64()) {
1080 unsigned Mask = TI.getARMLDREXMask();
1081 unsigned Bits = Context.getTypeSize(T: ValType);
1082 if (IsDoubleWord) {
1083 // Explicit request for ldrexd/strexd means only double word sizes
1084 // supported if the target supports them.
1085 Mask &= TargetInfo::ARM_LDREX_D;
1086 }
1087 bool Supported =
1088 (llvm::isPowerOf2_64(Value: Bits)) && Bits >= 8 && (Mask & (Bits / 8));
1089
1090 if (!Supported) {
1091 // Emit a diagnostic saying that this size isn't available. If _no_ size
1092 // of exclusive access is supported on this target, we emit a diagnostic
1093 // with special wording for that case, but otherwise, we emit
1094 // err_atomic_exclusive_builtin_pointer_size and loop over `Mask` to
1095 // control what subset of sizes it lists as legal.
1096 if (Mask) {
1097 auto D = Diag(Loc: DRE->getBeginLoc(),
1098 DiagID: diag::err_atomic_exclusive_builtin_pointer_size)
1099 << PointerArg->getType();
1100 bool Started = false;
1101 for (unsigned Size = 1; Size <= 8; Size <<= 1) {
1102 // For each of the sizes 1,2,4,8, pass two integers into the
1103 // diagnostic. The first selects a separator from the previous
1104 // number: 0 for no separator at all, 1 for a comma, 2 for " or "
1105 // which appears before the final number in a list of more than one.
1106 // The second integer just indicates whether we print this size in
1107 // the message at all.
1108 if (!(Mask & Size)) {
1109 // This size isn't one of the supported ones, so emit no separator
1110 // text and don't print the size itself.
1111 D << 0 << 0;
1112 } else {
1113 // This size is supported, so print it, and an appropriate
1114 // separator.
1115 Mask &= ~Size;
1116 if (!Started)
1117 D << 0; // No separator if this is the first size we've printed
1118 else if (Mask)
1119 D << 1; // "," if there's still another size to come
1120 else
1121 D << 2; // " or " if the size we're about to print is the last
1122 D << 1; // print the size itself
1123 Started = true;
1124 }
1125 }
1126 } else {
1127 bool EmitDoubleWordDiagnostic =
1128 IsDoubleWord && !Mask && TI.getARMLDREXMask();
1129 Diag(Loc: DRE->getBeginLoc(),
1130 DiagID: diag::err_atomic_exclusive_builtin_pointer_size_none)
1131 << (EmitDoubleWordDiagnostic ? 1 : 0)
1132 << PointerArg->getSourceRange();
1133 }
1134 }
1135 }
1136
1137 switch (ValType.getObjCLifetime()) {
1138 case Qualifiers::OCL_None:
1139 case Qualifiers::OCL_ExplicitNone:
1140 // okay
1141 break;
1142
1143 case Qualifiers::OCL_Weak:
1144 case Qualifiers::OCL_Strong:
1145 case Qualifiers::OCL_Autoreleasing:
1146 Diag(Loc: DRE->getBeginLoc(), DiagID: diag::err_arc_atomic_ownership)
1147 << ValType << PointerArg->getSourceRange();
1148 return true;
1149 }
1150
1151 if (IsLdrex) {
1152 TheCall->setType(ValType);
1153 return false;
1154 }
1155
1156 // Initialize the argument to be stored.
1157 ExprResult ValArg = TheCall->getArg(Arg: 0);
1158 InitializedEntity Entity = InitializedEntity::InitializeParameter(
1159 Context, Type: ValType, /*consume*/ Consumed: false);
1160 ValArg = SemaRef.PerformCopyInitialization(Entity, EqualLoc: SourceLocation(), Init: ValArg);
1161 if (ValArg.isInvalid())
1162 return true;
1163 TheCall->setArg(Arg: 0, ArgExpr: ValArg.get());
1164
1165 // __builtin_arm_strex always returns an int. It's marked as such in the .def,
1166 // but the custom checker bypasses all default analysis.
1167 TheCall->setType(Context.IntTy);
1168 return false;
1169}
1170
1171static bool checkFPMScaleIfConstant(Sema &S, CallExpr *Call, unsigned ArgNum,
1172 int64_t Low, int64_t High) {
1173 Expr *Arg = Call->getArg(Arg: ArgNum);
1174
1175 if (Arg->isTypeDependent() || Arg->isValueDependent())
1176 return false;
1177
1178 std::optional<llvm::APSInt> Value = Arg->getIntegerConstantExpr(Ctx: S.Context);
1179
1180 // Runtime value: accept it.
1181 if (!Value)
1182 return false;
1183
1184 if (*Value < Low || *Value > High)
1185 return S.Diag(Loc: Call->getBeginLoc(), DiagID: diag::warn_argument_invalid_range)
1186 << toString(I: *Value, Radix: 10) << Low << High << Arg->getSourceRange();
1187
1188 return false;
1189}
1190
1191bool SemaARM::CheckARMBuiltinFunctionCall(const TargetInfo &TI,
1192 unsigned BuiltinID,
1193 CallExpr *TheCall) {
1194 if (BuiltinID == ARM::BI__builtin_arm_ldrex ||
1195 BuiltinID == ARM::BI__builtin_arm_ldrexd ||
1196 BuiltinID == ARM::BI__builtin_arm_ldaex ||
1197 BuiltinID == ARM::BI__builtin_arm_strex ||
1198 BuiltinID == ARM::BI__builtin_arm_strexd ||
1199 BuiltinID == ARM::BI__builtin_arm_stlex) {
1200 return CheckARMBuiltinExclusiveCall(TI, BuiltinID, TheCall);
1201 }
1202
1203 if (BuiltinID == ARM::BI__builtin_arm_prefetch) {
1204 return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 1, Low: 0, High: 1) ||
1205 SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 2, Low: 0, High: 1);
1206 }
1207
1208 if (BuiltinID == ARM::BI__builtin_arm_rsr64 ||
1209 BuiltinID == ARM::BI__builtin_arm_wsr64)
1210 return BuiltinARMSpecialReg(BuiltinID, TheCall, ArgNum: 0, ExpectedFieldNum: 3, AllowName: false);
1211
1212 if (BuiltinID == ARM::BI__builtin_arm_rsr ||
1213 BuiltinID == ARM::BI__builtin_arm_rsrp ||
1214 BuiltinID == ARM::BI__builtin_arm_wsr ||
1215 BuiltinID == ARM::BI__builtin_arm_wsrp)
1216 return BuiltinARMSpecialReg(BuiltinID, TheCall, ArgNum: 0, ExpectedFieldNum: 5, AllowName: true);
1217
1218 if (CheckNeonBuiltinFunctionCall(TI, BuiltinID, TheCall))
1219 return true;
1220 if (CheckMVEBuiltinFunctionCall(BuiltinID, TheCall))
1221 return true;
1222 if (CheckCDEBuiltinFunctionCall(TI, BuiltinID, TheCall))
1223 return true;
1224 // For intrinsics which take an immediate value as part of the instruction,
1225 // range check them here.
1226 // FIXME: VFP Intrinsics should error if VFP not present.
1227 switch (BuiltinID) {
1228 default:
1229 return false;
1230 case ARM::BI__builtin_arm_ssat:
1231 return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 1, Low: 1, High: 32);
1232 case ARM::BI__builtin_arm_usat:
1233 return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 1, Low: 0, High: 31);
1234 case ARM::BI__builtin_arm_ssat16:
1235 return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 1, Low: 1, High: 16);
1236 case ARM::BI__builtin_arm_usat16:
1237 return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 1, Low: 0, High: 15);
1238 case ARM::BI__builtin_arm_vcvtr_f:
1239 case ARM::BI__builtin_arm_vcvtr_d:
1240 return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 1, Low: 0, High: 1);
1241 case ARM::BI__builtin_arm_dmb:
1242 case ARM::BI__dmb:
1243 case ARM::BI__builtin_arm_dsb:
1244 case ARM::BI__dsb:
1245 case ARM::BI__builtin_arm_isb:
1246 case ARM::BI__isb:
1247 case ARM::BI__builtin_arm_dbg:
1248 return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 0, Low: 0, High: 15);
1249 case ARM::BI__builtin_arm_cdp:
1250 case ARM::BI__builtin_arm_cdp2:
1251 case ARM::BI__builtin_arm_mcr:
1252 case ARM::BI__builtin_arm_mcr2:
1253 case ARM::BI__builtin_arm_mrc:
1254 case ARM::BI__builtin_arm_mrc2:
1255 case ARM::BI__builtin_arm_mcrr:
1256 case ARM::BI__builtin_arm_mcrr2:
1257 case ARM::BI__builtin_arm_mrrc:
1258 case ARM::BI__builtin_arm_mrrc2:
1259 case ARM::BI__builtin_arm_ldc:
1260 case ARM::BI__builtin_arm_ldcl:
1261 case ARM::BI__builtin_arm_ldc2:
1262 case ARM::BI__builtin_arm_ldc2l:
1263 case ARM::BI__builtin_arm_stc:
1264 case ARM::BI__builtin_arm_stcl:
1265 case ARM::BI__builtin_arm_stc2:
1266 case ARM::BI__builtin_arm_stc2l:
1267 return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 0, Low: 0, High: 15) ||
1268 CheckARMCoprocessorImmediate(TI, CoprocArg: TheCall->getArg(Arg: 0),
1269 /*WantCDE*/ false);
1270 }
1271}
1272
1273bool SemaARM::CheckAArch64BuiltinFunctionCall(const TargetInfo &TI,
1274 unsigned BuiltinID,
1275 CallExpr *TheCall) {
1276 if (BuiltinID == AArch64::BI__builtin_arm_ldrex ||
1277 BuiltinID == AArch64::BI__builtin_arm_ldaex ||
1278 BuiltinID == AArch64::BI__builtin_arm_strex ||
1279 BuiltinID == AArch64::BI__builtin_arm_stlex) {
1280 return CheckARMBuiltinExclusiveCall(TI, BuiltinID, TheCall);
1281 }
1282
1283 if (BuiltinID == AArch64::BI__builtin_arm_prefetch) {
1284 return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 1, Low: 0, High: 1) ||
1285 SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 2, Low: 0, High: 3) ||
1286 SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 3, Low: 0, High: 1) ||
1287 SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 4, Low: 0, High: 1);
1288 }
1289
1290 if (BuiltinID == AArch64::BI__builtin_arm_range_prefetch_x) {
1291 return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 1, Low: 0, High: 1) ||
1292 SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 2, Low: 0, High: 1) ||
1293 SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 3, Low: -2097152, High: 2097151) ||
1294 SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 4, Low: 1, High: 65536) ||
1295 SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 5, Low: -2097152, High: 2097151);
1296 }
1297
1298 if (BuiltinID == AArch64::BI__builtin_arm_range_prefetch) {
1299 return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 1, Low: 0, High: 1) ||
1300 SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 2, Low: 0, High: 1);
1301 }
1302
1303 if (BuiltinID == AArch64::BI__builtin_arm_rsr64 ||
1304 BuiltinID == AArch64::BI__builtin_arm_wsr64 ||
1305 BuiltinID == AArch64::BI__builtin_arm_rsr128 ||
1306 BuiltinID == AArch64::BI__builtin_arm_wsr128)
1307 return BuiltinARMSpecialReg(BuiltinID, TheCall, ArgNum: 0, ExpectedFieldNum: 5, AllowName: true);
1308
1309 // Memory Tagging Extensions (MTE) Intrinsics
1310 if (BuiltinID == AArch64::BI__builtin_arm_irg ||
1311 BuiltinID == AArch64::BI__builtin_arm_addg ||
1312 BuiltinID == AArch64::BI__builtin_arm_gmi ||
1313 BuiltinID == AArch64::BI__builtin_arm_ldg ||
1314 BuiltinID == AArch64::BI__builtin_arm_stg ||
1315 BuiltinID == AArch64::BI__builtin_arm_subp) {
1316 return BuiltinARMMemoryTaggingCall(BuiltinID, TheCall);
1317 }
1318
1319 if (BuiltinID == AArch64::BI__builtin_arm_rsr ||
1320 BuiltinID == AArch64::BI__builtin_arm_rsrp ||
1321 BuiltinID == AArch64::BI__builtin_arm_wsr ||
1322 BuiltinID == AArch64::BI__builtin_arm_wsrp)
1323 return BuiltinARMSpecialReg(BuiltinID, TheCall, ArgNum: 0, ExpectedFieldNum: 5, AllowName: true);
1324
1325 if (BuiltinID == AArch64::BI__builtin_arm_atomic_store_with_hint ||
1326 BuiltinID == AArch64::BI__builtin_arm_atomic_fetch_add_with_hint ||
1327 BuiltinID == AArch64::BI__builtin_arm_atomic_fetch_sub_with_hint ||
1328 BuiltinID == AArch64::BI__builtin_arm_atomic_fetch_and_with_hint ||
1329 BuiltinID == AArch64::BI__builtin_arm_atomic_fetch_xor_with_hint ||
1330 BuiltinID == AArch64::BI__builtin_arm_atomic_fetch_or_with_hint)
1331 return BuiltinARMAtomicHintCall(BuiltinID, TheCall);
1332
1333 // Only check the valid encoding range. Any constant in this range would be
1334 // converted to a register of the form S2_2_C3_C4_5. Let the hardware throw
1335 // an exception for incorrect registers. This matches MSVC behavior.
1336 // Bit 14 is o0, i.e. op0 - 2, so op0 == 2 registers have it clear and encode
1337 // below 0x4000.
1338 if (BuiltinID == AArch64::BI_ReadStatusReg ||
1339 BuiltinID == AArch64::BI_WriteStatusReg)
1340 return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 0, Low: 0, High: 0x7fff);
1341
1342 if (BuiltinID == AArch64::BI__sys)
1343 return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 0, Low: 0, High: 0x3fff);
1344
1345 if (BuiltinID == AArch64::BI__getReg || BuiltinID == AArch64::BI__setReg ||
1346 BuiltinID == AArch64::BI__getRegFp || BuiltinID == AArch64::BI__setRegFp)
1347 return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 0, Low: 0, High: 31);
1348
1349 if (BuiltinID == AArch64::BI__prefetch2)
1350 return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 1, Low: 0, High: 31);
1351
1352 if (BuiltinID == AArch64::BI__break)
1353 return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 0, Low: 0, High: 0xffff);
1354
1355 if (BuiltinID == AArch64::BI__hlt)
1356 return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 0, Low: 0, High: 0xffff);
1357
1358 if (BuiltinID == AArch64::BI__hvc || BuiltinID == AArch64::BI__svc) {
1359 // The immediate is the instruction number; the remaining arguments (at most
1360 // four) are passed in X0-X3, so the call takes at most five arguments.
1361 if (SemaRef.checkArgCountAtMost(Call: TheCall, MaxArgCount: 5) ||
1362 SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 0, Low: 0, High: 0xffff))
1363 return true;
1364 const FunctionDecl *FD = TheCall->getDirectCallee();
1365 for (unsigned I = 1, N = TheCall->getNumArgs(); I < N; ++I) {
1366 const Expr *Arg = TheCall->getArg(Arg: I);
1367 QualType Ty = Arg->getType();
1368 if (!Ty->isIntegerType() && !Ty->isAnyPointerType() &&
1369 !Ty->isBlockPointerType() && !Ty->isFloatingType())
1370 return Diag(Loc: Arg->getBeginLoc(),
1371 DiagID: diag::err_aarch64_svc_hvc_invalid_arg_type)
1372 << I + 1 << FD << Ty << Arg->getSourceRange();
1373 }
1374 return false;
1375 }
1376
1377 if (CheckNeonBuiltinFunctionCall(TI, BuiltinID, TheCall))
1378 return true;
1379
1380 if (CheckSVEBuiltinFunctionCall(BuiltinID, TheCall))
1381 return true;
1382
1383 if (CheckSMEBuiltinFunctionCall(BuiltinID, TheCall))
1384 return true;
1385
1386 if (BuiltinID == AArch64::BI__arm_set_fpm_lscale)
1387 return checkFPMScaleIfConstant(S&: SemaRef, Call: TheCall, ArgNum: 1, Low: 0, High: 127);
1388
1389 if (BuiltinID == AArch64::BI__arm_set_fpm_nscale)
1390 return checkFPMScaleIfConstant(S&: SemaRef, Call: TheCall, ArgNum: 1, Low: -128, High: 127);
1391
1392 if (BuiltinID == AArch64::BI__arm_set_fpm_lscale2)
1393 return checkFPMScaleIfConstant(S&: SemaRef, Call: TheCall, ArgNum: 1, Low: 0, High: 63);
1394
1395 // For intrinsics which take an immediate value as part of the instruction,
1396 // range check them here.
1397 unsigned i = 0, l = 0, u = 0;
1398 switch (BuiltinID) {
1399 default: return false;
1400 case AArch64::BI__builtin_arm_dmb:
1401 case AArch64::BI__dmb:
1402 case AArch64::BI__builtin_arm_dsb:
1403 case AArch64::BI__dsb:
1404 case AArch64::BI__builtin_arm_isb:
1405 case AArch64::BI__isb:
1406 l = 0;
1407 u = 15;
1408 break;
1409 }
1410
1411 return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: i, Low: l, High: u + l);
1412}
1413
1414namespace {
1415struct IntrinToName {
1416 uint32_t Id;
1417 int32_t FullName;
1418 int32_t ShortName;
1419};
1420} // unnamed namespace
1421
1422static bool BuiltinAliasValid(unsigned BuiltinID, StringRef AliasName,
1423 ArrayRef<IntrinToName> Map,
1424 const char *IntrinNames) {
1425 AliasName.consume_front(Prefix: "__arm_");
1426 const IntrinToName *It =
1427 llvm::lower_bound(Range&: Map, Value&: BuiltinID, C: [](const IntrinToName &L, unsigned Id) {
1428 return L.Id < Id;
1429 });
1430 if (It == Map.end() || It->Id != BuiltinID)
1431 return false;
1432 StringRef FullName(&IntrinNames[It->FullName]);
1433 if (AliasName == FullName)
1434 return true;
1435 if (It->ShortName == -1)
1436 return false;
1437 StringRef ShortName(&IntrinNames[It->ShortName]);
1438 return AliasName == ShortName;
1439}
1440
1441bool SemaARM::MveAliasValid(unsigned BuiltinID, StringRef AliasName) {
1442#include "clang/Basic/arm_mve_builtin_aliases.inc"
1443 // The included file defines:
1444 // - ArrayRef<IntrinToName> Map
1445 // - const char IntrinNames[]
1446 return BuiltinAliasValid(BuiltinID, AliasName, Map, IntrinNames);
1447}
1448
1449bool SemaARM::CdeAliasValid(unsigned BuiltinID, StringRef AliasName) {
1450#include "clang/Basic/arm_cde_builtin_aliases.inc"
1451 return BuiltinAliasValid(BuiltinID, AliasName, Map, IntrinNames);
1452}
1453
1454bool SemaARM::SveAliasValid(unsigned BuiltinID, StringRef AliasName) {
1455 if (getASTContext().BuiltinInfo.isAuxBuiltinID(ID: BuiltinID))
1456 BuiltinID = getASTContext().BuiltinInfo.getAuxBuiltinID(ID: BuiltinID);
1457 return BuiltinID >= AArch64::FirstSVEBuiltin &&
1458 BuiltinID <= AArch64::LastSVEBuiltin;
1459}
1460
1461bool SemaARM::SmeAliasValid(unsigned BuiltinID, StringRef AliasName) {
1462 if (getASTContext().BuiltinInfo.isAuxBuiltinID(ID: BuiltinID))
1463 BuiltinID = getASTContext().BuiltinInfo.getAuxBuiltinID(ID: BuiltinID);
1464 return BuiltinID >= AArch64::FirstSMEBuiltin &&
1465 BuiltinID <= AArch64::LastSMEBuiltin;
1466}
1467
1468void SemaARM::handleBuiltinAliasAttr(Decl *D, const ParsedAttr &AL) {
1469 ASTContext &Context = getASTContext();
1470 if (!AL.isArgIdent(Arg: 0)) {
1471 Diag(Loc: AL.getLoc(), DiagID: diag::err_attribute_argument_n_type)
1472 << AL << 1 << AANT_ArgumentIdentifier;
1473 return;
1474 }
1475
1476 IdentifierInfo *Ident = AL.getArgAsIdent(Arg: 0)->getIdentifierInfo();
1477 unsigned BuiltinID = Ident->getBuiltinID();
1478 StringRef AliasName = cast<FunctionDecl>(Val: D)->getIdentifier()->getName();
1479
1480 bool IsAArch64 = Context.getTargetInfo().getTriple().isAArch64();
1481 if ((IsAArch64 && !SveAliasValid(BuiltinID, AliasName) &&
1482 !SmeAliasValid(BuiltinID, AliasName)) ||
1483 (!IsAArch64 && !MveAliasValid(BuiltinID, AliasName) &&
1484 !CdeAliasValid(BuiltinID, AliasName))) {
1485 Diag(Loc: AL.getLoc(), DiagID: diag::err_attribute_arm_builtin_alias);
1486 return;
1487 }
1488
1489 D->addAttr(A: ::new (Context) ArmBuiltinAliasAttr(Context, AL, Ident));
1490}
1491
1492static bool checkNewAttrMutualExclusion(
1493 Sema &S, const ParsedAttr &AL, const FunctionProtoType *FPT,
1494 FunctionType::ArmStateValue CurrentState, StringRef StateName) {
1495 auto CheckForIncompatibleAttr =
1496 [&](FunctionType::ArmStateValue IncompatibleState,
1497 StringRef IncompatibleStateName) {
1498 if (CurrentState == IncompatibleState) {
1499 S.Diag(Loc: AL.getLoc(), DiagID: diag::err_attributes_are_not_compatible)
1500 << (std::string("'__arm_new(\"") + StateName.str() + "\")'")
1501 << (std::string("'") + IncompatibleStateName.str() + "(\"" +
1502 StateName.str() + "\")'")
1503 << true;
1504 AL.setInvalid();
1505 }
1506 };
1507
1508 CheckForIncompatibleAttr(FunctionType::ARM_In, "__arm_in");
1509 CheckForIncompatibleAttr(FunctionType::ARM_Out, "__arm_out");
1510 CheckForIncompatibleAttr(FunctionType::ARM_InOut, "__arm_inout");
1511 CheckForIncompatibleAttr(FunctionType::ARM_Preserves, "__arm_preserves");
1512 return AL.isInvalid();
1513}
1514
1515void SemaARM::handleNewAttr(Decl *D, const ParsedAttr &AL) {
1516 if (!AL.getNumArgs()) {
1517 Diag(Loc: AL.getLoc(), DiagID: diag::err_missing_arm_state) << AL;
1518 AL.setInvalid();
1519 return;
1520 }
1521
1522 std::vector<StringRef> NewState;
1523 if (const auto *ExistingAttr = D->getAttr<ArmNewAttr>()) {
1524 for (StringRef S : ExistingAttr->newArgs())
1525 NewState.push_back(x: S);
1526 }
1527
1528 bool HasZA = false;
1529 bool HasZT0 = false;
1530 for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) {
1531 StringRef StateName;
1532 SourceLocation LiteralLoc;
1533 if (!SemaRef.checkStringLiteralArgumentAttr(Attr: AL, ArgNum: I, Str&: StateName, ArgLocation: &LiteralLoc))
1534 return;
1535
1536 if (StateName == "za")
1537 HasZA = true;
1538 else if (StateName == "zt0")
1539 HasZT0 = true;
1540 else {
1541 Diag(Loc: LiteralLoc, DiagID: diag::err_unknown_arm_state) << StateName;
1542 AL.setInvalid();
1543 return;
1544 }
1545
1546 if (!llvm::is_contained(Range&: NewState, Element: StateName)) // Avoid adding duplicates.
1547 NewState.push_back(x: StateName);
1548 }
1549
1550 if (auto *FPT = dyn_cast<FunctionProtoType>(Val: D->getFunctionType())) {
1551 FunctionType::ArmStateValue ZAState =
1552 FunctionType::getArmZAState(AttrBits: FPT->getAArch64SMEAttributes());
1553 if (HasZA && ZAState != FunctionType::ARM_None &&
1554 checkNewAttrMutualExclusion(S&: SemaRef, AL, FPT, CurrentState: ZAState, StateName: "za"))
1555 return;
1556 FunctionType::ArmStateValue ZT0State =
1557 FunctionType::getArmZT0State(AttrBits: FPT->getAArch64SMEAttributes());
1558 if (HasZT0 && ZT0State != FunctionType::ARM_None &&
1559 checkNewAttrMutualExclusion(S&: SemaRef, AL, FPT, CurrentState: ZT0State, StateName: "zt0"))
1560 return;
1561 }
1562
1563 D->dropAttr<ArmNewAttr>();
1564 D->addAttr(A: ::new (getASTContext()) ArmNewAttr(
1565 getASTContext(), AL, NewState.data(), NewState.size()));
1566}
1567
1568void SemaARM::handleCmseNSEntryAttr(Decl *D, const ParsedAttr &AL) {
1569 if (getLangOpts().CPlusPlus && !D->getDeclContext()->isExternCContext()) {
1570 Diag(Loc: AL.getLoc(), DiagID: diag::err_attribute_not_clinkage) << AL;
1571 return;
1572 }
1573
1574 const auto *FD = cast<FunctionDecl>(Val: D);
1575 if (!FD->isExternallyVisible()) {
1576 Diag(Loc: AL.getLoc(), DiagID: diag::warn_attribute_cmse_entry_static);
1577 return;
1578 }
1579
1580 D->addAttr(A: ::new (getASTContext()) CmseNSEntryAttr(getASTContext(), AL));
1581}
1582
1583void SemaARM::handleInterruptAttr(Decl *D, const ParsedAttr &AL) {
1584 // Check the attribute arguments.
1585 if (AL.getNumArgs() > 1) {
1586 Diag(Loc: AL.getLoc(), DiagID: diag::err_attribute_too_many_arguments) << AL << 1;
1587 return;
1588 }
1589
1590 StringRef Str;
1591 SourceLocation ArgLoc;
1592
1593 if (AL.getNumArgs() == 0)
1594 Str = "";
1595 else if (!SemaRef.checkStringLiteralArgumentAttr(Attr: AL, ArgNum: 0, Str, ArgLocation: &ArgLoc))
1596 return;
1597
1598 ARMInterruptAttr::InterruptType Kind;
1599 if (!ARMInterruptAttr::ConvertStrToInterruptType(Val: Str, Out&: Kind)) {
1600 Diag(Loc: AL.getLoc(), DiagID: diag::warn_attribute_type_not_supported)
1601 << AL << Str << ArgLoc;
1602 return;
1603 }
1604
1605 if (!D->hasAttr<ARMSaveFPAttr>()) {
1606 const TargetInfo &TI = getASTContext().getTargetInfo();
1607 if (TI.hasFeature(Feature: "vfp"))
1608 Diag(Loc: D->getLocation(), DiagID: diag::warn_arm_interrupt_vfp_clobber);
1609 }
1610
1611 D->addAttr(A: ::new (getASTContext())
1612 ARMInterruptAttr(getASTContext(), AL, Kind));
1613}
1614
1615void SemaARM::handleInterruptSaveFPAttr(Decl *D, const ParsedAttr &AL) {
1616 // Go ahead and add ARMSaveFPAttr because handleInterruptAttr() checks for
1617 // it when deciding to issue a diagnostic about clobbering floating point
1618 // registers, which ARMSaveFPAttr prevents.
1619 D->addAttr(A: ::new (SemaRef.Context) ARMSaveFPAttr(SemaRef.Context, AL));
1620 SemaRef.ARM().handleInterruptAttr(D, AL);
1621
1622 // If ARM().handleInterruptAttr() failed, remove ARMSaveFPAttr.
1623 if (!D->hasAttr<ARMInterruptAttr>()) {
1624 D->dropAttr<ARMSaveFPAttr>();
1625 return;
1626 }
1627
1628 // If VFP not enabled, remove ARMSaveFPAttr but leave ARMInterruptAttr.
1629 bool VFP = SemaRef.Context.getTargetInfo().hasFeature(Feature: "vfp");
1630
1631 if (!VFP) {
1632 SemaRef.Diag(Loc: D->getLocation(), DiagID: diag::warn_arm_interrupt_save_fp_without_vfp_unit);
1633 D->dropAttr<ARMSaveFPAttr>();
1634 }
1635}
1636
1637// Check if the function definition uses any AArch64 SME features without
1638// having the '+sme' feature enabled and warn user if sme locally streaming
1639// function returns or uses arguments with VL-based types.
1640void SemaARM::CheckSMEFunctionDefAttributes(const FunctionDecl *FD) {
1641 const auto *Attr = FD->getAttr<ArmNewAttr>();
1642 bool UsesSM = FD->hasAttr<ArmLocallyStreamingAttr>();
1643 bool UsesZA = Attr && Attr->isNewZA();
1644 bool UsesZT0 = Attr && Attr->isNewZT0();
1645
1646 if (UsesZA || UsesZT0) {
1647 if (const auto *FPT = FD->getType()->getAs<FunctionProtoType>()) {
1648 FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
1649 if (EPI.AArch64SMEAttributes & FunctionType::SME_AgnosticZAStateMask)
1650 Diag(Loc: FD->getLocation(), DiagID: diag::err_sme_unsupported_agnostic_new);
1651 }
1652 }
1653
1654 if (FD->hasAttr<ArmLocallyStreamingAttr>()) {
1655 if (FD->getReturnType()->isSizelessVectorType())
1656 Diag(Loc: FD->getLocation(),
1657 DiagID: diag::warn_sme_locally_streaming_has_vl_args_returns)
1658 << /*IsArg=*/false;
1659 if (llvm::any_of(Range: FD->parameters(), P: [](ParmVarDecl *P) {
1660 return P->getOriginalType()->isSizelessVectorType();
1661 }))
1662 Diag(Loc: FD->getLocation(),
1663 DiagID: diag::warn_sme_locally_streaming_has_vl_args_returns)
1664 << /*IsArg=*/true;
1665 }
1666 if (const auto *FPT = FD->getType()->getAs<FunctionProtoType>()) {
1667 FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
1668 UsesSM |= EPI.AArch64SMEAttributes & FunctionType::SME_PStateSMEnabledMask;
1669 UsesZA |= FunctionType::getArmZAState(AttrBits: EPI.AArch64SMEAttributes) !=
1670 FunctionType::ARM_None;
1671 UsesZT0 |= FunctionType::getArmZT0State(AttrBits: EPI.AArch64SMEAttributes) !=
1672 FunctionType::ARM_None;
1673 }
1674
1675 ASTContext &Context = getASTContext();
1676 if (UsesSM || UsesZA) {
1677 llvm::StringMap<bool> FeatureMap;
1678 Context.getFunctionFeatureMap(FeatureMap, FD);
1679 if (!FeatureMap.contains(Key: "sme")) {
1680 if (UsesSM)
1681 Diag(Loc: FD->getLocation(),
1682 DiagID: diag::err_sme_definition_using_sm_in_non_sme_target);
1683 else
1684 Diag(Loc: FD->getLocation(),
1685 DiagID: diag::err_sme_definition_using_za_in_non_sme_target);
1686 }
1687 }
1688 if (UsesZT0) {
1689 llvm::StringMap<bool> FeatureMap;
1690 Context.getFunctionFeatureMap(FeatureMap, FD);
1691 if (!FeatureMap.contains(Key: "sme2")) {
1692 Diag(Loc: FD->getLocation(),
1693 DiagID: diag::err_sme_definition_using_zt0_in_non_sme2_target);
1694 }
1695 }
1696}
1697
1698/// getSVETypeSize - Return SVE vector or predicate register size.
1699static uint64_t getSVETypeSize(ASTContext &Context, const BuiltinType *Ty,
1700 bool IsStreaming) {
1701 assert(Ty->isSveVLSBuiltinType() && "Invalid SVE Type");
1702 uint64_t VScale = IsStreaming ? Context.getLangOpts().VScaleStreamingMin
1703 : Context.getLangOpts().VScaleMin;
1704 if (Ty->getKind() == BuiltinType::SveBool ||
1705 Ty->getKind() == BuiltinType::SveCount)
1706 return (VScale * 128) / Context.getCharWidth();
1707 return VScale * 128;
1708}
1709
1710bool SemaARM::areCompatibleSveTypes(QualType FirstType, QualType SecondType) {
1711 bool IsStreaming = false;
1712 if (getLangOpts().VScaleMin != getLangOpts().VScaleStreamingMin ||
1713 getLangOpts().VScaleMax != getLangOpts().VScaleStreamingMax) {
1714 if (const FunctionDecl *FD =
1715 SemaRef.getCurFunctionDecl(/*AllowLambda=*/true)) {
1716 // For streaming-compatible functions, we don't know vector length.
1717 if (const auto *T = FD->getType()->getAs<FunctionProtoType>()) {
1718 if (T->getAArch64SMEAttributes() &
1719 FunctionType::SME_PStateSMCompatibleMask)
1720 return false;
1721 }
1722
1723 if (IsArmStreamingFunction(FD, /*IncludeLocallyStreaming=*/true))
1724 IsStreaming = true;
1725 }
1726 }
1727
1728 auto IsValidCast = [&](QualType FirstType, QualType SecondType) {
1729 if (const auto *BT = FirstType->getAs<BuiltinType>()) {
1730 if (const auto *VT = SecondType->getAs<VectorType>()) {
1731 // Predicates have the same representation as uint8 so we also have to
1732 // check the kind to make these types incompatible.
1733 ASTContext &Context = getASTContext();
1734 if (VT->getVectorKind() == VectorKind::SveFixedLengthPredicate)
1735 return BT->getKind() == BuiltinType::SveBool;
1736 else if (VT->getVectorKind() == VectorKind::SveFixedLengthData)
1737 return VT->getElementType().getCanonicalType() ==
1738 FirstType->getSveEltType(Ctx: Context) &&
1739 BT->getKind() != BuiltinType::SveBool;
1740 else if (VT->getVectorKind() == VectorKind::Generic)
1741 return Context.getTypeSize(T: SecondType) ==
1742 getSVETypeSize(Context, Ty: BT, IsStreaming) &&
1743 Context.hasSameType(
1744 T1: VT->getElementType(),
1745 T2: Context.getBuiltinVectorTypeInfo(VecTy: BT).ElementType);
1746 }
1747 }
1748 return false;
1749 };
1750
1751 return IsValidCast(FirstType, SecondType) ||
1752 IsValidCast(SecondType, FirstType);
1753}
1754
1755bool SemaARM::areLaxCompatibleSveTypes(QualType FirstType,
1756 QualType SecondType) {
1757 bool IsStreaming = false;
1758 if (getLangOpts().VScaleMin != getLangOpts().VScaleStreamingMin ||
1759 getLangOpts().VScaleMax != getLangOpts().VScaleStreamingMax) {
1760 if (const FunctionDecl *FD =
1761 SemaRef.getCurFunctionDecl(/*AllowLambda=*/true)) {
1762 // For streaming-compatible functions, we don't know vector length.
1763 if (const auto *T = FD->getType()->getAs<FunctionProtoType>())
1764 if (T->getAArch64SMEAttributes() &
1765 FunctionType::SME_PStateSMCompatibleMask)
1766 return false;
1767
1768 if (IsArmStreamingFunction(FD, /*IncludeLocallyStreaming=*/true))
1769 IsStreaming = true;
1770 }
1771 }
1772
1773 auto IsLaxCompatible = [&](QualType FirstType, QualType SecondType) {
1774 const auto *BT = FirstType->getAs<BuiltinType>();
1775 if (!BT)
1776 return false;
1777
1778 const auto *VecTy = SecondType->getAs<VectorType>();
1779 if (VecTy && (VecTy->getVectorKind() == VectorKind::SveFixedLengthData ||
1780 VecTy->getVectorKind() == VectorKind::Generic)) {
1781 const LangOptions::LaxVectorConversionKind LVCKind =
1782 getLangOpts().getLaxVectorConversions();
1783 ASTContext &Context = getASTContext();
1784
1785 // Can not convert between sve predicates and sve vectors because of
1786 // different size.
1787 if (BT->getKind() == BuiltinType::SveBool &&
1788 VecTy->getVectorKind() == VectorKind::SveFixedLengthData)
1789 return false;
1790
1791 // If __ARM_FEATURE_SVE_BITS != N do not allow GNU vector lax conversion.
1792 // "Whenever __ARM_FEATURE_SVE_BITS==N, GNUT implicitly
1793 // converts to VLAT and VLAT implicitly converts to GNUT."
1794 // ACLE Spec Version 00bet6, 3.7.3.2. Behavior common to vectors and
1795 // predicates.
1796 if (VecTy->getVectorKind() == VectorKind::Generic &&
1797 Context.getTypeSize(T: SecondType) !=
1798 getSVETypeSize(Context, Ty: BT, IsStreaming))
1799 return false;
1800
1801 // If -flax-vector-conversions=all is specified, the types are
1802 // certainly compatible.
1803 if (LVCKind == LangOptions::LaxVectorConversionKind::All)
1804 return true;
1805
1806 // If -flax-vector-conversions=integer is specified, the types are
1807 // compatible if the elements are integer types.
1808 if (LVCKind == LangOptions::LaxVectorConversionKind::Integer)
1809 return VecTy->getElementType().getCanonicalType()->isIntegerType() &&
1810 FirstType->getSveEltType(Ctx: Context)->isIntegerType();
1811 }
1812
1813 return false;
1814 };
1815
1816 return IsLaxCompatible(FirstType, SecondType) ||
1817 IsLaxCompatible(SecondType, FirstType);
1818}
1819
1820static void appendFeature(StringRef Feat, SmallString<64> &Buffer) {
1821 if (!Buffer.empty())
1822 Buffer.append(RHS: "+");
1823 Buffer.append(RHS: Feat);
1824}
1825
1826static void convertPriorityString(unsigned Priority,
1827 SmallString<64> &NewParam) {
1828 StringRef PriorityString[8] = {"P0", "P1", "P2", "P3",
1829 "P4", "P5", "P6", "P7"};
1830
1831 assert(Priority > 0 && Priority < 256 && "priority out of range");
1832 // Convert priority=[1-255] -> P0 + ... + P7
1833 for (unsigned BitPos = 0; BitPos < 8; ++BitPos)
1834 if (Priority & (1U << BitPos))
1835 appendFeature(Feat: PriorityString[BitPos], Buffer&: NewParam);
1836}
1837
1838bool SemaARM::checkTargetVersionAttr(const StringRef Param,
1839 const SourceLocation Loc,
1840 SmallString<64> &NewParam) {
1841 using namespace DiagAttrParams;
1842
1843 auto [LHS, RHS] = Param.split(Separator: ';');
1844 RHS = RHS.trim();
1845 bool IsDefault = false;
1846 llvm::SmallVector<StringRef, 8> Features;
1847 LHS.split(A&: Features, Separator: '+');
1848 for (StringRef Feat : Features) {
1849 Feat = Feat.trim();
1850 if (Feat == "default")
1851 IsDefault = true;
1852 else if (!getASTContext().getTargetInfo().validateCpuSupports(Name: Feat))
1853 return Diag(Loc, DiagID: diag::warn_unsupported_target_attribute)
1854 << Unsupported << None << Feat << TargetVersion;
1855 appendFeature(Feat, Buffer&: NewParam);
1856 }
1857
1858 if (!RHS.empty() && RHS.consume_front(Prefix: "priority=")) {
1859 if (IsDefault)
1860 Diag(Loc, DiagID: diag::warn_invalid_default_version_priority);
1861 else {
1862 unsigned Digit;
1863 if (RHS.getAsInteger(Radix: 0, Result&: Digit) || Digit < 1 || Digit > 255)
1864 Diag(Loc, DiagID: diag::warn_version_priority_out_of_range) << RHS;
1865 else
1866 convertPriorityString(Priority: Digit, NewParam);
1867 }
1868 }
1869 return false;
1870}
1871
1872bool SemaARM::checkTargetClonesAttr(
1873 SmallVectorImpl<StringRef> &Params, SmallVectorImpl<SourceLocation> &Locs,
1874 SmallVectorImpl<SmallString<64>> &NewParams) {
1875 using namespace DiagAttrParams;
1876
1877 if (!getASTContext().getTargetInfo().hasFeature(Feature: "fmv"))
1878 return true;
1879
1880 assert(Params.size() == Locs.size() &&
1881 "Mismatch between number of string parameters and locations");
1882
1883 bool HasDefault = false;
1884 bool HasNonDefault = false;
1885 for (unsigned I = 0, E = Params.size(); I < E; ++I) {
1886 const StringRef Param = Params[I].trim();
1887 const SourceLocation &Loc = Locs[I];
1888
1889 auto [LHS, RHS] = Param.split(Separator: ';');
1890 RHS = RHS.trim();
1891 bool HasPriority = !RHS.empty() && RHS.consume_front(Prefix: "priority=");
1892
1893 if (LHS.empty())
1894 return Diag(Loc, DiagID: diag::warn_unsupported_target_attribute)
1895 << Unsupported << None << "" << TargetClones;
1896
1897 if (LHS == "default") {
1898 if (HasDefault)
1899 Diag(Loc, DiagID: diag::warn_target_clone_duplicate_options);
1900 else {
1901 if (HasPriority)
1902 Diag(Loc, DiagID: diag::warn_invalid_default_version_priority);
1903 NewParams.push_back(Elt: LHS);
1904 HasDefault = true;
1905 }
1906 continue;
1907 }
1908
1909 bool HasCodeGenImpact = false;
1910 llvm::SmallVector<StringRef, 8> Features;
1911 llvm::SmallVector<StringRef, 8> ValidFeatures;
1912 LHS.split(A&: Features, Separator: '+');
1913 for (StringRef Feat : Features) {
1914 Feat = Feat.trim();
1915 if (!getASTContext().getTargetInfo().validateCpuSupports(Name: Feat)) {
1916 Diag(Loc, DiagID: diag::warn_unsupported_target_attribute)
1917 << Unsupported << None << Feat << TargetClones;
1918 continue;
1919 }
1920 if (getASTContext().getTargetInfo().doesFeatureAffectCodeGen(Feature: Feat))
1921 HasCodeGenImpact = true;
1922 ValidFeatures.push_back(Elt: Feat);
1923 }
1924
1925 // Ignore features that don't impact code generation.
1926 if (!HasCodeGenImpact) {
1927 Diag(Loc, DiagID: diag::warn_target_clone_no_impact_options);
1928 continue;
1929 }
1930
1931 if (ValidFeatures.empty())
1932 continue;
1933
1934 // Canonicalize attribute parameter.
1935 llvm::sort(C&: ValidFeatures);
1936 SmallString<64> NewParam(llvm::join(R&: ValidFeatures, Separator: "+"));
1937 if (llvm::is_contained(Range&: NewParams, Element: NewParam)) {
1938 Diag(Loc, DiagID: diag::warn_target_clone_duplicate_options);
1939 continue;
1940 }
1941
1942 if (HasPriority) {
1943 unsigned Digit;
1944 if (RHS.getAsInteger(Radix: 0, Result&: Digit) || Digit < 1 || Digit > 255)
1945 Diag(Loc, DiagID: diag::warn_version_priority_out_of_range) << RHS;
1946 else
1947 convertPriorityString(Priority: Digit, NewParam);
1948 }
1949
1950 // Valid non-default argument.
1951 NewParams.push_back(Elt: NewParam);
1952 HasNonDefault = true;
1953 }
1954
1955 return !HasNonDefault;
1956}
1957
1958bool SemaARM::checkSVETypeSupport(QualType Ty, SourceLocation Loc,
1959 const FunctionDecl *FD,
1960 const llvm::StringMap<bool> &FeatureMap) {
1961 if (!Ty->isSVESizelessBuiltinType())
1962 return false;
1963
1964 if (FeatureMap.lookup(Key: "sve"))
1965 return false;
1966
1967 // No SVE environment available.
1968 if (!FeatureMap.lookup(Key: "sme"))
1969 return Diag(Loc, DiagID: diag::err_sve_vector_in_non_sve_target) << Ty;
1970
1971 // SVE environment only available to streaming functions.
1972 if (FD && !FD->getType().isNull() &&
1973 !IsArmStreamingFunction(FD, /*IncludeLocallyStreaming=*/true))
1974 return Diag(Loc, DiagID: diag::err_sve_vector_in_non_streaming_function) << Ty;
1975
1976 return false;
1977}
1978} // namespace clang
1979