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