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
20 namespace clang {
21
SemaARM(Sema & S)22 SemaARM::SemaARM(Sema &S) : SemaBase(S) {}
23
24 /// BuiltinARMMemoryTaggingCall - Handle calls of memory tagging extensions
BuiltinARMMemoryTaggingCall(unsigned BuiltinID,CallExpr * TheCall)25 bool SemaARM::BuiltinARMMemoryTaggingCall(unsigned BuiltinID,
26 CallExpr *TheCall) {
27 ASTContext &Context = getASTContext();
28
29 if (BuiltinID == AArch64::BI__builtin_arm_irg) {
30 if (SemaRef.checkArgCount(TheCall, 2))
31 return true;
32 Expr *Arg0 = TheCall->getArg(0);
33 Expr *Arg1 = TheCall->getArg(1);
34
35 ExprResult FirstArg = SemaRef.DefaultFunctionArrayLvalueConversion(Arg0);
36 if (FirstArg.isInvalid())
37 return true;
38 QualType FirstArgType = FirstArg.get()->getType();
39 if (!FirstArgType->isAnyPointerType())
40 return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer)
41 << "first" << FirstArgType << Arg0->getSourceRange();
42 TheCall->setArg(0, FirstArg.get());
43
44 ExprResult SecArg = SemaRef.DefaultLvalueConversion(Arg1);
45 if (SecArg.isInvalid())
46 return true;
47 QualType SecArgType = SecArg.get()->getType();
48 if (!SecArgType->isIntegerType())
49 return Diag(TheCall->getBeginLoc(), 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(TheCall, 2))
59 return true;
60
61 Expr *Arg0 = TheCall->getArg(0);
62 ExprResult FirstArg = SemaRef.DefaultFunctionArrayLvalueConversion(Arg0);
63 if (FirstArg.isInvalid())
64 return true;
65 QualType FirstArgType = FirstArg.get()->getType();
66 if (!FirstArgType->isAnyPointerType())
67 return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer)
68 << "first" << FirstArgType << Arg0->getSourceRange();
69 TheCall->setArg(0, 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, 1, 0, 15);
76 }
77
78 if (BuiltinID == AArch64::BI__builtin_arm_gmi) {
79 if (SemaRef.checkArgCount(TheCall, 2))
80 return true;
81 Expr *Arg0 = TheCall->getArg(0);
82 Expr *Arg1 = TheCall->getArg(1);
83
84 ExprResult FirstArg = SemaRef.DefaultFunctionArrayLvalueConversion(Arg0);
85 if (FirstArg.isInvalid())
86 return true;
87 QualType FirstArgType = FirstArg.get()->getType();
88 if (!FirstArgType->isAnyPointerType())
89 return Diag(TheCall->getBeginLoc(), 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(TheCall->getBeginLoc(), 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(TheCall, 1))
103 return true;
104 Expr *Arg0 = TheCall->getArg(0);
105 ExprResult FirstArg = SemaRef.DefaultFunctionArrayLvalueConversion(Arg0);
106 if (FirstArg.isInvalid())
107 return true;
108
109 QualType FirstArgType = FirstArg.get()->getType();
110 if (!FirstArgType->isAnyPointerType())
111 return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer)
112 << "first" << FirstArgType << Arg0->getSourceRange();
113 TheCall->setArg(0, 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(0);
123 Expr *ArgB = TheCall->getArg(1);
124
125 ExprResult ArgExprA = SemaRef.DefaultFunctionArrayLvalueConversion(ArgA);
126 ExprResult ArgExprB = SemaRef.DefaultFunctionArrayLvalueConversion(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(Context,
136 Expr::NPC_ValueDependentIsNotNull);
137 };
138
139 // argument should be either a pointer or null
140 if (!ArgTypeA->isAnyPointerType() && !isNull(ArgA))
141 return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_null_or_pointer)
142 << "first" << ArgTypeA << ArgA->getSourceRange();
143
144 if (!ArgTypeB->isAnyPointerType() && !isNull(ArgB))
145 return Diag(TheCall->getBeginLoc(), 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 Context.getCanonicalType(pointeeA).getUnqualifiedType(),
155 Context.getCanonicalType(pointeeB).getUnqualifiedType())) {
156 return Diag(TheCall->getBeginLoc(),
157 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(TheCall->getBeginLoc(), 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(ArgExprA.get(), ArgTypeB, CK_NullToPointer);
171
172 if (isNull(ArgB))
173 ArgExprB =
174 SemaRef.ImpCastExprToType(ArgExprB.get(), ArgTypeA, CK_NullToPointer);
175
176 TheCall->setArg(0, ArgExprA.get());
177 TheCall->setArg(1, 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.
BuiltinARMSpecialReg(unsigned BuiltinID,CallExpr * TheCall,int ArgNum,unsigned ExpectedFieldNum,bool AllowName)187 bool 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(ArgNum);
208 if (Arg->isTypeDependent() || Arg->isValueDependent())
209 return false;
210
211 // Check if the argument is a string literal.
212 if (!isa<StringLiteral>(Arg->IgnoreParenImpCasts()))
213 return Diag(TheCall->getBeginLoc(), diag::err_expr_not_string_literal)
214 << Arg->getSourceRange();
215
216 // Check the type of special register given.
217 StringRef Reg = cast<StringLiteral>(Arg->IgnoreParenImpCasts())->getString();
218 SmallVector<StringRef, 6> Fields;
219 Reg.split(Fields, ":");
220
221 if (Fields.size() != ExpectedFieldNum && !(AllowName && Fields.size() == 1))
222 return Diag(TheCall->getBeginLoc(), 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("cp") ||
235 Fields[0].starts_with_insensitive("p");
236 if (ValidString)
237 Fields[0] = Fields[0].drop_front(
238 Fields[0].starts_with_insensitive("cp") ? 2 : 1);
239
240 ValidString &= Fields[2].starts_with_insensitive("c");
241 if (ValidString)
242 Fields[2] = Fields[2].drop_front(1);
243
244 if (FiveFields) {
245 ValidString &= Fields[3].starts_with_insensitive("c");
246 if (ValidString)
247 Fields[3] = Fields[3].drop_front(1);
248 }
249 }
250
251 SmallVector<int, 5> Ranges;
252 if (FiveFields)
253 Ranges.append({IsAArch64Builtin ? 1 : 15, 7, 15, 15, 7});
254 else
255 Ranges.append({15, 7, 15});
256
257 for (unsigned i = 0; i < Fields.size(); ++i) {
258 int IntField;
259 ValidString &= !Fields[i].getAsInteger(10, IntField);
260 ValidString &= (IntField >= 0 && IntField <= Ranges[i]);
261 }
262
263 if (!ValidString)
264 return Diag(TheCall->getBeginLoc(), 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("spsel", 15)
282 .CaseLower("daifclr", 15)
283 .CaseLower("daifset", 15)
284 .CaseLower("pan", 15)
285 .CaseLower("uao", 15)
286 .CaseLower("dit", 15)
287 .CaseLower("ssbs", 15)
288 .CaseLower("tco", 15)
289 .CaseLower("allint", 1)
290 .CaseLower("pm", 1)
291 .Default(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, 1, 0, *MaxLimit);
312 }
313
314 return false;
315 }
316
317 // Get the valid immediate range for the specified NEON type code.
RFT(unsigned t,bool shift=false,bool ForceQuad=false)318 static 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.
getNeonEltType(NeonTypeFlags Flags,ASTContext & Context,bool IsPolyUnsigned,bool IsInt64Long)354 static 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
392 enum 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
ParseSVEImmChecks(CallExpr * TheCall,SmallVector<std::tuple<int,int,int>,3> & ImmChecks)406 bool 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(ArgNum, CheckTy, 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(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, Imm))
428 return true;
429
430 if (!CheckImm(Imm.getSExtValue()))
431 return Diag(TheCall->getBeginLoc(), ErrDiag) << Arg->getSourceRange();
432 return false;
433 };
434
435 switch ((SVETypeFlags::ImmCheckType)CheckTy) {
436 case SVETypeFlags::ImmCheck0_31:
437 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, 31))
438 HasError = true;
439 break;
440 case SVETypeFlags::ImmCheck0_13:
441 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, 13))
442 HasError = true;
443 break;
444 case SVETypeFlags::ImmCheck1_16:
445 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 1, 16))
446 HasError = true;
447 break;
448 case SVETypeFlags::ImmCheck0_7:
449 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, 7))
450 HasError = true;
451 break;
452 case SVETypeFlags::ImmCheck1_1:
453 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 1, 1))
454 HasError = true;
455 break;
456 case SVETypeFlags::ImmCheck1_3:
457 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 1, 3))
458 HasError = true;
459 break;
460 case SVETypeFlags::ImmCheck1_7:
461 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 1, 7))
462 HasError = true;
463 break;
464 case SVETypeFlags::ImmCheckExtract:
465 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0,
466 (2048 / ElementSizeInBits) - 1))
467 HasError = true;
468 break;
469 case SVETypeFlags::ImmCheckShiftRight:
470 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 1,
471 ElementSizeInBits))
472 HasError = true;
473 break;
474 case SVETypeFlags::ImmCheckShiftRightNarrow:
475 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 1,
476 ElementSizeInBits / 2))
477 HasError = true;
478 break;
479 case SVETypeFlags::ImmCheckShiftLeft:
480 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0,
481 ElementSizeInBits - 1))
482 HasError = true;
483 break;
484 case SVETypeFlags::ImmCheckLaneIndex:
485 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0,
486 (128 / (1 * ElementSizeInBits)) - 1))
487 HasError = true;
488 break;
489 case SVETypeFlags::ImmCheckLaneIndexCompRotate:
490 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0,
491 (128 / (2 * ElementSizeInBits)) - 1))
492 HasError = true;
493 break;
494 case SVETypeFlags::ImmCheckLaneIndexDot:
495 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0,
496 (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, 0, 1))
514 HasError = true;
515 break;
516 case SVETypeFlags::ImmCheck0_2:
517 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, 2))
518 HasError = true;
519 break;
520 case SVETypeFlags::ImmCheck0_3:
521 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, 3))
522 HasError = true;
523 break;
524 case SVETypeFlags::ImmCheck0_0:
525 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, 0))
526 HasError = true;
527 break;
528 case SVETypeFlags::ImmCheck0_15:
529 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, 15))
530 HasError = true;
531 break;
532 case SVETypeFlags::ImmCheck0_255:
533 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, 255))
534 HasError = true;
535 break;
536 case SVETypeFlags::ImmCheck2_4_Mul2:
537 if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 2, 4) ||
538 SemaRef.BuiltinConstantArgMultiple(TheCall, ArgNum, 2))
539 HasError = true;
540 break;
541 }
542 }
543
544 return HasError;
545 }
546
getArmStreamingFnType(const FunctionDecl * FD)547 SemaARM::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
checkArmStreamingBuiltin(Sema & S,CallExpr * TheCall,const FunctionDecl * FD,SemaARM::ArmStreamingType BuiltinType,unsigned BuiltinID)563 static 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(S))
577 Map[K] = false;
578 };
579
580 llvm::StringMap<bool> CallerFeatureMapWithoutSVE;
581 S.Context.getFunctionFeatureMap(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(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(BuiltinID));
604 bool SatisfiesSVE = Builtin::evaluateRequiredTargetFeatures(
605 BuiltinTargetGuards, CallerFeatureMapWithoutSME);
606 bool SatisfiesSME = Builtin::evaluateRequiredTargetFeatures(
607 BuiltinTargetGuards, 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(TheCall->getBeginLoc(), 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(TheCall->getBeginLoc(), diag::err_attribute_arm_sm_incompat_builtin)
628 << TheCall->getSourceRange() << "streaming";
629 else
630 return false;
631
632 return true;
633 }
634
hasArmZAState(const FunctionDecl * FD)635 static bool hasArmZAState(const FunctionDecl *FD) {
636 const auto *T = FD->getType()->getAs<FunctionProtoType>();
637 return (T && FunctionType::getArmZAState(T->getAArch64SMEAttributes()) !=
638 FunctionType::ARM_None) ||
639 (FD->hasAttr<ArmNewAttr>() && FD->getAttr<ArmNewAttr>()->isNewZA());
640 }
641
hasArmZT0State(const FunctionDecl * FD)642 static bool hasArmZT0State(const FunctionDecl *FD) {
643 const auto *T = FD->getType()->getAs<FunctionProtoType>();
644 return (T && FunctionType::getArmZT0State(T->getAArch64SMEAttributes()) !=
645 FunctionType::ARM_None) ||
646 (FD->hasAttr<ArmNewAttr>() && FD->getAttr<ArmNewAttr>()->isNewZT0());
647 }
648
getSMEState(unsigned BuiltinID)649 static 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
CheckSMEBuiltinFunctionCall(unsigned BuiltinID,CallExpr * TheCall)659 bool 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(SemaRef, TheCall, FD, *BuiltinType, BuiltinID))
672 return true;
673
674 if ((getSMEState(BuiltinID) & ArmZAMask) && !hasArmZAState(FD))
675 Diag(TheCall->getBeginLoc(),
676 diag::warn_attribute_arm_za_builtin_no_za_state)
677 << TheCall->getSourceRange();
678
679 if ((getSMEState(BuiltinID) & ArmZT0Mask) && !hasArmZT0State(FD))
680 Diag(TheCall->getBeginLoc(),
681 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
CheckSVEBuiltinFunctionCall(unsigned BuiltinID,CallExpr * TheCall)699 bool 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(SemaRef, TheCall, FD, *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
CheckNeonBuiltinFunctionCall(const TargetInfo & TI,unsigned BuiltinID,CallExpr * TheCall)727 bool 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(SemaRef, TheCall, FD, 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, ImmArg, Result))
766 return true;
767
768 TV = Result.getLimitedValue(64);
769 if ((TV > 63) || (mask & (1ULL << TV)) == 0)
770 return Diag(TheCall->getBeginLoc(), diag::err_invalid_neon_type_code)
771 << TheCall->getArg(ImmArg)->getSourceRange();
772 }
773
774 if (PtrArgNum >= 0) {
775 // Check that pointer arguments have the specified type.
776 Expr *Arg = TheCall->getArg(PtrArgNum);
777 if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg))
778 Arg = ICE->getSubExpr();
779 ExprResult RHS = SemaRef.DefaultFunctionArrayLvalueConversion(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(NeonTypeFlags(TV), getASTContext(),
788 IsPolyUnsigned, IsInt64Long);
789 if (HasConstPtr)
790 EltTy = EltTy.withConst();
791 QualType LHSTy = getASTContext().getPointerType(EltTy);
792 Sema::AssignConvertType ConvTy;
793 ConvTy = SemaRef.CheckSingleAssignmentConstraints(LHSTy, RHS);
794 if (RHS.isInvalid())
795 return true;
796 if (SemaRef.DiagnoseAssignmentResult(ConvTy, Arg->getBeginLoc(), LHSTy,
797 RHSTy, RHS.get(), 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, i, l, u + l);
814 }
815
CheckMVEBuiltinFunctionCall(unsigned BuiltinID,CallExpr * TheCall)816 bool 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
CheckCDEBuiltinFunctionCall(const TargetInfo & TI,unsigned BuiltinID,CallExpr * TheCall)825 bool 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, TheCall->getArg(0), /*WantCDE*/ true);
839 }
840
CheckARMCoprocessorImmediate(const TargetInfo & TI,const Expr * CoprocArg,bool WantCDE)841 bool 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(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(CoprocArg->getBeginLoc(), diag::err_arm_invalid_coproc)
861 << (int)CoprocNo << (int)WantCDE << CoprocArg->getSourceRange();
862
863 return false;
864 }
865
CheckARMBuiltinExclusiveCall(unsigned BuiltinID,CallExpr * TheCall,unsigned MaxWidth)866 bool 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>(TheCall->getCallee()->IgnoreParenCasts());
886
887 // Ensure that we have the proper number of arguments.
888 if (SemaRef.checkArgCount(TheCall, 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(IsLdrex ? 0 : 1);
896 ExprResult PointerArgRes =
897 SemaRef.DefaultFunctionArrayLvalueConversion(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(DRE->getBeginLoc(), 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(ValType)) {
920 CastNeeded = CK_BitCast;
921 Diag(DRE->getBeginLoc(), diag::ext_typecheck_convert_discards_qualifiers)
922 << PointerArg->getType() << Context.getPointerType(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(AddrType);
928 PointerArgRes = SemaRef.ImpCastExprToType(PointerArg, AddrType, CastNeeded);
929 if (PointerArgRes.isInvalid())
930 return true;
931 PointerArg = PointerArgRes.get();
932
933 TheCall->setArg(IsLdrex ? 0 : 1, 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(DRE->getBeginLoc(), 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(ValType) > MaxWidth) {
945 assert(MaxWidth == 64 && "Diagnostic unexpectedly inaccurate");
946 Diag(DRE->getBeginLoc(), 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(DRE->getBeginLoc(), 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(0);
972 InitializedEntity Entity = InitializedEntity::InitializeParameter(
973 Context, ValType, /*consume*/ false);
974 ValArg = SemaRef.PerformCopyInitialization(Entity, SourceLocation(), ValArg);
975 if (ValArg.isInvalid())
976 return true;
977 TheCall->setArg(0, 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
CheckARMBuiltinFunctionCall(const TargetInfo & TI,unsigned BuiltinID,CallExpr * TheCall)985 bool 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, 64);
993 }
994
995 if (BuiltinID == ARM::BI__builtin_arm_prefetch) {
996 return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 1) ||
997 SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 1);
998 }
999
1000 if (BuiltinID == ARM::BI__builtin_arm_rsr64 ||
1001 BuiltinID == ARM::BI__builtin_arm_wsr64)
1002 return BuiltinARMSpecialReg(BuiltinID, TheCall, 0, 3, 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, 0, 5, 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, 1, 1, 32);
1025 case ARM::BI__builtin_arm_usat:
1026 return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 31);
1027 case ARM::BI__builtin_arm_ssat16:
1028 return SemaRef.BuiltinConstantArgRange(TheCall, 1, 1, 16);
1029 case ARM::BI__builtin_arm_usat16:
1030 return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 15);
1031 case ARM::BI__builtin_arm_vcvtr_f:
1032 case ARM::BI__builtin_arm_vcvtr_d:
1033 return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 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, 0, 0, 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, 0, 0, 15) ||
1058 CheckARMCoprocessorImmediate(TI, TheCall->getArg(0),
1059 /*WantCDE*/ false);
1060 }
1061 }
1062
CheckAArch64BuiltinFunctionCall(const TargetInfo & TI,unsigned BuiltinID,CallExpr * TheCall)1063 bool 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, 128);
1071 }
1072
1073 if (BuiltinID == AArch64::BI__builtin_arm_prefetch) {
1074 return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 1) ||
1075 SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 3) ||
1076 SemaRef.BuiltinConstantArgRange(TheCall, 3, 0, 1) ||
1077 SemaRef.BuiltinConstantArgRange(TheCall, 4, 0, 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, 0, 5, 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, 0, 5, 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, 0, 0, 0x7fff);
1108
1109 if (BuiltinID == AArch64::BI__getReg)
1110 return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 31);
1111
1112 if (BuiltinID == AArch64::BI__break)
1113 return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 0xffff);
1114
1115 if (BuiltinID == AArch64::BI__hlt)
1116 return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 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, i, l, u + l);
1139 }
1140
1141 namespace {
1142 struct IntrinToName {
1143 uint32_t Id;
1144 int32_t FullName;
1145 int32_t ShortName;
1146 };
1147 } // unnamed namespace
1148
BuiltinAliasValid(unsigned BuiltinID,StringRef AliasName,ArrayRef<IntrinToName> Map,const char * IntrinNames)1149 static bool BuiltinAliasValid(unsigned BuiltinID, StringRef AliasName,
1150 ArrayRef<IntrinToName> Map,
1151 const char *IntrinNames) {
1152 AliasName.consume_front("__arm_");
1153 const IntrinToName *It =
1154 llvm::lower_bound(Map, BuiltinID, [](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
MveAliasValid(unsigned BuiltinID,StringRef AliasName)1168 bool 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
CdeAliasValid(unsigned BuiltinID,StringRef AliasName)1176 bool SemaARM::CdeAliasValid(unsigned BuiltinID, StringRef AliasName) {
1177 #include "clang/Basic/arm_cde_builtin_aliases.inc"
1178 return BuiltinAliasValid(BuiltinID, AliasName, Map, IntrinNames);
1179 }
1180
SveAliasValid(unsigned BuiltinID,StringRef AliasName)1181 bool SemaARM::SveAliasValid(unsigned BuiltinID, StringRef AliasName) {
1182 if (getASTContext().BuiltinInfo.isAuxBuiltinID(BuiltinID))
1183 BuiltinID = getASTContext().BuiltinInfo.getAuxBuiltinID(BuiltinID);
1184 return BuiltinID >= AArch64::FirstSVEBuiltin &&
1185 BuiltinID <= AArch64::LastSVEBuiltin;
1186 }
1187
SmeAliasValid(unsigned BuiltinID,StringRef AliasName)1188 bool SemaARM::SmeAliasValid(unsigned BuiltinID, StringRef AliasName) {
1189 if (getASTContext().BuiltinInfo.isAuxBuiltinID(BuiltinID))
1190 BuiltinID = getASTContext().BuiltinInfo.getAuxBuiltinID(BuiltinID);
1191 return BuiltinID >= AArch64::FirstSMEBuiltin &&
1192 BuiltinID <= AArch64::LastSMEBuiltin;
1193 }
1194
handleBuiltinAliasAttr(Decl * D,const ParsedAttr & AL)1195 void SemaARM::handleBuiltinAliasAttr(Decl *D, const ParsedAttr &AL) {
1196 ASTContext &Context = getASTContext();
1197 if (!AL.isArgIdent(0)) {
1198 Diag(AL.getLoc(), diag::err_attribute_argument_n_type)
1199 << AL << 1 << AANT_ArgumentIdentifier;
1200 return;
1201 }
1202
1203 IdentifierInfo *Ident = AL.getArgAsIdent(0)->Ident;
1204 unsigned BuiltinID = Ident->getBuiltinID();
1205 StringRef AliasName = cast<FunctionDecl>(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(AL.getLoc(), diag::err_attribute_arm_builtin_alias);
1213 return;
1214 }
1215
1216 D->addAttr(::new (Context) ArmBuiltinAliasAttr(Context, AL, Ident));
1217 }
1218
checkNewAttrMutualExclusion(Sema & S,const ParsedAttr & AL,const FunctionProtoType * FPT,FunctionType::ArmStateValue CurrentState,StringRef StateName)1219 static 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(AL.getLoc(), 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
handleNewAttr(Decl * D,const ParsedAttr & AL)1242 void SemaARM::handleNewAttr(Decl *D, const ParsedAttr &AL) {
1243 if (!AL.getNumArgs()) {
1244 Diag(AL.getLoc(), 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(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(AL, I, StateName, &LiteralLoc))
1261 return;
1262
1263 if (StateName == "za")
1264 HasZA = true;
1265 else if (StateName == "zt0")
1266 HasZT0 = true;
1267 else {
1268 Diag(LiteralLoc, diag::err_unknown_arm_state) << StateName;
1269 AL.setInvalid();
1270 return;
1271 }
1272
1273 if (!llvm::is_contained(NewState, StateName)) // Avoid adding duplicates.
1274 NewState.push_back(StateName);
1275 }
1276
1277 if (auto *FPT = dyn_cast<FunctionProtoType>(D->getFunctionType())) {
1278 FunctionType::ArmStateValue ZAState =
1279 FunctionType::getArmZAState(FPT->getAArch64SMEAttributes());
1280 if (HasZA && ZAState != FunctionType::ARM_None &&
1281 checkNewAttrMutualExclusion(SemaRef, AL, FPT, ZAState, "za"))
1282 return;
1283 FunctionType::ArmStateValue ZT0State =
1284 FunctionType::getArmZT0State(FPT->getAArch64SMEAttributes());
1285 if (HasZT0 && ZT0State != FunctionType::ARM_None &&
1286 checkNewAttrMutualExclusion(SemaRef, AL, FPT, ZT0State, "zt0"))
1287 return;
1288 }
1289
1290 D->dropAttr<ArmNewAttr>();
1291 D->addAttr(::new (getASTContext()) ArmNewAttr(
1292 getASTContext(), AL, NewState.data(), NewState.size()));
1293 }
1294
handleCmseNSEntryAttr(Decl * D,const ParsedAttr & AL)1295 void SemaARM::handleCmseNSEntryAttr(Decl *D, const ParsedAttr &AL) {
1296 if (getLangOpts().CPlusPlus && !D->getDeclContext()->isExternCContext()) {
1297 Diag(AL.getLoc(), diag::err_attribute_not_clinkage) << AL;
1298 return;
1299 }
1300
1301 const auto *FD = cast<FunctionDecl>(D);
1302 if (!FD->isExternallyVisible()) {
1303 Diag(AL.getLoc(), diag::warn_attribute_cmse_entry_static);
1304 return;
1305 }
1306
1307 D->addAttr(::new (getASTContext()) CmseNSEntryAttr(getASTContext(), AL));
1308 }
1309
handleInterruptAttr(Decl * D,const ParsedAttr & AL)1310 void SemaARM::handleInterruptAttr(Decl *D, const ParsedAttr &AL) {
1311 // Check the attribute arguments.
1312 if (AL.getNumArgs() > 1) {
1313 Diag(AL.getLoc(), 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(AL, 0, Str, &ArgLoc))
1323 return;
1324
1325 ARMInterruptAttr::InterruptType Kind;
1326 if (!ARMInterruptAttr::ConvertStrToInterruptType(Str, Kind)) {
1327 Diag(AL.getLoc(), diag::warn_attribute_type_not_supported)
1328 << AL << Str << ArgLoc;
1329 return;
1330 }
1331
1332 const TargetInfo &TI = getASTContext().getTargetInfo();
1333 if (TI.hasFeature("vfp"))
1334 Diag(D->getLocation(), diag::warn_arm_interrupt_vfp_clobber);
1335
1336 D->addAttr(::new (getASTContext())
1337 ARMInterruptAttr(getASTContext(), AL, Kind));
1338 }
1339
1340 } // namespace clang
1341