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