1//===------ SemaARM.cpp ---------- ARM target-specific routines -----------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements semantic analysis functions specific to ARM.
10//
11//===----------------------------------------------------------------------===//
12
13#include "clang/Sema/SemaARM.h"
14#include "clang/Basic/DiagnosticSema.h"
15#include "clang/Basic/TargetBuiltins.h"
16#include "clang/Basic/TargetInfo.h"
17#include "clang/Sema/Initialization.h"
18#include "clang/Sema/ParsedAttr.h"
19#include "clang/Sema/Sema.h"
20
21namespace clang {
22
23SemaARM::SemaARM(Sema &S) : SemaBase(S) {}
24
25/// BuiltinARMMemoryTaggingCall - Handle calls of memory tagging extensions
26bool SemaARM::BuiltinARMMemoryTaggingCall(unsigned BuiltinID,
27 CallExpr *TheCall) {
28 ASTContext &Context = getASTContext();
29
30 if (BuiltinID == AArch64::BI__builtin_arm_irg) {
31 if (SemaRef.checkArgCount(Call: TheCall, DesiredArgCount: 2))
32 return true;
33 Expr *Arg0 = TheCall->getArg(Arg: 0);
34 Expr *Arg1 = TheCall->getArg(Arg: 1);
35
36 ExprResult FirstArg = SemaRef.DefaultFunctionArrayLvalueConversion(E: Arg0);
37 if (FirstArg.isInvalid())
38 return true;
39 QualType FirstArgType = FirstArg.get()->getType();
40 if (!FirstArgType->isAnyPointerType())
41 return Diag(Loc: TheCall->getBeginLoc(), DiagID: diag::err_memtag_arg_must_be_pointer)
42 << "first" << FirstArgType << Arg0->getSourceRange();
43 TheCall->setArg(Arg: 0, ArgExpr: FirstArg.get());
44
45 InitializedEntity Entity = InitializedEntity::InitializeParameter(
46 Context, Type: Context.getIntTypeForBitwidth(DestWidth: 64, /*Signed=*/false),
47 /*Consumed=*/false);
48 ExprResult SecArg =
49 SemaRef.PerformCopyInitialization(Entity,
50 /*EqualLoc=*/SourceLocation(), Init: Arg1);
51 if (SecArg.isInvalid())
52 return true;
53 TheCall->setArg(Arg: 1, ArgExpr: 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(Call: TheCall, DesiredArgCount: 2))
62 return true;
63
64 Expr *Arg0 = TheCall->getArg(Arg: 0);
65 ExprResult FirstArg = SemaRef.DefaultFunctionArrayLvalueConversion(E: Arg0);
66 if (FirstArg.isInvalid())
67 return true;
68 QualType FirstArgType = FirstArg.get()->getType();
69 if (!FirstArgType->isAnyPointerType())
70 return Diag(Loc: TheCall->getBeginLoc(), DiagID: diag::err_memtag_arg_must_be_pointer)
71 << "first" << FirstArgType << Arg0->getSourceRange();
72 TheCall->setArg(Arg: 0, ArgExpr: 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, ArgNum: 1, Low: 0, High: 15);
79 }
80
81 if (BuiltinID == AArch64::BI__builtin_arm_gmi) {
82 if (SemaRef.checkArgCount(Call: TheCall, DesiredArgCount: 2))
83 return true;
84 Expr *Arg0 = TheCall->getArg(Arg: 0);
85 Expr *Arg1 = TheCall->getArg(Arg: 1);
86
87 ExprResult FirstArg = SemaRef.DefaultFunctionArrayLvalueConversion(E: Arg0);
88 if (FirstArg.isInvalid())
89 return true;
90 QualType FirstArgType = FirstArg.get()->getType();
91 if (!FirstArgType->isAnyPointerType())
92 return Diag(Loc: TheCall->getBeginLoc(), DiagID: diag::err_memtag_arg_must_be_pointer)
93 << "first" << FirstArgType << Arg0->getSourceRange();
94 TheCall->setArg(Arg: 0, ArgExpr: FirstArg.get());
95
96 InitializedEntity Entity = InitializedEntity::InitializeParameter(
97 Context, Type: Context.getIntTypeForBitwidth(DestWidth: 64, /*Signed=*/false),
98 /*Consumed=*/false);
99 ExprResult SecArg =
100 SemaRef.PerformCopyInitialization(Entity,
101 /*EqualLoc=*/SourceLocation(), Init: Arg1);
102 if (SecArg.isInvalid())
103 return true;
104 TheCall->setArg(Arg: 1, ArgExpr: 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(Call: TheCall, DesiredArgCount: 1))
112 return true;
113 Expr *Arg0 = TheCall->getArg(Arg: 0);
114 ExprResult FirstArg = SemaRef.DefaultFunctionArrayLvalueConversion(E: Arg0);
115 if (FirstArg.isInvalid())
116 return true;
117
118 QualType FirstArgType = FirstArg.get()->getType();
119 if (!FirstArgType->isAnyPointerType())
120 return Diag(Loc: TheCall->getBeginLoc(), DiagID: diag::err_memtag_arg_must_be_pointer)
121 << "first" << FirstArgType << Arg0->getSourceRange();
122 TheCall->setArg(Arg: 0, ArgExpr: 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(Arg: 0);
132 Expr *ArgB = TheCall->getArg(Arg: 1);
133
134 ExprResult ArgExprA = SemaRef.DefaultFunctionArrayLvalueConversion(E: ArgA);
135 ExprResult ArgExprB = SemaRef.DefaultFunctionArrayLvalueConversion(E: 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(Ctx&: Context,
145 NPC: Expr::NPC_ValueDependentIsNotNull);
146 };
147
148 // argument should be either a pointer or null
149 if (!ArgTypeA->isAnyPointerType() && !isNull(ArgA))
150 return Diag(Loc: TheCall->getBeginLoc(), DiagID: diag::err_memtag_arg_null_or_pointer)
151 << "first" << ArgTypeA << ArgA->getSourceRange();
152
153 if (!ArgTypeB->isAnyPointerType() && !isNull(ArgB))
154 return Diag(Loc: TheCall->getBeginLoc(), DiagID: 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 T1: Context.getCanonicalType(T: pointeeA).getUnqualifiedType(),
164 T2: Context.getCanonicalType(T: pointeeB).getUnqualifiedType())) {
165 return Diag(Loc: TheCall->getBeginLoc(),
166 DiagID: 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(Loc: TheCall->getBeginLoc(), DiagID: 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(E: ArgExprA.get(), Type: ArgTypeB, CK: CK_NullToPointer);
180
181 if (isNull(ArgB))
182 ArgExprB =
183 SemaRef.ImpCastExprToType(E: ArgExprB.get(), Type: ArgTypeA, CK: CK_NullToPointer);
184
185 TheCall->setArg(Arg: 0, ArgExpr: ArgExprA.get());
186 TheCall->setArg(Arg: 1, ArgExpr: 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(Arg: ArgNum);
216 if (Arg->isTypeDependent() || Arg->isValueDependent())
217 return false;
218
219 // Check if the argument is a string literal.
220 if (!isa<StringLiteral>(Val: Arg->IgnoreParenImpCasts()))
221 return Diag(Loc: TheCall->getBeginLoc(), DiagID: diag::err_expr_not_string_literal)
222 << Arg->getSourceRange();
223
224 // Check the type of special register given.
225 StringRef Reg = cast<StringLiteral>(Val: Arg->IgnoreParenImpCasts())->getString();
226 SmallVector<StringRef, 6> Fields;
227 Reg.split(A&: Fields, Separator: ":");
228
229 if (Fields.size() != ExpectedFieldNum && !(AllowName && Fields.size() == 1))
230 return Diag(Loc: TheCall->getBeginLoc(), DiagID: 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(Prefix: "cp") ||
243 Fields[0].starts_with_insensitive(Prefix: "p");
244 if (ValidString)
245 Fields[0] = Fields[0].drop_front(
246 N: Fields[0].starts_with_insensitive(Prefix: "cp") ? 2 : 1);
247
248 ValidString &= Fields[2].starts_with_insensitive(Prefix: "c");
249 if (ValidString)
250 Fields[2] = Fields[2].drop_front(N: 1);
251
252 if (FiveFields) {
253 ValidString &= Fields[3].starts_with_insensitive(Prefix: "c");
254 if (ValidString)
255 Fields[3] = Fields[3].drop_front(N: 1);
256 }
257 }
258
259 SmallVector<int, 5> FieldBitWidths;
260 if (FiveFields)
261 FieldBitWidths.append(IL: {IsAArch64Builtin ? 2 : 4, 3, 4, 4, 3});
262 else
263 FieldBitWidths.append(IL: {4, 3, 4});
264
265 for (unsigned i = 0; i < Fields.size(); ++i) {
266 int IntField;
267 ValidString &= !Fields[i].getAsInteger(Radix: 10, Result&: IntField);
268 ValidString &= (IntField >= 0 && IntField < (1 << FieldBitWidths[i]));
269 }
270
271 if (!ValidString)
272 return Diag(Loc: TheCall->getBeginLoc(), DiagID: 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(S: "spsel", Value: 15)
290 .CaseLower(S: "daifclr", Value: 15)
291 .CaseLower(S: "daifset", Value: 15)
292 .CaseLower(S: "pan", Value: 15)
293 .CaseLower(S: "uao", Value: 15)
294 .CaseLower(S: "dit", Value: 15)
295 .CaseLower(S: "ssbs", Value: 15)
296 .CaseLower(S: "tco", Value: 15)
297 .CaseLower(S: "allint", Value: 1)
298 .CaseLower(S: "pm", Value: 1)
299 .Default(Value: 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, ArgNum: 1, Low: 0, High: *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.
328static QualType getNeonEltType(NeonTypeFlags Flags, ASTContext &Context,
329 bool IsPolyUnsigned, bool IsInt64Long) {
330 switch (Flags.getEltType()) {
331 case NeonTypeFlags::Int8:
332 return Flags.isUnsigned() ? Context.UnsignedCharTy : Context.SignedCharTy;
333 case NeonTypeFlags::Int16:
334 return Flags.isUnsigned() ? Context.UnsignedShortTy : Context.ShortTy;
335 case NeonTypeFlags::Int32:
336 return Flags.isUnsigned() ? Context.UnsignedIntTy : Context.IntTy;
337 case NeonTypeFlags::Int64:
338 if (IsInt64Long)
339 return Flags.isUnsigned() ? Context.UnsignedLongTy : Context.LongTy;
340 else
341 return Flags.isUnsigned() ? Context.UnsignedLongLongTy
342 : Context.LongLongTy;
343 case NeonTypeFlags::Poly8:
344 return IsPolyUnsigned ? Context.UnsignedCharTy : Context.SignedCharTy;
345 case NeonTypeFlags::Poly16:
346 return IsPolyUnsigned ? Context.UnsignedShortTy : Context.ShortTy;
347 case NeonTypeFlags::Poly64:
348 if (IsInt64Long)
349 return Context.UnsignedLongTy;
350 else
351 return Context.UnsignedLongLongTy;
352 case NeonTypeFlags::Poly128:
353 break;
354 case NeonTypeFlags::Float16:
355 return Context.HalfTy;
356 case NeonTypeFlags::Float32:
357 return Context.FloatTy;
358 case NeonTypeFlags::Float64:
359 return Context.DoubleTy;
360 case NeonTypeFlags::BFloat16:
361 return Context.BFloat16Ty;
362 case NeonTypeFlags::MFloat8:
363 return Context.MFloat8Ty;
364 }
365 llvm_unreachable("Invalid NeonTypeFlag!");
366}
367
368enum ArmSMEState : unsigned {
369 ArmNoState = 0,
370
371 ArmInZA = 0b01,
372 ArmOutZA = 0b10,
373 ArmInOutZA = 0b11,
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(Arg: 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, ArgNum: ArgIdx, Result&: Imm))
397 return true;
398
399 if (!llvm::is_contained(Set, Element: Imm.getSExtValue()))
400 return Diag(Loc: TheCall->getBeginLoc(), DiagID: ErrDiag) << Arg->getSourceRange();
401 return false;
402 };
403
404 switch ((ImmCheckType)CheckTy) {
405 case ImmCheckType::ImmCheck0_31:
406 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: ArgIdx, Low: 0, High: 31))
407 return true;
408 break;
409 case ImmCheckType::ImmCheck0_13:
410 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: ArgIdx, Low: 0, High: 13))
411 return true;
412 break;
413 case ImmCheckType::ImmCheck0_63:
414 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: ArgIdx, Low: 0, High: 63))
415 return true;
416 break;
417 case ImmCheckType::ImmCheck1_16:
418 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: ArgIdx, Low: 1, High: 16))
419 return true;
420 break;
421 case ImmCheckType::ImmCheck0_7:
422 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: ArgIdx, Low: 0, High: 7))
423 return true;
424 break;
425 case ImmCheckType::ImmCheck1_1:
426 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: ArgIdx, Low: 1, High: 1))
427 return true;
428 break;
429 case ImmCheckType::ImmCheck1_3:
430 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: ArgIdx, Low: 1, High: 3))
431 return true;
432 break;
433 case ImmCheckType::ImmCheck1_7:
434 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: ArgIdx, Low: 1, High: 7))
435 return true;
436 break;
437 case ImmCheckType::ImmCheckExtract:
438 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: ArgIdx, Low: 0,
439 High: (2048 / EltBitWidth) - 1))
440 return true;
441 break;
442 case ImmCheckType::ImmCheckCvt:
443 case ImmCheckType::ImmCheckShiftRight:
444 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: ArgIdx, Low: 1, High: EltBitWidth))
445 return true;
446 break;
447 case ImmCheckType::ImmCheckShiftRightNarrow:
448 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: ArgIdx, Low: 1, High: EltBitWidth / 2))
449 return true;
450 break;
451 case ImmCheckType::ImmCheckShiftLeft:
452 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: ArgIdx, Low: 0, High: EltBitWidth - 1))
453 return true;
454 break;
455 case ImmCheckType::ImmCheckShiftLeftLong:
456 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: ArgIdx, Low: 0, High: (EltBitWidth / 2)))
457 return true;
458 break;
459 case ImmCheckType::ImmCheckLaneIndex:
460 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: ArgIdx, Low: 0,
461 High: (ContainerBitWidth / EltBitWidth) - 1))
462 return true;
463 break;
464 case ImmCheckType::ImmCheckLaneIndexCompRotate:
465 if (SemaRef.BuiltinConstantArgRange(
466 TheCall, ArgNum: ArgIdx, Low: 0, High: (ContainerBitWidth / (2 * EltBitWidth)) - 1))
467 return true;
468 break;
469 case ImmCheckType::ImmCheckLaneIndexDot:
470 if (SemaRef.BuiltinConstantArgRange(
471 TheCall, ArgNum: ArgIdx, Low: 0, High: (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, ArgNum: ArgIdx, Low: 0, High: 1))
485 return true;
486 break;
487 case ImmCheckType::ImmCheck0_2:
488 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: ArgIdx, Low: 0, High: 2))
489 return true;
490 break;
491 case ImmCheckType::ImmCheck0_3:
492 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: ArgIdx, Low: 0, High: 3))
493 return true;
494 break;
495 case ImmCheckType::ImmCheck0_0:
496 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: ArgIdx, Low: 0, High: 0))
497 return true;
498 break;
499 case ImmCheckType::ImmCheck0_15:
500 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: ArgIdx, Low: 0, High: 15))
501 return true;
502 break;
503 case ImmCheckType::ImmCheck0_255:
504 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: ArgIdx, Low: 0, High: 255))
505 return true;
506 break;
507 case ImmCheckType::ImmCheck1_32:
508 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: ArgIdx, Low: 1, High: 32))
509 return true;
510 break;
511 case ImmCheckType::ImmCheck1_64:
512 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: ArgIdx, Low: 1, High: 64))
513 return true;
514 break;
515 case ImmCheckType::ImmCheck2_4_Mul2:
516 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: ArgIdx, Low: 2, High: 4) ||
517 SemaRef.BuiltinConstantArgMultiple(TheCall, ArgNum: ArgIdx, Multiple: 2))
518 return true;
519 break;
520 }
521 return false;
522}
523
524bool SemaARM::PerformNeonImmChecks(
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, EltBitWidth: ElementBitWidth,
537 ContainerBitWidth: VecBitWidth);
538 }
539
540 return HasError;
541}
542
543bool SemaARM::PerformSVEImmChecks(
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, EltBitWidth: ElementBitWidth, ContainerBitWidth: 128);
551 }
552
553 return HasError;
554}
555
556SemaARM::ArmStreamingType getArmStreamingFnType(const FunctionDecl *FD) {
557 if (FD->hasAttr<ArmLocallyStreamingAttr>())
558 return SemaARM::ArmStreaming;
559 if (const Type *Ty = FD->getType().getTypePtrOrNull()) {
560 if (const auto *FPT = Ty->getAs<FunctionProtoType>()) {
561 if (FPT->getAArch64SMEAttributes() &
562 FunctionType::SME_PStateSMEnabledMask)
563 return SemaARM::ArmStreaming;
564 if (FPT->getAArch64SMEAttributes() &
565 FunctionType::SME_PStateSMCompatibleMask)
566 return SemaARM::ArmStreamingCompatible;
567 }
568 }
569 return SemaARM::ArmNonStreaming;
570}
571
572static bool checkArmStreamingBuiltin(Sema &S, CallExpr *TheCall,
573 const FunctionDecl *FD,
574 SemaARM::ArmStreamingType BuiltinType,
575 unsigned BuiltinID) {
576 SemaARM::ArmStreamingType FnType = getArmStreamingFnType(FD);
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.
582 if (BuiltinType == SemaARM::VerifyRuntimeMode) {
583 llvm::StringMap<bool> CallerFeatures;
584 S.Context.getFunctionFeatureMap(FeatureMap&: 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: 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 =
605 S.Context.BuiltinInfo.getRequiredFeatures(ID: BuiltinID);
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 RequiredFatures: NonStreamingBuiltinGuard, TargetFetureMap: CallerFeatures);
614 bool SatisfiesSME = Builtin::evaluateRequiredTargetFeatures(
615 RequiredFatures: StreamingBuiltinGuard, TargetFetureMap: CallerFeatures);
616
617 if (SatisfiesSVE && SatisfiesSME)
618 // Function type is irrelevant for streaming-agnostic builtins.
619 return false;
620 else if (SatisfiesSVE)
621 BuiltinType = SemaARM::ArmNonStreaming;
622 else if (SatisfiesSME)
623 BuiltinType = SemaARM::ArmStreaming;
624 else
625 // This should be diagnosed by CodeGen
626 return false;
627 }
628
629 if (FnType != SemaARM::ArmNonStreaming &&
630 BuiltinType == SemaARM::ArmNonStreaming)
631 S.Diag(Loc: TheCall->getBeginLoc(), DiagID: diag::err_attribute_arm_sm_incompat_builtin)
632 << TheCall->getSourceRange() << "non-streaming";
633 else if (FnType != SemaARM::ArmStreaming &&
634 BuiltinType == SemaARM::ArmStreaming)
635 S.Diag(Loc: TheCall->getBeginLoc(), DiagID: 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
653bool SemaARM::CheckSMEBuiltinFunctionCall(unsigned BuiltinID,
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(S&: SemaRef, TheCall, FD, BuiltinType: *BuiltinType, BuiltinID))
667 return true;
668
669 if ((getSMEState(BuiltinID) & ArmZAMask) && !hasArmZAState(FD))
670 Diag(Loc: TheCall->getBeginLoc(),
671 DiagID: diag::warn_attribute_arm_za_builtin_no_za_state)
672 << TheCall->getSourceRange();
673
674 if ((getSMEState(BuiltinID) & ArmZT0Mask) && !hasArmZT0State(FD))
675 Diag(Loc: TheCall->getBeginLoc(),
676 DiagID: diag::warn_attribute_arm_zt0_builtin_no_zt0_state)
677 << TheCall->getSourceRange();
678 }
679
680 // Range check SME intrinsics that take immediate values.
681 SmallVector<std::tuple<int, int, int>, 3> ImmChecks;
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
694bool SemaARM::CheckSVEBuiltinFunctionCall(unsigned BuiltinID,
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(S&: SemaRef, TheCall, FD, BuiltinType: *BuiltinType, BuiltinID))
707 return true;
708 }
709 // Range check SVE intrinsics that take immediate values.
710 SmallVector<std::tuple<int, int, int>, 3> ImmChecks;
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
723bool SemaARM::CheckNeonBuiltinFunctionCall(const TargetInfo &TI,
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(S&: SemaRef, TheCall, FD, BuiltinType: *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, ArgNum: 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(Limit: 64);
764 if ((TV > 63) || (mask & (1ULL << TV)) == 0)
765 return Diag(Loc: TheCall->getBeginLoc(), DiagID: diag::err_invalid_neon_type_code)
766 << TheCall->getArg(Arg: ImmArg)->getSourceRange();
767 }
768
769 if (PtrArgNum >= 0) {
770 // Check that pointer arguments have the specified type.
771 Expr *Arg = TheCall->getArg(Arg: PtrArgNum);
772 if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Val: Arg))
773 Arg = ICE->getSubExpr();
774 ExprResult RHS = SemaRef.DefaultFunctionArrayLvalueConversion(E: 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;
782 QualType EltTy = getNeonEltType(Flags: NeonTypeFlags(TV), Context&: getASTContext(),
783 IsPolyUnsigned, IsInt64Long);
784 if (HasConstPtr)
785 EltTy = EltTy.withConst();
786 QualType LHSTy = getASTContext().getPointerType(T: EltTy);
787 AssignConvertType ConvTy;
788 ConvTy = SemaRef.CheckSingleAssignmentConstraints(LHSType: LHSTy, RHS);
789 if (RHS.isInvalid())
790 return true;
791 if (SemaRef.DiagnoseAssignmentResult(ConvTy, Loc: Arg->getBeginLoc(), DstType: LHSTy,
792 SrcType: RHSTy, SrcExpr: RHS.get(),
793 Action: AssignmentAction::Assigning))
794 return true;
795 }
796
797 // For NEON intrinsics which take an immediate value as part of the
798 // instruction, range check them here.
799 SmallVector<std::tuple<int, int, int, int>, 2> ImmChecks;
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, OverloadType: TV);
810}
811
812bool SemaARM::CheckMVEBuiltinFunctionCall(unsigned BuiltinID,
813 CallExpr *TheCall) {
814 switch (BuiltinID) {
815 default:
816 return false;
817#include "clang/Basic/arm_mve_builtin_sema.inc"
818 }
819}
820
821bool SemaARM::CheckCDEBuiltinFunctionCall(const TargetInfo &TI,
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, CoprocArg: TheCall->getArg(Arg: 0), /*WantCDE*/ true);
835}
836
837bool SemaARM::CheckARMCoprocessorImmediate(const TargetInfo &TI,
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(Ctx: 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(Loc: CoprocArg->getBeginLoc(), DiagID: diag::err_arm_invalid_coproc)
857 << (int)CoprocNo << (int)WantCDE << CoprocArg->getSourceRange();
858
859 return false;
860}
861
862bool SemaARM::CheckARMBuiltinExclusiveCall(const TargetInfo &TI,
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 =
886 cast<DeclRefExpr>(Val: TheCall->getCallee()->IgnoreParenCasts());
887
888 // Ensure that we have the proper number of arguments.
889 if (SemaRef.checkArgCount(Call: TheCall, DesiredArgCount: 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(Arg: IsLdrex ? 0 : 1);
897 ExprResult PointerArgRes =
898 SemaRef.DefaultFunctionArrayLvalueConversion(E: 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(Loc: DRE->getBeginLoc(), DiagID: 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(other: ValType, Ctx: getASTContext())) {
921 CastNeeded = CK_BitCast;
922 Diag(Loc: DRE->getBeginLoc(), DiagID: diag::ext_typecheck_convert_discards_qualifiers)
923 << PointerArg->getType() << Context.getPointerType(T: 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(T: AddrType);
929 PointerArgRes = SemaRef.ImpCastExprToType(E: PointerArg, Type: AddrType, CK: CastNeeded);
930 if (PointerArgRes.isInvalid())
931 return true;
932 PointerArg = PointerArgRes.get();
933
934 TheCall->setArg(Arg: IsLdrex ? 0 : 1, ArgExpr: 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(Loc: DRE->getBeginLoc(), DiagID: 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(T: ValType);
949 if (IsDoubleWord) {
950 // Explicit request for ldrexd/strexd means only double word sizes
951 // supported if the target supports them.
952 Mask &= TargetInfo::ARM_LDREX_D;
953 }
954 bool Supported =
955 (llvm::isPowerOf2_64(Value: 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(Loc: DRE->getBeginLoc(),
965 DiagID: 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(Loc: DRE->getBeginLoc(),
997 DiagID: diag::err_atomic_exclusive_builtin_pointer_size_none)
998 << (EmitDoubleWordDiagnostic ? 1 : 0)
999 << PointerArg->getSourceRange();
1000 }
1001 }
1002 }
1003
1004 switch (ValType.getObjCLifetime()) {
1005 case Qualifiers::OCL_None:
1006 case Qualifiers::OCL_ExplicitNone:
1007 // okay
1008 break;
1009
1010 case Qualifiers::OCL_Weak:
1011 case Qualifiers::OCL_Strong:
1012 case Qualifiers::OCL_Autoreleasing:
1013 Diag(Loc: DRE->getBeginLoc(), DiagID: 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(Arg: 0);
1025 InitializedEntity Entity = InitializedEntity::InitializeParameter(
1026 Context, Type: ValType, /*consume*/ Consumed: false);
1027 ValArg = SemaRef.PerformCopyInitialization(Entity, EqualLoc: SourceLocation(), Init: ValArg);
1028 if (ValArg.isInvalid())
1029 return true;
1030 TheCall->setArg(Arg: 0, ArgExpr: 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
1038bool SemaARM::CheckARMBuiltinFunctionCall(const TargetInfo &TI,
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, ArgNum: 1, Low: 0, High: 1) ||
1052 SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 2, Low: 0, High: 1);
1053 }
1054
1055 if (BuiltinID == ARM::BI__builtin_arm_rsr64 ||
1056 BuiltinID == ARM::BI__builtin_arm_wsr64)
1057 return BuiltinARMSpecialReg(BuiltinID, TheCall, ArgNum: 0, ExpectedFieldNum: 3, AllowName: 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, ArgNum: 0, ExpectedFieldNum: 5, AllowName: 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, ArgNum: 1, Low: 1, High: 32);
1080 case ARM::BI__builtin_arm_usat:
1081 return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 1, Low: 0, High: 31);
1082 case ARM::BI__builtin_arm_ssat16:
1083 return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 1, Low: 1, High: 16);
1084 case ARM::BI__builtin_arm_usat16:
1085 return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 1, Low: 0, High: 15);
1086 case ARM::BI__builtin_arm_vcvtr_f:
1087 case ARM::BI__builtin_arm_vcvtr_d:
1088 return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 1, Low: 0, High: 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, ArgNum: 0, Low: 0, High: 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, ArgNum: 0, Low: 0, High: 15) ||
1116 CheckARMCoprocessorImmediate(TI, CoprocArg: TheCall->getArg(Arg: 0),
1117 /*WantCDE*/ false);
1118 }
1119}
1120
1121bool SemaARM::CheckAArch64BuiltinFunctionCall(const TargetInfo &TI,
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, ArgNum: 1, Low: 0, High: 1) ||
1133 SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 2, Low: 0, High: 3) ||
1134 SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 3, Low: 0, High: 1) ||
1135 SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 4, Low: 0, High: 1);
1136 }
1137
1138 if (BuiltinID == AArch64::BI__builtin_arm_range_prefetch_x) {
1139 return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 1, Low: 0, High: 1) ||
1140 SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 2, Low: 0, High: 1) ||
1141 SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 3, Low: -2097152, High: 2097151) ||
1142 SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 4, Low: 1, High: 65536) ||
1143 SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 5, Low: -2097152, High: 2097151);
1144 }
1145
1146 if (BuiltinID == AArch64::BI__builtin_arm_range_prefetch) {
1147 return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 1, Low: 0, High: 1) ||
1148 SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 2, Low: 0, High: 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, ArgNum: 0, ExpectedFieldNum: 5, AllowName: 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, ArgNum: 0, ExpectedFieldNum: 5, AllowName: 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, ArgNum: 0, Low: 0x4000, High: 0x7fff);
1179
1180 if (BuiltinID == AArch64::BI__sys)
1181 return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 0, Low: 0, High: 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, ArgNum: 0, Low: 0, High: 31);
1186
1187 if (BuiltinID == AArch64::BI__prefetch2)
1188 return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 1, Low: 0, High: 31);
1189
1190 if (BuiltinID == AArch64::BI__break)
1191 return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 0, Low: 0, High: 0xffff);
1192
1193 if (BuiltinID == AArch64::BI__hlt)
1194 return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 0, Low: 0, High: 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(Call: TheCall, MaxArgCount: 5) ||
1200 SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 0, Low: 0, High: 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(Arg: I);
1205 QualType Ty = Arg->getType();
1206 if (!Ty->isIntegerType() && !Ty->isAnyPointerType() &&
1207 !Ty->isBlockPointerType() && !Ty->isFloatingType())
1208 return Diag(Loc: Arg->getBeginLoc(),
1209 DiagID: 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, ArgNum: i, Low: l, High: 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,
1252 ArrayRef<IntrinToName> Map,
1253 const char *IntrinNames) {
1254 AliasName.consume_front(Prefix: "__arm_");
1255 const IntrinToName *It =
1256 llvm::lower_bound(Range&: Map, Value&: BuiltinID, C: [](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(ID: BuiltinID))
1285 BuiltinID = getASTContext().BuiltinInfo.getAuxBuiltinID(ID: BuiltinID);
1286 return BuiltinID >= AArch64::FirstSVEBuiltin &&
1287 BuiltinID <= AArch64::LastSVEBuiltin;
1288}
1289
1290bool SemaARM::SmeAliasValid(unsigned BuiltinID, StringRef AliasName) {
1291 if (getASTContext().BuiltinInfo.isAuxBuiltinID(ID: BuiltinID))
1292 BuiltinID = getASTContext().BuiltinInfo.getAuxBuiltinID(ID: BuiltinID);
1293 return BuiltinID >= AArch64::FirstSMEBuiltin &&
1294 BuiltinID <= AArch64::LastSMEBuiltin;
1295}
1296
1297void SemaARM::handleBuiltinAliasAttr(Decl *D, const ParsedAttr &AL) {
1298 ASTContext &Context = getASTContext();
1299 if (!AL.isArgIdent(Arg: 0)) {
1300 Diag(Loc: AL.getLoc(), DiagID: diag::err_attribute_argument_n_type)
1301 << AL << 1 << AANT_ArgumentIdentifier;
1302 return;
1303 }
1304
1305 IdentifierInfo *Ident = AL.getArgAsIdent(Arg: 0)->getIdentifierInfo();
1306 unsigned BuiltinID = Ident->getBuiltinID();
1307 StringRef AliasName = cast<FunctionDecl>(Val: 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(Loc: AL.getLoc(), DiagID: diag::err_attribute_arm_builtin_alias);
1315 return;
1316 }
1317
1318 D->addAttr(A: ::new (Context) ArmBuiltinAliasAttr(Context, AL, Ident));
1319}
1320
1321static bool checkNewAttrMutualExclusion(
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(Loc: AL.getLoc(), DiagID: 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
1344void SemaARM::handleNewAttr(Decl *D, const ParsedAttr &AL) {
1345 if (!AL.getNumArgs()) {
1346 Diag(Loc: AL.getLoc(), DiagID: 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(x: 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(Attr: AL, ArgNum: I, Str&: StateName, ArgLocation: &LiteralLoc))
1363 return;
1364
1365 if (StateName == "za")
1366 HasZA = true;
1367 else if (StateName == "zt0")
1368 HasZT0 = true;
1369 else {
1370 Diag(Loc: LiteralLoc, DiagID: diag::err_unknown_arm_state) << StateName;
1371 AL.setInvalid();
1372 return;
1373 }
1374
1375 if (!llvm::is_contained(Range&: NewState, Element: StateName)) // Avoid adding duplicates.
1376 NewState.push_back(x: StateName);
1377 }
1378
1379 if (auto *FPT = dyn_cast<FunctionProtoType>(Val: D->getFunctionType())) {
1380 FunctionType::ArmStateValue ZAState =
1381 FunctionType::getArmZAState(AttrBits: FPT->getAArch64SMEAttributes());
1382 if (HasZA && ZAState != FunctionType::ARM_None &&
1383 checkNewAttrMutualExclusion(S&: SemaRef, AL, FPT, CurrentState: ZAState, StateName: "za"))
1384 return;
1385 FunctionType::ArmStateValue ZT0State =
1386 FunctionType::getArmZT0State(AttrBits: FPT->getAArch64SMEAttributes());
1387 if (HasZT0 && ZT0State != FunctionType::ARM_None &&
1388 checkNewAttrMutualExclusion(S&: SemaRef, AL, FPT, CurrentState: ZT0State, StateName: "zt0"))
1389 return;
1390 }
1391
1392 D->dropAttr<ArmNewAttr>();
1393 D->addAttr(A: ::new (getASTContext()) ArmNewAttr(
1394 getASTContext(), AL, NewState.data(), NewState.size()));
1395}
1396
1397void SemaARM::handleCmseNSEntryAttr(Decl *D, const ParsedAttr &AL) {
1398 if (getLangOpts().CPlusPlus && !D->getDeclContext()->isExternCContext()) {
1399 Diag(Loc: AL.getLoc(), DiagID: diag::err_attribute_not_clinkage) << AL;
1400 return;
1401 }
1402
1403 const auto *FD = cast<FunctionDecl>(Val: D);
1404 if (!FD->isExternallyVisible()) {
1405 Diag(Loc: AL.getLoc(), DiagID: diag::warn_attribute_cmse_entry_static);
1406 return;
1407 }
1408
1409 D->addAttr(A: ::new (getASTContext()) CmseNSEntryAttr(getASTContext(), AL));
1410}
1411
1412void SemaARM::handleInterruptAttr(Decl *D, const ParsedAttr &AL) {
1413 // Check the attribute arguments.
1414 if (AL.getNumArgs() > 1) {
1415 Diag(Loc: AL.getLoc(), DiagID: 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(Attr: AL, ArgNum: 0, Str, ArgLocation: &ArgLoc))
1425 return;
1426
1427 ARMInterruptAttr::InterruptType Kind;
1428 if (!ARMInterruptAttr::ConvertStrToInterruptType(Val: Str, Out&: Kind)) {
1429 Diag(Loc: AL.getLoc(), DiagID: 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(Feature: "vfp"))
1437 Diag(Loc: D->getLocation(), DiagID: diag::warn_arm_interrupt_vfp_clobber);
1438 }
1439
1440 D->addAttr(A: ::new (getASTContext())
1441 ARMInterruptAttr(getASTContext(), AL, Kind));
1442}
1443
1444void SemaARM::handleInterruptSaveFPAttr(Decl *D, const ParsedAttr &AL) {
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(A: ::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(Feature: "vfp");
1459
1460 if (!VFP) {
1461 SemaRef.Diag(Loc: D->getLocation(), DiagID: 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.
1469void SemaARM::CheckSMEFunctionDefAttributes(const FunctionDecl *FD) {
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();
1478 if (EPI.AArch64SMEAttributes & FunctionType::SME_AgnosticZAStateMask)
1479 Diag(Loc: FD->getLocation(), DiagID: diag::err_sme_unsupported_agnostic_new);
1480 }
1481 }
1482
1483 if (FD->hasAttr<ArmLocallyStreamingAttr>()) {
1484 if (FD->getReturnType()->isSizelessVectorType())
1485 Diag(Loc: FD->getLocation(),
1486 DiagID: diag::warn_sme_locally_streaming_has_vl_args_returns)
1487 << /*IsArg=*/false;
1488 if (llvm::any_of(Range: FD->parameters(), P: [](ParmVarDecl *P) {
1489 return P->getOriginalType()->isSizelessVectorType();
1490 }))
1491 Diag(Loc: FD->getLocation(),
1492 DiagID: 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();
1497 UsesSM |= EPI.AArch64SMEAttributes & FunctionType::SME_PStateSMEnabledMask;
1498 UsesZA |= FunctionType::getArmZAState(AttrBits: EPI.AArch64SMEAttributes) !=
1499 FunctionType::ARM_None;
1500 UsesZT0 |= FunctionType::getArmZT0State(AttrBits: EPI.AArch64SMEAttributes) !=
1501 FunctionType::ARM_None;
1502 }
1503
1504 ASTContext &Context = getASTContext();
1505 if (UsesSM || UsesZA) {
1506 llvm::StringMap<bool> FeatureMap;
1507 Context.getFunctionFeatureMap(FeatureMap, FD);
1508 if (!FeatureMap.contains(Key: "sme")) {
1509 if (UsesSM)
1510 Diag(Loc: FD->getLocation(),
1511 DiagID: diag::err_sme_definition_using_sm_in_non_sme_target);
1512 else
1513 Diag(Loc: FD->getLocation(),
1514 DiagID: 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(Key: "sme2")) {
1521 Diag(Loc: FD->getLocation(),
1522 DiagID: 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
1539bool SemaARM::areCompatibleSveTypes(QualType FirstType, QualType SecondType) {
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() &
1548 FunctionType::SME_PStateSMCompatibleMask)
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(Ctx: Context) &&
1568 BT->getKind() != BuiltinType::SveBool;
1569 else if (VT->getVectorKind() == VectorKind::Generic)
1570 return Context.getTypeSize(T: SecondType) ==
1571 getSVETypeSize(Context, Ty: BT, IsStreaming) &&
1572 Context.hasSameType(
1573 T1: VT->getElementType(),
1574 T2: Context.getBuiltinVectorTypeInfo(VecTy: BT).ElementType);
1575 }
1576 }
1577 return false;
1578 };
1579
1580 return IsValidCast(FirstType, SecondType) ||
1581 IsValidCast(SecondType, FirstType);
1582}
1583
1584bool SemaARM::areLaxCompatibleSveTypes(QualType FirstType,
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() &
1594 FunctionType::SME_PStateSMCompatibleMask)
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)) {
1610 const LangOptions::LaxVectorConversionKind LVCKind =
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(T: SecondType) !=
1627 getSVETypeSize(Context, Ty: BT, IsStreaming))
1628 return false;
1629
1630 // If -flax-vector-conversions=all is specified, the types are
1631 // certainly compatible.
1632 if (LVCKind == LangOptions::LaxVectorConversionKind::All)
1633 return true;
1634
1635 // If -flax-vector-conversions=integer is specified, the types are
1636 // compatible if the elements are integer types.
1637 if (LVCKind == LangOptions::LaxVectorConversionKind::Integer)
1638 return VecTy->getElementType().getCanonicalType()->isIntegerType() &&
1639 FirstType->getSveEltType(Ctx: 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(RHS: "+");
1652 Buffer.append(RHS: 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(Feat: PriorityString[BitPos], Buffer&: 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(Separator: ';');
1673 RHS = RHS.trim();
1674 bool IsDefault = false;
1675 llvm::SmallVector<StringRef, 8> Features;
1676 LHS.split(A&: Features, Separator: '+');
1677 for (StringRef Feat : Features) {
1678 Feat = Feat.trim();
1679 if (Feat == "default")
1680 IsDefault = true;
1681 else if (!getASTContext().getTargetInfo().validateCpuSupports(Name: Feat))
1682 return Diag(Loc, DiagID: diag::warn_unsupported_target_attribute)
1683 << Unsupported << None << Feat << TargetVersion;
1684 appendFeature(Feat, Buffer&: NewParam);
1685 }
1686
1687 if (!RHS.empty() && RHS.consume_front(Prefix: "priority=")) {
1688 if (IsDefault)
1689 Diag(Loc, DiagID: diag::warn_invalid_default_version_priority);
1690 else {
1691 unsigned Digit;
1692 if (RHS.getAsInteger(Radix: 0, Result&: Digit) || Digit < 1 || Digit > 255)
1693 Diag(Loc, DiagID: diag::warn_version_priority_out_of_range) << RHS;
1694 else
1695 convertPriorityString(Priority: Digit, NewParam);
1696 }
1697 }
1698 return false;
1699}
1700
1701bool SemaARM::checkTargetClonesAttr(
1702 SmallVectorImpl<StringRef> &Params, SmallVectorImpl<SourceLocation> &Locs,
1703 SmallVectorImpl<SmallString<64>> &NewParams) {
1704 using namespace DiagAttrParams;
1705
1706 if (!getASTContext().getTargetInfo().hasFeature(Feature: "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(Separator: ';');
1719 RHS = RHS.trim();
1720 bool HasPriority = !RHS.empty() && RHS.consume_front(Prefix: "priority=");
1721
1722 if (LHS.empty())
1723 return Diag(Loc, DiagID: diag::warn_unsupported_target_attribute)
1724 << Unsupported << None << "" << TargetClones;
1725
1726 if (LHS == "default") {
1727 if (HasDefault)
1728 Diag(Loc, DiagID: diag::warn_target_clone_duplicate_options);
1729 else {
1730 if (HasPriority)
1731 Diag(Loc, DiagID: diag::warn_invalid_default_version_priority);
1732 NewParams.push_back(Elt: LHS);
1733 HasDefault = true;
1734 }
1735 continue;
1736 }
1737
1738 bool HasCodeGenImpact = false;
1739 llvm::SmallVector<StringRef, 8> Features;
1740 llvm::SmallVector<StringRef, 8> ValidFeatures;
1741 LHS.split(A&: Features, Separator: '+');
1742 for (StringRef Feat : Features) {
1743 Feat = Feat.trim();
1744 if (!getASTContext().getTargetInfo().validateCpuSupports(Name: Feat)) {
1745 Diag(Loc, DiagID: diag::warn_unsupported_target_attribute)
1746 << Unsupported << None << Feat << TargetClones;
1747 continue;
1748 }
1749 if (getASTContext().getTargetInfo().doesFeatureAffectCodeGen(Feature: Feat))
1750 HasCodeGenImpact = true;
1751 ValidFeatures.push_back(Elt: Feat);
1752 }
1753
1754 // Ignore features that don't impact code generation.
1755 if (!HasCodeGenImpact) {
1756 Diag(Loc, DiagID: 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(C&: ValidFeatures);
1765 SmallString<64> NewParam(llvm::join(R&: ValidFeatures, Separator: "+"));
1766 if (llvm::is_contained(Range&: NewParams, Element: NewParam)) {
1767 Diag(Loc, DiagID: diag::warn_target_clone_duplicate_options);
1768 continue;
1769 }
1770
1771 if (HasPriority) {
1772 unsigned Digit;
1773 if (RHS.getAsInteger(Radix: 0, Result&: Digit) || Digit < 1 || Digit > 255)
1774 Diag(Loc, DiagID: diag::warn_version_priority_out_of_range) << RHS;
1775 else
1776 convertPriorityString(Priority: Digit, NewParam);
1777 }
1778
1779 // Valid non-default argument.
1780 NewParams.push_back(Elt: NewParam);
1781 HasNonDefault = true;
1782 }
1783
1784 return !HasNonDefault;
1785}
1786
1787bool SemaARM::checkSVETypeSupport(QualType Ty, SourceLocation Loc,
1788 const FunctionDecl *FD,
1789 const llvm::StringMap<bool> &FeatureMap) {
1790 if (!Ty->isSVESizelessBuiltinType())
1791 return false;
1792
1793 if (FeatureMap.lookup(Key: "sve"))
1794 return false;
1795
1796 // No SVE environment available.
1797 if (!FeatureMap.lookup(Key: "sme"))
1798 return Diag(Loc, DiagID: 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, DiagID: diag::err_sve_vector_in_non_streaming_function) << Ty;
1804
1805 return false;
1806}
1807} // namespace clang
1808