brintos

brintos / llvm-project-archived public Read only

0
0
Text · 61.9 KiB · a5164a9 Raw
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