Path: blob/main/contrib/llvm-project/clang/lib/Sema/SemaARM.cpp
35234 views
//===------ SemaARM.cpp ---------- ARM target-specific routines -----------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file implements semantic analysis functions specific to ARM.9//10//===----------------------------------------------------------------------===//1112#include "clang/Sema/SemaARM.h"13#include "clang/Basic/DiagnosticSema.h"14#include "clang/Basic/TargetBuiltins.h"15#include "clang/Sema/Initialization.h"16#include "clang/Sema/ParsedAttr.h"17#include "clang/Sema/Sema.h"1819namespace clang {2021SemaARM::SemaARM(Sema &S) : SemaBase(S) {}2223/// BuiltinARMMemoryTaggingCall - Handle calls of memory tagging extensions24bool SemaARM::BuiltinARMMemoryTaggingCall(unsigned BuiltinID,25CallExpr *TheCall) {26ASTContext &Context = getASTContext();2728if (BuiltinID == AArch64::BI__builtin_arm_irg) {29if (SemaRef.checkArgCount(TheCall, 2))30return true;31Expr *Arg0 = TheCall->getArg(0);32Expr *Arg1 = TheCall->getArg(1);3334ExprResult FirstArg = SemaRef.DefaultFunctionArrayLvalueConversion(Arg0);35if (FirstArg.isInvalid())36return true;37QualType FirstArgType = FirstArg.get()->getType();38if (!FirstArgType->isAnyPointerType())39return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer)40<< "first" << FirstArgType << Arg0->getSourceRange();41TheCall->setArg(0, FirstArg.get());4243ExprResult SecArg = SemaRef.DefaultLvalueConversion(Arg1);44if (SecArg.isInvalid())45return true;46QualType SecArgType = SecArg.get()->getType();47if (!SecArgType->isIntegerType())48return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_integer)49<< "second" << SecArgType << Arg1->getSourceRange();5051// Derive the return type from the pointer argument.52TheCall->setType(FirstArgType);53return false;54}5556if (BuiltinID == AArch64::BI__builtin_arm_addg) {57if (SemaRef.checkArgCount(TheCall, 2))58return true;5960Expr *Arg0 = TheCall->getArg(0);61ExprResult FirstArg = SemaRef.DefaultFunctionArrayLvalueConversion(Arg0);62if (FirstArg.isInvalid())63return true;64QualType FirstArgType = FirstArg.get()->getType();65if (!FirstArgType->isAnyPointerType())66return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer)67<< "first" << FirstArgType << Arg0->getSourceRange();68TheCall->setArg(0, FirstArg.get());6970// Derive the return type from the pointer argument.71TheCall->setType(FirstArgType);7273// Second arg must be an constant in range [0,15]74return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 15);75}7677if (BuiltinID == AArch64::BI__builtin_arm_gmi) {78if (SemaRef.checkArgCount(TheCall, 2))79return true;80Expr *Arg0 = TheCall->getArg(0);81Expr *Arg1 = TheCall->getArg(1);8283ExprResult FirstArg = SemaRef.DefaultFunctionArrayLvalueConversion(Arg0);84if (FirstArg.isInvalid())85return true;86QualType FirstArgType = FirstArg.get()->getType();87if (!FirstArgType->isAnyPointerType())88return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer)89<< "first" << FirstArgType << Arg0->getSourceRange();9091QualType SecArgType = Arg1->getType();92if (!SecArgType->isIntegerType())93return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_integer)94<< "second" << SecArgType << Arg1->getSourceRange();95TheCall->setType(Context.IntTy);96return false;97}9899if (BuiltinID == AArch64::BI__builtin_arm_ldg ||100BuiltinID == AArch64::BI__builtin_arm_stg) {101if (SemaRef.checkArgCount(TheCall, 1))102return true;103Expr *Arg0 = TheCall->getArg(0);104ExprResult FirstArg = SemaRef.DefaultFunctionArrayLvalueConversion(Arg0);105if (FirstArg.isInvalid())106return true;107108QualType FirstArgType = FirstArg.get()->getType();109if (!FirstArgType->isAnyPointerType())110return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer)111<< "first" << FirstArgType << Arg0->getSourceRange();112TheCall->setArg(0, FirstArg.get());113114// Derive the return type from the pointer argument.115if (BuiltinID == AArch64::BI__builtin_arm_ldg)116TheCall->setType(FirstArgType);117return false;118}119120if (BuiltinID == AArch64::BI__builtin_arm_subp) {121Expr *ArgA = TheCall->getArg(0);122Expr *ArgB = TheCall->getArg(1);123124ExprResult ArgExprA = SemaRef.DefaultFunctionArrayLvalueConversion(ArgA);125ExprResult ArgExprB = SemaRef.DefaultFunctionArrayLvalueConversion(ArgB);126127if (ArgExprA.isInvalid() || ArgExprB.isInvalid())128return true;129130QualType ArgTypeA = ArgExprA.get()->getType();131QualType ArgTypeB = ArgExprB.get()->getType();132133auto isNull = [&](Expr *E) -> bool {134return E->isNullPointerConstant(Context,135Expr::NPC_ValueDependentIsNotNull);136};137138// argument should be either a pointer or null139if (!ArgTypeA->isAnyPointerType() && !isNull(ArgA))140return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_null_or_pointer)141<< "first" << ArgTypeA << ArgA->getSourceRange();142143if (!ArgTypeB->isAnyPointerType() && !isNull(ArgB))144return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_null_or_pointer)145<< "second" << ArgTypeB << ArgB->getSourceRange();146147// Ensure Pointee types are compatible148if (ArgTypeA->isAnyPointerType() && !isNull(ArgA) &&149ArgTypeB->isAnyPointerType() && !isNull(ArgB)) {150QualType pointeeA = ArgTypeA->getPointeeType();151QualType pointeeB = ArgTypeB->getPointeeType();152if (!Context.typesAreCompatible(153Context.getCanonicalType(pointeeA).getUnqualifiedType(),154Context.getCanonicalType(pointeeB).getUnqualifiedType())) {155return Diag(TheCall->getBeginLoc(),156diag::err_typecheck_sub_ptr_compatible)157<< ArgTypeA << ArgTypeB << ArgA->getSourceRange()158<< ArgB->getSourceRange();159}160}161162// at least one argument should be pointer type163if (!ArgTypeA->isAnyPointerType() && !ArgTypeB->isAnyPointerType())164return Diag(TheCall->getBeginLoc(), diag::err_memtag_any2arg_pointer)165<< ArgTypeA << ArgTypeB << ArgA->getSourceRange();166167if (isNull(ArgA)) // adopt type of the other pointer168ArgExprA =169SemaRef.ImpCastExprToType(ArgExprA.get(), ArgTypeB, CK_NullToPointer);170171if (isNull(ArgB))172ArgExprB =173SemaRef.ImpCastExprToType(ArgExprB.get(), ArgTypeA, CK_NullToPointer);174175TheCall->setArg(0, ArgExprA.get());176TheCall->setArg(1, ArgExprB.get());177TheCall->setType(Context.LongLongTy);178return false;179}180assert(false && "Unhandled ARM MTE intrinsic");181return true;182}183184/// BuiltinARMSpecialReg - Handle a check if argument ArgNum of CallExpr185/// TheCall is an ARM/AArch64 special register string literal.186bool SemaARM::BuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall,187int ArgNum, unsigned ExpectedFieldNum,188bool AllowName) {189bool IsARMBuiltin = BuiltinID == ARM::BI__builtin_arm_rsr64 ||190BuiltinID == ARM::BI__builtin_arm_wsr64 ||191BuiltinID == ARM::BI__builtin_arm_rsr ||192BuiltinID == ARM::BI__builtin_arm_rsrp ||193BuiltinID == ARM::BI__builtin_arm_wsr ||194BuiltinID == ARM::BI__builtin_arm_wsrp;195bool IsAArch64Builtin = BuiltinID == AArch64::BI__builtin_arm_rsr64 ||196BuiltinID == AArch64::BI__builtin_arm_wsr64 ||197BuiltinID == AArch64::BI__builtin_arm_rsr128 ||198BuiltinID == AArch64::BI__builtin_arm_wsr128 ||199BuiltinID == AArch64::BI__builtin_arm_rsr ||200BuiltinID == AArch64::BI__builtin_arm_rsrp ||201BuiltinID == AArch64::BI__builtin_arm_wsr ||202BuiltinID == AArch64::BI__builtin_arm_wsrp;203assert((IsARMBuiltin || IsAArch64Builtin) && "Unexpected ARM builtin.");204205// We can't check the value of a dependent argument.206Expr *Arg = TheCall->getArg(ArgNum);207if (Arg->isTypeDependent() || Arg->isValueDependent())208return false;209210// Check if the argument is a string literal.211if (!isa<StringLiteral>(Arg->IgnoreParenImpCasts()))212return Diag(TheCall->getBeginLoc(), diag::err_expr_not_string_literal)213<< Arg->getSourceRange();214215// Check the type of special register given.216StringRef Reg = cast<StringLiteral>(Arg->IgnoreParenImpCasts())->getString();217SmallVector<StringRef, 6> Fields;218Reg.split(Fields, ":");219220if (Fields.size() != ExpectedFieldNum && !(AllowName && Fields.size() == 1))221return Diag(TheCall->getBeginLoc(), diag::err_arm_invalid_specialreg)222<< Arg->getSourceRange();223224// If the string is the name of a register then we cannot check that it is225// valid here but if the string is of one the forms described in ACLE then we226// can check that the supplied fields are integers and within the valid227// ranges.228if (Fields.size() > 1) {229bool FiveFields = Fields.size() == 5;230231bool ValidString = true;232if (IsARMBuiltin) {233ValidString &= Fields[0].starts_with_insensitive("cp") ||234Fields[0].starts_with_insensitive("p");235if (ValidString)236Fields[0] = Fields[0].drop_front(237Fields[0].starts_with_insensitive("cp") ? 2 : 1);238239ValidString &= Fields[2].starts_with_insensitive("c");240if (ValidString)241Fields[2] = Fields[2].drop_front(1);242243if (FiveFields) {244ValidString &= Fields[3].starts_with_insensitive("c");245if (ValidString)246Fields[3] = Fields[3].drop_front(1);247}248}249250SmallVector<int, 5> Ranges;251if (FiveFields)252Ranges.append({IsAArch64Builtin ? 1 : 15, 7, 15, 15, 7});253else254Ranges.append({15, 7, 15});255256for (unsigned i = 0; i < Fields.size(); ++i) {257int IntField;258ValidString &= !Fields[i].getAsInteger(10, IntField);259ValidString &= (IntField >= 0 && IntField <= Ranges[i]);260}261262if (!ValidString)263return Diag(TheCall->getBeginLoc(), diag::err_arm_invalid_specialreg)264<< Arg->getSourceRange();265} else if (IsAArch64Builtin && Fields.size() == 1) {266// This code validates writes to PSTATE registers.267268// Not a write.269if (TheCall->getNumArgs() != 2)270return false;271272// The 128-bit system register accesses do not touch PSTATE.273if (BuiltinID == AArch64::BI__builtin_arm_rsr128 ||274BuiltinID == AArch64::BI__builtin_arm_wsr128)275return false;276277// These are the named PSTATE accesses using "MSR (immediate)" instructions,278// along with the upper limit on the immediates allowed.279auto MaxLimit = llvm::StringSwitch<std::optional<unsigned>>(Reg)280.CaseLower("spsel", 15)281.CaseLower("daifclr", 15)282.CaseLower("daifset", 15)283.CaseLower("pan", 15)284.CaseLower("uao", 15)285.CaseLower("dit", 15)286.CaseLower("ssbs", 15)287.CaseLower("tco", 15)288.CaseLower("allint", 1)289.CaseLower("pm", 1)290.Default(std::nullopt);291292// If this is not a named PSTATE, just continue without validating, as this293// will be lowered to an "MSR (register)" instruction directly294if (!MaxLimit)295return false;296297// Here we only allow constants in the range for that pstate, as required by298// the ACLE.299//300// While clang also accepts the names of system registers in its ACLE301// intrinsics, we prevent this with the PSTATE names used in MSR (immediate)302// as the value written via a register is different to the value used as an303// immediate to have the same effect. e.g., for the instruction `msr tco,304// x0`, it is bit 25 of register x0 that is written into PSTATE.TCO, but305// with `msr tco, #imm`, it is bit 0 of xN that is written into PSTATE.TCO.306//307// If a programmer wants to codegen the MSR (register) form of `msr tco,308// xN`, they can still do so by specifying the register using five309// colon-separated numbers in a string.310return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, *MaxLimit);311}312313return false;314}315316// Get the valid immediate range for the specified NEON type code.317static unsigned RFT(unsigned t, bool shift = false, bool ForceQuad = false) {318NeonTypeFlags Type(t);319int IsQuad = ForceQuad ? true : Type.isQuad();320switch (Type.getEltType()) {321case NeonTypeFlags::Int8:322case NeonTypeFlags::Poly8:323return shift ? 7 : (8 << IsQuad) - 1;324case NeonTypeFlags::Int16:325case NeonTypeFlags::Poly16:326return shift ? 15 : (4 << IsQuad) - 1;327case NeonTypeFlags::Int32:328return shift ? 31 : (2 << IsQuad) - 1;329case NeonTypeFlags::Int64:330case NeonTypeFlags::Poly64:331return shift ? 63 : (1 << IsQuad) - 1;332case NeonTypeFlags::Poly128:333return shift ? 127 : (1 << IsQuad) - 1;334case NeonTypeFlags::Float16:335assert(!shift && "cannot shift float types!");336return (4 << IsQuad) - 1;337case NeonTypeFlags::Float32:338assert(!shift && "cannot shift float types!");339return (2 << IsQuad) - 1;340case NeonTypeFlags::Float64:341assert(!shift && "cannot shift float types!");342return (1 << IsQuad) - 1;343case NeonTypeFlags::BFloat16:344assert(!shift && "cannot shift float types!");345return (4 << IsQuad) - 1;346}347llvm_unreachable("Invalid NeonTypeFlag!");348}349350/// getNeonEltType - Return the QualType corresponding to the elements of351/// the vector type specified by the NeonTypeFlags. This is used to check352/// the pointer arguments for Neon load/store intrinsics.353static QualType getNeonEltType(NeonTypeFlags Flags, ASTContext &Context,354bool IsPolyUnsigned, bool IsInt64Long) {355switch (Flags.getEltType()) {356case NeonTypeFlags::Int8:357return Flags.isUnsigned() ? Context.UnsignedCharTy : Context.SignedCharTy;358case NeonTypeFlags::Int16:359return Flags.isUnsigned() ? Context.UnsignedShortTy : Context.ShortTy;360case NeonTypeFlags::Int32:361return Flags.isUnsigned() ? Context.UnsignedIntTy : Context.IntTy;362case NeonTypeFlags::Int64:363if (IsInt64Long)364return Flags.isUnsigned() ? Context.UnsignedLongTy : Context.LongTy;365else366return Flags.isUnsigned() ? Context.UnsignedLongLongTy367: Context.LongLongTy;368case NeonTypeFlags::Poly8:369return IsPolyUnsigned ? Context.UnsignedCharTy : Context.SignedCharTy;370case NeonTypeFlags::Poly16:371return IsPolyUnsigned ? Context.UnsignedShortTy : Context.ShortTy;372case NeonTypeFlags::Poly64:373if (IsInt64Long)374return Context.UnsignedLongTy;375else376return Context.UnsignedLongLongTy;377case NeonTypeFlags::Poly128:378break;379case NeonTypeFlags::Float16:380return Context.HalfTy;381case NeonTypeFlags::Float32:382return Context.FloatTy;383case NeonTypeFlags::Float64:384return Context.DoubleTy;385case NeonTypeFlags::BFloat16:386return Context.BFloat16Ty;387}388llvm_unreachable("Invalid NeonTypeFlag!");389}390391enum ArmSMEState : unsigned {392ArmNoState = 0,393394ArmInZA = 0b01,395ArmOutZA = 0b10,396ArmInOutZA = 0b11,397ArmZAMask = 0b11,398399ArmInZT0 = 0b01 << 2,400ArmOutZT0 = 0b10 << 2,401ArmInOutZT0 = 0b11 << 2,402ArmZT0Mask = 0b11 << 2403};404405bool SemaARM::ParseSVEImmChecks(406CallExpr *TheCall, SmallVector<std::tuple<int, int, int>, 3> &ImmChecks) {407// Perform all the immediate checks for this builtin call.408bool HasError = false;409for (auto &I : ImmChecks) {410int ArgNum, CheckTy, ElementSizeInBits;411std::tie(ArgNum, CheckTy, ElementSizeInBits) = I;412413typedef bool (*OptionSetCheckFnTy)(int64_t Value);414415// Function that checks whether the operand (ArgNum) is an immediate416// that is one of the predefined values.417auto CheckImmediateInSet = [&](OptionSetCheckFnTy CheckImm,418int ErrDiag) -> bool {419// We can't check the value of a dependent argument.420Expr *Arg = TheCall->getArg(ArgNum);421if (Arg->isTypeDependent() || Arg->isValueDependent())422return false;423424// Check constant-ness first.425llvm::APSInt Imm;426if (SemaRef.BuiltinConstantArg(TheCall, ArgNum, Imm))427return true;428429if (!CheckImm(Imm.getSExtValue()))430return Diag(TheCall->getBeginLoc(), ErrDiag) << Arg->getSourceRange();431return false;432};433434switch ((SVETypeFlags::ImmCheckType)CheckTy) {435case SVETypeFlags::ImmCheck0_31:436if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, 31))437HasError = true;438break;439case SVETypeFlags::ImmCheck0_13:440if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, 13))441HasError = true;442break;443case SVETypeFlags::ImmCheck1_16:444if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 1, 16))445HasError = true;446break;447case SVETypeFlags::ImmCheck0_7:448if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, 7))449HasError = true;450break;451case SVETypeFlags::ImmCheck1_1:452if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 1, 1))453HasError = true;454break;455case SVETypeFlags::ImmCheck1_3:456if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 1, 3))457HasError = true;458break;459case SVETypeFlags::ImmCheck1_7:460if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 1, 7))461HasError = true;462break;463case SVETypeFlags::ImmCheckExtract:464if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0,465(2048 / ElementSizeInBits) - 1))466HasError = true;467break;468case SVETypeFlags::ImmCheckShiftRight:469if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 1,470ElementSizeInBits))471HasError = true;472break;473case SVETypeFlags::ImmCheckShiftRightNarrow:474if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 1,475ElementSizeInBits / 2))476HasError = true;477break;478case SVETypeFlags::ImmCheckShiftLeft:479if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0,480ElementSizeInBits - 1))481HasError = true;482break;483case SVETypeFlags::ImmCheckLaneIndex:484if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0,485(128 / (1 * ElementSizeInBits)) - 1))486HasError = true;487break;488case SVETypeFlags::ImmCheckLaneIndexCompRotate:489if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0,490(128 / (2 * ElementSizeInBits)) - 1))491HasError = true;492break;493case SVETypeFlags::ImmCheckLaneIndexDot:494if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0,495(128 / (4 * ElementSizeInBits)) - 1))496HasError = true;497break;498case SVETypeFlags::ImmCheckComplexRot90_270:499if (CheckImmediateInSet([](int64_t V) { return V == 90 || V == 270; },500diag::err_rotation_argument_to_cadd))501HasError = true;502break;503case SVETypeFlags::ImmCheckComplexRotAll90:504if (CheckImmediateInSet(505[](int64_t V) {506return V == 0 || V == 90 || V == 180 || V == 270;507},508diag::err_rotation_argument_to_cmla))509HasError = true;510break;511case SVETypeFlags::ImmCheck0_1:512if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, 1))513HasError = true;514break;515case SVETypeFlags::ImmCheck0_2:516if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, 2))517HasError = true;518break;519case SVETypeFlags::ImmCheck0_3:520if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, 3))521HasError = true;522break;523case SVETypeFlags::ImmCheck0_0:524if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, 0))525HasError = true;526break;527case SVETypeFlags::ImmCheck0_15:528if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, 15))529HasError = true;530break;531case SVETypeFlags::ImmCheck0_255:532if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, 255))533HasError = true;534break;535case SVETypeFlags::ImmCheck2_4_Mul2:536if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 2, 4) ||537SemaRef.BuiltinConstantArgMultiple(TheCall, ArgNum, 2))538HasError = true;539break;540}541}542543return HasError;544}545546SemaARM::ArmStreamingType getArmStreamingFnType(const FunctionDecl *FD) {547if (FD->hasAttr<ArmLocallyStreamingAttr>())548return SemaARM::ArmStreaming;549if (const Type *Ty = FD->getType().getTypePtrOrNull()) {550if (const auto *FPT = Ty->getAs<FunctionProtoType>()) {551if (FPT->getAArch64SMEAttributes() &552FunctionType::SME_PStateSMEnabledMask)553return SemaARM::ArmStreaming;554if (FPT->getAArch64SMEAttributes() &555FunctionType::SME_PStateSMCompatibleMask)556return SemaARM::ArmStreamingCompatible;557}558}559return SemaARM::ArmNonStreaming;560}561562static bool checkArmStreamingBuiltin(Sema &S, CallExpr *TheCall,563const FunctionDecl *FD,564SemaARM::ArmStreamingType BuiltinType,565unsigned BuiltinID) {566SemaARM::ArmStreamingType FnType = getArmStreamingFnType(FD);567568// Check if the intrinsic is available in the right mode, i.e.569// * When compiling for SME only, the caller must be in streaming mode.570// * When compiling for SVE only, the caller must be in non-streaming mode.571// * When compiling for both SVE and SME, the caller can be in either mode.572if (BuiltinType == SemaARM::VerifyRuntimeMode) {573auto DisableFeatures = [](llvm::StringMap<bool> &Map, StringRef S) {574for (StringRef K : Map.keys())575if (K.starts_with(S))576Map[K] = false;577};578579llvm::StringMap<bool> CallerFeatureMapWithoutSVE;580S.Context.getFunctionFeatureMap(CallerFeatureMapWithoutSVE, FD);581DisableFeatures(CallerFeatureMapWithoutSVE, "sve");582583// Avoid emitting diagnostics for a function that can never compile.584if (FnType == SemaARM::ArmStreaming && !CallerFeatureMapWithoutSVE["sme"])585return false;586587llvm::StringMap<bool> CallerFeatureMapWithoutSME;588S.Context.getFunctionFeatureMap(CallerFeatureMapWithoutSME, FD);589DisableFeatures(CallerFeatureMapWithoutSME, "sme");590591// We know the builtin requires either some combination of SVE flags, or592// some combination of SME flags, but we need to figure out which part593// of the required features is satisfied by the target features.594//595// For a builtin with target guard 'sve2p1|sme2', if we compile with596// '+sve2p1,+sme', then we know that it satisfies the 'sve2p1' part if we597// evaluate the features for '+sve2p1,+sme,+nosme'.598//599// Similarly, if we compile with '+sve2,+sme2', then we know it satisfies600// the 'sme2' part if we evaluate the features for '+sve2,+sme2,+nosve'.601StringRef BuiltinTargetGuards(602S.Context.BuiltinInfo.getRequiredFeatures(BuiltinID));603bool SatisfiesSVE = Builtin::evaluateRequiredTargetFeatures(604BuiltinTargetGuards, CallerFeatureMapWithoutSME);605bool SatisfiesSME = Builtin::evaluateRequiredTargetFeatures(606BuiltinTargetGuards, CallerFeatureMapWithoutSVE);607608if ((SatisfiesSVE && SatisfiesSME) ||609(SatisfiesSVE && FnType == SemaARM::ArmStreamingCompatible))610return false;611else if (SatisfiesSVE)612BuiltinType = SemaARM::ArmNonStreaming;613else if (SatisfiesSME)614BuiltinType = SemaARM::ArmStreaming;615else616// This should be diagnosed by CodeGen617return false;618}619620if (FnType != SemaARM::ArmNonStreaming &&621BuiltinType == SemaARM::ArmNonStreaming)622S.Diag(TheCall->getBeginLoc(), diag::err_attribute_arm_sm_incompat_builtin)623<< TheCall->getSourceRange() << "non-streaming";624else if (FnType != SemaARM::ArmStreaming &&625BuiltinType == SemaARM::ArmStreaming)626S.Diag(TheCall->getBeginLoc(), diag::err_attribute_arm_sm_incompat_builtin)627<< TheCall->getSourceRange() << "streaming";628else629return false;630631return true;632}633634static bool hasArmZAState(const FunctionDecl *FD) {635const auto *T = FD->getType()->getAs<FunctionProtoType>();636return (T && FunctionType::getArmZAState(T->getAArch64SMEAttributes()) !=637FunctionType::ARM_None) ||638(FD->hasAttr<ArmNewAttr>() && FD->getAttr<ArmNewAttr>()->isNewZA());639}640641static bool hasArmZT0State(const FunctionDecl *FD) {642const auto *T = FD->getType()->getAs<FunctionProtoType>();643return (T && FunctionType::getArmZT0State(T->getAArch64SMEAttributes()) !=644FunctionType::ARM_None) ||645(FD->hasAttr<ArmNewAttr>() && FD->getAttr<ArmNewAttr>()->isNewZT0());646}647648static ArmSMEState getSMEState(unsigned BuiltinID) {649switch (BuiltinID) {650default:651return ArmNoState;652#define GET_SME_BUILTIN_GET_STATE653#include "clang/Basic/arm_sme_builtins_za_state.inc"654#undef GET_SME_BUILTIN_GET_STATE655}656}657658bool SemaARM::CheckSMEBuiltinFunctionCall(unsigned BuiltinID,659CallExpr *TheCall) {660if (const FunctionDecl *FD = SemaRef.getCurFunctionDecl()) {661std::optional<ArmStreamingType> BuiltinType;662663switch (BuiltinID) {664#define GET_SME_STREAMING_ATTRS665#include "clang/Basic/arm_sme_streaming_attrs.inc"666#undef GET_SME_STREAMING_ATTRS667}668669if (BuiltinType &&670checkArmStreamingBuiltin(SemaRef, TheCall, FD, *BuiltinType, BuiltinID))671return true;672673if ((getSMEState(BuiltinID) & ArmZAMask) && !hasArmZAState(FD))674Diag(TheCall->getBeginLoc(),675diag::warn_attribute_arm_za_builtin_no_za_state)676<< TheCall->getSourceRange();677678if ((getSMEState(BuiltinID) & ArmZT0Mask) && !hasArmZT0State(FD))679Diag(TheCall->getBeginLoc(),680diag::warn_attribute_arm_zt0_builtin_no_zt0_state)681<< TheCall->getSourceRange();682}683684// Range check SME intrinsics that take immediate values.685SmallVector<std::tuple<int, int, int>, 3> ImmChecks;686687switch (BuiltinID) {688default:689return false;690#define GET_SME_IMMEDIATE_CHECK691#include "clang/Basic/arm_sme_sema_rangechecks.inc"692#undef GET_SME_IMMEDIATE_CHECK693}694695return ParseSVEImmChecks(TheCall, ImmChecks);696}697698bool SemaARM::CheckSVEBuiltinFunctionCall(unsigned BuiltinID,699CallExpr *TheCall) {700if (const FunctionDecl *FD = SemaRef.getCurFunctionDecl()) {701std::optional<ArmStreamingType> BuiltinType;702703switch (BuiltinID) {704#define GET_SVE_STREAMING_ATTRS705#include "clang/Basic/arm_sve_streaming_attrs.inc"706#undef GET_SVE_STREAMING_ATTRS707}708if (BuiltinType &&709checkArmStreamingBuiltin(SemaRef, TheCall, FD, *BuiltinType, BuiltinID))710return true;711}712// Range check SVE intrinsics that take immediate values.713SmallVector<std::tuple<int, int, int>, 3> ImmChecks;714715switch (BuiltinID) {716default:717return false;718#define GET_SVE_IMMEDIATE_CHECK719#include "clang/Basic/arm_sve_sema_rangechecks.inc"720#undef GET_SVE_IMMEDIATE_CHECK721}722723return ParseSVEImmChecks(TheCall, ImmChecks);724}725726bool SemaARM::CheckNeonBuiltinFunctionCall(const TargetInfo &TI,727unsigned BuiltinID,728CallExpr *TheCall) {729if (const FunctionDecl *FD = SemaRef.getCurFunctionDecl()) {730731switch (BuiltinID) {732default:733break;734#define GET_NEON_BUILTINS735#define TARGET_BUILTIN(id, ...) case NEON::BI##id:736#define BUILTIN(id, ...) case NEON::BI##id:737#include "clang/Basic/arm_neon.inc"738if (checkArmStreamingBuiltin(SemaRef, TheCall, FD, ArmNonStreaming,739BuiltinID))740return true;741break;742#undef TARGET_BUILTIN743#undef BUILTIN744#undef GET_NEON_BUILTINS745}746}747748llvm::APSInt Result;749uint64_t mask = 0;750unsigned TV = 0;751int PtrArgNum = -1;752bool HasConstPtr = false;753switch (BuiltinID) {754#define GET_NEON_OVERLOAD_CHECK755#include "clang/Basic/arm_fp16.inc"756#include "clang/Basic/arm_neon.inc"757#undef GET_NEON_OVERLOAD_CHECK758}759760// For NEON intrinsics which are overloaded on vector element type, validate761// the immediate which specifies which variant to emit.762unsigned ImmArg = TheCall->getNumArgs() - 1;763if (mask) {764if (SemaRef.BuiltinConstantArg(TheCall, ImmArg, Result))765return true;766767TV = Result.getLimitedValue(64);768if ((TV > 63) || (mask & (1ULL << TV)) == 0)769return Diag(TheCall->getBeginLoc(), diag::err_invalid_neon_type_code)770<< TheCall->getArg(ImmArg)->getSourceRange();771}772773if (PtrArgNum >= 0) {774// Check that pointer arguments have the specified type.775Expr *Arg = TheCall->getArg(PtrArgNum);776if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg))777Arg = ICE->getSubExpr();778ExprResult RHS = SemaRef.DefaultFunctionArrayLvalueConversion(Arg);779QualType RHSTy = RHS.get()->getType();780781llvm::Triple::ArchType Arch = TI.getTriple().getArch();782bool IsPolyUnsigned = Arch == llvm::Triple::aarch64 ||783Arch == llvm::Triple::aarch64_32 ||784Arch == llvm::Triple::aarch64_be;785bool IsInt64Long = TI.getInt64Type() == TargetInfo::SignedLong;786QualType EltTy = getNeonEltType(NeonTypeFlags(TV), getASTContext(),787IsPolyUnsigned, IsInt64Long);788if (HasConstPtr)789EltTy = EltTy.withConst();790QualType LHSTy = getASTContext().getPointerType(EltTy);791Sema::AssignConvertType ConvTy;792ConvTy = SemaRef.CheckSingleAssignmentConstraints(LHSTy, RHS);793if (RHS.isInvalid())794return true;795if (SemaRef.DiagnoseAssignmentResult(ConvTy, Arg->getBeginLoc(), LHSTy,796RHSTy, RHS.get(), Sema::AA_Assigning))797return true;798}799800// For NEON intrinsics which take an immediate value as part of the801// instruction, range check them here.802unsigned i = 0, l = 0, u = 0;803switch (BuiltinID) {804default:805return false;806#define GET_NEON_IMMEDIATE_CHECK807#include "clang/Basic/arm_fp16.inc"808#include "clang/Basic/arm_neon.inc"809#undef GET_NEON_IMMEDIATE_CHECK810}811812return SemaRef.BuiltinConstantArgRange(TheCall, i, l, u + l);813}814815bool SemaARM::CheckMVEBuiltinFunctionCall(unsigned BuiltinID,816CallExpr *TheCall) {817switch (BuiltinID) {818default:819return false;820#include "clang/Basic/arm_mve_builtin_sema.inc"821}822}823824bool SemaARM::CheckCDEBuiltinFunctionCall(const TargetInfo &TI,825unsigned BuiltinID,826CallExpr *TheCall) {827bool Err = false;828switch (BuiltinID) {829default:830return false;831#include "clang/Basic/arm_cde_builtin_sema.inc"832}833834if (Err)835return true;836837return CheckARMCoprocessorImmediate(TI, TheCall->getArg(0), /*WantCDE*/ true);838}839840bool SemaARM::CheckARMCoprocessorImmediate(const TargetInfo &TI,841const Expr *CoprocArg,842bool WantCDE) {843ASTContext &Context = getASTContext();844if (SemaRef.isConstantEvaluatedContext())845return false;846847// We can't check the value of a dependent argument.848if (CoprocArg->isTypeDependent() || CoprocArg->isValueDependent())849return false;850851llvm::APSInt CoprocNoAP = *CoprocArg->getIntegerConstantExpr(Context);852int64_t CoprocNo = CoprocNoAP.getExtValue();853assert(CoprocNo >= 0 && "Coprocessor immediate must be non-negative");854855uint32_t CDECoprocMask = TI.getARMCDECoprocMask();856bool IsCDECoproc = CoprocNo <= 7 && (CDECoprocMask & (1 << CoprocNo));857858if (IsCDECoproc != WantCDE)859return Diag(CoprocArg->getBeginLoc(), diag::err_arm_invalid_coproc)860<< (int)CoprocNo << (int)WantCDE << CoprocArg->getSourceRange();861862return false;863}864865bool SemaARM::CheckARMBuiltinExclusiveCall(unsigned BuiltinID,866CallExpr *TheCall,867unsigned MaxWidth) {868assert((BuiltinID == ARM::BI__builtin_arm_ldrex ||869BuiltinID == ARM::BI__builtin_arm_ldaex ||870BuiltinID == ARM::BI__builtin_arm_strex ||871BuiltinID == ARM::BI__builtin_arm_stlex ||872BuiltinID == AArch64::BI__builtin_arm_ldrex ||873BuiltinID == AArch64::BI__builtin_arm_ldaex ||874BuiltinID == AArch64::BI__builtin_arm_strex ||875BuiltinID == AArch64::BI__builtin_arm_stlex) &&876"unexpected ARM builtin");877bool IsLdrex = BuiltinID == ARM::BI__builtin_arm_ldrex ||878BuiltinID == ARM::BI__builtin_arm_ldaex ||879BuiltinID == AArch64::BI__builtin_arm_ldrex ||880BuiltinID == AArch64::BI__builtin_arm_ldaex;881882ASTContext &Context = getASTContext();883DeclRefExpr *DRE =884cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts());885886// Ensure that we have the proper number of arguments.887if (SemaRef.checkArgCount(TheCall, IsLdrex ? 1 : 2))888return true;889890// Inspect the pointer argument of the atomic builtin. This should always be891// a pointer type, whose element is an integral scalar or pointer type.892// Because it is a pointer type, we don't have to worry about any implicit893// casts here.894Expr *PointerArg = TheCall->getArg(IsLdrex ? 0 : 1);895ExprResult PointerArgRes =896SemaRef.DefaultFunctionArrayLvalueConversion(PointerArg);897if (PointerArgRes.isInvalid())898return true;899PointerArg = PointerArgRes.get();900901const PointerType *pointerType = PointerArg->getType()->getAs<PointerType>();902if (!pointerType) {903Diag(DRE->getBeginLoc(), diag::err_atomic_builtin_must_be_pointer)904<< PointerArg->getType() << 0 << PointerArg->getSourceRange();905return true;906}907908// ldrex takes a "const volatile T*" and strex takes a "volatile T*". Our next909// task is to insert the appropriate casts into the AST. First work out just910// what the appropriate type is.911QualType ValType = pointerType->getPointeeType();912QualType AddrType = ValType.getUnqualifiedType().withVolatile();913if (IsLdrex)914AddrType.addConst();915916// Issue a warning if the cast is dodgy.917CastKind CastNeeded = CK_NoOp;918if (!AddrType.isAtLeastAsQualifiedAs(ValType)) {919CastNeeded = CK_BitCast;920Diag(DRE->getBeginLoc(), diag::ext_typecheck_convert_discards_qualifiers)921<< PointerArg->getType() << Context.getPointerType(AddrType)922<< Sema::AA_Passing << PointerArg->getSourceRange();923}924925// Finally, do the cast and replace the argument with the corrected version.926AddrType = Context.getPointerType(AddrType);927PointerArgRes = SemaRef.ImpCastExprToType(PointerArg, AddrType, CastNeeded);928if (PointerArgRes.isInvalid())929return true;930PointerArg = PointerArgRes.get();931932TheCall->setArg(IsLdrex ? 0 : 1, PointerArg);933934// In general, we allow ints, floats and pointers to be loaded and stored.935if (!ValType->isIntegerType() && !ValType->isAnyPointerType() &&936!ValType->isBlockPointerType() && !ValType->isFloatingType()) {937Diag(DRE->getBeginLoc(), diag::err_atomic_builtin_must_be_pointer_intfltptr)938<< PointerArg->getType() << 0 << PointerArg->getSourceRange();939return true;940}941942// But ARM doesn't have instructions to deal with 128-bit versions.943if (Context.getTypeSize(ValType) > MaxWidth) {944assert(MaxWidth == 64 && "Diagnostic unexpectedly inaccurate");945Diag(DRE->getBeginLoc(), diag::err_atomic_exclusive_builtin_pointer_size)946<< PointerArg->getType() << PointerArg->getSourceRange();947return true;948}949950switch (ValType.getObjCLifetime()) {951case Qualifiers::OCL_None:952case Qualifiers::OCL_ExplicitNone:953// okay954break;955956case Qualifiers::OCL_Weak:957case Qualifiers::OCL_Strong:958case Qualifiers::OCL_Autoreleasing:959Diag(DRE->getBeginLoc(), diag::err_arc_atomic_ownership)960<< ValType << PointerArg->getSourceRange();961return true;962}963964if (IsLdrex) {965TheCall->setType(ValType);966return false;967}968969// Initialize the argument to be stored.970ExprResult ValArg = TheCall->getArg(0);971InitializedEntity Entity = InitializedEntity::InitializeParameter(972Context, ValType, /*consume*/ false);973ValArg = SemaRef.PerformCopyInitialization(Entity, SourceLocation(), ValArg);974if (ValArg.isInvalid())975return true;976TheCall->setArg(0, ValArg.get());977978// __builtin_arm_strex always returns an int. It's marked as such in the .def,979// but the custom checker bypasses all default analysis.980TheCall->setType(Context.IntTy);981return false;982}983984bool SemaARM::CheckARMBuiltinFunctionCall(const TargetInfo &TI,985unsigned BuiltinID,986CallExpr *TheCall) {987if (BuiltinID == ARM::BI__builtin_arm_ldrex ||988BuiltinID == ARM::BI__builtin_arm_ldaex ||989BuiltinID == ARM::BI__builtin_arm_strex ||990BuiltinID == ARM::BI__builtin_arm_stlex) {991return CheckARMBuiltinExclusiveCall(BuiltinID, TheCall, 64);992}993994if (BuiltinID == ARM::BI__builtin_arm_prefetch) {995return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 1) ||996SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 1);997}998999if (BuiltinID == ARM::BI__builtin_arm_rsr64 ||1000BuiltinID == ARM::BI__builtin_arm_wsr64)1001return BuiltinARMSpecialReg(BuiltinID, TheCall, 0, 3, false);10021003if (BuiltinID == ARM::BI__builtin_arm_rsr ||1004BuiltinID == ARM::BI__builtin_arm_rsrp ||1005BuiltinID == ARM::BI__builtin_arm_wsr ||1006BuiltinID == ARM::BI__builtin_arm_wsrp)1007return BuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true);10081009if (CheckNeonBuiltinFunctionCall(TI, BuiltinID, TheCall))1010return true;1011if (CheckMVEBuiltinFunctionCall(BuiltinID, TheCall))1012return true;1013if (CheckCDEBuiltinFunctionCall(TI, BuiltinID, TheCall))1014return true;10151016// For intrinsics which take an immediate value as part of the instruction,1017// range check them here.1018// FIXME: VFP Intrinsics should error if VFP not present.1019switch (BuiltinID) {1020default:1021return false;1022case ARM::BI__builtin_arm_ssat:1023return SemaRef.BuiltinConstantArgRange(TheCall, 1, 1, 32);1024case ARM::BI__builtin_arm_usat:1025return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 31);1026case ARM::BI__builtin_arm_ssat16:1027return SemaRef.BuiltinConstantArgRange(TheCall, 1, 1, 16);1028case ARM::BI__builtin_arm_usat16:1029return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 15);1030case ARM::BI__builtin_arm_vcvtr_f:1031case ARM::BI__builtin_arm_vcvtr_d:1032return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 1);1033case ARM::BI__builtin_arm_dmb:1034case ARM::BI__builtin_arm_dsb:1035case ARM::BI__builtin_arm_isb:1036case ARM::BI__builtin_arm_dbg:1037return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 15);1038case ARM::BI__builtin_arm_cdp:1039case ARM::BI__builtin_arm_cdp2:1040case ARM::BI__builtin_arm_mcr:1041case ARM::BI__builtin_arm_mcr2:1042case ARM::BI__builtin_arm_mrc:1043case ARM::BI__builtin_arm_mrc2:1044case ARM::BI__builtin_arm_mcrr:1045case ARM::BI__builtin_arm_mcrr2:1046case ARM::BI__builtin_arm_mrrc:1047case ARM::BI__builtin_arm_mrrc2:1048case ARM::BI__builtin_arm_ldc:1049case ARM::BI__builtin_arm_ldcl:1050case ARM::BI__builtin_arm_ldc2:1051case ARM::BI__builtin_arm_ldc2l:1052case ARM::BI__builtin_arm_stc:1053case ARM::BI__builtin_arm_stcl:1054case ARM::BI__builtin_arm_stc2:1055case ARM::BI__builtin_arm_stc2l:1056return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 15) ||1057CheckARMCoprocessorImmediate(TI, TheCall->getArg(0),1058/*WantCDE*/ false);1059}1060}10611062bool SemaARM::CheckAArch64BuiltinFunctionCall(const TargetInfo &TI,1063unsigned BuiltinID,1064CallExpr *TheCall) {1065if (BuiltinID == AArch64::BI__builtin_arm_ldrex ||1066BuiltinID == AArch64::BI__builtin_arm_ldaex ||1067BuiltinID == AArch64::BI__builtin_arm_strex ||1068BuiltinID == AArch64::BI__builtin_arm_stlex) {1069return CheckARMBuiltinExclusiveCall(BuiltinID, TheCall, 128);1070}10711072if (BuiltinID == AArch64::BI__builtin_arm_prefetch) {1073return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 1) ||1074SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 3) ||1075SemaRef.BuiltinConstantArgRange(TheCall, 3, 0, 1) ||1076SemaRef.BuiltinConstantArgRange(TheCall, 4, 0, 1);1077}10781079if (BuiltinID == AArch64::BI__builtin_arm_rsr64 ||1080BuiltinID == AArch64::BI__builtin_arm_wsr64 ||1081BuiltinID == AArch64::BI__builtin_arm_rsr128 ||1082BuiltinID == AArch64::BI__builtin_arm_wsr128)1083return BuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true);10841085// Memory Tagging Extensions (MTE) Intrinsics1086if (BuiltinID == AArch64::BI__builtin_arm_irg ||1087BuiltinID == AArch64::BI__builtin_arm_addg ||1088BuiltinID == AArch64::BI__builtin_arm_gmi ||1089BuiltinID == AArch64::BI__builtin_arm_ldg ||1090BuiltinID == AArch64::BI__builtin_arm_stg ||1091BuiltinID == AArch64::BI__builtin_arm_subp) {1092return BuiltinARMMemoryTaggingCall(BuiltinID, TheCall);1093}10941095if (BuiltinID == AArch64::BI__builtin_arm_rsr ||1096BuiltinID == AArch64::BI__builtin_arm_rsrp ||1097BuiltinID == AArch64::BI__builtin_arm_wsr ||1098BuiltinID == AArch64::BI__builtin_arm_wsrp)1099return BuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true);11001101// Only check the valid encoding range. Any constant in this range would be1102// converted to a register of the form S1_2_C3_C4_5. Let the hardware throw1103// an exception for incorrect registers. This matches MSVC behavior.1104if (BuiltinID == AArch64::BI_ReadStatusReg ||1105BuiltinID == AArch64::BI_WriteStatusReg)1106return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 0x7fff);11071108if (BuiltinID == AArch64::BI__getReg)1109return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 31);11101111if (BuiltinID == AArch64::BI__break)1112return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 0xffff);11131114if (BuiltinID == AArch64::BI__hlt)1115return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 0xffff);11161117if (CheckNeonBuiltinFunctionCall(TI, BuiltinID, TheCall))1118return true;11191120if (CheckSVEBuiltinFunctionCall(BuiltinID, TheCall))1121return true;11221123if (CheckSMEBuiltinFunctionCall(BuiltinID, TheCall))1124return true;11251126// For intrinsics which take an immediate value as part of the instruction,1127// range check them here.1128unsigned i = 0, l = 0, u = 0;1129switch (BuiltinID) {1130default: return false;1131case AArch64::BI__builtin_arm_dmb:1132case AArch64::BI__builtin_arm_dsb:1133case AArch64::BI__builtin_arm_isb: l = 0; u = 15; break;1134case AArch64::BI__builtin_arm_tcancel: l = 0; u = 65535; break;1135}11361137return SemaRef.BuiltinConstantArgRange(TheCall, i, l, u + l);1138}11391140namespace {1141struct IntrinToName {1142uint32_t Id;1143int32_t FullName;1144int32_t ShortName;1145};1146} // unnamed namespace11471148static bool BuiltinAliasValid(unsigned BuiltinID, StringRef AliasName,1149ArrayRef<IntrinToName> Map,1150const char *IntrinNames) {1151AliasName.consume_front("__arm_");1152const IntrinToName *It =1153llvm::lower_bound(Map, BuiltinID, [](const IntrinToName &L, unsigned Id) {1154return L.Id < Id;1155});1156if (It == Map.end() || It->Id != BuiltinID)1157return false;1158StringRef FullName(&IntrinNames[It->FullName]);1159if (AliasName == FullName)1160return true;1161if (It->ShortName == -1)1162return false;1163StringRef ShortName(&IntrinNames[It->ShortName]);1164return AliasName == ShortName;1165}11661167bool SemaARM::MveAliasValid(unsigned BuiltinID, StringRef AliasName) {1168#include "clang/Basic/arm_mve_builtin_aliases.inc"1169// The included file defines:1170// - ArrayRef<IntrinToName> Map1171// - const char IntrinNames[]1172return BuiltinAliasValid(BuiltinID, AliasName, Map, IntrinNames);1173}11741175bool SemaARM::CdeAliasValid(unsigned BuiltinID, StringRef AliasName) {1176#include "clang/Basic/arm_cde_builtin_aliases.inc"1177return BuiltinAliasValid(BuiltinID, AliasName, Map, IntrinNames);1178}11791180bool SemaARM::SveAliasValid(unsigned BuiltinID, StringRef AliasName) {1181if (getASTContext().BuiltinInfo.isAuxBuiltinID(BuiltinID))1182BuiltinID = getASTContext().BuiltinInfo.getAuxBuiltinID(BuiltinID);1183return BuiltinID >= AArch64::FirstSVEBuiltin &&1184BuiltinID <= AArch64::LastSVEBuiltin;1185}11861187bool SemaARM::SmeAliasValid(unsigned BuiltinID, StringRef AliasName) {1188if (getASTContext().BuiltinInfo.isAuxBuiltinID(BuiltinID))1189BuiltinID = getASTContext().BuiltinInfo.getAuxBuiltinID(BuiltinID);1190return BuiltinID >= AArch64::FirstSMEBuiltin &&1191BuiltinID <= AArch64::LastSMEBuiltin;1192}11931194void SemaARM::handleBuiltinAliasAttr(Decl *D, const ParsedAttr &AL) {1195ASTContext &Context = getASTContext();1196if (!AL.isArgIdent(0)) {1197Diag(AL.getLoc(), diag::err_attribute_argument_n_type)1198<< AL << 1 << AANT_ArgumentIdentifier;1199return;1200}12011202IdentifierInfo *Ident = AL.getArgAsIdent(0)->Ident;1203unsigned BuiltinID = Ident->getBuiltinID();1204StringRef AliasName = cast<FunctionDecl>(D)->getIdentifier()->getName();12051206bool IsAArch64 = Context.getTargetInfo().getTriple().isAArch64();1207if ((IsAArch64 && !SveAliasValid(BuiltinID, AliasName) &&1208!SmeAliasValid(BuiltinID, AliasName)) ||1209(!IsAArch64 && !MveAliasValid(BuiltinID, AliasName) &&1210!CdeAliasValid(BuiltinID, AliasName))) {1211Diag(AL.getLoc(), diag::err_attribute_arm_builtin_alias);1212return;1213}12141215D->addAttr(::new (Context) ArmBuiltinAliasAttr(Context, AL, Ident));1216}12171218static bool checkNewAttrMutualExclusion(1219Sema &S, const ParsedAttr &AL, const FunctionProtoType *FPT,1220FunctionType::ArmStateValue CurrentState, StringRef StateName) {1221auto CheckForIncompatibleAttr =1222[&](FunctionType::ArmStateValue IncompatibleState,1223StringRef IncompatibleStateName) {1224if (CurrentState == IncompatibleState) {1225S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible)1226<< (std::string("'__arm_new(\"") + StateName.str() + "\")'")1227<< (std::string("'") + IncompatibleStateName.str() + "(\"" +1228StateName.str() + "\")'")1229<< true;1230AL.setInvalid();1231}1232};12331234CheckForIncompatibleAttr(FunctionType::ARM_In, "__arm_in");1235CheckForIncompatibleAttr(FunctionType::ARM_Out, "__arm_out");1236CheckForIncompatibleAttr(FunctionType::ARM_InOut, "__arm_inout");1237CheckForIncompatibleAttr(FunctionType::ARM_Preserves, "__arm_preserves");1238return AL.isInvalid();1239}12401241void SemaARM::handleNewAttr(Decl *D, const ParsedAttr &AL) {1242if (!AL.getNumArgs()) {1243Diag(AL.getLoc(), diag::err_missing_arm_state) << AL;1244AL.setInvalid();1245return;1246}12471248std::vector<StringRef> NewState;1249if (const auto *ExistingAttr = D->getAttr<ArmNewAttr>()) {1250for (StringRef S : ExistingAttr->newArgs())1251NewState.push_back(S);1252}12531254bool HasZA = false;1255bool HasZT0 = false;1256for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) {1257StringRef StateName;1258SourceLocation LiteralLoc;1259if (!SemaRef.checkStringLiteralArgumentAttr(AL, I, StateName, &LiteralLoc))1260return;12611262if (StateName == "za")1263HasZA = true;1264else if (StateName == "zt0")1265HasZT0 = true;1266else {1267Diag(LiteralLoc, diag::err_unknown_arm_state) << StateName;1268AL.setInvalid();1269return;1270}12711272if (!llvm::is_contained(NewState, StateName)) // Avoid adding duplicates.1273NewState.push_back(StateName);1274}12751276if (auto *FPT = dyn_cast<FunctionProtoType>(D->getFunctionType())) {1277FunctionType::ArmStateValue ZAState =1278FunctionType::getArmZAState(FPT->getAArch64SMEAttributes());1279if (HasZA && ZAState != FunctionType::ARM_None &&1280checkNewAttrMutualExclusion(SemaRef, AL, FPT, ZAState, "za"))1281return;1282FunctionType::ArmStateValue ZT0State =1283FunctionType::getArmZT0State(FPT->getAArch64SMEAttributes());1284if (HasZT0 && ZT0State != FunctionType::ARM_None &&1285checkNewAttrMutualExclusion(SemaRef, AL, FPT, ZT0State, "zt0"))1286return;1287}12881289D->dropAttr<ArmNewAttr>();1290D->addAttr(::new (getASTContext()) ArmNewAttr(1291getASTContext(), AL, NewState.data(), NewState.size()));1292}12931294void SemaARM::handleCmseNSEntryAttr(Decl *D, const ParsedAttr &AL) {1295if (getLangOpts().CPlusPlus && !D->getDeclContext()->isExternCContext()) {1296Diag(AL.getLoc(), diag::err_attribute_not_clinkage) << AL;1297return;1298}12991300const auto *FD = cast<FunctionDecl>(D);1301if (!FD->isExternallyVisible()) {1302Diag(AL.getLoc(), diag::warn_attribute_cmse_entry_static);1303return;1304}13051306D->addAttr(::new (getASTContext()) CmseNSEntryAttr(getASTContext(), AL));1307}13081309void SemaARM::handleInterruptAttr(Decl *D, const ParsedAttr &AL) {1310// Check the attribute arguments.1311if (AL.getNumArgs() > 1) {1312Diag(AL.getLoc(), diag::err_attribute_too_many_arguments) << AL << 1;1313return;1314}13151316StringRef Str;1317SourceLocation ArgLoc;13181319if (AL.getNumArgs() == 0)1320Str = "";1321else if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))1322return;13231324ARMInterruptAttr::InterruptType Kind;1325if (!ARMInterruptAttr::ConvertStrToInterruptType(Str, Kind)) {1326Diag(AL.getLoc(), diag::warn_attribute_type_not_supported)1327<< AL << Str << ArgLoc;1328return;1329}13301331const TargetInfo &TI = getASTContext().getTargetInfo();1332if (TI.hasFeature("vfp"))1333Diag(D->getLocation(), diag::warn_arm_interrupt_vfp_clobber);13341335D->addAttr(::new (getASTContext())1336ARMInterruptAttr(getASTContext(), AL, Kind));1337}13381339} // namespace clang134013411342