clang 20.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
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 if (SecArg.isInvalid())
47 return true;
48 QualType SecArgType = SecArg.get()->getType();
49 if (!SecArgType->isIntegerType())
50 return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_integer)
51 << "second" << SecArgType << Arg1->getSourceRange();
52
53 // Derive the return type from the pointer argument.
54 TheCall->setType(FirstArgType);
55 return false;
56 }
57
58 if (BuiltinID == AArch64::BI__builtin_arm_addg) {
59 if (SemaRef.checkArgCount(TheCall, 2))
60 return true;
61
62 Expr *Arg0 = TheCall->getArg(0);
64 if (FirstArg.isInvalid())
65 return true;
66 QualType FirstArgType = FirstArg.get()->getType();
67 if (!FirstArgType->isAnyPointerType())
68 return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer)
69 << "first" << FirstArgType << Arg0->getSourceRange();
70 TheCall->setArg(0, FirstArg.get());
71
72 // Derive the return type from the pointer argument.
73 TheCall->setType(FirstArgType);
74
75 // Second arg must be an constant in range [0,15]
76 return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 15);
77 }
78
79 if (BuiltinID == AArch64::BI__builtin_arm_gmi) {
80 if (SemaRef.checkArgCount(TheCall, 2))
81 return true;
82 Expr *Arg0 = TheCall->getArg(0);
83 Expr *Arg1 = TheCall->getArg(1);
84
86 if (FirstArg.isInvalid())
87 return true;
88 QualType FirstArgType = FirstArg.get()->getType();
89 if (!FirstArgType->isAnyPointerType())
90 return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer)
91 << "first" << FirstArgType << Arg0->getSourceRange();
92
93 QualType SecArgType = Arg1->getType();
94 if (!SecArgType->isIntegerType())
95 return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_integer)
96 << "second" << SecArgType << Arg1->getSourceRange();
97 TheCall->setType(Context.IntTy);
98 return false;
99 }
100
101 if (BuiltinID == AArch64::BI__builtin_arm_ldg ||
102 BuiltinID == AArch64::BI__builtin_arm_stg) {
103 if (SemaRef.checkArgCount(TheCall, 1))
104 return true;
105 Expr *Arg0 = TheCall->getArg(0);
107 if (FirstArg.isInvalid())
108 return true;
109
110 QualType FirstArgType = FirstArg.get()->getType();
111 if (!FirstArgType->isAnyPointerType())
112 return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer)
113 << "first" << FirstArgType << Arg0->getSourceRange();
114 TheCall->setArg(0, FirstArg.get());
115
116 // Derive the return type from the pointer argument.
117 if (BuiltinID == AArch64::BI__builtin_arm_ldg)
118 TheCall->setType(FirstArgType);
119 return false;
120 }
121
122 if (BuiltinID == AArch64::BI__builtin_arm_subp) {
123 Expr *ArgA = TheCall->getArg(0);
124 Expr *ArgB = TheCall->getArg(1);
125
128
129 if (ArgExprA.isInvalid() || ArgExprB.isInvalid())
130 return true;
131
132 QualType ArgTypeA = ArgExprA.get()->getType();
133 QualType ArgTypeB = ArgExprB.get()->getType();
134
135 auto isNull = [&](Expr *E) -> bool {
136 return E->isNullPointerConstant(Context,
138 };
139
140 // argument should be either a pointer or null
141 if (!ArgTypeA->isAnyPointerType() && !isNull(ArgA))
142 return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_null_or_pointer)
143 << "first" << ArgTypeA << ArgA->getSourceRange();
144
145 if (!ArgTypeB->isAnyPointerType() && !isNull(ArgB))
146 return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_null_or_pointer)
147 << "second" << ArgTypeB << ArgB->getSourceRange();
148
149 // Ensure Pointee types are compatible
150 if (ArgTypeA->isAnyPointerType() && !isNull(ArgA) &&
151 ArgTypeB->isAnyPointerType() && !isNull(ArgB)) {
152 QualType pointeeA = ArgTypeA->getPointeeType();
153 QualType pointeeB = ArgTypeB->getPointeeType();
154 if (!Context.typesAreCompatible(
155 Context.getCanonicalType(pointeeA).getUnqualifiedType(),
156 Context.getCanonicalType(pointeeB).getUnqualifiedType())) {
157 return Diag(TheCall->getBeginLoc(),
158 diag::err_typecheck_sub_ptr_compatible)
159 << ArgTypeA << ArgTypeB << ArgA->getSourceRange()
160 << ArgB->getSourceRange();
161 }
162 }
163
164 // at least one argument should be pointer type
165 if (!ArgTypeA->isAnyPointerType() && !ArgTypeB->isAnyPointerType())
166 return Diag(TheCall->getBeginLoc(), diag::err_memtag_any2arg_pointer)
167 << ArgTypeA << ArgTypeB << ArgA->getSourceRange();
168
169 if (isNull(ArgA)) // adopt type of the other pointer
170 ArgExprA =
171 SemaRef.ImpCastExprToType(ArgExprA.get(), ArgTypeB, CK_NullToPointer);
172
173 if (isNull(ArgB))
174 ArgExprB =
175 SemaRef.ImpCastExprToType(ArgExprB.get(), ArgTypeA, CK_NullToPointer);
176
177 TheCall->setArg(0, ArgExprA.get());
178 TheCall->setArg(1, ArgExprB.get());
179 TheCall->setType(Context.LongLongTy);
180 return false;
181 }
182 assert(false && "Unhandled ARM MTE intrinsic");
183 return true;
184}
185
186/// BuiltinARMSpecialReg - Handle a check if argument ArgNum of CallExpr
187/// TheCall is an ARM/AArch64 special register string literal.
188bool SemaARM::BuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall,
189 int ArgNum, unsigned ExpectedFieldNum,
190 bool AllowName) {
191 bool IsARMBuiltin = BuiltinID == ARM::BI__builtin_arm_rsr64 ||
192 BuiltinID == ARM::BI__builtin_arm_wsr64 ||
193 BuiltinID == ARM::BI__builtin_arm_rsr ||
194 BuiltinID == ARM::BI__builtin_arm_rsrp ||
195 BuiltinID == ARM::BI__builtin_arm_wsr ||
196 BuiltinID == ARM::BI__builtin_arm_wsrp;
197 bool IsAArch64Builtin = BuiltinID == AArch64::BI__builtin_arm_rsr64 ||
198 BuiltinID == AArch64::BI__builtin_arm_wsr64 ||
199 BuiltinID == AArch64::BI__builtin_arm_rsr128 ||
200 BuiltinID == AArch64::BI__builtin_arm_wsr128 ||
201 BuiltinID == AArch64::BI__builtin_arm_rsr ||
202 BuiltinID == AArch64::BI__builtin_arm_rsrp ||
203 BuiltinID == AArch64::BI__builtin_arm_wsr ||
204 BuiltinID == AArch64::BI__builtin_arm_wsrp;
205 assert((IsARMBuiltin || IsAArch64Builtin) && "Unexpected ARM builtin.");
206
207 // We can't check the value of a dependent argument.
208 Expr *Arg = TheCall->getArg(ArgNum);
209 if (Arg->isTypeDependent() || Arg->isValueDependent())
210 return false;
211
212 // Check if the argument is a string literal.
213 if (!isa<StringLiteral>(Arg->IgnoreParenImpCasts()))
214 return Diag(TheCall->getBeginLoc(), diag::err_expr_not_string_literal)
215 << Arg->getSourceRange();
216
217 // Check the type of special register given.
218 StringRef Reg = cast<StringLiteral>(Arg->IgnoreParenImpCasts())->getString();
220 Reg.split(Fields, ":");
221
222 if (Fields.size() != ExpectedFieldNum && !(AllowName && Fields.size() == 1))
223 return Diag(TheCall->getBeginLoc(), diag::err_arm_invalid_specialreg)
224 << Arg->getSourceRange();
225
226 // If the string is the name of a register then we cannot check that it is
227 // valid here but if the string is of one the forms described in ACLE then we
228 // can check that the supplied fields are integers and within the valid
229 // ranges.
230 if (Fields.size() > 1) {
231 bool FiveFields = Fields.size() == 5;
232
233 bool ValidString = true;
234 if (IsARMBuiltin) {
235 ValidString &= Fields[0].starts_with_insensitive("cp") ||
236 Fields[0].starts_with_insensitive("p");
237 if (ValidString)
238 Fields[0] = Fields[0].drop_front(
239 Fields[0].starts_with_insensitive("cp") ? 2 : 1);
240
241 ValidString &= Fields[2].starts_with_insensitive("c");
242 if (ValidString)
243 Fields[2] = Fields[2].drop_front(1);
244
245 if (FiveFields) {
246 ValidString &= Fields[3].starts_with_insensitive("c");
247 if (ValidString)
248 Fields[3] = Fields[3].drop_front(1);
249 }
250 }
251
252 SmallVector<int, 5> Ranges;
253 if (FiveFields)
254 Ranges.append({IsAArch64Builtin ? 1 : 15, 7, 15, 15, 7});
255 else
256 Ranges.append({15, 7, 15});
257
258 for (unsigned i = 0; i < Fields.size(); ++i) {
259 int IntField;
260 ValidString &= !Fields[i].getAsInteger(10, IntField);
261 ValidString &= (IntField >= 0 && IntField <= Ranges[i]);
262 }
263
264 if (!ValidString)
265 return Diag(TheCall->getBeginLoc(), diag::err_arm_invalid_specialreg)
266 << Arg->getSourceRange();
267 } else if (IsAArch64Builtin && Fields.size() == 1) {
268 // This code validates writes to PSTATE registers.
269
270 // Not a write.
271 if (TheCall->getNumArgs() != 2)
272 return false;
273
274 // The 128-bit system register accesses do not touch PSTATE.
275 if (BuiltinID == AArch64::BI__builtin_arm_rsr128 ||
276 BuiltinID == AArch64::BI__builtin_arm_wsr128)
277 return false;
278
279 // These are the named PSTATE accesses using "MSR (immediate)" instructions,
280 // along with the upper limit on the immediates allowed.
281 auto MaxLimit = llvm::StringSwitch<std::optional<unsigned>>(Reg)
282 .CaseLower("spsel", 15)
283 .CaseLower("daifclr", 15)
284 .CaseLower("daifset", 15)
285 .CaseLower("pan", 15)
286 .CaseLower("uao", 15)
287 .CaseLower("dit", 15)
288 .CaseLower("ssbs", 15)
289 .CaseLower("tco", 15)
290 .CaseLower("allint", 1)
291 .CaseLower("pm", 1)
292 .Default(std::nullopt);
293
294 // If this is not a named PSTATE, just continue without validating, as this
295 // will be lowered to an "MSR (register)" instruction directly
296 if (!MaxLimit)
297 return false;
298
299 // Here we only allow constants in the range for that pstate, as required by
300 // the ACLE.
301 //
302 // While clang also accepts the names of system registers in its ACLE
303 // intrinsics, we prevent this with the PSTATE names used in MSR (immediate)
304 // as the value written via a register is different to the value used as an
305 // immediate to have the same effect. e.g., for the instruction `msr tco,
306 // x0`, it is bit 25 of register x0 that is written into PSTATE.TCO, but
307 // with `msr tco, #imm`, it is bit 0 of xN that is written into PSTATE.TCO.
308 //
309 // If a programmer wants to codegen the MSR (register) form of `msr tco,
310 // xN`, they can still do so by specifying the register using five
311 // colon-separated numbers in a string.
312 return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, *MaxLimit);
313 }
314
315 return false;
316}
317
318/// getNeonEltType - Return the QualType corresponding to the elements of
319/// the vector type specified by the NeonTypeFlags. This is used to check
320/// the pointer arguments for Neon load/store intrinsics.
322 bool IsPolyUnsigned, bool IsInt64Long) {
323 switch (Flags.getEltType()) {
325 return Flags.isUnsigned() ? Context.UnsignedCharTy : Context.SignedCharTy;
327 return Flags.isUnsigned() ? Context.UnsignedShortTy : Context.ShortTy;
329 return Flags.isUnsigned() ? Context.UnsignedIntTy : Context.IntTy;
331 if (IsInt64Long)
332 return Flags.isUnsigned() ? Context.UnsignedLongTy : Context.LongTy;
333 else
334 return Flags.isUnsigned() ? Context.UnsignedLongLongTy
335 : Context.LongLongTy;
337 return IsPolyUnsigned ? Context.UnsignedCharTy : Context.SignedCharTy;
339 return IsPolyUnsigned ? Context.UnsignedShortTy : Context.ShortTy;
341 if (IsInt64Long)
342 return Context.UnsignedLongTy;
343 else
344 return Context.UnsignedLongLongTy;
346 break;
348 return Context.HalfTy;
350 return Context.FloatTy;
352 return Context.DoubleTy;
354 return Context.BFloat16Ty;
355 }
356 llvm_unreachable("Invalid NeonTypeFlag!");
357}
358
359enum ArmSMEState : unsigned {
361
362 ArmInZA = 0b01,
363 ArmOutZA = 0b10,
365 ArmZAMask = 0b11,
366
367 ArmInZT0 = 0b01 << 2,
368 ArmOutZT0 = 0b10 << 2,
369 ArmInOutZT0 = 0b11 << 2,
370 ArmZT0Mask = 0b11 << 2
372
373bool SemaARM::CheckImmediateArg(CallExpr *TheCall, unsigned CheckTy,
374 unsigned ArgIdx, unsigned EltBitWidth,
375 unsigned ContainerBitWidth) {
376 // Function that checks whether the operand (ArgIdx) is an immediate
377 // that is one of a given set of values.
378 auto CheckImmediateInSet = [&](std::initializer_list<int64_t> Set,
379 int ErrDiag) -> bool {
380 // We can't check the value of a dependent argument.
381 Expr *Arg = TheCall->getArg(ArgIdx);
382 if (Arg->isTypeDependent() || Arg->isValueDependent())
383 return false;
384
385 // Check constant-ness first.
386 llvm::APSInt Imm;
387 if (SemaRef.BuiltinConstantArg(TheCall, ArgIdx, Imm))
388 return true;
389
390 if (std::find(Set.begin(), Set.end(), Imm.getSExtValue()) == Set.end())
391 return Diag(TheCall->getBeginLoc(), ErrDiag) << Arg->getSourceRange();
392 return false;
393 };
394
395 switch ((ImmCheckType)CheckTy) {
396 case ImmCheckType::ImmCheck0_31:
397 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 0, 31))
398 return true;
399 break;
400 case ImmCheckType::ImmCheck0_13:
401 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 0, 13))
402 return true;
403 break;
404 case ImmCheckType::ImmCheck0_63:
405 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 0, 63))
406 return true;
407 break;
408 case ImmCheckType::ImmCheck1_16:
409 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 1, 16))
410 return true;
411 break;
412 case ImmCheckType::ImmCheck0_7:
413 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 0, 7))
414 return true;
415 break;
416 case ImmCheckType::ImmCheck1_1:
417 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 1, 1))
418 return true;
419 break;
420 case ImmCheckType::ImmCheck1_3:
421 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 1, 3))
422 return true;
423 break;
424 case ImmCheckType::ImmCheck1_7:
425 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 1, 7))
426 return true;
427 break;
428 case ImmCheckType::ImmCheckExtract:
429 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 0,
430 (2048 / EltBitWidth) - 1))
431 return true;
432 break;
433 case ImmCheckType::ImmCheckCvt:
434 case ImmCheckType::ImmCheckShiftRight:
435 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 1, EltBitWidth))
436 return true;
437 break;
438 case ImmCheckType::ImmCheckShiftRightNarrow:
439 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 1, EltBitWidth / 2))
440 return true;
441 break;
442 case ImmCheckType::ImmCheckShiftLeft:
443 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 0, EltBitWidth - 1))
444 return true;
445 break;
446 case ImmCheckType::ImmCheckLaneIndex:
447 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 0,
448 (ContainerBitWidth / EltBitWidth) - 1))
449 return true;
450 break;
451 case ImmCheckType::ImmCheckLaneIndexCompRotate:
453 TheCall, ArgIdx, 0, (ContainerBitWidth / (2 * EltBitWidth)) - 1))
454 return true;
455 break;
456 case ImmCheckType::ImmCheckLaneIndexDot:
458 TheCall, ArgIdx, 0, (ContainerBitWidth / (4 * EltBitWidth)) - 1))
459 return true;
460 break;
461 case ImmCheckType::ImmCheckComplexRot90_270:
462 if (CheckImmediateInSet({90, 270}, diag::err_rotation_argument_to_cadd))
463 return true;
464 break;
465 case ImmCheckType::ImmCheckComplexRotAll90:
466 if (CheckImmediateInSet({0, 90, 180, 270},
467 diag::err_rotation_argument_to_cmla))
468 return true;
469 break;
470 case ImmCheckType::ImmCheck0_1:
471 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 0, 1))
472 return true;
473 break;
474 case ImmCheckType::ImmCheck0_2:
475 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 0, 2))
476 return true;
477 break;
478 case ImmCheckType::ImmCheck0_3:
479 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 0, 3))
480 return true;
481 break;
482 case ImmCheckType::ImmCheck0_0:
483 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 0, 0))
484 return true;
485 break;
486 case ImmCheckType::ImmCheck0_15:
487 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 0, 15))
488 return true;
489 break;
490 case ImmCheckType::ImmCheck0_255:
491 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 0, 255))
492 return true;
493 break;
494 case ImmCheckType::ImmCheck1_32:
495 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 1, 32))
496 return true;
497 break;
498 case ImmCheckType::ImmCheck1_64:
499 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 1, 64))
500 return true;
501 break;
502 case ImmCheckType::ImmCheck2_4_Mul2:
503 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 2, 4) ||
504 SemaRef.BuiltinConstantArgMultiple(TheCall, ArgIdx, 2))
505 return true;
506 break;
507 }
508 return false;
509}
510
512 CallExpr *TheCall,
513 SmallVectorImpl<std::tuple<int, int, int, int>> &ImmChecks,
514 int OverloadType) {
515 bool HasError = false;
516
517 for (const auto &I : ImmChecks) {
518 auto [ArgIdx, CheckTy, ElementBitWidth, VecBitWidth] = I;
519
520 if (OverloadType >= 0)
521 ElementBitWidth = NeonTypeFlags(OverloadType).getEltSizeInBits();
522
523 HasError |= CheckImmediateArg(TheCall, CheckTy, ArgIdx, ElementBitWidth,
524 VecBitWidth);
525 }
526
527 return HasError;
528}
529
531 CallExpr *TheCall, SmallVectorImpl<std::tuple<int, int, int>> &ImmChecks) {
532 bool HasError = false;
533
534 for (const auto &I : ImmChecks) {
535 auto [ArgIdx, CheckTy, ElementBitWidth] = I;
536 HasError |=
537 CheckImmediateArg(TheCall, CheckTy, ArgIdx, ElementBitWidth, 128);
538 }
539
540 return HasError;
541}
542
544 if (FD->hasAttr<ArmLocallyStreamingAttr>())
546 if (const Type *Ty = FD->getType().getTypePtrOrNull()) {
547 if (const auto *FPT = Ty->getAs<FunctionProtoType>()) {
548 if (FPT->getAArch64SMEAttributes() &
551 if (FPT->getAArch64SMEAttributes() &
554 }
555 }
557}
558
559static bool checkArmStreamingBuiltin(Sema &S, CallExpr *TheCall,
560 const FunctionDecl *FD,
562 unsigned BuiltinID) {
564
565 // Check if the intrinsic is available in the right mode, i.e.
566 // * When compiling for SME only, the caller must be in streaming mode.
567 // * When compiling for SVE only, the caller must be in non-streaming mode.
568 // * When compiling for both SVE and SME, the caller can be in either mode.
570 llvm::StringMap<bool> CallerFeatureMapWithoutSVE;
571 S.Context.getFunctionFeatureMap(CallerFeatureMapWithoutSVE, FD);
572 CallerFeatureMapWithoutSVE["sve"] = false;
573
574 // Avoid emitting diagnostics for a function that can never compile.
575 if (FnType == SemaARM::ArmStreaming && !CallerFeatureMapWithoutSVE["sme"])
576 return false;
577
578 llvm::StringMap<bool> CallerFeatureMapWithoutSME;
579 S.Context.getFunctionFeatureMap(CallerFeatureMapWithoutSME, FD);
580 CallerFeatureMapWithoutSME["sme"] = false;
581
582 // We know the builtin requires either some combination of SVE flags, or
583 // some combination of SME flags, but we need to figure out which part
584 // of the required features is satisfied by the target features.
585 //
586 // For a builtin with target guard 'sve2p1|sme2', if we compile with
587 // '+sve2p1,+sme', then we know that it satisfies the 'sve2p1' part if we
588 // evaluate the features for '+sve2p1,+sme,+nosme'.
589 //
590 // Similarly, if we compile with '+sve2,+sme2', then we know it satisfies
591 // the 'sme2' part if we evaluate the features for '+sve2,+sme2,+nosve'.
592 StringRef BuiltinTargetGuards(
594 bool SatisfiesSVE = Builtin::evaluateRequiredTargetFeatures(
595 BuiltinTargetGuards, CallerFeatureMapWithoutSME);
596 bool SatisfiesSME = Builtin::evaluateRequiredTargetFeatures(
597 BuiltinTargetGuards, CallerFeatureMapWithoutSVE);
598
599 if ((SatisfiesSVE && SatisfiesSME) ||
600 (SatisfiesSVE && FnType == SemaARM::ArmStreamingCompatible))
601 return false;
602 else if (SatisfiesSVE)
604 else if (SatisfiesSME)
606 else
607 // This should be diagnosed by CodeGen
608 return false;
609 }
610
611 if (FnType != SemaARM::ArmNonStreaming &&
613 S.Diag(TheCall->getBeginLoc(), diag::err_attribute_arm_sm_incompat_builtin)
614 << TheCall->getSourceRange() << "non-streaming";
615 else if (FnType != SemaARM::ArmStreaming &&
617 S.Diag(TheCall->getBeginLoc(), diag::err_attribute_arm_sm_incompat_builtin)
618 << TheCall->getSourceRange() << "streaming";
619 else
620 return false;
621
622 return true;
623}
624
625static bool hasArmZAState(const FunctionDecl *FD) {
626 const auto *T = FD->getType()->getAs<FunctionProtoType>();
629 (FD->hasAttr<ArmNewAttr>() && FD->getAttr<ArmNewAttr>()->isNewZA());
630}
631
632static bool hasArmZT0State(const FunctionDecl *FD) {
633 const auto *T = FD->getType()->getAs<FunctionProtoType>();
636 (FD->hasAttr<ArmNewAttr>() && FD->getAttr<ArmNewAttr>()->isNewZT0());
637}
638
639static ArmSMEState getSMEState(unsigned BuiltinID) {
640 switch (BuiltinID) {
641 default:
642 return ArmNoState;
643#define GET_SME_BUILTIN_GET_STATE
644#include "clang/Basic/arm_sme_builtins_za_state.inc"
645#undef GET_SME_BUILTIN_GET_STATE
646 }
647}
648
650 CallExpr *TheCall) {
651 if (const FunctionDecl *FD = SemaRef.getCurFunctionDecl()) {
652 std::optional<ArmStreamingType> BuiltinType;
653
654 switch (BuiltinID) {
655#define GET_SME_STREAMING_ATTRS
656#include "clang/Basic/arm_sme_streaming_attrs.inc"
657#undef GET_SME_STREAMING_ATTRS
658 }
659
660 if (BuiltinType &&
661 checkArmStreamingBuiltin(SemaRef, TheCall, FD, *BuiltinType, BuiltinID))
662 return true;
663
664 if ((getSMEState(BuiltinID) & ArmZAMask) && !hasArmZAState(FD))
665 Diag(TheCall->getBeginLoc(),
666 diag::warn_attribute_arm_za_builtin_no_za_state)
667 << TheCall->getSourceRange();
668
669 if ((getSMEState(BuiltinID) & ArmZT0Mask) && !hasArmZT0State(FD))
670 Diag(TheCall->getBeginLoc(),
671 diag::warn_attribute_arm_zt0_builtin_no_zt0_state)
672 << TheCall->getSourceRange();
673 }
674
675 // Range check SME intrinsics that take immediate values.
677
678 switch (BuiltinID) {
679 default:
680 return false;
681#define GET_SME_IMMEDIATE_CHECK
682#include "clang/Basic/arm_sme_sema_rangechecks.inc"
683#undef GET_SME_IMMEDIATE_CHECK
684 }
685
686 return PerformSVEImmChecks(TheCall, ImmChecks);
687}
688
690 CallExpr *TheCall) {
691 if (const FunctionDecl *FD = SemaRef.getCurFunctionDecl()) {
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 = SemaRef.getCurFunctionDecl()) {
721
722 switch (BuiltinID) {
723 default:
724 break;
725#define GET_NEON_BUILTINS
726#define TARGET_BUILTIN(id, ...) case NEON::BI##id:
727#define BUILTIN(id, ...) case NEON::BI##id:
728#include "clang/Basic/arm_neon.inc"