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/Sema/Initialization.h"
17#include "clang/Sema/ParsedAttr.h"
18#include "clang/Sema/Sema.h"
19
20namespace clang {
21
22SemaARM::SemaARM(Sema &S) : SemaBase(S) {}
23
24/// BuiltinARMMemoryTaggingCall - Handle calls of memory tagging extensions
25bool SemaARM::BuiltinARMMemoryTaggingCall(unsigned BuiltinID,
26 CallExpr *TheCall) {
27 ASTContext &Context = getASTContext();
28
29 if (BuiltinID == AArch64::BI__builtin_arm_irg) {
30 if (SemaRef.checkArgCount(Call: TheCall, DesiredArgCount: 2))
31 return true;
32 Expr *Arg0 = TheCall->getArg(Arg: 0);
33 Expr *Arg1 = TheCall->getArg(Arg: 1);
34
35 ExprResult FirstArg = SemaRef.DefaultFunctionArrayLvalueConversion(E: Arg0);
36 if (FirstArg.isInvalid())
37 return true;
38 QualType FirstArgType = FirstArg.get()->getType();
39 if (!FirstArgType->isAnyPointerType())
40 return Diag(Loc: TheCall->getBeginLoc(), DiagID: diag::err_memtag_arg_must_be_pointer)
41 << "first" << FirstArgType << Arg0->getSourceRange();
42 TheCall->setArg(Arg: 0, ArgExpr: FirstArg.get());
43
44 ExprResult SecArg = SemaRef.DefaultLvalueConversion(E: Arg1);
45 if (SecArg.isInvalid())
46 return true;
47 QualType SecArgType = SecArg.get()->getType();
48 if (!SecArgType->isIntegerType())
49 return Diag(Loc: TheCall->getBeginLoc(), DiagID: diag::err_memtag_arg_must_be_integer)
50 << "second" << SecArgType << Arg1->getSourceRange();
51
52 // Derive the return type from the pointer argument.
53 TheCall->setType(FirstArgType);
54 return false;
55 }
56
57 if (BuiltinID == AArch64::BI__builtin_arm_addg) {
58 if (SemaRef.checkArgCount(Call: TheCall, DesiredArgCount: 2))
59 return true;
60
61 Expr *Arg0 = TheCall->getArg(Arg: 0);
62 ExprResult FirstArg = SemaRef.DefaultFunctionArrayLvalueConversion(E: Arg0);
63 if (FirstArg.isInvalid())
64 return true;
65 QualType FirstArgType = FirstArg.get()->getType();
66 if (!FirstArgType->isAnyPointerType())
67 return Diag(Loc: TheCall->getBeginLoc(), DiagID: diag::err_memtag_arg_must_be_pointer)
68 << "first" << FirstArgType << Arg0->getSourceRange();
69 TheCall->setArg(Arg: 0, ArgExpr: FirstArg.get());
70
71 // Derive the return type from the pointer argument.
72 TheCall->setType(FirstArgType);
73
74 // Second arg must be an constant in range [0,15]
75 return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 1, Low: 0, High: 15);
76 }
77
78 if (BuiltinID == AArch64::BI__builtin_arm_gmi) {
79 if (SemaRef.checkArgCount(Call: TheCall, DesiredArgCount: 2))
80 return true;
81 Expr *Arg0 = TheCall->getArg(Arg: 0);
82 Expr *Arg1 = TheCall->getArg(Arg: 1);
83
84 ExprResult FirstArg = SemaRef.DefaultFunctionArrayLvalueConversion(E: Arg0);
85 if (FirstArg.isInvalid())
86 return true;
87 QualType FirstArgType = FirstArg.get()->getType();
88 if (!FirstArgType->isAnyPointerType())
89 return Diag(Loc: TheCall->getBeginLoc(), DiagID: diag::err_memtag_arg_must_be_pointer)
90 << "first" << FirstArgType << Arg0->getSourceRange();
91
92 QualType SecArgType = Arg1->getType();
93 if (!SecArgType->isIntegerType())
94 return Diag(Loc: TheCall->getBeginLoc(), DiagID: diag::err_memtag_arg_must_be_integer)
95 << "second" << SecArgType << Arg1->getSourceRange();
96 TheCall->setType(Context.IntTy);
97 return false;
98 }
99
100 if (BuiltinID == AArch64::BI__builtin_arm_ldg ||
101 BuiltinID == AArch64::BI__builtin_arm_stg) {
102 if (SemaRef.checkArgCount(Call: TheCall, DesiredArgCount: 1))
103 return true;
104 Expr *Arg0 = TheCall->getArg(Arg: 0);
105 ExprResult FirstArg = SemaRef.DefaultFunctionArrayLvalueConversion(E: Arg0);
106 if (FirstArg.isInvalid())
107 return true;
108
109 QualType FirstArgType = FirstArg.get()->getType();
110 if (!FirstArgType->isAnyPointerType())
111 return Diag(Loc: TheCall->getBeginLoc(), DiagID: diag::err_memtag_arg_must_be_pointer)
112 << "first" << FirstArgType << Arg0->getSourceRange();
113 TheCall->setArg(Arg: 0, ArgExpr: FirstArg.get());
114
115 // Derive the return type from the pointer argument.
116 if (BuiltinID == AArch64::BI__builtin_arm_ldg)
117 TheCall->setType(FirstArgType);
118 return false;
119 }
120
121 if (BuiltinID == AArch64::BI__builtin_arm_subp) {
122 Expr *ArgA = TheCall->getArg(Arg: 0);
123 Expr *ArgB = TheCall->getArg(Arg: 1);
124
125 ExprResult ArgExprA = SemaRef.DefaultFunctionArrayLvalueConversion(E: ArgA);
126 ExprResult ArgExprB = SemaRef.DefaultFunctionArrayLvalueConversion(E: ArgB);
127
128 if (ArgExprA.isInvalid() || ArgExprB.isInvalid())
129 return true;
130
131 QualType ArgTypeA = ArgExprA.get()->getType();
132 QualType ArgTypeB = ArgExprB.get()->getType();
133
134 auto isNull = [&](Expr *E) -> bool {
135 return E->isNullPointerConstant(Ctx&: Context,
136 NPC: Expr::NPC_ValueDependentIsNotNull);
137 };
138
139 // argument should be either a pointer or null
140 if (!ArgTypeA->isAnyPointerType() && !isNull(ArgA))
141 return Diag(Loc: TheCall->getBeginLoc(), DiagID: diag::err_memtag_arg_null_or_pointer)
142 << "first" << ArgTypeA << ArgA->getSourceRange();
143
144 if (!ArgTypeB->isAnyPointerType() && !isNull(ArgB))
145 return Diag(Loc: TheCall->getBeginLoc(), DiagID: diag::err_memtag_arg_null_or_pointer)
146 << "second" << ArgTypeB << ArgB->getSourceRange();
147
148 // Ensure Pointee types are compatible
149 if (ArgTypeA->isAnyPointerType() && !isNull(ArgA) &&
150 ArgTypeB->isAnyPointerType() && !isNull(ArgB)) {
151 QualType pointeeA = ArgTypeA->getPointeeType();
152 QualType pointeeB = ArgTypeB->getPointeeType();
153 if (!Context.typesAreCompatible(
154 T1: Context.getCanonicalType(T: pointeeA).getUnqualifiedType(),
155 T2: Context.getCanonicalType(T: pointeeB).getUnqualifiedType())) {
156 return Diag(Loc: TheCall->getBeginLoc(),
157 DiagID: diag::err_typecheck_sub_ptr_compatible)
158 << ArgTypeA << ArgTypeB << ArgA->getSourceRange()
159 << ArgB->getSourceRange();
160 }
161 }
162
163 // at least one argument should be pointer type
164 if (!ArgTypeA->isAnyPointerType() && !ArgTypeB->isAnyPointerType())
165 return Diag(Loc: TheCall->getBeginLoc(), DiagID: diag::err_memtag_any2arg_pointer)
166 << ArgTypeA << ArgTypeB << ArgA->getSourceRange();
167
168 if (isNull(ArgA)) // adopt type of the other pointer
169 ArgExprA =
170 SemaRef.ImpCastExprToType(E: ArgExprA.get(), Type: ArgTypeB, CK: CK_NullToPointer);
171
172 if (isNull(ArgB))
173 ArgExprB =
174 SemaRef.ImpCastExprToType(E: ArgExprB.get(), Type: ArgTypeA, CK: CK_NullToPointer);
175
176 TheCall->setArg(Arg: 0, ArgExpr: ArgExprA.get());
177 TheCall->setArg(Arg: 1, ArgExpr: ArgExprB.get());
178 TheCall->setType(Context.LongLongTy);
179 return false;
180 }
181 assert(false && "Unhandled ARM MTE intrinsic");
182 return true;
183}
184
185/// BuiltinARMSpecialReg - Handle a check if argument ArgNum of CallExpr
186/// TheCall is an ARM/AArch64 special register string literal.
187bool SemaARM::BuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall,
188 int ArgNum, unsigned ExpectedFieldNum,
189 bool AllowName) {
190 bool IsARMBuiltin = BuiltinID == ARM::BI__builtin_arm_rsr64 ||
191 BuiltinID == ARM::BI__builtin_arm_wsr64 ||
192 BuiltinID == ARM::BI__builtin_arm_rsr ||
193 BuiltinID == ARM::BI__builtin_arm_rsrp ||
194 BuiltinID == ARM::BI__builtin_arm_wsr ||
195 BuiltinID == ARM::BI__builtin_arm_wsrp;
196 bool IsAArch64Builtin = BuiltinID == AArch64::BI__builtin_arm_rsr64 ||
197 BuiltinID == AArch64::BI__builtin_arm_wsr64 ||
198 BuiltinID == AArch64::BI__builtin_arm_rsr128 ||
199 BuiltinID == AArch64::BI__builtin_arm_wsr128 ||
200 BuiltinID == AArch64::BI__builtin_arm_rsr ||
201 BuiltinID == AArch64::BI__builtin_arm_rsrp ||
202 BuiltinID == AArch64::BI__builtin_arm_wsr ||
203 BuiltinID == AArch64::BI__builtin_arm_wsrp;
204 assert((IsARMBuiltin || IsAArch64Builtin) && "Unexpected ARM builtin.");
205
206 // We can't check the value of a dependent argument.
207 Expr *Arg = TheCall->getArg(Arg: ArgNum);
208 if (Arg->isTypeDependent() || Arg->isValueDependent())
209 return false;
210
211 // Check if the argument is a string literal.
212 if (!isa<StringLiteral>(Val: Arg->IgnoreParenImpCasts()))
213 return Diag(Loc: TheCall->getBeginLoc(), DiagID: diag::err_expr_not_string_literal)
214 << Arg->getSourceRange();
215
216 // Check the type of special register given.
217 StringRef Reg = cast<StringLiteral>(Val: Arg->IgnoreParenImpCasts())->getString();
218 SmallVector<StringRef, 6> Fields;
219 Reg.split(A&: Fields, Separator: ":");
220
221 if (Fields.size() != ExpectedFieldNum && !(AllowName && Fields.size() == 1))
222 return Diag(Loc: TheCall->getBeginLoc(), DiagID: diag::err_arm_invalid_specialreg)
223 << Arg->getSourceRange();
224
225 // If the string is the name of a register then we cannot check that it is
226 // valid here but if the string is of one the forms described in ACLE then we
227 // can check that the supplied fields are integers and within the valid
228 // ranges.
229 if (Fields.size() > 1) {
230 bool FiveFields = Fields.size() == 5;
231
232 bool ValidString = true;
233 if (IsARMBuiltin) {
234 ValidString &= Fields[0].starts_with_insensitive(Prefix: "cp") ||
235 Fields[0].starts_with_insensitive(Prefix: "p");
236 if (ValidString)
237 Fields[0] = Fields[0].drop_front(
238 N: Fields[0].starts_with_insensitive(Prefix: "cp") ? 2 : 1);
239
240 ValidString &= Fields[2].starts_with_insensitive(Prefix: "c");
241 if (ValidString)
242 Fields[2] = Fields[2].drop_front(N: 1);
243
244 if (FiveFields) {
245 ValidString &= Fields[3].starts_with_insensitive(Prefix: "c");
246 if (ValidString)
247 Fields[3] = Fields[3].drop_front(N: 1);
248 }
249 }
250
251 SmallVector<int, 5> Ranges;
252 if (FiveFields)
253 Ranges.append(IL: {IsAArch64Builtin ? 1 : 15, 7, 15, 15, 7});
254 else
255 Ranges.append(IL: {15, 7, 15});
256
257 for (unsigned i = 0; i < Fields.size(); ++i) {
258 int IntField;
259 ValidString &= !Fields[i].getAsInteger(Radix: 10, Result&: IntField);
260 ValidString &= (IntField >= 0 && IntField <= Ranges[i]);
261 }
262
263 if (!ValidString)
264 return Diag(Loc: TheCall->getBeginLoc(), DiagID: diag::err_arm_invalid_specialreg)
265 << Arg->getSourceRange();
266 } else if (IsAArch64Builtin && Fields.size() == 1) {
267 // This code validates writes to PSTATE registers.
268
269 // Not a write.
270 if (TheCall->getNumArgs() != 2)
271 return false;
272
273 // The 128-bit system register accesses do not touch PSTATE.
274 if (BuiltinID == AArch64::BI__builtin_arm_rsr128 ||
275 BuiltinID == AArch64::BI__builtin_arm_wsr128)
276 return false;
277
278 // These are the named PSTATE accesses using "MSR (immediate)" instructions,
279 // along with the upper limit on the immediates allowed.
280 auto MaxLimit = llvm::StringSwitch<std::optional<unsigned>>(Reg)
281 .CaseLower(S: "spsel", Value: 15)
282 .CaseLower(S: "daifclr", Value: 15)
283 .CaseLower(S: "daifset", Value: 15)
284 .CaseLower(S: "pan", Value: 15)
285 .CaseLower(S: "uao", Value: 15)
286 .CaseLower(S: "dit", Value: 15)
287 .CaseLower(S: "ssbs", Value: 15)
288 .CaseLower(S: "tco", Value: 15)
289 .CaseLower(S: "allint", Value: 1)
290 .CaseLower(S: "pm", Value: 1)
291 .Default(Value: std::nullopt);
292
293 // If this is not a named PSTATE, just continue without validating, as this
294 // will be lowered to an "MSR (register)" instruction directly
295 if (!MaxLimit)
296 return false;
297
298 // Here we only allow constants in the range for that pstate, as required by
299 // the ACLE.
300 //
301 // While clang also accepts the names of system registers in its ACLE
302 // intrinsics, we prevent this with the PSTATE names used in MSR (immediate)
303 // as the value written via a register is different to the value used as an
304 // immediate to have the same effect. e.g., for the instruction `msr tco,
305 // x0`, it is bit 25 of register x0 that is written into PSTATE.TCO, but
306 // with `msr tco, #imm`, it is bit 0 of xN that is written into PSTATE.TCO.
307 //
308 // If a programmer wants to codegen the MSR (register) form of `msr tco,
309 // xN`, they can still do so by specifying the register using five
310 // colon-separated numbers in a string.
311 return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 1, Low: 0, High: *MaxLimit);
312 }
313
314 return false;
315}
316
317// Get the valid immediate range for the specified NEON type code.
318static unsigned RFT(unsigned t, bool shift = false, bool ForceQuad = false) {
319 NeonTypeFlags Type(t);
320 int IsQuad = ForceQuad ? true : Type.isQuad();
321 switch (Type.getEltType()) {
322 case NeonTypeFlags::Int8:
323 case NeonTypeFlags::Poly8:
324 return shift ? 7 : (8 << IsQuad) - 1;
325 case NeonTypeFlags::Int16:
326 case NeonTypeFlags::Poly16:
327 return shift ? 15 : (4 << IsQuad) - 1;
328 case NeonTypeFlags::Int32:
329 return shift ? 31 : (2 << IsQuad) - 1;
330 case NeonTypeFlags::Int64:
331 case NeonTypeFlags::Poly64:
332 return shift ? 63 : (1 << IsQuad) - 1;
333 case NeonTypeFlags::Poly128:
334 return shift ? 127 : (1 << IsQuad) - 1;
335 case NeonTypeFlags::Float16:
336 assert(!shift && "cannot shift float types!");
337 return (4 << IsQuad) - 1;
338 case NeonTypeFlags::Float32:
339 assert(!shift && "cannot shift float types!");
340 return (2 << IsQuad) - 1;
341 case NeonTypeFlags::Float64:
342 assert(!shift && "cannot shift float types!");
343 return (1 << IsQuad) - 1;
344 case NeonTypeFlags::BFloat16:
345 assert(!shift && "cannot shift float types!");
346 return (4 << IsQuad) - 1;
347 }
348 llvm_unreachable("Invalid NeonTypeFlag!");
349}
350
351/// getNeonEltType - Return the QualType corresponding to the elements of
352/// the vector type specified by the NeonTypeFlags. This is used to check
353/// the pointer arguments for Neon load/store intrinsics.
354static QualType getNeonEltType(NeonTypeFlags Flags, ASTContext &Context,
355 bool IsPolyUnsigned, bool IsInt64Long) {
356 switch (Flags.getEltType()) {
357 case NeonTypeFlags::Int8:
358 return Flags.isUnsigned() ? Context.UnsignedCharTy : Context.SignedCharTy;
359 case NeonTypeFlags::Int16:
360 return Flags.isUnsigned() ? Context.UnsignedShortTy : Context.ShortTy;
361 case NeonTypeFlags::Int32:
362 return Flags.isUnsigned() ? Context.UnsignedIntTy : Context.IntTy;
363 case NeonTypeFlags::Int64:
364 if (IsInt64Long)
365 return Flags.isUnsigned() ? Context.UnsignedLongTy : Context.LongTy;
366 else
367 return Flags.isUnsigned() ? Context.UnsignedLongLongTy
368 : Context.LongLongTy;
369 case NeonTypeFlags::Poly8:
370 return IsPolyUnsigned ? Context.UnsignedCharTy : Context.SignedCharTy;
371 case NeonTypeFlags::Poly16:
372 return IsPolyUnsigned ? Context.UnsignedShortTy : Context.ShortTy;
373 case NeonTypeFlags::Poly64:
374 if (IsInt64Long)
375 return Context.UnsignedLongTy;
376 else
377 return Context.UnsignedLongLongTy;
378 case NeonTypeFlags::Poly128:
379 break;
380 case NeonTypeFlags::Float16:
381 return Context.HalfTy;
382 case NeonTypeFlags::Float32:
383 return Context.FloatTy;
384 case NeonTypeFlags::Float64:
385 return Context.DoubleTy;
386 case NeonTypeFlags::BFloat16:
387 return Context.BFloat16Ty;
388 }
389 llvm_unreachable("Invalid NeonTypeFlag!");
390}
391
392enum ArmSMEState : unsigned {
393 ArmNoState = 0,
394
395 ArmInZA = 0b01,
396 ArmOutZA = 0b10,
397 ArmInOutZA = 0b11,
398 ArmZAMask = 0b11,
399
400 ArmInZT0 = 0b01 << 2,
401 ArmOutZT0 = 0b10 << 2,
402 ArmInOutZT0 = 0b11 << 2,
403 ArmZT0Mask = 0b11 << 2
404};
405
406bool SemaARM::ParseSVEImmChecks(
407 CallExpr *TheCall, SmallVector<std::tuple<int, int, int>, 3> &ImmChecks) {
408 // Perform all the immediate checks for this builtin call.
409 bool HasError = false;
410 for (auto &I : ImmChecks) {
411 int ArgNum, CheckTy, ElementSizeInBits;
412 std::tie(args&: ArgNum, args&: CheckTy, args&: ElementSizeInBits) = I;
413
414 typedef bool (*OptionSetCheckFnTy)(int64_t Value);
415
416 // Function that checks whether the operand (ArgNum) is an immediate
417 // that is one of the predefined values.
418 auto CheckImmediateInSet = [&](OptionSetCheckFnTy CheckImm,
419 int ErrDiag) -> bool {
420 // We can't check the value of a dependent argument.
421 Expr *Arg = TheCall->getArg(Arg: ArgNum);
422 if (Arg->isTypeDependent() || Arg->isValueDependent())
423 return false;
424
425 // Check constant-ness first.
426 llvm::APSInt Imm;
427 if (SemaRef.BuiltinConstantArg(TheCall, ArgNum, Result&: Imm))
428 return true;
429
430 if (!CheckImm(Imm.getSExtValue()))
431 return Diag(Loc: TheCall->getBeginLoc(), DiagID: ErrDiag) << Arg->getSourceRange();
432 return false;
433 };
434
435 switch ((SVETypeFlags::ImmCheckType)CheckTy) {
436 case SVETypeFlags::ImmCheck0_31:
437 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, Low: 0, High: 31))
438 HasError = true;
439 break;
440 case SVETypeFlags::ImmCheck0_13:
441 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, Low: 0, High: 13))
442 HasError = true;
443 break;
444 case SVETypeFlags::ImmCheck1_16:
445 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, Low: 1, High: 16))
446 HasError = true;
447 break;
448 case SVETypeFlags::ImmCheck0_7:
449 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, Low: 0, High: 7))
450 HasError = true;
451 break;
452 case SVETypeFlags::ImmCheck1_1:
453 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, Low: 1, High: 1))
454 HasError = true;
455 break;
456 case SVETypeFlags::ImmCheck1_3:
457 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, Low: 1, High: 3))
458 HasError = true;
459 break;
460 case SVETypeFlags::ImmCheck1_7:
461 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, Low: 1, High: 7))
462 HasError = true;
463 break;
464 case SVETypeFlags::ImmCheckExtract:
465 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, Low: 0,
466 High: (2048 / ElementSizeInBits) - 1))
467 HasError = true;
468 break;
469 case SVETypeFlags::ImmCheckShiftRight:
470 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, Low: 1,
471 High: ElementSizeInBits))
472 HasError = true;
473 break;
474 case SVETypeFlags::ImmCheckShiftRightNarrow:
475 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, Low: 1,
476 High: ElementSizeInBits / 2))
477 HasError = true;
478 break;
479 case SVETypeFlags::ImmCheckShiftLeft:
480 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, Low: 0,
481 High: ElementSizeInBits - 1))
482 HasError = true;
483 break;
484 case SVETypeFlags::ImmCheckLaneIndex:
485 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, Low: 0,
486 High: (128 / (1 * ElementSizeInBits)) - 1))
487 HasError = true;
488 break;
489 case SVETypeFlags::ImmCheckLaneIndexCompRotate:
490 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, Low: 0,
491 High: (128 / (2 * ElementSizeInBits)) - 1))
492 HasError = true;
493 break;
494 case SVETypeFlags::ImmCheckLaneIndexDot:
495 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, Low: 0,
496 High: (128 / (4 * ElementSizeInBits)) - 1))
497 HasError = true;
498 break;
499 case SVETypeFlags::ImmCheckComplexRot90_270:
500 if (CheckImmediateInSet([](int64_t V) { return V == 90 || V == 270; },
501 diag::err_rotation_argument_to_cadd))
502 HasError = true;
503 break;
504 case SVETypeFlags::ImmCheckComplexRotAll90:
505 if (CheckImmediateInSet(
506 [](int64_t V) {
507 return V == 0 || V == 90 || V == 180 || V == 270;
508 },
509 diag::err_rotation_argument_to_cmla))
510 HasError = true;
511 break;
512 case SVETypeFlags::ImmCheck0_1:
513 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, Low: 0, High: 1))
514 HasError = true;
515 break;
516 case SVETypeFlags::ImmCheck0_2:
517 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, Low: 0, High: 2))
518 HasError = true;
519 break;
520 case SVETypeFlags::ImmCheck0_3:
521 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, Low: 0, High: 3))
522 HasError = true;
523 break;
524 case SVETypeFlags::ImmCheck0_0:
525 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, Low: 0, High: 0))
526 HasError = true;
527 break;
528 case SVETypeFlags::ImmCheck0_15:
529 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, Low: 0, High: 15))
530 HasError = true;
531 break;
532 case SVETypeFlags::ImmCheck0_255:
533 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, Low: 0, High: 255))
534 HasError = true;
535 break;
536 case SVETypeFlags::ImmCheck2_4_Mul2:
537 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, Low: 2, High: 4) ||
538 SemaRef.BuiltinConstantArgMultiple(TheCall, ArgNum, Multiple: 2))
539 HasError = true;
540 break;
541 }
542 }
543
544 return HasError;
545}
546
547SemaARM::ArmStreamingType getArmStreamingFnType(const FunctionDecl *FD) {
548 if (FD->hasAttr<ArmLocallyStreamingAttr>())
549 return SemaARM::ArmStreaming;
550 if (const Type *Ty = FD->getType().getTypePtrOrNull()) {
551 if (const auto *FPT = Ty->getAs<FunctionProtoType>()) {
552 if (FPT->getAArch64SMEAttributes() &
553 FunctionType::SME_PStateSMEnabledMask)
554 return SemaARM::ArmStreaming;
555 if (FPT->getAArch64SMEAttributes() &
556 FunctionType::SME_PStateSMCompatibleMask)
557 return SemaARM::ArmStreamingCompatible;
558 }
559 }
560 return SemaARM::ArmNonStreaming;
561}
562
563static bool checkArmStreamingBuiltin(Sema &S, CallExpr *TheCall,
564 const FunctionDecl *FD,
565 SemaARM::ArmStreamingType BuiltinType,
566 unsigned BuiltinID) {
567 SemaARM::ArmStreamingType FnType = getArmStreamingFnType(FD);
568
569 // Check if the intrinsic is available in the right mode, i.e.
570 // * When compiling for SME only, the caller must be in streaming mode.
571 // * When compiling for SVE only, the caller must be in non-streaming mode.
572 // * When compiling for both SVE and SME, the caller can be in either mode.
573 if (BuiltinType == SemaARM::VerifyRuntimeMode) {
574 auto DisableFeatures = [](llvm::StringMap<bool> &Map, StringRef S) {
575 for (StringRef K : Map.keys())
576 if (K.starts_with(Prefix: S))
577 Map[K] = false;
578 };
579
580 llvm::StringMap<bool> CallerFeatureMapWithoutSVE;
581 S.Context.getFunctionFeatureMap(FeatureMap&: CallerFeatureMapWithoutSVE, FD);
582 DisableFeatures(CallerFeatureMapWithoutSVE, "sve");
583
584 // Avoid emitting diagnostics for a function that can never compile.
585 if (FnType == SemaARM::ArmStreaming && !CallerFeatureMapWithoutSVE["sme"])
586 return false;
587
588 llvm::StringMap<bool> CallerFeatureMapWithoutSME;
589 S.Context.getFunctionFeatureMap(FeatureMap&: CallerFeatureMapWithoutSME, FD);
590 DisableFeatures(CallerFeatureMapWithoutSME, "sme");
591
592 // We know the builtin requires either some combination of SVE flags, or
593 // some combination of SME flags, but we need to figure out which part
594 // of the required features is satisfied by the target features.
595 //
596 // For a builtin with target guard 'sve2p1|sme2', if we compile with
597 // '+sve2p1,+sme', then we know that it satisfies the 'sve2p1' part if we
598 // evaluate the features for '+sve2p1,+sme,+nosme'.
599 //
600 // Similarly, if we compile with '+sve2,+sme2', then we know it satisfies
601 // the 'sme2' part if we evaluate the features for '+sve2,+sme2,+nosve'.
602 StringRef BuiltinTargetGuards(
603 S.Context.BuiltinInfo.getRequiredFeatures(ID: BuiltinID));
604 bool SatisfiesSVE = Builtin::evaluateRequiredTargetFeatures(
605 RequiredFatures: BuiltinTargetGuards, TargetFetureMap: CallerFeatureMapWithoutSME);
606 bool SatisfiesSME = Builtin::evaluateRequiredTargetFeatures(
607 RequiredFatures: BuiltinTargetGuards, TargetFetureMap: CallerFeatureMapWithoutSVE);
608
609 if ((SatisfiesSVE && SatisfiesSME) ||
610 (SatisfiesSVE && FnType == SemaARM::ArmStreamingCompatible))
611 return false;
612 else if (SatisfiesSVE)
613 BuiltinType = SemaARM::ArmNonStreaming;
614 else if (SatisfiesSME)
615 BuiltinType = SemaARM::ArmStreaming;
616 else
617 // This should be diagnosed by CodeGen
618 return false;
619 }
620
621 if (FnType != SemaARM::ArmNonStreaming &&
622 BuiltinType == SemaARM::ArmNonStreaming)
623 S.Diag(Loc: TheCall->getBeginLoc(), DiagID: diag::err_attribute_arm_sm_incompat_builtin)
624 << TheCall->getSourceRange() << "non-streaming";
625 else if (FnType != SemaARM::ArmStreaming &&
626 BuiltinType == SemaARM::ArmStreaming)
627 S.Diag(Loc: TheCall->getBeginLoc(), DiagID: diag::err_attribute_arm_sm_incompat_builtin)
628 << TheCall->getSourceRange() << "streaming";
629 else
630 return false;
631
632 return true;
633}
634
635static bool hasArmZAState(const FunctionDecl *FD) {
636 const auto *T = FD->getType()->getAs<FunctionProtoType>();
637 return (T && FunctionType::getArmZAState(AttrBits: T->getAArch64SMEAttributes()) !=
638 FunctionType::ARM_None) ||
639 (FD->hasAttr<ArmNewAttr>() && FD->getAttr<ArmNewAttr>()->isNewZA());
640}
641
642static bool hasArmZT0State(const FunctionDecl *FD) {
643 const auto *T = FD->getType()->getAs<FunctionProtoType>();
644 return (T && FunctionType::getArmZT0State(AttrBits: T->getAArch64SMEAttributes()) !=
645 FunctionType::ARM_None) ||
646 (FD->hasAttr<ArmNewAttr>() && FD->getAttr<ArmNewAttr>()->isNewZT0());
647}
648
649static ArmSMEState getSMEState(unsigned BuiltinID) {
650 switch (BuiltinID) {
651 default:
652 return ArmNoState;
653#define GET_SME_BUILTIN_GET_STATE
654#include "clang/Basic/arm_sme_builtins_za_state.inc"
655#undef GET_SME_BUILTIN_GET_STATE
656 }
657}
658
659bool SemaARM::CheckSMEBuiltinFunctionCall(unsigned BuiltinID,
660 CallExpr *TheCall) {
661 if (const FunctionDecl *FD = SemaRef.getCurFunctionDecl()) {
662 std::optional<ArmStreamingType> BuiltinType;
663
664 switch (BuiltinID) {
665#define GET_SME_STREAMING_ATTRS
666#include "clang/Basic/arm_sme_streaming_attrs.inc"
667#undef GET_SME_STREAMING_ATTRS
668 }
669
670 if (BuiltinType &&
671 checkArmStreamingBuiltin(S&: SemaRef, TheCall, FD, BuiltinType: *BuiltinType, BuiltinID))
672 return true;
673
674 if ((getSMEState(BuiltinID) & ArmZAMask) && !hasArmZAState(FD))
675 Diag(Loc: TheCall->getBeginLoc(),
676 DiagID: diag::warn_attribute_arm_za_builtin_no_za_state)
677 << TheCall->getSourceRange();
678
679 if ((getSMEState(BuiltinID) & ArmZT0Mask) && !hasArmZT0State(FD))
680 Diag(Loc: TheCall->getBeginLoc(),
681 DiagID: diag::warn_attribute_arm_zt0_builtin_no_zt0_state)
682 << TheCall->getSourceRange();
683 }
684
685 // Range check SME intrinsics that take immediate values.
686 SmallVector<std::tuple<int, int, int>, 3> ImmChecks;
687
688 switch (BuiltinID) {
689 default:
690 return false;
691#define GET_SME_IMMEDIATE_CHECK
692#include "clang/Basic/arm_sme_sema_rangechecks.inc"
693#undef GET_SME_IMMEDIATE_CHECK
694 }
695
696 return ParseSVEImmChecks(TheCall, ImmChecks);
697}
698
699bool SemaARM::CheckSVEBuiltinFunctionCall(unsigned BuiltinID,
700 CallExpr *TheCall) {
701 if (const FunctionDecl *FD = SemaRef.getCurFunctionDecl()) {
702 std::optional<ArmStreamingType> BuiltinType;
703
704 switch (BuiltinID) {
705#define GET_SVE_STREAMING_ATTRS
706#include "clang/Basic/arm_sve_streaming_attrs.inc"
707#undef GET_SVE_STREAMING_ATTRS
708 }
709 if (BuiltinType &&
710 checkArmStreamingBuiltin(S&: SemaRef, TheCall, FD, BuiltinType: *BuiltinType, BuiltinID))
711 return true;
712 }
713 // Range check SVE intrinsics that take immediate values.
714 SmallVector<std::tuple<int, int, int>, 3> ImmChecks;
715
716 switch (BuiltinID) {
717 default:
718 return false;
719#define GET_SVE_IMMEDIATE_CHECK
720#include "clang/Basic/arm_sve_sema_rangechecks.inc"
721#undef GET_SVE_IMMEDIATE_CHECK
722 }
723
724 return ParseSVEImmChecks(TheCall, ImmChecks);
725}
726
727bool SemaARM::CheckNeonBuiltinFunctionCall(const TargetInfo &TI,
728 unsigned BuiltinID,
729 CallExpr *TheCall) {
730 if (const FunctionDecl *FD = SemaRef.getCurFunctionDecl()) {
731
732 switch (BuiltinID) {
733 default:
734 break;
735#define GET_NEON_BUILTINS
736#define TARGET_BUILTIN(id, ...) case NEON::BI##id:
737#define BUILTIN(id, ...) case NEON::BI##id:
738#include "clang/Basic/arm_neon.inc"
739 if (checkArmStreamingBuiltin(S&: SemaRef, TheCall, FD, BuiltinType: ArmNonStreaming,
740 BuiltinID))
741 return true;
742 break;
743#undef TARGET_BUILTIN
744#undef BUILTIN
745#undef GET_NEON_BUILTINS
746 }
747 }
748
749 llvm::APSInt Result;
750 uint64_t mask = 0;
751 unsigned TV = 0;
752 int PtrArgNum = -1;
753 bool HasConstPtr = false;
754 switch (BuiltinID) {
755#define GET_NEON_OVERLOAD_CHECK
756#include "clang/Basic/arm_fp16.inc"
757#include "clang/Basic/arm_neon.inc"
758#undef GET_NEON_OVERLOAD_CHECK
759 }
760
761 // For NEON intrinsics which are overloaded on vector element type, validate
762 // the immediate which specifies which variant to emit.
763 unsigned ImmArg = TheCall->getNumArgs() - 1;
764 if (mask) {
765 if (SemaRef.BuiltinConstantArg(TheCall, ArgNum: ImmArg, Result))
766 return true;
767
768 TV = Result.getLimitedValue(Limit: 64);
769 if ((TV > 63) || (mask & (1ULL << TV)) == 0)
770 return Diag(Loc: TheCall->getBeginLoc(), DiagID: diag::err_invalid_neon_type_code)
771 << TheCall->getArg(Arg: ImmArg)->getSourceRange();
772 }
773
774 if (PtrArgNum >= 0) {
775 // Check that pointer arguments have the specified type.
776 Expr *Arg = TheCall->getArg(Arg: PtrArgNum);
777 if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Val: Arg))
778 Arg = ICE->getSubExpr();
779 ExprResult RHS = SemaRef.DefaultFunctionArrayLvalueConversion(E: Arg);
780 QualType RHSTy = RHS.get()->getType();
781
782 llvm::Triple::ArchType Arch = TI.getTriple().getArch();
783 bool IsPolyUnsigned = Arch == llvm::Triple::aarch64 ||
784 Arch == llvm::Triple::aarch64_32 ||
785 Arch == llvm::Triple::aarch64_be;
786 bool IsInt64Long = TI.getInt64Type() == TargetInfo::SignedLong;
787 QualType EltTy = getNeonEltType(Flags: NeonTypeFlags(TV), Context&: getASTContext(),
788 IsPolyUnsigned, IsInt64Long);
789 if (HasConstPtr)
790 EltTy = EltTy.withConst();
791 QualType LHSTy = getASTContext().getPointerType(T: EltTy);
792 Sema::AssignConvertType ConvTy;
793 ConvTy = SemaRef.CheckSingleAssignmentConstraints(LHSType: LHSTy, RHS);
794 if (RHS.isInvalid())
795 return true;
796 if (SemaRef.DiagnoseAssignmentResult(ConvTy, Loc: Arg->getBeginLoc(), DstType: LHSTy,
797 SrcType: RHSTy, SrcExpr: RHS.get(), Action: Sema::AA_Assigning))
798 return true;
799 }
800
801 // For NEON intrinsics which take an immediate value as part of the
802 // instruction, range check them here.
803 unsigned i = 0, l = 0, u = 0;
804 switch (BuiltinID) {
805 default:
806 return false;
807#define GET_NEON_IMMEDIATE_CHECK
808#include "clang/Basic/arm_fp16.inc"
809#include "clang/Basic/arm_neon.inc"
810#undef GET_NEON_IMMEDIATE_CHECK
811 }
812
813 return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: i, Low: l, High: u + l);
814}
815
816bool SemaARM::CheckMVEBuiltinFunctionCall(unsigned BuiltinID,
817 CallExpr *TheCall) {
818 switch (BuiltinID) {
819 default:
820 return false;
821#include "clang/Basic/arm_mve_builtin_sema.inc"
822 }
823}
824
825bool SemaARM::CheckCDEBuiltinFunctionCall(const TargetInfo &TI,
826 unsigned BuiltinID,
827 CallExpr *TheCall) {
828 bool Err = false;
829 switch (BuiltinID) {
830 default:
831 return false;
832#include "clang/Basic/arm_cde_builtin_sema.inc"
833 }
834
835 if (Err)
836 return true;
837
838 return CheckARMCoprocessorImmediate(TI, CoprocArg: TheCall->getArg(Arg: 0), /*WantCDE*/ true);
839}
840
841bool SemaARM::CheckARMCoprocessorImmediate(const TargetInfo &TI,
842 const Expr *CoprocArg,
843 bool WantCDE) {
844 ASTContext &Context = getASTContext();
845 if (SemaRef.isConstantEvaluatedContext())
846 return false;
847
848 // We can't check the value of a dependent argument.
849 if (CoprocArg->isTypeDependent() || CoprocArg->isValueDependent())
850 return false;
851
852 llvm::APSInt CoprocNoAP = *CoprocArg->getIntegerConstantExpr(Ctx: Context);
853 int64_t CoprocNo = CoprocNoAP.getExtValue();
854 assert(CoprocNo >= 0 && "Coprocessor immediate must be non-negative");
855
856 uint32_t CDECoprocMask = TI.getARMCDECoprocMask();
857 bool IsCDECoproc = CoprocNo <= 7 && (CDECoprocMask & (1 << CoprocNo));
858
859 if (IsCDECoproc != WantCDE)
860 return Diag(Loc: CoprocArg->getBeginLoc(), DiagID: diag::err_arm_invalid_coproc)
861 << (int)CoprocNo << (int)WantCDE << CoprocArg->getSourceRange();
862
863 return false;
864}
865
866bool SemaARM::CheckARMBuiltinExclusiveCall(unsigned BuiltinID,
867 CallExpr *TheCall,
868 unsigned MaxWidth) {
869 assert((BuiltinID == ARM::BI__builtin_arm_ldrex ||
870 BuiltinID == ARM::BI__builtin_arm_ldaex ||
871 BuiltinID == ARM::BI__builtin_arm_strex ||
872 BuiltinID == ARM::BI__builtin_arm_stlex ||
873 BuiltinID == AArch64::BI__builtin_arm_ldrex ||
874 BuiltinID == AArch64::BI__builtin_arm_ldaex ||
875 BuiltinID == AArch64::BI__builtin_arm_strex ||
876 BuiltinID == AArch64::BI__builtin_arm_stlex) &&
877 "unexpected ARM builtin");
878 bool IsLdrex = BuiltinID == ARM::BI__builtin_arm_ldrex ||
879 BuiltinID == ARM::BI__builtin_arm_ldaex ||
880 BuiltinID == AArch64::BI__builtin_arm_ldrex ||
881 BuiltinID == AArch64::BI__builtin_arm_ldaex;
882
883 ASTContext &Context = getASTContext();
884 DeclRefExpr *DRE =
885 cast<DeclRefExpr>(Val: TheCall->getCallee()->IgnoreParenCasts());
886
887 // Ensure that we have the proper number of arguments.
888 if (SemaRef.checkArgCount(Call: TheCall, DesiredArgCount: IsLdrex ? 1 : 2))
889 return true;
890
891 // Inspect the pointer argument of the atomic builtin. This should always be
892 // a pointer type, whose element is an integral scalar or pointer type.
893 // Because it is a pointer type, we don't have to worry about any implicit
894 // casts here.
895 Expr *PointerArg = TheCall->getArg(Arg: IsLdrex ? 0 : 1);
896 ExprResult PointerArgRes =
897 SemaRef.DefaultFunctionArrayLvalueConversion(E: PointerArg);
898 if (PointerArgRes.isInvalid())
899 return true;
900 PointerArg = PointerArgRes.get();
901
902 const PointerType *pointerType = PointerArg->getType()->getAs<PointerType>();
903 if (!pointerType) {
904 Diag(Loc: DRE->getBeginLoc(), DiagID: diag::err_atomic_builtin_must_be_pointer)
905 << PointerArg->getType() << 0 << PointerArg->getSourceRange();
906 return true;
907 }
908
909 // ldrex takes a "const volatile T*" and strex takes a "volatile T*". Our next
910 // task is to insert the appropriate casts into the AST. First work out just
911 // what the appropriate type is.
912 QualType ValType = pointerType->getPointeeType();
913 QualType AddrType = ValType.getUnqualifiedType().withVolatile();
914 if (IsLdrex)
915 AddrType.addConst();
916
917 // Issue a warning if the cast is dodgy.
918 CastKind CastNeeded = CK_NoOp;
919 if (!AddrType.isAtLeastAsQualifiedAs(other: ValType)) {
920 CastNeeded = CK_BitCast;
921 Diag(Loc: DRE->getBeginLoc(), DiagID: diag::ext_typecheck_convert_discards_qualifiers)
922 << PointerArg->getType() << Context.getPointerType(T: AddrType)
923 << Sema::AA_Passing << PointerArg->getSourceRange();
924 }
925
926 // Finally, do the cast and replace the argument with the corrected version.
927 AddrType = Context.getPointerType(T: AddrType);
928 PointerArgRes = SemaRef.ImpCastExprToType(E: PointerArg, Type: AddrType, CK: CastNeeded);
929 if (PointerArgRes.isInvalid())
930 return true;
931 PointerArg = PointerArgRes.get();
932
933 TheCall->setArg(Arg: IsLdrex ? 0 : 1, ArgExpr: PointerArg);
934
935 // In general, we allow ints, floats and pointers to be loaded and stored.
936 if (!ValType->isIntegerType() && !ValType->isAnyPointerType() &&
937 !ValType->isBlockPointerType() && !ValType->isFloatingType()) {
938 Diag(Loc: DRE->getBeginLoc(), DiagID: diag::err_atomic_builtin_must_be_pointer_intfltptr)
939 << PointerArg->getType() << 0 << PointerArg->getSourceRange();
940 return true;
941 }
942
943 // But ARM doesn't have instructions to deal with 128-bit versions.
944 if (Context.getTypeSize(T: ValType) > MaxWidth) {
945 assert(MaxWidth == 64 && "Diagnostic unexpectedly inaccurate");
946 Diag(Loc: DRE->getBeginLoc(), DiagID: diag::err_atomic_exclusive_builtin_pointer_size)
947 << PointerArg->getType() << PointerArg->getSourceRange();
948 return true;
949 }
950
951 switch (ValType.getObjCLifetime()) {
952 case Qualifiers::OCL_None:
953 case Qualifiers::OCL_ExplicitNone:
954 // okay
955 break;
956
957 case Qualifiers::OCL_Weak:
958 case Qualifiers::OCL_Strong:
959 case Qualifiers::OCL_Autoreleasing:
960 Diag(Loc: DRE->getBeginLoc(), DiagID: diag::err_arc_atomic_ownership)
961 << ValType << PointerArg->getSourceRange();
962 return true;
963 }
964
965 if (IsLdrex) {
966 TheCall->setType(ValType);
967 return false;
968 }
969
970 // Initialize the argument to be stored.
971 ExprResult ValArg = TheCall->getArg(Arg: 0);
972 InitializedEntity Entity = InitializedEntity::InitializeParameter(
973 Context, Type: ValType, /*consume*/ Consumed: false);
974 ValArg = SemaRef.PerformCopyInitialization(Entity, EqualLoc: SourceLocation(), Init: ValArg);
975 if (ValArg.isInvalid())
976 return true;
977 TheCall->setArg(Arg: 0, ArgExpr: ValArg.get());
978
979 // __builtin_arm_strex always returns an int. It's marked as such in the .def,
980 // but the custom checker bypasses all default analysis.
981 TheCall->setType(Context.IntTy);
982 return false;
983}
984
985bool SemaARM::CheckARMBuiltinFunctionCall(const TargetInfo &TI,
986 unsigned BuiltinID,
987 CallExpr *TheCall) {
988 if (BuiltinID == ARM::BI__builtin_arm_ldrex ||
989 BuiltinID == ARM::BI__builtin_arm_ldaex ||
990 BuiltinID == ARM::BI__builtin_arm_strex ||
991 BuiltinID == ARM::BI__builtin_arm_stlex) {
992 return CheckARMBuiltinExclusiveCall(BuiltinID, TheCall, MaxWidth: 64);
993 }
994
995 if (BuiltinID == ARM::BI__builtin_arm_prefetch) {
996 return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 1, Low: 0, High: 1) ||
997 SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 2, Low: 0, High: 1);
998 }
999
1000 if (BuiltinID == ARM::BI__builtin_arm_rsr64 ||
1001 BuiltinID == ARM::BI__builtin_arm_wsr64)
1002 return BuiltinARMSpecialReg(BuiltinID, TheCall, ArgNum: 0, ExpectedFieldNum: 3, AllowName: false);
1003
1004 if (BuiltinID == ARM::BI__builtin_arm_rsr ||
1005 BuiltinID == ARM::BI__builtin_arm_rsrp ||
1006 BuiltinID == ARM::BI__builtin_arm_wsr ||
1007 BuiltinID == ARM::BI__builtin_arm_wsrp)
1008 return BuiltinARMSpecialReg(BuiltinID, TheCall, ArgNum: 0, ExpectedFieldNum: 5, AllowName: true);
1009
1010 if (CheckNeonBuiltinFunctionCall(TI, BuiltinID, TheCall))
1011 return true;
1012 if (CheckMVEBuiltinFunctionCall(BuiltinID, TheCall))
1013 return true;
1014 if (CheckCDEBuiltinFunctionCall(TI, BuiltinID, TheCall))
1015 return true;
1016
1017 // For intrinsics which take an immediate value as part of the instruction,
1018 // range check them here.
1019 // FIXME: VFP Intrinsics should error if VFP not present.
1020 switch (BuiltinID) {
1021 default:
1022 return false;
1023 case ARM::BI__builtin_arm_ssat:
1024 return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 1, Low: 1, High: 32);
1025 case ARM::BI__builtin_arm_usat:
1026 return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 1, Low: 0, High: 31);
1027 case ARM::BI__builtin_arm_ssat16:
1028 return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 1, Low: 1, High: 16);
1029 case ARM::BI__builtin_arm_usat16:
1030 return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 1, Low: 0, High: 15);
1031 case ARM::BI__builtin_arm_vcvtr_f:
1032 case ARM::BI__builtin_arm_vcvtr_d:
1033 return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 1, Low: 0, High: 1);
1034 case ARM::BI__builtin_arm_dmb:
1035 case ARM::BI__builtin_arm_dsb:
1036 case ARM::BI__builtin_arm_isb:
1037 case ARM::BI__builtin_arm_dbg:
1038 return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 0, Low: 0, High: 15);
1039 case ARM::BI__builtin_arm_cdp:
1040 case ARM::BI__builtin_arm_cdp2:
1041 case ARM::BI__builtin_arm_mcr:
1042 case ARM::BI__builtin_arm_mcr2:
1043 case ARM::BI__builtin_arm_mrc:
1044 case ARM::BI__builtin_arm_mrc2:
1045 case ARM::BI__builtin_arm_mcrr:
1046 case ARM::BI__builtin_arm_mcrr2:
1047 case ARM::BI__builtin_arm_mrrc:
1048 case ARM::BI__builtin_arm_mrrc2:
1049 case ARM::BI__builtin_arm_ldc:
1050 case ARM::BI__builtin_arm_ldcl:
1051 case ARM::BI__builtin_arm_ldc2:
1052 case ARM::BI__builtin_arm_ldc2l:
1053 case ARM::BI__builtin_arm_stc:
1054 case ARM::BI__builtin_arm_stcl:
1055 case ARM::BI__builtin_arm_stc2:
1056 case ARM::BI__builtin_arm_stc2l:
1057 return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 0, Low: 0, High: 15) ||
1058 CheckARMCoprocessorImmediate(TI, CoprocArg: TheCall->getArg(Arg: 0),
1059 /*WantCDE*/ false);
1060 }
1061}
1062
1063bool SemaARM::CheckAArch64BuiltinFunctionCall(const TargetInfo &TI,
1064 unsigned BuiltinID,
1065 CallExpr *TheCall) {
1066 if (BuiltinID == AArch64::BI__builtin_arm_ldrex ||
1067 BuiltinID == AArch64::BI__builtin_arm_ldaex ||
1068 BuiltinID == AArch64::BI__builtin_arm_strex ||
1069 BuiltinID == AArch64::BI__builtin_arm_stlex) {
1070 return CheckARMBuiltinExclusiveCall(BuiltinID, TheCall, MaxWidth: 128);
1071 }
1072
1073 if (BuiltinID == AArch64::BI__builtin_arm_prefetch) {
1074 return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 1, Low: 0, High: 1) ||
1075 SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 2, Low: 0, High: 3) ||
1076 SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 3, Low: 0, High: 1) ||
1077 SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 4, Low: 0, High: 1);
1078 }
1079
1080 if (BuiltinID == AArch64::BI__builtin_arm_rsr64 ||
1081 BuiltinID == AArch64::BI__builtin_arm_wsr64 ||
1082 BuiltinID == AArch64::BI__builtin_arm_rsr128 ||
1083 BuiltinID == AArch64::BI__builtin_arm_wsr128)
1084 return BuiltinARMSpecialReg(BuiltinID, TheCall, ArgNum: 0, ExpectedFieldNum: 5, AllowName: true);
1085
1086 // Memory Tagging Extensions (MTE) Intrinsics
1087 if (BuiltinID == AArch64::BI__builtin_arm_irg ||
1088 BuiltinID == AArch64::BI__builtin_arm_addg ||
1089 BuiltinID == AArch64::BI__builtin_arm_gmi ||
1090 BuiltinID == AArch64::BI__builtin_arm_ldg ||
1091 BuiltinID == AArch64::BI__builtin_arm_stg ||
1092 BuiltinID == AArch64::BI__builtin_arm_subp) {
1093 return BuiltinARMMemoryTaggingCall(BuiltinID, TheCall);
1094 }
1095
1096 if (BuiltinID == AArch64::BI__builtin_arm_rsr ||
1097 BuiltinID == AArch64::BI__builtin_arm_rsrp ||
1098 BuiltinID == AArch64::BI__builtin_arm_wsr ||
1099 BuiltinID == AArch64::BI__builtin_arm_wsrp)
1100 return BuiltinARMSpecialReg(BuiltinID, TheCall, ArgNum: 0, ExpectedFieldNum: 5, AllowName: true);
1101
1102 // Only check the valid encoding range. Any constant in this range would be
1103 // converted to a register of the form S1_2_C3_C4_5. Let the hardware throw
1104 // an exception for incorrect registers. This matches MSVC behavior.
1105 if (BuiltinID == AArch64::BI_ReadStatusReg ||
1106 BuiltinID == AArch64::BI_WriteStatusReg)
1107 return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 0, Low: 0, High: 0x7fff);
1108
1109 if (BuiltinID == AArch64::BI__getReg)
1110 return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 0, Low: 0, High: 31);
1111
1112 if (BuiltinID == AArch64::BI__break)
1113 return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 0, Low: 0, High: 0xffff);
1114
1115 if (BuiltinID == AArch64::BI__hlt)
1116 return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 0, Low: 0, High: 0xffff);
1117
1118 if (CheckNeonBuiltinFunctionCall(TI, BuiltinID, TheCall))
1119 return true;
1120
1121 if (CheckSVEBuiltinFunctionCall(BuiltinID, TheCall))
1122 return true;
1123
1124 if (CheckSMEBuiltinFunctionCall(BuiltinID, TheCall))
1125 return true;
1126
1127 // For intrinsics which take an immediate value as part of the instruction,
1128 // range check them here.
1129 unsigned i = 0, l = 0, u = 0;
1130 switch (BuiltinID) {
1131 default: return false;
1132 case AArch64::BI__builtin_arm_dmb:
1133 case AArch64::BI__builtin_arm_dsb:
1134 case AArch64::BI__builtin_arm_isb: l = 0; u = 15; break;
1135 case AArch64::BI__builtin_arm_tcancel: l = 0; u = 65535; break;
1136 }
1137
1138 return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: i, Low: l, High: u + l);
1139}
1140
1141namespace {
1142struct IntrinToName {
1143 uint32_t Id;
1144 int32_t FullName;
1145 int32_t ShortName;
1146};
1147} // unnamed namespace
1148
1149static bool BuiltinAliasValid(unsigned BuiltinID, StringRef AliasName,
1150 ArrayRef<IntrinToName> Map,
1151 const char *IntrinNames) {
1152 AliasName.consume_front(Prefix: "__arm_");
1153 const IntrinToName *It =
1154 llvm::lower_bound(Range&: Map, Value&: BuiltinID, C: [](const IntrinToName &L, unsigned Id) {
1155 return L.Id < Id;
1156 });
1157 if (It == Map.end() || It->Id != BuiltinID)
1158 return false;
1159 StringRef FullName(&IntrinNames[It->FullName]);
1160 if (AliasName == FullName)
1161 return true;
1162 if (It->ShortName == -1)
1163 return false;
1164 StringRef ShortName(&IntrinNames[It->ShortName]);
1165 return AliasName == ShortName;
1166}
1167
1168bool SemaARM::MveAliasValid(unsigned BuiltinID, StringRef AliasName) {
1169#include "clang/Basic/arm_mve_builtin_aliases.inc"
1170 // The included file defines:
1171 // - ArrayRef<IntrinToName> Map
1172 // - const char IntrinNames[]
1173 return BuiltinAliasValid(BuiltinID, AliasName, Map, IntrinNames);
1174}
1175
1176bool SemaARM::CdeAliasValid(unsigned BuiltinID, StringRef AliasName) {
1177#include "clang/Basic/arm_cde_builtin_aliases.inc"
1178 return BuiltinAliasValid(BuiltinID, AliasName, Map, IntrinNames);
1179}
1180
1181bool SemaARM::SveAliasValid(unsigned BuiltinID, StringRef AliasName) {
1182 if (getASTContext().BuiltinInfo.isAuxBuiltinID(ID: BuiltinID))
1183 BuiltinID = getASTContext().BuiltinInfo.getAuxBuiltinID(ID: BuiltinID);
1184 return BuiltinID >= AArch64::FirstSVEBuiltin &&
1185 BuiltinID <= AArch64::LastSVEBuiltin;
1186}
1187
1188bool SemaARM::SmeAliasValid(unsigned BuiltinID, StringRef AliasName) {
1189 if (getASTContext().BuiltinInfo.isAuxBuiltinID(ID: BuiltinID))
1190 BuiltinID = getASTContext().BuiltinInfo.getAuxBuiltinID(ID: BuiltinID);
1191 return BuiltinID >= AArch64::FirstSMEBuiltin &&
1192 BuiltinID <= AArch64::LastSMEBuiltin;
1193}
1194
1195void SemaARM::handleBuiltinAliasAttr(Decl *D, const ParsedAttr &AL) {
1196 ASTContext &Context = getASTContext();
1197 if (!AL.isArgIdent(Arg: 0)) {
1198 Diag(Loc: AL.getLoc(), DiagID: diag::err_attribute_argument_n_type)
1199 << AL << 1 << AANT_ArgumentIdentifier;
1200 return;
1201 }
1202
1203 IdentifierInfo *Ident = AL.getArgAsIdent(Arg: 0)->Ident;
1204 unsigned BuiltinID = Ident->getBuiltinID();
1205 StringRef AliasName = cast<FunctionDecl>(Val: D)->getIdentifier()->getName();
1206
1207 bool IsAArch64 = Context.getTargetInfo().getTriple().isAArch64();
1208 if ((IsAArch64 && !SveAliasValid(BuiltinID, AliasName) &&
1209 !SmeAliasValid(BuiltinID, AliasName)) ||
1210 (!IsAArch64 && !MveAliasValid(BuiltinID, AliasName) &&
1211 !CdeAliasValid(BuiltinID, AliasName))) {
1212 Diag(Loc: AL.getLoc(), DiagID: diag::err_attribute_arm_builtin_alias);
1213 return;
1214 }
1215
1216 D->addAttr(A: ::new (Context) ArmBuiltinAliasAttr(Context, AL, Ident));
1217}
1218
1219static bool checkNewAttrMutualExclusion(
1220 Sema &S, const ParsedAttr &AL, const FunctionProtoType *FPT,
1221 FunctionType::ArmStateValue CurrentState, StringRef StateName) {
1222 auto CheckForIncompatibleAttr =
1223 [&](FunctionType::ArmStateValue IncompatibleState,
1224 StringRef IncompatibleStateName) {
1225 if (CurrentState == IncompatibleState) {
1226 S.Diag(Loc: AL.getLoc(), DiagID: diag::err_attributes_are_not_compatible)
1227 << (std::string("'__arm_new(\"") + StateName.str() + "\")'")
1228 << (std::string("'") + IncompatibleStateName.str() + "(\"" +
1229 StateName.str() + "\")'")
1230 << true;
1231 AL.setInvalid();
1232 }
1233 };
1234
1235 CheckForIncompatibleAttr(FunctionType::ARM_In, "__arm_in");
1236 CheckForIncompatibleAttr(FunctionType::ARM_Out, "__arm_out");
1237 CheckForIncompatibleAttr(FunctionType::ARM_InOut, "__arm_inout");
1238 CheckForIncompatibleAttr(FunctionType::ARM_Preserves, "__arm_preserves");
1239 return AL.isInvalid();
1240}
1241
1242void SemaARM::handleNewAttr(Decl *D, const ParsedAttr &AL) {
1243 if (!AL.getNumArgs()) {
1244 Diag(Loc: AL.getLoc(), DiagID: diag::err_missing_arm_state) << AL;
1245 AL.setInvalid();
1246 return;
1247 }
1248
1249 std::vector<StringRef> NewState;
1250 if (const auto *ExistingAttr = D->getAttr<ArmNewAttr>()) {
1251 for (StringRef S : ExistingAttr->newArgs())
1252 NewState.push_back(x: S);
1253 }
1254
1255 bool HasZA = false;
1256 bool HasZT0 = false;
1257 for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) {
1258 StringRef StateName;
1259 SourceLocation LiteralLoc;
1260 if (!SemaRef.checkStringLiteralArgumentAttr(Attr: AL, ArgNum: I, Str&: StateName, ArgLocation: &LiteralLoc))
1261 return;
1262
1263 if (StateName == "za")
1264 HasZA = true;
1265 else if (StateName == "zt0")
1266 HasZT0 = true;
1267 else {
1268 Diag(Loc: LiteralLoc, DiagID: diag::err_unknown_arm_state) << StateName;
1269 AL.setInvalid();
1270 return;
1271 }
1272
1273 if (!llvm::is_contained(Range&: NewState, Element: StateName)) // Avoid adding duplicates.
1274 NewState.push_back(x: StateName);
1275 }
1276
1277 if (auto *FPT = dyn_cast<FunctionProtoType>(Val: D->getFunctionType())) {
1278 FunctionType::ArmStateValue ZAState =
1279 FunctionType::getArmZAState(AttrBits: FPT->getAArch64SMEAttributes());
1280 if (HasZA && ZAState != FunctionType::ARM_None &&
1281 checkNewAttrMutualExclusion(S&: SemaRef, AL, FPT, CurrentState: ZAState, StateName: "za"))
1282 return;
1283 FunctionType::ArmStateValue ZT0State =
1284 FunctionType::getArmZT0State(AttrBits: FPT->getAArch64SMEAttributes());
1285 if (HasZT0 && ZT0State != FunctionType::ARM_None &&
1286 checkNewAttrMutualExclusion(S&: SemaRef, AL, FPT, CurrentState: ZT0State, StateName: "zt0"))
1287 return;
1288 }
1289
1290 D->dropAttr<ArmNewAttr>();
1291 D->addAttr(A: ::new (getASTContext()) ArmNewAttr(
1292 getASTContext(), AL, NewState.data(), NewState.size()));
1293}
1294
1295void SemaARM::handleCmseNSEntryAttr(Decl *D, const ParsedAttr &AL) {
1296 if (getLangOpts().CPlusPlus && !D->getDeclContext()->isExternCContext()) {
1297 Diag(Loc: AL.getLoc(), DiagID: diag::err_attribute_not_clinkage) << AL;
1298 return;
1299 }
1300
1301 const auto *FD = cast<FunctionDecl>(Val: D);
1302 if (!FD->isExternallyVisible()) {
1303 Diag(Loc: AL.getLoc(), DiagID: diag::warn_attribute_cmse_entry_static);
1304 return;
1305 }
1306
1307 D->addAttr(A: ::new (getASTContext()) CmseNSEntryAttr(getASTContext(), AL));
1308}
1309
1310void SemaARM::handleInterruptAttr(Decl *D, const ParsedAttr &AL) {
1311 // Check the attribute arguments.
1312 if (AL.getNumArgs() > 1) {
1313 Diag(Loc: AL.getLoc(), DiagID: diag::err_attribute_too_many_arguments) << AL << 1;
1314 return;
1315 }
1316
1317 StringRef Str;
1318 SourceLocation ArgLoc;
1319
1320 if (AL.getNumArgs() == 0)
1321 Str = "";
1322 else if (!SemaRef.checkStringLiteralArgumentAttr(Attr: AL, ArgNum: 0, Str, ArgLocation: &ArgLoc))
1323 return;
1324
1325 ARMInterruptAttr::InterruptType Kind;
1326 if (!ARMInterruptAttr::ConvertStrToInterruptType(Val: Str, Out&: Kind)) {
1327 Diag(Loc: AL.getLoc(), DiagID: diag::warn_attribute_type_not_supported)
1328 << AL << Str << ArgLoc;
1329 return;
1330 }
1331
1332 const TargetInfo &TI = getASTContext().getTargetInfo();
1333 if (TI.hasFeature(Feature: "vfp"))
1334 Diag(Loc: D->getLocation(), DiagID: diag::warn_arm_interrupt_vfp_clobber);
1335
1336 D->addAttr(A: ::new (getASTContext())
1337 ARMInterruptAttr(getASTContext(), AL, Kind));
1338}
1339
1340} // namespace clang
1341