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