clang 24.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::ImmCheckShiftLeftLong:
456 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 0, (EltBitWidth / 2)))
457 return true;
458 break;
459 case ImmCheckType::ImmCheckLaneIndex:
460 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 0,
461 (ContainerBitWidth / EltBitWidth) - 1))
462 return true;
463 break;
464 case ImmCheckType::ImmCheckLaneIndexCompRotate:
465 if (SemaRef.BuiltinConstantArgRange(
466 TheCall, ArgIdx, 0, (ContainerBitWidth / (2 * EltBitWidth)) - 1))
467 return true;
468 break;
469 case ImmCheckType::ImmCheckLaneIndexDot:
470 if (SemaRef.BuiltinConstantArgRange(
471 TheCall, ArgIdx, 0, (ContainerBitWidth / (4 * EltBitWidth)) - 1))
472 return true;
473 break;
474 case ImmCheckType::ImmCheckComplexRot90_270:
475 if (CheckImmediateInSet({90, 270}, diag::err_rotation_argument_to_cadd))
476 return true;
477 break;
478 case ImmCheckType::ImmCheckComplexRotAll90:
479 if (CheckImmediateInSet({0, 90, 180, 270},
480 diag::err_rotation_argument_to_cmla))
481 return true;
482 break;
483 case ImmCheckType::ImmCheck0_1:
484 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 0, 1))
485 return true;
486 break;
487 case ImmCheckType::ImmCheck0_2:
488 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 0, 2))
489 return true;
490 break;
491 case ImmCheckType::ImmCheck0_3:
492 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 0, 3))
493 return true;
494 break;
495 case ImmCheckType::ImmCheck0_0:
496 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 0, 0))
497 return true;
498 break;
499 case ImmCheckType::ImmCheck0_15:
500 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 0, 15))
501 return true;
502 break;
503 case ImmCheckType::ImmCheck0_255:
504 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 0, 255))
505 return true;
506 break;
507 case ImmCheckType::ImmCheck1_32:
508 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 1, 32))
509 return true;
510 break;
511 case ImmCheckType::ImmCheck1_64:
512 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 1, 64))
513 return true;
514 break;
515 case ImmCheckType::ImmCheck2_4_Mul2:
516 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 2, 4) ||
517 SemaRef.BuiltinConstantArgMultiple(TheCall, ArgIdx, 2))
518 return true;
519 break;
520 }
521 return false;
522}
523
525 CallExpr *TheCall,
526 SmallVectorImpl<std::tuple<int, int, int, int>> &ImmChecks,
527 int OverloadType) {
528 bool HasError = false;
529
530 for (const auto &I : ImmChecks) {
531 auto [ArgIdx, CheckTy, ElementBitWidth, VecBitWidth] = I;
532
533 if (OverloadType >= 0)
534 ElementBitWidth = NeonTypeFlags(OverloadType).getEltSizeInBits();
535
536 HasError |= CheckImmediateArg(TheCall, CheckTy, ArgIdx, ElementBitWidth,
537 VecBitWidth);
538 }
539
540 return HasError;
541}
542
544 CallExpr *TheCall, SmallVectorImpl<std::tuple<int, int, int>> &ImmChecks) {
545 bool HasError = false;
546
547 for (const auto &I : ImmChecks) {
548 auto [ArgIdx, CheckTy, ElementBitWidth] = I;
549 HasError |=
550 CheckImmediateArg(TheCall, CheckTy, ArgIdx, ElementBitWidth, 128);
551 }
552
553 return HasError;
554}
555
557 if (FD->hasAttr<ArmLocallyStreamingAttr>())
559 if (const Type *Ty = FD->getType().getTypePtrOrNull()) {
560 if (const auto *FPT = Ty->getAs<FunctionProtoType>()) {
561 if (FPT->getAArch64SMEAttributes() &
564 if (FPT->getAArch64SMEAttributes() &
567 }
568 }
570}
571
572static bool checkArmStreamingBuiltin(Sema &S, CallExpr *TheCall,
573 const FunctionDecl *FD,
575 unsigned BuiltinID) {
577
578 // Check if the intrinsic is available in the right mode, i.e.
579 // * When compiling for SME only, the caller must be in streaming mode.
580 // * When compiling for SVE only, the caller must be in non-streaming mode.
581 // * When compiling for both SVE and SME, the caller can be in either mode.
583 llvm::StringMap<bool> CallerFeatures;
584 S.Context.getFunctionFeatureMap(CallerFeatures, FD);
585
586 // Avoid emitting diagnostics for a function that can never compile.
587 if (FnType == SemaARM::ArmStreaming && !CallerFeatures["sme"])
588 return false;
589
590 const auto FindTopLevelPipe = [](const char *S) {
591 unsigned Depth = 0;
592 unsigned I = 0, E = strlen(S);
593 for (; I < E; ++I) {
594 if (S[I] == '|' && Depth == 0)
595 break;
596 if (S[I] == '(')
597 ++Depth;
598 else if (S[I] == ')')
599 --Depth;
600 }
601 return I;
602 };
603
604 const char *RequiredFeatures =
606 unsigned PipeIdx = FindTopLevelPipe(RequiredFeatures);
607 assert(PipeIdx != 0 && PipeIdx != strlen(RequiredFeatures) &&
608 "Expected feature string of the form 'SVE-EXPR|SME-EXPR'");
609 StringRef NonStreamingBuiltinGuard = StringRef(RequiredFeatures, PipeIdx);
610 StringRef StreamingBuiltinGuard = StringRef(RequiredFeatures + PipeIdx + 1);
611
612 bool SatisfiesSVE = Builtin::evaluateRequiredTargetFeatures(
613 NonStreamingBuiltinGuard, CallerFeatures);
614 bool SatisfiesSME = Builtin::evaluateRequiredTargetFeatures(
615 StreamingBuiltinGuard, CallerFeatures);
616
617 if (SatisfiesSVE && SatisfiesSME)
618 // Function type is irrelevant for streaming-agnostic builtins.
619 return false;
620 else if (SatisfiesSVE)
622 else if (SatisfiesSME)
624 else
625 // This should be diagnosed by CodeGen
626 return false;
627 }
628
629 if (FnType != SemaARM::ArmNonStreaming &&
631 S.Diag(TheCall->getBeginLoc(), diag::err_attribute_arm_sm_incompat_builtin)
632 << TheCall->getSourceRange() << "non-streaming";
633 else if (FnType != SemaARM::ArmStreaming &&
635 S.Diag(TheCall->getBeginLoc(), diag::err_attribute_arm_sm_incompat_builtin)
636 << TheCall->getSourceRange() << "streaming";
637 else
638 return false;
639
640 return true;
641}
642
643static ArmSMEState getSMEState(unsigned BuiltinID) {
644 switch (BuiltinID) {
645 default:
646 return ArmNoState;
647#define GET_SME_BUILTIN_GET_STATE
648#include "clang/Basic/arm_sme_builtins_za_state.inc"
649#undef GET_SME_BUILTIN_GET_STATE
650 }
651}
652
654 CallExpr *TheCall) {
655 if (const FunctionDecl *FD =
656 SemaRef.getCurFunctionDecl(/*AllowLambda=*/true)) {
657 std::optional<ArmStreamingType> BuiltinType;
658
659 switch (BuiltinID) {
660#define GET_SME_STREAMING_ATTRS
661#include "clang/Basic/arm_sme_streaming_attrs.inc"
662#undef GET_SME_STREAMING_ATTRS
663 }
664
665 if (BuiltinType &&
666 checkArmStreamingBuiltin(SemaRef, TheCall, FD, *BuiltinType, BuiltinID))
667 return true;
668
669 if ((getSMEState(BuiltinID) & ArmZAMask) && !hasArmZAState(FD))
670 Diag(TheCall->getBeginLoc(),
671 diag::warn_attribute_arm_za_builtin_no_za_state)
672 << TheCall->getSourceRange();
673
674 if ((getSMEState(BuiltinID) & ArmZT0Mask) && !hasArmZT0State(FD))
675 Diag(TheCall->getBeginLoc(),
676 diag::warn_attribute_arm_zt0_builtin_no_zt0_state)
677 << TheCall->getSourceRange();
678 }
679
680 // Range check SME intrinsics that take immediate values.
682
683 switch (BuiltinID) {
684 default:
685 return false;
686#define GET_SME_IMMEDIATE_CHECK
687#include "clang/Basic/arm_sme_sema_rangechecks.inc"
688#undef GET_SME_IMMEDIATE_CHECK
689 }
690
691 return PerformSVEImmChecks(TheCall, ImmChecks);
692}
693
695 CallExpr *TheCall) {
696 if (const FunctionDecl *FD =
697 SemaRef.getCurFunctionDecl(/*AllowLambda=*/true)) {
698 std::optional<ArmStreamingType> BuiltinType;
699
700 switch (BuiltinID) {
701#define GET_SVE_STREAMING_ATTRS
702#include "clang/Basic/arm_sve_streaming_attrs.inc"
703#undef GET_SVE_STREAMING_ATTRS
704 }
705 if (BuiltinType &&
706 checkArmStreamingBuiltin(SemaRef, TheCall, FD, *BuiltinType, BuiltinID))
707 return true;
708 }
709 // Range check SVE intrinsics that take immediate values.
711
712 switch (BuiltinID) {
713 default:
714 return false;
715#define GET_SVE_IMMEDIATE_CHECK
716#include "clang/Basic/arm_sve_sema_rangechecks.inc"
717#undef GET_SVE_IMMEDIATE_CHECK
718 }
719
720 return PerformSVEImmChecks(TheCall, ImmChecks);
721}
722
724 unsigned BuiltinID,
725 CallExpr *TheCall) {
726 if (const FunctionDecl *FD =
727 SemaRef.getCurFunctionDecl(/*AllowLambda=*/true)) {
728 std::optional<ArmStreamingType> BuiltinType;
729
730 switch (BuiltinID) {
731 default:
732 break;
733#define GET_NEON_STREAMING_COMPAT_FLAG
734#include "clang/Basic/arm_neon.inc"
735#undef GET_NEON_STREAMING_COMPAT_FLAG
736 }
737 if (BuiltinType &&
738 checkArmStreamingBuiltin(SemaRef, TheCall, FD, *BuiltinType, BuiltinID))
739 return true;
740 }
741
742 llvm::APSInt Result;
743 uint64_t mask = 0;
744 int TV = -1;
745 int PtrArgNum = -1;
746 bool HasConstPtr = false;
747 switch (BuiltinID) {
748#define GET_NEON_OVERLOAD_CHECK
749#include "clang/Basic/arm_fp16.inc"
750#include "clang/Basic/arm_neon.inc"
751#undef GET_NEON_OVERLOAD_CHECK
752 }
753
754 // For NEON intrinsics which are overloaded on vector element type, validate
755 // the immediate which specifies which variant to emit.
756 if (mask) {
757 unsigned ImmArg = TheCall->getNumArgs() - 1;
758 if (SemaRef.BuiltinConstantArg(TheCall, ImmArg, Result))
759 return true;
760
761 // FIXME: This is effectively dead code. Change the logic above so that the
762 // following check is actually run.
763 TV = Result.getLimitedValue(64);
764 if ((TV > 63) || (mask & (1ULL << TV)) == 0)
765 return Diag(TheCall->getBeginLoc(), diag::err_invalid_neon_type_code)
766 << TheCall->getArg(ImmArg)->getSourceRange();
767 }
768
769 if (PtrArgNum >= 0) {
770 // Check that pointer arguments have the specified type.
771 Expr *Arg = TheCall->getArg(PtrArgNum);
772 if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg))
773 Arg = ICE->getSubExpr();
774 ExprResult RHS = SemaRef.DefaultFunctionArrayLvalueConversion(Arg);
775 QualType RHSTy = RHS.get()->getType();
776
777 llvm::Triple::ArchType Arch = TI.getTriple().getArch();
778 bool IsPolyUnsigned = Arch == llvm::Triple::aarch64 ||
779 Arch == llvm::Triple::aarch64_32 ||
780 Arch == llvm::Triple::aarch64_be;
781 bool IsInt64Long = TI.getInt64Type() == TargetInfo::SignedLong;
783 IsPolyUnsigned, IsInt64Long);
784 if (HasConstPtr)
785 EltTy = EltTy.withConst();
786 QualType LHSTy = getASTContext().getPointerType(EltTy);
787 AssignConvertType ConvTy;
788 ConvTy = SemaRef.CheckSingleAssignmentConstraints(LHSTy, RHS);
789 if (RHS.isInvalid())
790 return true;
791 if (SemaRef.DiagnoseAssignmentResult(ConvTy, Arg->getBeginLoc(), LHSTy,
792 RHSTy, RHS.get(),
794 return true;
795 }
796
797 // For NEON intrinsics which take an immediate value as part of the
798 // instruction, range check them here.
800 switch (BuiltinID) {
801 default:
802 return false;
803#define GET_NEON_IMMEDIATE_CHECK
804#include "clang/Basic/arm_fp16.inc"
805#include "clang/Basic/arm_neon.inc"
806#undef GET_NEON_IMMEDIATE_CHECK
807 }
808
809 return PerformNeonImmChecks(TheCall, ImmChecks, TV);
810}
811
813 CallExpr *TheCall) {
814 switch (BuiltinID) {
815 default:
816 return false;
817#include "clang/Basic/arm_mve_builtin_sema.inc"
818 }
819}
820
822 unsigned BuiltinID,
823 CallExpr *TheCall) {
824 bool Err = false;
825 switch (BuiltinID) {
826 default:
827 return false;
828#include "clang/Basic/arm_cde_builtin_sema.inc"
829 }
830
831 if (Err)
832 return true;
833
834 return CheckARMCoprocessorImmediate(TI, TheCall->getArg(0), /*WantCDE*/ true);
835}
836
838 const Expr *CoprocArg,
839 bool WantCDE) {
840 ASTContext &Context = getASTContext();
841 if (SemaRef.isConstantEvaluatedContext())
842 return false;
843
844 // We can't check the value of a dependent argument.
845 if (CoprocArg->isTypeDependent() || CoprocArg->isValueDependent())
846 return false;
847
848 llvm::APSInt CoprocNoAP = *CoprocArg->getIntegerConstantExpr(Context);
849 int64_t CoprocNo = CoprocNoAP.getExtValue();
850 assert(CoprocNo >= 0 && "Coprocessor immediate must be non-negative");
851
852 uint32_t CDECoprocMask = TI.getARMCDECoprocMask();
853 bool IsCDECoproc = CoprocNo <= 7 && (CDECoprocMask & (1 << CoprocNo));
854
855 if (IsCDECoproc != WantCDE)
856 return Diag(CoprocArg->getBeginLoc(), diag::err_arm_invalid_coproc)
857 << (int)CoprocNo << (int)WantCDE << CoprocArg->getSourceRange();
858
859 return false;
860}
861
863 unsigned BuiltinID,
864 CallExpr *TheCall) {
865 assert((BuiltinID == ARM::BI__builtin_arm_ldrex ||
866 BuiltinID == ARM::BI__builtin_arm_ldrexd ||
867 BuiltinID == ARM::BI__builtin_arm_ldaex ||
868 BuiltinID == ARM::BI__builtin_arm_strex ||
869 BuiltinID == ARM::BI__builtin_arm_strexd ||
870 BuiltinID == ARM::BI__builtin_arm_stlex ||
871 BuiltinID == AArch64::BI__builtin_arm_ldrex ||
872 BuiltinID == AArch64::BI__builtin_arm_ldaex ||
873 BuiltinID == AArch64::BI__builtin_arm_strex ||
874 BuiltinID == AArch64::BI__builtin_arm_stlex) &&
875 "unexpected ARM builtin");
876 bool IsLdrex = BuiltinID == ARM::BI__builtin_arm_ldrex ||
877 BuiltinID == ARM::BI__builtin_arm_ldrexd ||
878 BuiltinID == ARM::BI__builtin_arm_ldaex ||
879 BuiltinID == AArch64::BI__builtin_arm_ldrex ||
880 BuiltinID == AArch64::BI__builtin_arm_ldaex;
881 bool IsDoubleWord = BuiltinID == ARM::BI__builtin_arm_ldrexd ||
882 BuiltinID == ARM::BI__builtin_arm_strexd;
883
884 ASTContext &Context = getASTContext();
885 DeclRefExpr *DRE =
887
888 // Ensure that we have the proper number of arguments.
889 if (SemaRef.checkArgCount(TheCall, IsLdrex ? 1 : 2))
890 return true;
891
892 // Inspect the pointer argument of the atomic builtin. This should always be
893 // a pointer type, whose element is an integral scalar or pointer type.
894 // Because it is a pointer type, we don't have to worry about any implicit
895 // casts here.
896 Expr *PointerArg = TheCall->getArg(IsLdrex ? 0 : 1);
897 ExprResult PointerArgRes =
898 SemaRef.DefaultFunctionArrayLvalueConversion(PointerArg);
899 if (PointerArgRes.isInvalid())
900 return true;
901 PointerArg = PointerArgRes.get();
902
903 const PointerType *pointerType = PointerArg->getType()->getAs<PointerType>();
904 if (!pointerType) {
905 Diag(DRE->getBeginLoc(), diag::err_atomic_builtin_must_be_pointer)
906 << PointerArg->getType() << 0 << PointerArg->getSourceRange();
907 return true;
908 }
909
910 // ldrex takes a "const volatile T*" and strex takes a "volatile T*". Our next
911 // task is to insert the appropriate casts into the AST. First work out just
912 // what the appropriate type is.
913 QualType ValType = pointerType->getPointeeType();
914 QualType AddrType = ValType.getUnqualifiedType().withVolatile();
915 if (IsLdrex)
916 AddrType.addConst();
917
918 // Issue a warning if the cast is dodgy.
919 CastKind CastNeeded = CK_NoOp;
920 if (!AddrType.isAtLeastAsQualifiedAs(ValType, getASTContext())) {
921 CastNeeded = CK_BitCast;
922 Diag(DRE->getBeginLoc(), diag::ext_typecheck_convert_discards_qualifiers)
923 << PointerArg->getType() << Context.getPointerType(AddrType)
924 << AssignmentAction::Passing << PointerArg->getSourceRange();
925 }
926
927 // Finally, do the cast and replace the argument with the corrected version.
928 AddrType = Context.getPointerType(AddrType);
929 PointerArgRes = SemaRef.ImpCastExprToType(PointerArg, AddrType, CastNeeded);
930 if (PointerArgRes.isInvalid())
931 return true;
932 PointerArg = PointerArgRes.get();
933
934 TheCall->setArg(IsLdrex ? 0 : 1, PointerArg);
935
936 // In general, we allow ints, floats and pointers to be loaded and stored.
937 if (!ValType->isIntegerType() && !ValType->isAnyPointerType() &&
938 !ValType->isBlockPointerType() && !ValType->isFloatingType()) {
939 Diag(DRE->getBeginLoc(), diag::err_atomic_builtin_must_be_pointer_intfltptr)
940 << PointerArg->getType() << 0 << PointerArg->getSourceRange();
941 return true;
942 }
943
944 // Check whether the size of the type can be handled atomically on this
945 // target.
946 if (!TI.getTriple().isAArch64()) {
947 unsigned Mask = TI.getARMLDREXMask();
948 unsigned Bits = Context.getTypeSize(ValType);
949 if (IsDoubleWord) {
950 // Explicit request for ldrexd/strexd means only double word sizes
951 // supported if the target supports them.
953 }
954 bool Supported =
955 (llvm::isPowerOf2_64(Bits)) && Bits >= 8 && (Mask & (Bits / 8));
956
957 if (!Supported) {
958 // Emit a diagnostic saying that this size isn't available. If _no_ size
959 // of exclusive access is supported on this target, we emit a diagnostic
960 // with special wording for that case, but otherwise, we emit
961 // err_atomic_exclusive_builtin_pointer_size and loop over `Mask` to
962 // control what subset of sizes it lists as legal.
963 if (Mask) {
964 auto D = Diag(DRE->getBeginLoc(),
965 diag::err_atomic_exclusive_builtin_pointer_size)
966 << PointerArg->getType();
967 bool Started = false;
968 for (unsigned Size = 1; Size <= 8; Size <<= 1) {
969 // For each of the sizes 1,2,4,8, pass two integers into the
970 // diagnostic. The first selects a separator from the previous
971 // number: 0 for no separator at all, 1 for a comma, 2 for " or "
972 // which appears before the final number in a list of more than one.
973 // The second integer just indicates whether we print this size in
974 // the message at all.
975 if (!(Mask & Size)) {
976 // This size isn't one of the supported ones, so emit no separator
977 // text and don't print the size itself.
978 D << 0 << 0;
979 } else {
980 // This size is supported, so print it, and an appropriate
981 // separator.
982 Mask &= ~Size;
983 if (!Started)
984 D << 0; // No separator if this is the first size we've printed
985 else if (Mask)
986 D << 1; // "," if there's still another size to come
987 else
988 D << 2; // " or " if the size we're about to print is the last
989 D << 1; // print the size itself
990 Started = true;
991 }
992 }
993 } else {
994 bool EmitDoubleWordDiagnostic =
995 IsDoubleWord && !Mask && TI.getARMLDREXMask();
996 Diag(DRE->getBeginLoc(),
997 diag::err_atomic_exclusive_builtin_pointer_size_none)
998 << (EmitDoubleWordDiagnostic ? 1 : 0)
999 << PointerArg->getSourceRange();
1000 }
1001 }
1002 }
1003
1004 switch (ValType.getObjCLifetime()) {
1007 // okay
1008 break;
1009
1013 Diag(DRE->getBeginLoc(), diag::err_arc_atomic_ownership)
1014 << ValType << PointerArg->getSourceRange();
1015 return true;
1016 }
1017
1018 if (IsLdrex) {
1019 TheCall->setType(ValType);
1020 return false;
1021 }
1022
1023 // Initialize the argument to be stored.
1024 ExprResult ValArg = TheCall->getArg(0);
1026 Context, ValType, /*consume*/ false);
1027 ValArg = SemaRef.PerformCopyInitialization(Entity, SourceLocation(), ValArg);
1028 if (ValArg.isInvalid())
1029 return true;
1030 TheCall->setArg(0, ValArg.get());
1031
1032 // __builtin_arm_strex always returns an int. It's marked as such in the .def,
1033 // but the custom checker bypasses all default analysis.
1034 TheCall->setType(Context.IntTy);
1035 return false;
1036}
1037
1039 unsigned BuiltinID,
1040 CallExpr *TheCall) {
1041 if (BuiltinID == ARM::BI__builtin_arm_ldrex ||
1042 BuiltinID == ARM::BI__builtin_arm_ldrexd ||
1043 BuiltinID == ARM::BI__builtin_arm_ldaex ||
1044 BuiltinID == ARM::BI__builtin_arm_strex ||
1045 BuiltinID == ARM::BI__builtin_arm_strexd ||
1046 BuiltinID == ARM::BI__builtin_arm_stlex) {
1047 return CheckARMBuiltinExclusiveCall(TI, BuiltinID, TheCall);
1048 }
1049
1050 if (BuiltinID == ARM::BI__builtin_arm_prefetch) {
1051 return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 1) ||
1052 SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 1);
1053 }
1054
1055 if (BuiltinID == ARM::BI__builtin_arm_rsr64 ||
1056 BuiltinID == ARM::BI__builtin_arm_wsr64)
1057 return BuiltinARMSpecialReg(BuiltinID, TheCall, 0, 3, false);
1058
1059 if (BuiltinID == ARM::BI__builtin_arm_rsr ||
1060 BuiltinID == ARM::BI__builtin_arm_rsrp ||
1061 BuiltinID == ARM::BI__builtin_arm_wsr ||
1062 BuiltinID == ARM::BI__builtin_arm_wsrp)
1063 return BuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true);
1064
1065 if (CheckNeonBuiltinFunctionCall(TI, BuiltinID, TheCall))
1066 return true;
1067 if (CheckMVEBuiltinFunctionCall(BuiltinID, TheCall))
1068 return true;
1069 if (CheckCDEBuiltinFunctionCall(TI, BuiltinID, TheCall))
1070 return true;
1071
1072 // For intrinsics which take an immediate value as part of the instruction,
1073 // range check them here.
1074 // FIXME: VFP Intrinsics should error if VFP not present.
1075 switch (BuiltinID) {
1076 default:
1077 return false;
1078 case ARM::BI__builtin_arm_ssat:
1079 return SemaRef.BuiltinConstantArgRange(TheCall, 1, 1, 32);
1080 case ARM::BI__builtin_arm_usat:
1081 return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 31);
1082 case ARM::BI__builtin_arm_ssat16:
1083 return SemaRef.BuiltinConstantArgRange(TheCall, 1, 1, 16);
1084 case ARM::BI__builtin_arm_usat16:
1085 return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 15);
1086 case ARM::BI__builtin_arm_vcvtr_f:
1087 case ARM::BI__builtin_arm_vcvtr_d:
1088 return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 1);
1089 case ARM::BI__builtin_arm_dmb:
1090 case ARM::BI__dmb:
1091 case ARM::BI__builtin_arm_dsb:
1092 case ARM::BI__dsb:
1093 case ARM::BI__builtin_arm_isb:
1094 case ARM::BI__isb:
1095 case ARM::BI__builtin_arm_dbg:
1096 return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 15);
1097 case ARM::BI__builtin_arm_cdp:
1098 case ARM::BI__builtin_arm_cdp2:
1099 case ARM::BI__builtin_arm_mcr:
1100 case ARM::BI__builtin_arm_mcr2:
1101 case ARM::BI__builtin_arm_mrc:
1102 case ARM::BI__builtin_arm_mrc2:
1103 case ARM::BI__builtin_arm_mcrr:
1104 case ARM::BI__builtin_arm_mcrr2:
1105 case ARM::BI__builtin_arm_mrrc:
1106 case ARM::BI__builtin_arm_mrrc2:
1107 case ARM::BI__builtin_arm_ldc:
1108 case ARM::BI__builtin_arm_ldcl:
1109 case ARM::BI__builtin_arm_ldc2:
1110 case ARM::BI__builtin_arm_ldc2l:
1111 case ARM::BI__builtin_arm_stc:
1112 case ARM::BI__builtin_arm_stcl:
1113 case ARM::BI__builtin_arm_stc2:
1114 case ARM::BI__builtin_arm_stc2l:
1115 return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 15) ||
1116 CheckARMCoprocessorImmediate(TI, TheCall->getArg(0),
1117 /*WantCDE*/ false);
1118 }
1119}
1120
1122 unsigned BuiltinID,
1123 CallExpr *TheCall) {
1124 if (BuiltinID == AArch64::BI__builtin_arm_ldrex ||
1125 BuiltinID == AArch64::BI__builtin_arm_ldaex ||
1126 BuiltinID == AArch64::BI__builtin_arm_strex ||
1127 BuiltinID == AArch64::BI__builtin_arm_stlex) {
1128 return CheckARMBuiltinExclusiveCall(TI, BuiltinID, TheCall);
1129 }
1130
1131 if (BuiltinID == AArch64::BI__builtin_arm_prefetch) {
1132 return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 1) ||
1133 SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 3) ||
1134 SemaRef.BuiltinConstantArgRange(TheCall, 3, 0, 1) ||
1135 SemaRef.BuiltinConstantArgRange(TheCall, 4, 0, 1);
1136 }
1137
1138 if (BuiltinID == AArch64::BI__builtin_arm_range_prefetch_x) {
1139 return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 1) ||
1140 SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 1) ||
1141 SemaRef.BuiltinConstantArgRange(TheCall, 3, -2097152, 2097151) ||
1142 SemaRef.BuiltinConstantArgRange(TheCall, 4, 1, 65536) ||
1143 SemaRef.BuiltinConstantArgRange(TheCall, 5, -2097152, 2097151);
1144 }
1145
1146 if (BuiltinID == AArch64::BI__builtin_arm_range_prefetch) {
1147 return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 1) ||
1148 SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 1);
1149 }
1150
1151 if (BuiltinID == AArch64::BI__builtin_arm_rsr64 ||
1152 BuiltinID == AArch64::BI__builtin_arm_wsr64 ||
1153 BuiltinID == AArch64::BI__builtin_arm_rsr128 ||
1154 BuiltinID == AArch64::BI__builtin_arm_wsr128)
1155 return BuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true);
1156
1157 // Memory Tagging Extensions (MTE) Intrinsics
1158 if (BuiltinID == AArch64::BI__builtin_arm_irg ||
1159 BuiltinID == AArch64::BI__builtin_arm_addg ||
1160 BuiltinID == AArch64::BI__builtin_arm_gmi ||
1161 BuiltinID == AArch64::BI__builtin_arm_ldg ||
1162 BuiltinID == AArch64::BI__builtin_arm_stg ||
1163 BuiltinID == AArch64::BI__builtin_arm_subp) {
1164 return BuiltinARMMemoryTaggingCall(BuiltinID, TheCall);
1165 }
1166
1167 if (BuiltinID == AArch64::BI__builtin_arm_rsr ||
1168 BuiltinID == AArch64::BI__builtin_arm_rsrp ||
1169 BuiltinID == AArch64::BI__builtin_arm_wsr ||
1170 BuiltinID == AArch64::BI__builtin_arm_wsrp)
1171 return BuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true);
1172
1173 // Only check the valid encoding range. Any constant in this range would be
1174 // converted to a register of the form S2_2_C3_C4_5. Let the hardware throw
1175 // an exception for incorrect registers. This matches MSVC behavior.
1176 if (BuiltinID == AArch64::BI_ReadStatusReg ||
1177 BuiltinID == AArch64::BI_WriteStatusReg)
1178 return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0x4000, 0x7fff);
1179
1180 if (BuiltinID == AArch64::BI__sys)
1181 return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 0x3fff);
1182
1183 if (BuiltinID == AArch64::BI__getReg || BuiltinID == AArch64::BI__setReg ||
1184 BuiltinID == AArch64::BI__getRegFp || BuiltinID == AArch64::BI__setRegFp)
1185 return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 31);
1186
1187 if (BuiltinID == AArch64::BI__prefetch2)
1188 return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 31);
1189
1190 if (BuiltinID == AArch64::BI__break)
1191 return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 0xffff);
1192
1193 if (BuiltinID == AArch64::BI__hlt)
1194 return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 0xffff);
1195
1196 if (BuiltinID == AArch64::BI__hvc || BuiltinID == AArch64::BI__svc) {
1197 // The immediate is the instruction number; the remaining arguments (at most
1198 // four) are passed in X0-X3, so the call takes at most five arguments.
1199 if (SemaRef.checkArgCountAtMost(TheCall, 5) ||
1200 SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 0xffff))
1201 return true;
1202 const FunctionDecl *FD = TheCall->getDirectCallee();
1203 for (unsigned I = 1, N = TheCall->getNumArgs(); I < N; ++I) {
1204 const Expr *Arg = TheCall->getArg(I);
1205 QualType Ty = Arg->getType();
1206 if (!Ty->isIntegerType() && !Ty->isAnyPointerType() &&
1207 !Ty->isBlockPointerType() && !Ty->isFloatingType())
1208 return Diag(Arg->getBeginLoc(),
1209 diag::err_aarch64_svc_hvc_invalid_arg_type)
1210 << I + 1 << FD << Ty << Arg->getSourceRange();
1211 }
1212 return false;
1213 }
1214
1215 if (CheckNeonBuiltinFunctionCall(TI, BuiltinID, TheCall))
1216 return true;
1217
1218 if (CheckSVEBuiltinFunctionCall(BuiltinID, TheCall))
1219 return true;
1220
1221 if (CheckSMEBuiltinFunctionCall(BuiltinID, TheCall))
1222 return true;
1223
1224 // For intrinsics which take an immediate value as part of the instruction,
1225 // range check them here.
1226 unsigned i = 0, l = 0, u = 0;
1227 switch (BuiltinID) {
1228 default: return false;
1229 case AArch64::BI__builtin_arm_dmb:
1230 case AArch64::BI__dmb:
1231 case AArch64::BI__builtin_arm_dsb:
1232 case AArch64::BI__dsb:
1233 case AArch64::BI__builtin_arm_isb:
1234 case AArch64::BI__isb:
1235 l = 0;
1236 u = 15;
1237 break;
1238 }
1239
1240 return SemaRef.BuiltinConstantArgRange(TheCall, i, l, u + l);
1241}
1242
1243namespace {
1244struct IntrinToName {
1245 uint32_t Id;
1246 int32_t FullName;
1247 int32_t ShortName;
1248};
1249} // unnamed namespace
1250
1251static bool BuiltinAliasValid(unsigned BuiltinID, StringRef AliasName,
1253 const char *IntrinNames) {
1254 AliasName.consume_front("__arm_");
1255 const IntrinToName *It =
1256 llvm::lower_bound(Map, BuiltinID, [](const IntrinToName &L, unsigned Id) {
1257 return L.Id < Id;
1258 });
1259 if (It == Map.end() || It->Id != BuiltinID)
1260 return false;
1261 StringRef FullName(&IntrinNames[It->FullName]);
1262 if (AliasName == FullName)
1263 return true;
1264 if (It->ShortName == -1)
1265 return false;
1266 StringRef ShortName(&IntrinNames[It->ShortName]);
1267 return AliasName == ShortName;
1268}
1269
1270bool SemaARM::MveAliasValid(unsigned BuiltinID, StringRef AliasName) {
1271#include "clang/Basic/arm_mve_builtin_aliases.inc"
1272 // The included file defines:
1273 // - ArrayRef<IntrinToName> Map
1274 // - const char IntrinNames[]
1275 return BuiltinAliasValid(BuiltinID, AliasName, Map, IntrinNames);
1276}
1277
1278bool SemaARM::CdeAliasValid(unsigned BuiltinID, StringRef AliasName) {
1279#include "clang/Basic/arm_cde_builtin_aliases.inc"
1280 return BuiltinAliasValid(BuiltinID, AliasName, Map, IntrinNames);
1281}
1282
1283bool SemaARM::SveAliasValid(unsigned BuiltinID, StringRef AliasName) {
1284 if (getASTContext().BuiltinInfo.isAuxBuiltinID(BuiltinID))
1285 BuiltinID = getASTContext().BuiltinInfo.getAuxBuiltinID(BuiltinID);
1286 return BuiltinID >= AArch64::FirstSVEBuiltin &&
1287 BuiltinID <= AArch64::LastSVEBuiltin;
1288}
1289
1290bool SemaARM::SmeAliasValid(unsigned BuiltinID, StringRef AliasName) {
1291 if (getASTContext().BuiltinInfo.isAuxBuiltinID(BuiltinID))
1292 BuiltinID = getASTContext().BuiltinInfo.getAuxBuiltinID(BuiltinID);
1293 return BuiltinID >= AArch64::FirstSMEBuiltin &&
1294 BuiltinID <= AArch64::LastSMEBuiltin;
1295}
1296
1298 ASTContext &Context = getASTContext();
1299 if (!AL.isArgIdent(0)) {
1300 Diag(AL.getLoc(), diag::err_attribute_argument_n_type)
1301 << AL << 1 << AANT_ArgumentIdentifier;
1302 return;
1303 }
1304
1306 unsigned BuiltinID = Ident->getBuiltinID();
1307 StringRef AliasName = cast<FunctionDecl>(D)->getIdentifier()->getName();
1308
1309 bool IsAArch64 = Context.getTargetInfo().getTriple().isAArch64();
1310 if ((IsAArch64 && !SveAliasValid(BuiltinID, AliasName) &&
1311 !SmeAliasValid(BuiltinID, AliasName)) ||
1312 (!IsAArch64 && !MveAliasValid(BuiltinID, AliasName) &&
1313 !CdeAliasValid(BuiltinID, AliasName))) {
1314 Diag(AL.getLoc(), diag::err_attribute_arm_builtin_alias);
1315 return;
1316 }
1317
1318 D->addAttr(::new (Context) ArmBuiltinAliasAttr(Context, AL, Ident));
1319}
1320
1322 Sema &S, const ParsedAttr &AL, const FunctionProtoType *FPT,
1323 FunctionType::ArmStateValue CurrentState, StringRef StateName) {
1324 auto CheckForIncompatibleAttr =
1325 [&](FunctionType::ArmStateValue IncompatibleState,
1326 StringRef IncompatibleStateName) {
1327 if (CurrentState == IncompatibleState) {
1328 S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible)
1329 << (std::string("'__arm_new(\"") + StateName.str() + "\")'")
1330 << (std::string("'") + IncompatibleStateName.str() + "(\"" +
1331 StateName.str() + "\")'")
1332 << true;
1333 AL.setInvalid();
1334 }
1335 };
1336
1337 CheckForIncompatibleAttr(FunctionType::ARM_In, "__arm_in");
1338 CheckForIncompatibleAttr(FunctionType::ARM_Out, "__arm_out");
1339 CheckForIncompatibleAttr(FunctionType::ARM_InOut, "__arm_inout");
1340 CheckForIncompatibleAttr(FunctionType::ARM_Preserves, "__arm_preserves");
1341 return AL.isInvalid();
1342}
1343
1345 if (!AL.getNumArgs()) {
1346 Diag(AL.getLoc(), diag::err_missing_arm_state) << AL;
1347 AL.setInvalid();
1348 return;
1349 }
1350
1351 std::vector<StringRef> NewState;
1352 if (const auto *ExistingAttr = D->getAttr<ArmNewAttr>()) {
1353 for (StringRef S : ExistingAttr->newArgs())
1354 NewState.push_back(S);
1355 }
1356
1357 bool HasZA = false;
1358 bool HasZT0 = false;
1359 for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) {
1360 StringRef StateName;
1361 SourceLocation LiteralLoc;
1362 if (!SemaRef.checkStringLiteralArgumentAttr(AL, I, StateName, &LiteralLoc))
1363 return;
1364
1365 if (StateName == "za")
1366 HasZA = true;
1367 else if (StateName == "zt0")
1368 HasZT0 = true;
1369 else {
1370 Diag(LiteralLoc, diag::err_unknown_arm_state) << StateName;
1371 AL.setInvalid();
1372 return;
1373 }
1374
1375 if (!llvm::is_contained(NewState, StateName)) // Avoid adding duplicates.
1376 NewState.push_back(StateName);
1377 }
1378
1379 if (auto *FPT = dyn_cast<FunctionProtoType>(D->getFunctionType())) {
1381 FunctionType::getArmZAState(FPT->getAArch64SMEAttributes());
1382 if (HasZA && ZAState != FunctionType::ARM_None &&
1383 checkNewAttrMutualExclusion(SemaRef, AL, FPT, ZAState, "za"))
1384 return;
1386 FunctionType::getArmZT0State(FPT->getAArch64SMEAttributes());
1387 if (HasZT0 && ZT0State != FunctionType::ARM_None &&
1388 checkNewAttrMutualExclusion(SemaRef, AL, FPT, ZT0State, "zt0"))
1389 return;
1390 }
1391
1392 D->dropAttr<ArmNewAttr>();
1393 D->addAttr(::new (getASTContext()) ArmNewAttr(
1394 getASTContext(), AL, NewState.data(), NewState.size()));
1395}
1396
1399 Diag(AL.getLoc(), diag::err_attribute_not_clinkage) << AL;
1400 return;
1401 }
1402
1403 const auto *FD = cast<FunctionDecl>(D);
1404 if (!FD->isExternallyVisible()) {
1405 Diag(AL.getLoc(), diag::warn_attribute_cmse_entry_static);
1406 return;
1407 }
1408
1409 D->addAttr(::new (getASTContext()) CmseNSEntryAttr(getASTContext(), AL));
1410}
1411
1413 // Check the attribute arguments.
1414 if (AL.getNumArgs() > 1) {
1415 Diag(AL.getLoc(), diag::err_attribute_too_many_arguments) << AL << 1;
1416 return;
1417 }
1418
1419 StringRef Str;
1420 SourceLocation ArgLoc;
1421
1422 if (AL.getNumArgs() == 0)
1423 Str = "";
1424 else if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
1425 return;
1426
1427 ARMInterruptAttr::InterruptType Kind;
1428 if (!ARMInterruptAttr::ConvertStrToInterruptType(Str, Kind)) {
1429 Diag(AL.getLoc(), diag::warn_attribute_type_not_supported)
1430 << AL << Str << ArgLoc;
1431 return;
1432 }
1433
1434 if (!D->hasAttr<ARMSaveFPAttr>()) {
1435 const TargetInfo &TI = getASTContext().getTargetInfo();
1436 if (TI.hasFeature("vfp"))
1437 Diag(D->getLocation(), diag::warn_arm_interrupt_vfp_clobber);
1438 }
1439
1440 D->addAttr(::new (getASTContext())
1441 ARMInterruptAttr(getASTContext(), AL, Kind));
1442}
1443
1445 // Go ahead and add ARMSaveFPAttr because handleInterruptAttr() checks for
1446 // it when deciding to issue a diagnostic about clobbering floating point
1447 // registers, which ARMSaveFPAttr prevents.
1448 D->addAttr(::new (SemaRef.Context) ARMSaveFPAttr(SemaRef.Context, AL));
1449 SemaRef.ARM().handleInterruptAttr(D, AL);
1450
1451 // If ARM().handleInterruptAttr() failed, remove ARMSaveFPAttr.
1452 if (!D->hasAttr<ARMInterruptAttr>()) {
1453 D->dropAttr<ARMSaveFPAttr>();
1454 return;
1455 }
1456
1457 // If VFP not enabled, remove ARMSaveFPAttr but leave ARMInterruptAttr.
1458 bool VFP = SemaRef.Context.getTargetInfo().hasFeature("vfp");
1459
1460 if (!VFP) {
1461 SemaRef.Diag(D->getLocation(), diag::warn_arm_interrupt_save_fp_without_vfp_unit);
1462 D->dropAttr<ARMSaveFPAttr>();
1463 }
1464}
1465
1466// Check if the function definition uses any AArch64 SME features without
1467// having the '+sme' feature enabled and warn user if sme locally streaming
1468// function returns or uses arguments with VL-based types.
1470 const auto *Attr = FD->getAttr<ArmNewAttr>();
1471 bool UsesSM = FD->hasAttr<ArmLocallyStreamingAttr>();
1472 bool UsesZA = Attr && Attr->isNewZA();
1473 bool UsesZT0 = Attr && Attr->isNewZT0();
1474
1475 if (UsesZA || UsesZT0) {
1476 if (const auto *FPT = FD->getType()->getAs<FunctionProtoType>()) {
1477 FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
1479 Diag(FD->getLocation(), diag::err_sme_unsupported_agnostic_new);
1480 }
1481 }
1482
1483 if (FD->hasAttr<ArmLocallyStreamingAttr>()) {
1485 Diag(FD->getLocation(),
1486 diag::warn_sme_locally_streaming_has_vl_args_returns)
1487 << /*IsArg=*/false;
1488 if (llvm::any_of(FD->parameters(), [](ParmVarDecl *P) {
1489 return P->getOriginalType()->isSizelessVectorType();
1490 }))
1491 Diag(FD->getLocation(),
1492 diag::warn_sme_locally_streaming_has_vl_args_returns)
1493 << /*IsArg=*/true;
1494 }
1495 if (const auto *FPT = FD->getType()->getAs<FunctionProtoType>()) {
1496 FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
1502 }
1503
1504 ASTContext &Context = getASTContext();
1505 if (UsesSM || UsesZA) {
1506 llvm::StringMap<bool> FeatureMap;
1507 Context.getFunctionFeatureMap(FeatureMap, FD);
1508 if (!FeatureMap.contains("sme")) {
1509 if (UsesSM)
1510 Diag(FD->getLocation(),
1511 diag::err_sme_definition_using_sm_in_non_sme_target);
1512 else
1513 Diag(FD->getLocation(),
1514 diag::err_sme_definition_using_za_in_non_sme_target);
1515 }
1516 }
1517 if (UsesZT0) {
1518 llvm::StringMap<bool> FeatureMap;
1519 Context.getFunctionFeatureMap(FeatureMap, FD);
1520 if (!FeatureMap.contains("sme2")) {
1521 Diag(FD->getLocation(),
1522 diag::err_sme_definition_using_zt0_in_non_sme2_target);
1523 }
1524 }
1525}
1526
1527/// getSVETypeSize - Return SVE vector or predicate register size.
1528static uint64_t getSVETypeSize(ASTContext &Context, const BuiltinType *Ty,
1529 bool IsStreaming) {
1530 assert(Ty->isSveVLSBuiltinType() && "Invalid SVE Type");
1531 uint64_t VScale = IsStreaming ? Context.getLangOpts().VScaleStreamingMin
1532 : Context.getLangOpts().VScaleMin;
1533 if (Ty->getKind() == BuiltinType::SveBool ||
1534 Ty->getKind() == BuiltinType::SveCount)
1535 return (VScale * 128) / Context.getCharWidth();
1536 return VScale * 128;
1537}
1538
1540 bool IsStreaming = false;
1541 if (getLangOpts().VScaleMin != getLangOpts().VScaleStreamingMin ||
1542 getLangOpts().VScaleMax != getLangOpts().VScaleStreamingMax) {
1543 if (const FunctionDecl *FD =
1544 SemaRef.getCurFunctionDecl(/*AllowLambda=*/true)) {
1545 // For streaming-compatible functions, we don't know vector length.
1546 if (const auto *T = FD->getType()->getAs<FunctionProtoType>()) {
1547 if (T->getAArch64SMEAttributes() &
1549 return false;
1550 }
1551
1552 if (IsArmStreamingFunction(FD, /*IncludeLocallyStreaming=*/true))
1553 IsStreaming = true;
1554 }
1555 }
1556
1557 auto IsValidCast = [&](QualType FirstType, QualType SecondType) {
1558 if (const auto *BT = FirstType->getAs<BuiltinType>()) {
1559 if (const auto *VT = SecondType->getAs<VectorType>()) {
1560 // Predicates have the same representation as uint8 so we also have to
1561 // check the kind to make these types incompatible.
1562 ASTContext &Context = getASTContext();
1563 if (VT->getVectorKind() == VectorKind::SveFixedLengthPredicate)
1564 return BT->getKind() == BuiltinType::SveBool;
1565 else if (VT->getVectorKind() == VectorKind::SveFixedLengthData)
1566 return VT->getElementType().getCanonicalType() ==
1567 FirstType->getSveEltType(Context) &&
1568 BT->getKind() != BuiltinType::SveBool;
1569 else if (VT->getVectorKind() == VectorKind::Generic)
1570 return Context.getTypeSize(SecondType) ==
1571 getSVETypeSize(Context, BT, IsStreaming) &&
1572 Context.hasSameType(
1573 VT->getElementType(),
1574 Context.getBuiltinVectorTypeInfo(BT).ElementType);
1575 }
1576 }
1577 return false;
1578 };
1579
1580 return IsValidCast(FirstType, SecondType) ||
1581 IsValidCast(SecondType, FirstType);
1582}
1583
1585 QualType SecondType) {
1586 bool IsStreaming = false;
1587 if (getLangOpts().VScaleMin != getLangOpts().VScaleStreamingMin ||
1588 getLangOpts().VScaleMax != getLangOpts().VScaleStreamingMax) {
1589 if (const FunctionDecl *FD =
1590 SemaRef.getCurFunctionDecl(/*AllowLambda=*/true)) {
1591 // For streaming-compatible functions, we don't know vector length.
1592 if (const auto *T = FD->getType()->getAs<FunctionProtoType>())
1593 if (T->getAArch64SMEAttributes() &
1595 return false;
1596
1597 if (IsArmStreamingFunction(FD, /*IncludeLocallyStreaming=*/true))
1598 IsStreaming = true;
1599 }
1600 }
1601
1602 auto IsLaxCompatible = [&](QualType FirstType, QualType SecondType) {
1603 const auto *BT = FirstType->getAs<BuiltinType>();
1604 if (!BT)
1605 return false;
1606
1607 const auto *VecTy = SecondType->getAs<VectorType>();
1608 if (VecTy && (VecTy->getVectorKind() == VectorKind::SveFixedLengthData ||
1609 VecTy->getVectorKind() == VectorKind::Generic)) {
1611 getLangOpts().getLaxVectorConversions();
1612 ASTContext &Context = getASTContext();
1613
1614 // Can not convert between sve predicates and sve vectors because of
1615 // different size.
1616 if (BT->getKind() == BuiltinType::SveBool &&
1617 VecTy->getVectorKind() == VectorKind::SveFixedLengthData)
1618 return false;
1619
1620 // If __ARM_FEATURE_SVE_BITS != N do not allow GNU vector lax conversion.
1621 // "Whenever __ARM_FEATURE_SVE_BITS==N, GNUT implicitly
1622 // converts to VLAT and VLAT implicitly converts to GNUT."
1623 // ACLE Spec Version 00bet6, 3.7.3.2. Behavior common to vectors and
1624 // predicates.
1625 if (VecTy->getVectorKind() == VectorKind::Generic &&
1626 Context.getTypeSize(SecondType) !=
1627 getSVETypeSize(Context, BT, IsStreaming))
1628 return false;
1629
1630 // If -flax-vector-conversions=all is specified, the types are
1631 // certainly compatible.
1633 return true;
1634
1635 // If -flax-vector-conversions=integer is specified, the types are
1636 // compatible if the elements are integer types.
1638 return VecTy->getElementType().getCanonicalType()->isIntegerType() &&
1639 FirstType->getSveEltType(Context)->isIntegerType();
1640 }
1641
1642 return false;
1643 };
1644
1645 return IsLaxCompatible(FirstType, SecondType) ||
1646 IsLaxCompatible(SecondType, FirstType);
1647}
1648
1649static void appendFeature(StringRef Feat, SmallString<64> &Buffer) {
1650 if (!Buffer.empty())
1651 Buffer.append("+");
1652 Buffer.append(Feat);
1653}
1654
1655static void convertPriorityString(unsigned Priority,
1656 SmallString<64> &NewParam) {
1657 StringRef PriorityString[8] = {"P0", "P1", "P2", "P3",
1658 "P4", "P5", "P6", "P7"};
1659
1660 assert(Priority > 0 && Priority < 256 && "priority out of range");
1661 // Convert priority=[1-255] -> P0 + ... + P7
1662 for (unsigned BitPos = 0; BitPos < 8; ++BitPos)
1663 if (Priority & (1U << BitPos))
1664 appendFeature(PriorityString[BitPos], NewParam);
1665}
1666
1667bool SemaARM::checkTargetVersionAttr(const StringRef Param,
1668 const SourceLocation Loc,
1669 SmallString<64> &NewParam) {
1670 using namespace DiagAttrParams;
1671
1672 auto [LHS, RHS] = Param.split(';');
1673 RHS = RHS.trim();
1674 bool IsDefault = false;
1676 LHS.split(Features, '+');
1677 for (StringRef Feat : Features) {
1678 Feat = Feat.trim();
1679 if (Feat == "default")
1680 IsDefault = true;
1681 else if (!getASTContext().getTargetInfo().validateCpuSupports(Feat))
1682 return Diag(Loc, diag::warn_unsupported_target_attribute)
1683 << Unsupported << None << Feat << TargetVersion;
1684 appendFeature(Feat, NewParam);
1685 }
1686
1687 if (!RHS.empty() && RHS.consume_front("priority=")) {
1688 if (IsDefault)
1689 Diag(Loc, diag::warn_invalid_default_version_priority);
1690 else {
1691 unsigned Digit;
1692 if (RHS.getAsInteger(0, Digit) || Digit < 1 || Digit > 255)
1693 Diag(Loc, diag::warn_version_priority_out_of_range) << RHS;
1694 else
1695 convertPriorityString(Digit, NewParam);
1696 }
1697 }
1698 return false;
1699}
1700
1703 SmallVectorImpl<SmallString<64>> &NewParams) {
1704 using namespace DiagAttrParams;
1705
1706 if (!getASTContext().getTargetInfo().hasFeature("fmv"))
1707 return true;
1708
1709 assert(Params.size() == Locs.size() &&
1710 "Mismatch between number of string parameters and locations");
1711
1712 bool HasDefault = false;
1713 bool HasNonDefault = false;
1714 for (unsigned I = 0, E = Params.size(); I < E; ++I) {
1715 const StringRef Param = Params[I].trim();
1716 const SourceLocation &Loc = Locs[I];
1717
1718 auto [LHS, RHS] = Param.split(';');
1719 RHS = RHS.trim();
1720 bool HasPriority = !RHS.empty() && RHS.consume_front("priority=");
1721
1722 if (LHS.empty())
1723 return Diag(Loc, diag::warn_unsupported_target_attribute)
1724 << Unsupported << None << "" << TargetClones;
1725
1726 if (LHS == "default") {
1727 if (HasDefault)
1728 Diag(Loc, diag::warn_target_clone_duplicate_options);
1729 else {
1730 if (HasPriority)
1731 Diag(Loc, diag::warn_invalid_default_version_priority);
1732 NewParams.push_back(LHS);
1733 HasDefault = true;
1734 }
1735 continue;
1736 }
1737
1738 bool HasCodeGenImpact = false;
1740 llvm::SmallVector<StringRef, 8> ValidFeatures;
1741 LHS.split(Features, '+');
1742 for (StringRef Feat : Features) {
1743 Feat = Feat.trim();
1744 if (!getASTContext().getTargetInfo().validateCpuSupports(Feat)) {
1745 Diag(Loc, diag::warn_unsupported_target_attribute)
1746 << Unsupported << None << Feat << TargetClones;
1747 continue;
1748 }
1749 if (getASTContext().getTargetInfo().doesFeatureAffectCodeGen(Feat))
1750 HasCodeGenImpact = true;
1751 ValidFeatures.push_back(Feat);
1752 }
1753
1754 // Ignore features that don't impact code generation.
1755 if (!HasCodeGenImpact) {
1756 Diag(Loc, diag::warn_target_clone_no_impact_options);
1757 continue;
1758 }
1759
1760 if (ValidFeatures.empty())
1761 continue;
1762
1763 // Canonicalize attribute parameter.
1764 llvm::sort(ValidFeatures);
1765 SmallString<64> NewParam(llvm::join(ValidFeatures, "+"));
1766 if (llvm::is_contained(NewParams, NewParam)) {
1767 Diag(Loc, diag::warn_target_clone_duplicate_options);
1768 continue;
1769 }
1770
1771 if (HasPriority) {
1772 unsigned Digit;
1773 if (RHS.getAsInteger(0, Digit) || Digit < 1 || Digit > 255)
1774 Diag(Loc, diag::warn_version_priority_out_of_range) << RHS;
1775 else
1776 convertPriorityString(Digit, NewParam);
1777 }
1778
1779 // Valid non-default argument.
1780 NewParams.push_back(NewParam);
1781 HasNonDefault = true;
1782 }
1783
1784 return !HasNonDefault;
1785}
1786
1788 const FunctionDecl *FD,
1789 const llvm::StringMap<bool> &FeatureMap) {
1790 if (!Ty->isSVESizelessBuiltinType())
1791 return false;
1792
1793 if (FeatureMap.lookup("sve"))
1794 return false;
1795
1796 // No SVE environment available.
1797 if (!FeatureMap.lookup("sme"))
1798 return Diag(Loc, diag::err_sve_vector_in_non_sve_target) << Ty;
1799
1800 // SVE environment only available to streaming functions.
1801 if (FD && !FD->getType().isNull() &&
1802 !IsArmStreamingFunction(FD, /*IncludeLocallyStreaming=*/true))
1803 return Diag(Loc, diag::err_sve_vector_in_non_streaming_function) << Ty;
1804
1805 return false;
1806}
1807} // 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:810
const TargetInfo & getTargetInfo() const
Definition ASTContext.h:927
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:3238
Kind getKind() const
Definition TypeBase.h:3289
unsigned getAuxBuiltinID(unsigned ID) const
Return real builtin ID (i.e.
Definition Builtins.h:449
const char * getRequiredFeatures(unsigned ID) const
Definition Builtins.cpp:116
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition Expr.h:2949
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition Expr.h:3153
SourceLocation getBeginLoc() const
Definition Expr.h:3283
void setArg(unsigned Arg, Expr *ArgExpr)
setArg - Set the specified argument.
Definition Expr.h:3166
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
Definition Expr.h:3132
Expr * getCallee()
Definition Expr.h:3096
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Definition Expr.h:3140
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:1276
SourceLocation getBeginLoc() const
Definition Expr.h:1355
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:3106
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:3101
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:841
QualType getType() const
Definition Expr.h:144
Represents a function declaration or definition.
Definition Decl.h:2029
QualType getReturnType() const
Definition Decl.h:2885
ArrayRef< ParmVarDecl * > parameters() const
Definition Decl.h:2814
Represents a prototype with parameter type info, e.g.
Definition TypeBase.h:5418
static ArmStateValue getArmZT0State(unsigned AttrBits)
Definition TypeBase.h:4923
static ArmStateValue getArmZAState(unsigned AttrBits)
Definition TypeBase.h:4919
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:3859
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:1819
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:3405
A (possibly-)qualified type.
Definition TypeBase.h:938
QualType withConst() const
Definition TypeBase.h:1175
void addConst()
Add the const type qualifier to this QualType.
Definition TypeBase.h:1172
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition TypeBase.h:1005
QualType withVolatile() const
Definition TypeBase.h:1183
Qualifiers::ObjCLifetime getObjCLifetime() const
Returns lifetime attribute of this type.
Definition TypeBase.h:1454
QualType getUnqualifiedType() const
Retrieve the unqualified variant of the given type, removing as little sugar as possible.
Definition TypeBase.h:8595
const Type * getTypePtrOrNull() const
Definition TypeBase.h:8505
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:8666
@ OCL_Strong
Assigning into this object requires the old value to be released and the new value to be retained.
Definition TypeBase.h:362
@ OCL_ExplicitNone
This object can be modified without requiring retains or releases.
Definition TypeBase.h:355
@ OCL_None
There is no lifetime qualification on this type.
Definition TypeBase.h:351
@ OCL_Weak
Reading or writing from this object requires a barrier call.
Definition TypeBase.h:365
@ OCL_Autoreleasing
Assigning into this object requires a lifetime extension.
Definition TypeBase.h:368
void CheckSMEFunctionDefAttributes(const FunctionDecl *FD)
Definition SemaARM.cpp:1469
bool CheckARMBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, CallExpr *TheCall)
Definition SemaARM.cpp:1038
void handleInterruptSaveFPAttr(Decl *D, const ParsedAttr &AL)
Definition SemaARM.cpp:1444
bool CheckSMEBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall)
Definition SemaARM.cpp:653
bool CheckARMCoprocessorImmediate(const TargetInfo &TI, const Expr *CoprocArg, bool WantCDE)
Definition SemaARM.cpp:837
bool CheckSVEBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall)
Definition SemaARM.cpp:694
bool CheckNeonBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, CallExpr *TheCall)
Definition SemaARM.cpp:723
bool CheckCDEBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, CallExpr *TheCall)
Definition SemaARM.cpp:821
bool PerformNeonImmChecks(CallExpr *TheCall, SmallVectorImpl< std::tuple< int, int, int, int > > &ImmChecks, int OverloadType=-1)
Definition SemaARM.cpp:524
bool CheckMVEBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall)
Definition SemaARM.cpp:812
void handleInterruptAttr(Decl *D, const ParsedAttr &AL)
Definition SemaARM.cpp:1412
bool PerformSVEImmChecks(CallExpr *TheCall, SmallVectorImpl< std::tuple< int, int, int > > &ImmChecks)
Definition SemaARM.cpp:543
void handleBuiltinAliasAttr(Decl *D, const ParsedAttr &AL)
Definition SemaARM.cpp:1297
@ 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:1344
bool CheckARMBuiltinExclusiveCall(const TargetInfo &TI, unsigned BuiltinID, CallExpr *TheCall)
Definition SemaARM.cpp:862
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:1539
bool checkTargetVersionAttr(const StringRef Param, const SourceLocation Loc, SmallString< 64 > &NewParam)
Definition SemaARM.cpp:1667
bool checkSVETypeSupport(QualType Ty, SourceLocation Loc, const FunctionDecl *FD, const llvm::StringMap< bool > &FeatureMap)
Definition SemaARM.cpp:1787
bool SveAliasValid(unsigned BuiltinID, llvm::StringRef AliasName)
Definition SemaARM.cpp:1283
bool areLaxCompatibleSveTypes(QualType FirstType, QualType SecondType)
Return true if the given vector types are lax-compatible SVE vector types, false otherwise.
Definition SemaARM.cpp:1584
bool CheckAArch64BuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, CallExpr *TheCall)
Definition SemaARM.cpp:1121
bool MveAliasValid(unsigned BuiltinID, llvm::StringRef AliasName)
Definition SemaARM.cpp:1270
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:1397
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:1290
bool checkTargetClonesAttr(SmallVectorImpl< StringRef > &Params, SmallVectorImpl< SourceLocation > &Locs, SmallVectorImpl< SmallString< 64 > > &NewParams)
Definition SemaARM.cpp:1701
bool CdeAliasValid(unsigned BuiltinID, llvm::StringRef AliasName)
Definition SemaARM.cpp:1278
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:875
ASTContext & Context
Definition Sema.h:1316
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:429
@ 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:1876
bool isBlockPointerType() const
Definition TypeBase.h:8758
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
Definition TypeBase.h:9154
bool isSVESizelessBuiltinType() const
Returns true for SVE scalable vector types.
Definition Type.cpp:2671
bool isSveVLSBuiltinType() const
Determines if this is a sizeless type supported by the 'arm_sve_vector_bits' type attribute,...
Definition Type.cpp:2705
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:2744
bool isFloatingType() const
Definition Type.cpp:2393
bool isAnyPointerType() const
Definition TypeBase.h:8746
const T * getAs() const
Member-template getAs<specific type>'.
Definition TypeBase.h:9337
bool isSizelessVectorType() const
Returns true for all scalable vector types.
Definition Type.cpp:2667
QualType getType() const
Definition Decl.h:723
Represents a GCC generic vector type.
Definition TypeBase.h:4286
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:861
const AstTypeMatcher< PointerType > pointerType
Top level wrappers for InstallAPI frontend operations.
bool isa(CodeGen::Address addr)
Definition Address.h:330
static void convertPriorityString(unsigned Priority, SmallString< 64 > &NewParam)
Definition SemaARM.cpp:1655
@ CPlusPlus
static bool BuiltinAliasValid(unsigned BuiltinID, StringRef AliasName, ArrayRef< IntrinToName > Map, const char *IntrinNames)
Definition SemaARM.cpp:1251
static ArmSMEState getSMEState(unsigned BuiltinID)
Definition SemaARM.cpp:643
static bool checkArmStreamingBuiltin(Sema &S, CallExpr *TheCall, const FunctionDecl *FD, SemaARM::ArmStreamingType BuiltinType, unsigned BuiltinID)
Definition SemaARM.cpp:572
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:556
static uint64_t getSVETypeSize(ASTContext &Context, const BuiltinType *Ty, bool IsStreaming)
getSVETypeSize - Return SVE vector or predicate register size.
Definition SemaARM.cpp:1528
@ AANT_ArgumentIdentifier
@ Result
The result type of a method or function.
Definition TypeBase.h:906
const FunctionProtoType * T
AssignConvertType
AssignConvertType - All of the 'assignment' semantic checks return this enum to indicate whether the ...
Definition Sema.h:695
bool hasArmZT0State(const FunctionDecl *FD)
Returns whether the given FunctionDecl has Arm ZT0 state.
Definition Decl.cpp:6125
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:1321
static void appendFeature(StringRef Feat, SmallString< 64 > &Buffer)
Definition SemaARM.cpp:1649
@ SveFixedLengthData
is AArch64 SVE fixed-length data vector
Definition TypeBase.h:4265
@ Generic
not a target-specific vector type
Definition TypeBase.h:4247
@ SveFixedLengthPredicate
is AArch64 SVE fixed-length predicate vector
Definition TypeBase.h:4268
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:6104
ActionResult< Expr * > ExprResult
Definition Ownership.h:249
bool hasArmZAState(const FunctionDecl *FD)
Returns whether the given FunctionDecl has Arm ZA state.
Definition Decl.cpp:6118
__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:5503