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