diff options
author | Vlad Serebrennikov <serebrennikov.vladislav@gmail.com> | 2024-05-30 19:59:59 +0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-05-30 19:59:59 +0400 |
commit | ed35a92c404650b15a79ff38bcaff41de176cb78 (patch) | |
tree | fcf0585c3659ce41e6c6efb78f2c52e7f5dfe320 /clang/lib/Sema/SemaChecking.cpp | |
parent | b62ba7f5b1caf99a3cbbe06d0e1c788c2dc85416 (diff) | |
download | llvm-ed35a92c404650b15a79ff38bcaff41de176cb78.zip llvm-ed35a92c404650b15a79ff38bcaff41de176cb78.tar.gz llvm-ed35a92c404650b15a79ff38bcaff41de176cb78.tar.bz2 |
[clang] Introduce target-specific `Sema` components (#93179)
This patch introduces `SemaAMDGPU`, `SemaARM`, `SemaBPF`, `SemaHexagon`,
`SemaLoongArch`, `SemaMIPS`, `SemaNVPTX`, `SemaPPC`, `SemaSystemZ`,
`SemaWasm`. This continues previous efforts to split Sema up. Additional
context can be found in #84184 and #92682.
I decided to bundle target-specific components together because of their
low impact on `Sema`. That said, their impact on `SemaChecking.cpp` is
far from low, and I consider it a success.
Somewhat accidentally, I also moved Wasm- and AMDGPU-specific function
from `SemaDeclAttr.cpp`, because they were exposed in `Sema`. That went
well, and I consider it a success, too. I'd like to move the rest of
static target-specific functions out of `SemaDeclAttr.cpp` like we're
doing with built-ins in `SemaChecking.cpp` .
Diffstat (limited to 'clang/lib/Sema/SemaChecking.cpp')
-rw-r--r-- | clang/lib/Sema/SemaChecking.cpp | 3018 |
1 files changed, 27 insertions, 2991 deletions
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 7ce1486..300af022 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -61,9 +61,19 @@ #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/Sema.h" +#include "clang/Sema/SemaAMDGPU.h" +#include "clang/Sema/SemaARM.h" +#include "clang/Sema/SemaBPF.h" +#include "clang/Sema/SemaHexagon.h" #include "clang/Sema/SemaInternal.h" +#include "clang/Sema/SemaLoongArch.h" +#include "clang/Sema/SemaMIPS.h" +#include "clang/Sema/SemaNVPTX.h" #include "clang/Sema/SemaObjC.h" +#include "clang/Sema/SemaPPC.h" #include "clang/Sema/SemaRISCV.h" +#include "clang/Sema/SemaSystemZ.h" +#include "clang/Sema/SemaWasm.h" #include "clang/Sema/SemaX86.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" @@ -2259,23 +2269,23 @@ bool Sema::CheckTSBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, case llvm::Triple::armeb: case llvm::Triple::thumb: case llvm::Triple::thumbeb: - return CheckARMBuiltinFunctionCall(TI, BuiltinID, TheCall); + return ARM().CheckARMBuiltinFunctionCall(TI, BuiltinID, TheCall); case llvm::Triple::aarch64: case llvm::Triple::aarch64_32: case llvm::Triple::aarch64_be: - return CheckAArch64BuiltinFunctionCall(TI, BuiltinID, TheCall); + return ARM().CheckAArch64BuiltinFunctionCall(TI, BuiltinID, TheCall); case llvm::Triple::bpfeb: case llvm::Triple::bpfel: - return CheckBPFBuiltinFunctionCall(BuiltinID, TheCall); + return BPF().CheckBPFBuiltinFunctionCall(BuiltinID, TheCall); case llvm::Triple::hexagon: - return CheckHexagonBuiltinFunctionCall(BuiltinID, TheCall); + return Hexagon().CheckHexagonBuiltinFunctionCall(BuiltinID, TheCall); case llvm::Triple::mips: case llvm::Triple::mipsel: case llvm::Triple::mips64: case llvm::Triple::mips64el: - return CheckMipsBuiltinFunctionCall(TI, BuiltinID, TheCall); + return MIPS().CheckMipsBuiltinFunctionCall(TI, BuiltinID, TheCall); case llvm::Triple::systemz: - return CheckSystemZBuiltinFunctionCall(BuiltinID, TheCall); + return SystemZ().CheckSystemZBuiltinFunctionCall(BuiltinID, TheCall); case llvm::Triple::x86: case llvm::Triple::x86_64: return X86().CheckBuiltinFunctionCall(TI, BuiltinID, TheCall); @@ -2283,21 +2293,22 @@ bool Sema::CheckTSBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, case llvm::Triple::ppcle: case llvm::Triple::ppc64: case llvm::Triple::ppc64le: - return CheckPPCBuiltinFunctionCall(TI, BuiltinID, TheCall); + return PPC().CheckPPCBuiltinFunctionCall(TI, BuiltinID, TheCall); case llvm::Triple::amdgcn: - return CheckAMDGCNBuiltinFunctionCall(BuiltinID, TheCall); + return AMDGPU().CheckAMDGCNBuiltinFunctionCall(BuiltinID, TheCall); case llvm::Triple::riscv32: case llvm::Triple::riscv64: return RISCV().CheckBuiltinFunctionCall(TI, BuiltinID, TheCall); case llvm::Triple::loongarch32: case llvm::Triple::loongarch64: - return CheckLoongArchBuiltinFunctionCall(TI, BuiltinID, TheCall); + return LoongArch().CheckLoongArchBuiltinFunctionCall(TI, BuiltinID, + TheCall); case llvm::Triple::wasm32: case llvm::Triple::wasm64: - return CheckWebAssemblyBuiltinFunctionCall(TI, BuiltinID, TheCall); + return Wasm().CheckWebAssemblyBuiltinFunctionCall(TI, BuiltinID, TheCall); case llvm::Triple::nvptx: case llvm::Triple::nvptx64: - return CheckNVPTXBuiltinFunctionCall(TI, BuiltinID, TheCall); + return NVPTX().CheckNVPTXBuiltinFunctionCall(TI, BuiltinID, TheCall); } } @@ -3287,1982 +3298,6 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, return TheCallResult; } -// Get the valid immediate range for the specified NEON type code. -static unsigned RFT(unsigned t, bool shift = false, bool ForceQuad = false) { - NeonTypeFlags Type(t); - int IsQuad = ForceQuad ? true : Type.isQuad(); - switch (Type.getEltType()) { - case NeonTypeFlags::Int8: - case NeonTypeFlags::Poly8: - return shift ? 7 : (8 << IsQuad) - 1; - case NeonTypeFlags::Int16: - case NeonTypeFlags::Poly16: - return shift ? 15 : (4 << IsQuad) - 1; - case NeonTypeFlags::Int32: - return shift ? 31 : (2 << IsQuad) - 1; - case NeonTypeFlags::Int64: - case NeonTypeFlags::Poly64: - return shift ? 63 : (1 << IsQuad) - 1; - case NeonTypeFlags::Poly128: - return shift ? 127 : (1 << IsQuad) - 1; - case NeonTypeFlags::Float16: - assert(!shift && "cannot shift float types!"); - return (4 << IsQuad) - 1; - case NeonTypeFlags::Float32: - assert(!shift && "cannot shift float types!"); - return (2 << IsQuad) - 1; - case NeonTypeFlags::Float64: - assert(!shift && "cannot shift float types!"); - return (1 << IsQuad) - 1; - case NeonTypeFlags::BFloat16: - assert(!shift && "cannot shift float types!"); - return (4 << IsQuad) - 1; - } - llvm_unreachable("Invalid NeonTypeFlag!"); -} - -/// getNeonEltType - Return the QualType corresponding to the elements of -/// the vector type specified by the NeonTypeFlags. This is used to check -/// the pointer arguments for Neon load/store intrinsics. -static QualType getNeonEltType(NeonTypeFlags Flags, ASTContext &Context, - bool IsPolyUnsigned, bool IsInt64Long) { - switch (Flags.getEltType()) { - case NeonTypeFlags::Int8: - return Flags.isUnsigned() ? Context.UnsignedCharTy : Context.SignedCharTy; - case NeonTypeFlags::Int16: - return Flags.isUnsigned() ? Context.UnsignedShortTy : Context.ShortTy; - case NeonTypeFlags::Int32: - return Flags.isUnsigned() ? Context.UnsignedIntTy : Context.IntTy; - case NeonTypeFlags::Int64: - if (IsInt64Long) - return Flags.isUnsigned() ? Context.UnsignedLongTy : Context.LongTy; - else - return Flags.isUnsigned() ? Context.UnsignedLongLongTy - : Context.LongLongTy; - case NeonTypeFlags::Poly8: - return IsPolyUnsigned ? Context.UnsignedCharTy : Context.SignedCharTy; - case NeonTypeFlags::Poly16: - return IsPolyUnsigned ? Context.UnsignedShortTy : Context.ShortTy; - case NeonTypeFlags::Poly64: - if (IsInt64Long) - return Context.UnsignedLongTy; - else - return Context.UnsignedLongLongTy; - case NeonTypeFlags::Poly128: - break; - case NeonTypeFlags::Float16: - return Context.HalfTy; - case NeonTypeFlags::Float32: - return Context.FloatTy; - case NeonTypeFlags::Float64: - return Context.DoubleTy; - case NeonTypeFlags::BFloat16: - return Context.BFloat16Ty; - } - llvm_unreachable("Invalid NeonTypeFlag!"); -} - -enum ArmStreamingType { - ArmNonStreaming, - ArmStreaming, - ArmStreamingCompatible, - ArmStreamingOrSVE2p1 -}; - -enum ArmSMEState : unsigned { - ArmNoState = 0, - - ArmInZA = 0b01, - ArmOutZA = 0b10, - ArmInOutZA = 0b11, - ArmZAMask = 0b11, - - ArmInZT0 = 0b01 << 2, - ArmOutZT0 = 0b10 << 2, - ArmInOutZT0 = 0b11 << 2, - ArmZT0Mask = 0b11 << 2 -}; - -bool Sema::ParseSVEImmChecks( - CallExpr *TheCall, SmallVector<std::tuple<int, int, int>, 3> &ImmChecks) { - // Perform all the immediate checks for this builtin call. - bool HasError = false; - for (auto &I : ImmChecks) { - int ArgNum, CheckTy, ElementSizeInBits; - std::tie(ArgNum, CheckTy, ElementSizeInBits) = I; - - typedef bool (*OptionSetCheckFnTy)(int64_t Value); - - // Function that checks whether the operand (ArgNum) is an immediate - // that is one of the predefined values. - auto CheckImmediateInSet = [&](OptionSetCheckFnTy CheckImm, - int ErrDiag) -> bool { - // We can't check the value of a dependent argument. - Expr *Arg = TheCall->getArg(ArgNum); - if (Arg->isTypeDependent() || Arg->isValueDependent()) - return false; - - // Check constant-ness first. - llvm::APSInt Imm; - if (BuiltinConstantArg(TheCall, ArgNum, Imm)) - return true; - - if (!CheckImm(Imm.getSExtValue())) - return Diag(TheCall->getBeginLoc(), ErrDiag) << Arg->getSourceRange(); - return false; - }; - - switch ((SVETypeFlags::ImmCheckType)CheckTy) { - case SVETypeFlags::ImmCheck0_31: - if (BuiltinConstantArgRange(TheCall, ArgNum, 0, 31)) - HasError = true; - break; - case SVETypeFlags::ImmCheck0_13: - if (BuiltinConstantArgRange(TheCall, ArgNum, 0, 13)) - HasError = true; - break; - case SVETypeFlags::ImmCheck1_16: - if (BuiltinConstantArgRange(TheCall, ArgNum, 1, 16)) - HasError = true; - break; - case SVETypeFlags::ImmCheck0_7: - if (BuiltinConstantArgRange(TheCall, ArgNum, 0, 7)) - HasError = true; - break; - case SVETypeFlags::ImmCheck1_1: - if (BuiltinConstantArgRange(TheCall, ArgNum, 1, 1)) - HasError = true; - break; - case SVETypeFlags::ImmCheck1_3: - if (BuiltinConstantArgRange(TheCall, ArgNum, 1, 3)) - HasError = true; - break; - case SVETypeFlags::ImmCheck1_7: - if (BuiltinConstantArgRange(TheCall, ArgNum, 1, 7)) - HasError = true; - break; - case SVETypeFlags::ImmCheckExtract: - if (BuiltinConstantArgRange(TheCall, ArgNum, 0, - (2048 / ElementSizeInBits) - 1)) - HasError = true; - break; - case SVETypeFlags::ImmCheckShiftRight: - if (BuiltinConstantArgRange(TheCall, ArgNum, 1, ElementSizeInBits)) - HasError = true; - break; - case SVETypeFlags::ImmCheckShiftRightNarrow: - if (BuiltinConstantArgRange(TheCall, ArgNum, 1, ElementSizeInBits / 2)) - HasError = true; - break; - case SVETypeFlags::ImmCheckShiftLeft: - if (BuiltinConstantArgRange(TheCall, ArgNum, 0, ElementSizeInBits - 1)) - HasError = true; - break; - case SVETypeFlags::ImmCheckLaneIndex: - if (BuiltinConstantArgRange(TheCall, ArgNum, 0, - (128 / (1 * ElementSizeInBits)) - 1)) - HasError = true; - break; - case SVETypeFlags::ImmCheckLaneIndexCompRotate: - if (BuiltinConstantArgRange(TheCall, ArgNum, 0, - (128 / (2 * ElementSizeInBits)) - 1)) - HasError = true; - break; - case SVETypeFlags::ImmCheckLaneIndexDot: - if (BuiltinConstantArgRange(TheCall, ArgNum, 0, - (128 / (4 * ElementSizeInBits)) - 1)) - HasError = true; - break; - case SVETypeFlags::ImmCheckComplexRot90_270: - if (CheckImmediateInSet([](int64_t V) { return V == 90 || V == 270; }, - diag::err_rotation_argument_to_cadd)) - HasError = true; - break; - case SVETypeFlags::ImmCheckComplexRotAll90: - if (CheckImmediateInSet( - [](int64_t V) { - return V == 0 || V == 90 || V == 180 || V == 270; - }, - diag::err_rotation_argument_to_cmla)) - HasError = true; - break; - case SVETypeFlags::ImmCheck0_1: - if (BuiltinConstantArgRange(TheCall, ArgNum, 0, 1)) - HasError = true; - break; - case SVETypeFlags::ImmCheck0_2: - if (BuiltinConstantArgRange(TheCall, ArgNum, 0, 2)) - HasError = true; - break; - case SVETypeFlags::ImmCheck0_3: - if (BuiltinConstantArgRange(TheCall, ArgNum, 0, 3)) - HasError = true; - break; - case SVETypeFlags::ImmCheck0_0: - if (BuiltinConstantArgRange(TheCall, ArgNum, 0, 0)) - HasError = true; - break; - case SVETypeFlags::ImmCheck0_15: - if (BuiltinConstantArgRange(TheCall, ArgNum, 0, 15)) - HasError = true; - break; - case SVETypeFlags::ImmCheck0_255: - if (BuiltinConstantArgRange(TheCall, ArgNum, 0, 255)) - HasError = true; - break; - case SVETypeFlags::ImmCheck2_4_Mul2: - if (BuiltinConstantArgRange(TheCall, ArgNum, 2, 4) || - BuiltinConstantArgMultiple(TheCall, ArgNum, 2)) - HasError = true; - break; - } - } - - return HasError; -} - -static ArmStreamingType getArmStreamingFnType(const FunctionDecl *FD) { - if (FD->hasAttr<ArmLocallyStreamingAttr>()) - return ArmStreaming; - if (const Type *Ty = FD->getType().getTypePtrOrNull()) { - if (const auto *FPT = Ty->getAs<FunctionProtoType>()) { - if (FPT->getAArch64SMEAttributes() & - FunctionType::SME_PStateSMEnabledMask) - return ArmStreaming; - if (FPT->getAArch64SMEAttributes() & - FunctionType::SME_PStateSMCompatibleMask) - return ArmStreamingCompatible; - } - } - return ArmNonStreaming; -} - -static void checkArmStreamingBuiltin(Sema &S, CallExpr *TheCall, - const FunctionDecl *FD, - ArmStreamingType BuiltinType) { - ArmStreamingType FnType = getArmStreamingFnType(FD); - if (BuiltinType == ArmStreamingOrSVE2p1) { - // Check intrinsics that are available in [sve2p1 or sme/sme2]. - llvm::StringMap<bool> CallerFeatureMap; - S.Context.getFunctionFeatureMap(CallerFeatureMap, FD); - if (Builtin::evaluateRequiredTargetFeatures("sve2p1", CallerFeatureMap)) - BuiltinType = ArmStreamingCompatible; - else - BuiltinType = ArmStreaming; - } - - if (FnType == ArmStreaming && BuiltinType == ArmNonStreaming) - S.Diag(TheCall->getBeginLoc(), diag::warn_attribute_arm_sm_incompat_builtin) - << TheCall->getSourceRange() << "streaming"; - else if (FnType == ArmNonStreaming && BuiltinType == ArmStreaming) - S.Diag(TheCall->getBeginLoc(), diag::warn_attribute_arm_sm_incompat_builtin) - << TheCall->getSourceRange() << "non-streaming"; - else if (FnType == ArmStreamingCompatible && - BuiltinType != ArmStreamingCompatible) - S.Diag(TheCall->getBeginLoc(), diag::warn_attribute_arm_sm_incompat_builtin) - << TheCall->getSourceRange() << "streaming compatible"; -} - -static bool hasArmZAState(const FunctionDecl *FD) { - const auto *T = FD->getType()->getAs<FunctionProtoType>(); - return (T && FunctionType::getArmZAState(T->getAArch64SMEAttributes()) != - FunctionType::ARM_None) || - (FD->hasAttr<ArmNewAttr>() && FD->getAttr<ArmNewAttr>()->isNewZA()); -} - -static bool hasArmZT0State(const FunctionDecl *FD) { - const auto *T = FD->getType()->getAs<FunctionProtoType>(); - return (T && FunctionType::getArmZT0State(T->getAArch64SMEAttributes()) != - FunctionType::ARM_None) || - (FD->hasAttr<ArmNewAttr>() && FD->getAttr<ArmNewAttr>()->isNewZT0()); -} - -static ArmSMEState getSMEState(unsigned BuiltinID) { - switch (BuiltinID) { - default: - return ArmNoState; -#define GET_SME_BUILTIN_GET_STATE -#include "clang/Basic/arm_sme_builtins_za_state.inc" -#undef GET_SME_BUILTIN_GET_STATE - } -} - -bool Sema::CheckSMEBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { - if (const FunctionDecl *FD = getCurFunctionDecl()) { - std::optional<ArmStreamingType> BuiltinType; - - switch (BuiltinID) { -#define GET_SME_STREAMING_ATTRS -#include "clang/Basic/arm_sme_streaming_attrs.inc" -#undef GET_SME_STREAMING_ATTRS - } - - if (BuiltinType) - checkArmStreamingBuiltin(*this, TheCall, FD, *BuiltinType); - - if ((getSMEState(BuiltinID) & ArmZAMask) && !hasArmZAState(FD)) - Diag(TheCall->getBeginLoc(), - diag::warn_attribute_arm_za_builtin_no_za_state) - << TheCall->getSourceRange(); - - if ((getSMEState(BuiltinID) & ArmZT0Mask) && !hasArmZT0State(FD)) - Diag(TheCall->getBeginLoc(), - diag::warn_attribute_arm_zt0_builtin_no_zt0_state) - << TheCall->getSourceRange(); - } - - // Range check SME intrinsics that take immediate values. - SmallVector<std::tuple<int, int, int>, 3> ImmChecks; - - switch (BuiltinID) { - default: - return false; -#define GET_SME_IMMEDIATE_CHECK -#include "clang/Basic/arm_sme_sema_rangechecks.inc" -#undef GET_SME_IMMEDIATE_CHECK - } - - return ParseSVEImmChecks(TheCall, ImmChecks); -} - -bool Sema::CheckSVEBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { - if (const FunctionDecl *FD = getCurFunctionDecl()) { - std::optional<ArmStreamingType> BuiltinType; - - switch (BuiltinID) { -#define GET_SVE_STREAMING_ATTRS -#include "clang/Basic/arm_sve_streaming_attrs.inc" -#undef GET_SVE_STREAMING_ATTRS - } - if (BuiltinType) - checkArmStreamingBuiltin(*this, TheCall, FD, *BuiltinType); - } - // Range check SVE intrinsics that take immediate values. - SmallVector<std::tuple<int, int, int>, 3> ImmChecks; - - switch (BuiltinID) { - default: - return false; -#define GET_SVE_IMMEDIATE_CHECK -#include "clang/Basic/arm_sve_sema_rangechecks.inc" -#undef GET_SVE_IMMEDIATE_CHECK - } - - return ParseSVEImmChecks(TheCall, ImmChecks); -} - -bool Sema::CheckNeonBuiltinFunctionCall(const TargetInfo &TI, - unsigned BuiltinID, CallExpr *TheCall) { - if (const FunctionDecl *FD = getCurFunctionDecl()) { - - switch (BuiltinID) { - default: - break; -#define GET_NEON_BUILTINS -#define TARGET_BUILTIN(id, ...) case NEON::BI##id: -#define BUILTIN(id, ...) case NEON::BI##id: -#include "clang/Basic/arm_neon.inc" - checkArmStreamingBuiltin(*this, TheCall, FD, ArmNonStreaming); - break; -#undef TARGET_BUILTIN -#undef BUILTIN -#undef GET_NEON_BUILTINS - } - } - - llvm::APSInt Result; - uint64_t mask = 0; - unsigned TV = 0; - int PtrArgNum = -1; - bool HasConstPtr = false; - switch (BuiltinID) { -#define GET_NEON_OVERLOAD_CHECK -#include "clang/Basic/arm_neon.inc" -#include "clang/Basic/arm_fp16.inc" -#undef GET_NEON_OVERLOAD_CHECK - } - - // For NEON intrinsics which are overloaded on vector element type, validate - // the immediate which specifies which variant to emit. - unsigned ImmArg = TheCall->getNumArgs()-1; - if (mask) { - if (BuiltinConstantArg(TheCall, ImmArg, Result)) - return true; - - TV = Result.getLimitedValue(64); - if ((TV > 63) || (mask & (1ULL << TV)) == 0) - return Diag(TheCall->getBeginLoc(), diag::err_invalid_neon_type_code) - << TheCall->getArg(ImmArg)->getSourceRange(); - } - - if (PtrArgNum >= 0) { - // Check that pointer arguments have the specified type. - Expr *Arg = TheCall->getArg(PtrArgNum); - if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) - Arg = ICE->getSubExpr(); - ExprResult RHS = DefaultFunctionArrayLvalueConversion(Arg); - QualType RHSTy = RHS.get()->getType(); - - llvm::Triple::ArchType Arch = TI.getTriple().getArch(); - bool IsPolyUnsigned = Arch == llvm::Triple::aarch64 || - Arch == llvm::Triple::aarch64_32 || - Arch == llvm::Triple::aarch64_be; - bool IsInt64Long = TI.getInt64Type() == TargetInfo::SignedLong; - QualType EltTy = - getNeonEltType(NeonTypeFlags(TV), Context, IsPolyUnsigned, IsInt64Long); - if (HasConstPtr) - EltTy = EltTy.withConst(); - QualType LHSTy = Context.getPointerType(EltTy); - AssignConvertType ConvTy; - ConvTy = CheckSingleAssignmentConstraints(LHSTy, RHS); - if (RHS.isInvalid()) - return true; - if (DiagnoseAssignmentResult(ConvTy, Arg->getBeginLoc(), LHSTy, RHSTy, - RHS.get(), AA_Assigning)) - return true; - } - - // For NEON intrinsics which take an immediate value as part of the - // instruction, range check them here. - unsigned i = 0, l = 0, u = 0; - switch (BuiltinID) { - default: - return false; - #define GET_NEON_IMMEDIATE_CHECK - #include "clang/Basic/arm_neon.inc" - #include "clang/Basic/arm_fp16.inc" - #undef GET_NEON_IMMEDIATE_CHECK - } - - return BuiltinConstantArgRange(TheCall, i, l, u + l); -} - -bool Sema::CheckMVEBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { - switch (BuiltinID) { - default: - return false; - #include "clang/Basic/arm_mve_builtin_sema.inc" - } -} - -bool Sema::CheckCDEBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, - CallExpr *TheCall) { - bool Err = false; - switch (BuiltinID) { - default: - return false; -#include "clang/Basic/arm_cde_builtin_sema.inc" - } - - if (Err) - return true; - - return CheckARMCoprocessorImmediate(TI, TheCall->getArg(0), /*WantCDE*/ true); -} - -bool Sema::CheckARMCoprocessorImmediate(const TargetInfo &TI, - const Expr *CoprocArg, bool WantCDE) { - if (isConstantEvaluatedContext()) - return false; - - // We can't check the value of a dependent argument. - if (CoprocArg->isTypeDependent() || CoprocArg->isValueDependent()) - return false; - - llvm::APSInt CoprocNoAP = *CoprocArg->getIntegerConstantExpr(Context); - int64_t CoprocNo = CoprocNoAP.getExtValue(); - assert(CoprocNo >= 0 && "Coprocessor immediate must be non-negative"); - - uint32_t CDECoprocMask = TI.getARMCDECoprocMask(); - bool IsCDECoproc = CoprocNo <= 7 && (CDECoprocMask & (1 << CoprocNo)); - - if (IsCDECoproc != WantCDE) - return Diag(CoprocArg->getBeginLoc(), diag::err_arm_invalid_coproc) - << (int)CoprocNo << (int)WantCDE << CoprocArg->getSourceRange(); - - return false; -} - -bool Sema::CheckARMBuiltinExclusiveCall(unsigned BuiltinID, CallExpr *TheCall, - unsigned MaxWidth) { - assert((BuiltinID == ARM::BI__builtin_arm_ldrex || - BuiltinID == ARM::BI__builtin_arm_ldaex || - BuiltinID == ARM::BI__builtin_arm_strex || - BuiltinID == ARM::BI__builtin_arm_stlex || - BuiltinID == AArch64::BI__builtin_arm_ldrex || - BuiltinID == AArch64::BI__builtin_arm_ldaex || - BuiltinID == AArch64::BI__builtin_arm_strex || - BuiltinID == AArch64::BI__builtin_arm_stlex) && - "unexpected ARM builtin"); - bool IsLdrex = BuiltinID == ARM::BI__builtin_arm_ldrex || - BuiltinID == ARM::BI__builtin_arm_ldaex || - BuiltinID == AArch64::BI__builtin_arm_ldrex || - BuiltinID == AArch64::BI__builtin_arm_ldaex; - - DeclRefExpr *DRE =cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts()); - - // Ensure that we have the proper number of arguments. - if (checkArgCount(TheCall, IsLdrex ? 1 : 2)) - return true; - - // Inspect the pointer argument of the atomic builtin. This should always be - // a pointer type, whose element is an integral scalar or pointer type. - // Because it is a pointer type, we don't have to worry about any implicit - // casts here. - Expr *PointerArg = TheCall->getArg(IsLdrex ? 0 : 1); - ExprResult PointerArgRes = DefaultFunctionArrayLvalueConversion(PointerArg); - if (PointerArgRes.isInvalid()) - return true; - PointerArg = PointerArgRes.get(); - - const PointerType *pointerType = PointerArg->getType()->getAs<PointerType>(); - if (!pointerType) { - Diag(DRE->getBeginLoc(), diag::err_atomic_builtin_must_be_pointer) - << PointerArg->getType() << 0 << PointerArg->getSourceRange(); - return true; - } - - // ldrex takes a "const volatile T*" and strex takes a "volatile T*". Our next - // task is to insert the appropriate casts into the AST. First work out just - // what the appropriate type is. - QualType ValType = pointerType->getPointeeType(); - QualType AddrType = ValType.getUnqualifiedType().withVolatile(); - if (IsLdrex) - AddrType.addConst(); - - // Issue a warning if the cast is dodgy. - CastKind CastNeeded = CK_NoOp; - if (!AddrType.isAtLeastAsQualifiedAs(ValType)) { - CastNeeded = CK_BitCast; - Diag(DRE->getBeginLoc(), diag::ext_typecheck_convert_discards_qualifiers) - << PointerArg->getType() << Context.getPointerType(AddrType) - << AA_Passing << PointerArg->getSourceRange(); - } - - // Finally, do the cast and replace the argument with the corrected version. - AddrType = Context.getPointerType(AddrType); - PointerArgRes = ImpCastExprToType(PointerArg, AddrType, CastNeeded); - if (PointerArgRes.isInvalid()) - return true; - PointerArg = PointerArgRes.get(); - - TheCall->setArg(IsLdrex ? 0 : 1, PointerArg); - - // In general, we allow ints, floats and pointers to be loaded and stored. - if (!ValType->isIntegerType() && !ValType->isAnyPointerType() && - !ValType->isBlockPointerType() && !ValType->isFloatingType()) { - Diag(DRE->getBeginLoc(), diag::err_atomic_builtin_must_be_pointer_intfltptr) - << PointerArg->getType() << 0 << PointerArg->getSourceRange(); - return true; - } - - // But ARM doesn't have instructions to deal with 128-bit versions. - if (Context.getTypeSize(ValType) > MaxWidth) { - assert(MaxWidth == 64 && "Diagnostic unexpectedly inaccurate"); - Diag(DRE->getBeginLoc(), diag::err_atomic_exclusive_builtin_pointer_size) - << PointerArg->getType() << PointerArg->getSourceRange(); - return true; - } - - switch (ValType.getObjCLifetime()) { - case Qualifiers::OCL_None: - case Qualifiers::OCL_ExplicitNone: - // okay - break; - - case Qualifiers::OCL_Weak: - case Qualifiers::OCL_Strong: - case Qualifiers::OCL_Autoreleasing: - Diag(DRE->getBeginLoc(), diag::err_arc_atomic_ownership) - << ValType << PointerArg->getSourceRange(); - return true; - } - - if (IsLdrex) { - TheCall->setType(ValType); - return false; - } - - // Initialize the argument to be stored. - ExprResult ValArg = TheCall->getArg(0); - InitializedEntity Entity = InitializedEntity::InitializeParameter( - Context, ValType, /*consume*/ false); - ValArg = PerformCopyInitialization(Entity, SourceLocation(), ValArg); - if (ValArg.isInvalid()) - return true; - TheCall->setArg(0, ValArg.get()); - - // __builtin_arm_strex always returns an int. It's marked as such in the .def, - // but the custom checker bypasses all default analysis. - TheCall->setType(Context.IntTy); - return false; -} - -bool Sema::CheckARMBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, - CallExpr *TheCall) { - if (BuiltinID == ARM::BI__builtin_arm_ldrex || - BuiltinID == ARM::BI__builtin_arm_ldaex || - BuiltinID == ARM::BI__builtin_arm_strex || - BuiltinID == ARM::BI__builtin_arm_stlex) { - return CheckARMBuiltinExclusiveCall(BuiltinID, TheCall, 64); - } - - if (BuiltinID == ARM::BI__builtin_arm_prefetch) { - return BuiltinConstantArgRange(TheCall, 1, 0, 1) || - BuiltinConstantArgRange(TheCall, 2, 0, 1); - } - - if (BuiltinID == ARM::BI__builtin_arm_rsr64 || - BuiltinID == ARM::BI__builtin_arm_wsr64) - return BuiltinARMSpecialReg(BuiltinID, TheCall, 0, 3, false); - - if (BuiltinID == ARM::BI__builtin_arm_rsr || - BuiltinID == ARM::BI__builtin_arm_rsrp || - BuiltinID == ARM::BI__builtin_arm_wsr || - BuiltinID == ARM::BI__builtin_arm_wsrp) - return BuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true); - - if (CheckNeonBuiltinFunctionCall(TI, BuiltinID, TheCall)) - return true; - if (CheckMVEBuiltinFunctionCall(BuiltinID, TheCall)) - return true; - if (CheckCDEBuiltinFunctionCall(TI, BuiltinID, TheCall)) - return true; - - // For intrinsics which take an immediate value as part of the instruction, - // range check them here. - // FIXME: VFP Intrinsics should error if VFP not present. - switch (BuiltinID) { - default: return false; - case ARM::BI__builtin_arm_ssat: - return BuiltinConstantArgRange(TheCall, 1, 1, 32); - case ARM::BI__builtin_arm_usat: - return BuiltinConstantArgRange(TheCall, 1, 0, 31); - case ARM::BI__builtin_arm_ssat16: - return BuiltinConstantArgRange(TheCall, 1, 1, 16); - case ARM::BI__builtin_arm_usat16: - return BuiltinConstantArgRange(TheCall, 1, 0, 15); - case ARM::BI__builtin_arm_vcvtr_f: - case ARM::BI__builtin_arm_vcvtr_d: - return BuiltinConstantArgRange(TheCall, 1, 0, 1); - case ARM::BI__builtin_arm_dmb: - case ARM::BI__builtin_arm_dsb: - case ARM::BI__builtin_arm_isb: - case ARM::BI__builtin_arm_dbg: - return BuiltinConstantArgRange(TheCall, 0, 0, 15); - case ARM::BI__builtin_arm_cdp: - case ARM::BI__builtin_arm_cdp2: - case ARM::BI__builtin_arm_mcr: - case ARM::BI__builtin_arm_mcr2: - case ARM::BI__builtin_arm_mrc: - case ARM::BI__builtin_arm_mrc2: - case ARM::BI__builtin_arm_mcrr: - case ARM::BI__builtin_arm_mcrr2: - case ARM::BI__builtin_arm_mrrc: - case ARM::BI__builtin_arm_mrrc2: - case ARM::BI__builtin_arm_ldc: - case ARM::BI__builtin_arm_ldcl: - case ARM::BI__builtin_arm_ldc2: - case ARM::BI__builtin_arm_ldc2l: - case ARM::BI__builtin_arm_stc: - case ARM::BI__builtin_arm_stcl: - case ARM::BI__builtin_arm_stc2: - case ARM::BI__builtin_arm_stc2l: - return BuiltinConstantArgRange(TheCall, 0, 0, 15) || - CheckARMCoprocessorImmediate(TI, TheCall->getArg(0), - /*WantCDE*/ false); - } -} - -bool Sema::CheckAArch64BuiltinFunctionCall(const TargetInfo &TI, - unsigned BuiltinID, - CallExpr *TheCall) { - if (BuiltinID == AArch64::BI__builtin_arm_ldrex || - BuiltinID == AArch64::BI__builtin_arm_ldaex || - BuiltinID == AArch64::BI__builtin_arm_strex || - BuiltinID == AArch64::BI__builtin_arm_stlex) { - return CheckARMBuiltinExclusiveCall(BuiltinID, TheCall, 128); - } - - if (BuiltinID == AArch64::BI__builtin_arm_prefetch) { - return BuiltinConstantArgRange(TheCall, 1, 0, 1) || - BuiltinConstantArgRange(TheCall, 2, 0, 3) || - BuiltinConstantArgRange(TheCall, 3, 0, 1) || - BuiltinConstantArgRange(TheCall, 4, 0, 1); - } - - if (BuiltinID == AArch64::BI__builtin_arm_rsr64 || - BuiltinID == AArch64::BI__builtin_arm_wsr64 || - BuiltinID == AArch64::BI__builtin_arm_rsr128 || - BuiltinID == AArch64::BI__builtin_arm_wsr128) - return BuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true); - - // Memory Tagging Extensions (MTE) Intrinsics - if (BuiltinID == AArch64::BI__builtin_arm_irg || - BuiltinID == AArch64::BI__builtin_arm_addg || - BuiltinID == AArch64::BI__builtin_arm_gmi || - BuiltinID == AArch64::BI__builtin_arm_ldg || - BuiltinID == AArch64::BI__builtin_arm_stg || - BuiltinID == AArch64::BI__builtin_arm_subp) { - return BuiltinARMMemoryTaggingCall(BuiltinID, TheCall); - } - - if (BuiltinID == AArch64::BI__builtin_arm_rsr || - BuiltinID == AArch64::BI__builtin_arm_rsrp || - BuiltinID == AArch64::BI__builtin_arm_wsr || - BuiltinID == AArch64::BI__builtin_arm_wsrp) - return BuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true); - - // Only check the valid encoding range. Any constant in this range would be - // converted to a register of the form S1_2_C3_C4_5. Let the hardware throw - // an exception for incorrect registers. This matches MSVC behavior. - if (BuiltinID == AArch64::BI_ReadStatusReg || - BuiltinID == AArch64::BI_WriteStatusReg) - return BuiltinConstantArgRange(TheCall, 0, 0, 0x7fff); - - if (BuiltinID == AArch64::BI__getReg) - return BuiltinConstantArgRange(TheCall, 0, 0, 31); - - if (BuiltinID == AArch64::BI__break) - return BuiltinConstantArgRange(TheCall, 0, 0, 0xffff); - - if (CheckNeonBuiltinFunctionCall(TI, BuiltinID, TheCall)) - return true; - - if (CheckSVEBuiltinFunctionCall(BuiltinID, TheCall)) - return true; - - if (CheckSMEBuiltinFunctionCall(BuiltinID, TheCall)) - return true; - - // For intrinsics which take an immediate value as part of the instruction, - // range check them here. - unsigned i = 0, l = 0, u = 0; - switch (BuiltinID) { - default: return false; - case AArch64::BI__builtin_arm_dmb: - case AArch64::BI__builtin_arm_dsb: - case AArch64::BI__builtin_arm_isb: l = 0; u = 15; break; - case AArch64::BI__builtin_arm_tcancel: l = 0; u = 65535; break; - } - - return BuiltinConstantArgRange(TheCall, i, l, u + l); -} - -static bool isValidBPFPreserveFieldInfoArg(Expr *Arg) { - if (Arg->getType()->getAsPlaceholderType()) - return false; - - // The first argument needs to be a record field access. - // If it is an array element access, we delay decision - // to BPF backend to check whether the access is a - // field access or not. - return (Arg->IgnoreParens()->getObjectKind() == OK_BitField || - isa<MemberExpr>(Arg->IgnoreParens()) || - isa<ArraySubscriptExpr>(Arg->IgnoreParens())); -} - -static bool isValidBPFPreserveTypeInfoArg(Expr *Arg) { - QualType ArgType = Arg->getType(); - if (ArgType->getAsPlaceholderType()) - return false; - - // for TYPE_EXISTENCE/TYPE_MATCH/TYPE_SIZEOF reloc type - // format: - // 1. __builtin_preserve_type_info(*(<type> *)0, flag); - // 2. <type> var; - // __builtin_preserve_type_info(var, flag); - if (!isa<DeclRefExpr>(Arg->IgnoreParens()) && - !isa<UnaryOperator>(Arg->IgnoreParens())) - return false; - - // Typedef type. - if (ArgType->getAs<TypedefType>()) - return true; - - // Record type or Enum type. - const Type *Ty = ArgType->getUnqualifiedDesugaredType(); - if (const auto *RT = Ty->getAs<RecordType>()) { - if (!RT->getDecl()->getDeclName().isEmpty()) - return true; - } else if (const auto *ET = Ty->getAs<EnumType>()) { - if (!ET->getDecl()->getDeclName().isEmpty()) - return true; - } - - return false; -} - -static bool isValidBPFPreserveEnumValueArg(Expr *Arg) { - QualType ArgType = Arg->getType(); - if (ArgType->getAsPlaceholderType()) - return false; - - // for ENUM_VALUE_EXISTENCE/ENUM_VALUE reloc type - // format: - // __builtin_preserve_enum_value(*(<enum_type> *)<enum_value>, - // flag); - const auto *UO = dyn_cast<UnaryOperator>(Arg->IgnoreParens()); - if (!UO) - return false; - - const auto *CE = dyn_cast<CStyleCastExpr>(UO->getSubExpr()); - if (!CE) - return false; - if (CE->getCastKind() != CK_IntegralToPointer && - CE->getCastKind() != CK_NullToPointer) - return false; - - // The integer must be from an EnumConstantDecl. - const auto *DR = dyn_cast<DeclRefExpr>(CE->getSubExpr()); - if (!DR) - return false; - - const EnumConstantDecl *Enumerator = - dyn_cast<EnumConstantDecl>(DR->getDecl()); - if (!Enumerator) - return false; - - // The type must be EnumType. - const Type *Ty = ArgType->getUnqualifiedDesugaredType(); - const auto *ET = Ty->getAs<EnumType>(); - if (!ET) - return false; - - // The enum value must be supported. - return llvm::is_contained(ET->getDecl()->enumerators(), Enumerator); -} - -bool Sema::CheckBPFBuiltinFunctionCall(unsigned BuiltinID, - CallExpr *TheCall) { - assert((BuiltinID == BPF::BI__builtin_preserve_field_info || - BuiltinID == BPF::BI__builtin_btf_type_id || - BuiltinID == BPF::BI__builtin_preserve_type_info || - BuiltinID == BPF::BI__builtin_preserve_enum_value) && - "unexpected BPF builtin"); - - if (checkArgCount(TheCall, 2)) - return true; - - // The second argument needs to be a constant int - Expr *Arg = TheCall->getArg(1); - std::optional<llvm::APSInt> Value = Arg->getIntegerConstantExpr(Context); - diag::kind kind; - if (!Value) { - if (BuiltinID == BPF::BI__builtin_preserve_field_info) - kind = diag::err_preserve_field_info_not_const; - else if (BuiltinID == BPF::BI__builtin_btf_type_id) - kind = diag::err_btf_type_id_not_const; - else if (BuiltinID == BPF::BI__builtin_preserve_type_info) - kind = diag::err_preserve_type_info_not_const; - else - kind = diag::err_preserve_enum_value_not_const; - Diag(Arg->getBeginLoc(), kind) << 2 << Arg->getSourceRange(); - return true; - } - - // The first argument - Arg = TheCall->getArg(0); - bool InvalidArg = false; - bool ReturnUnsignedInt = true; - if (BuiltinID == BPF::BI__builtin_preserve_field_info) { - if (!isValidBPFPreserveFieldInfoArg(Arg)) { - InvalidArg = true; - kind = diag::err_preserve_field_info_not_field; - } - } else if (BuiltinID == BPF::BI__builtin_preserve_type_info) { - if (!isValidBPFPreserveTypeInfoArg(Arg)) { - InvalidArg = true; - kind = diag::err_preserve_type_info_invalid; - } - } else if (BuiltinID == BPF::BI__builtin_preserve_enum_value) { - if (!isValidBPFPreserveEnumValueArg(Arg)) { - InvalidArg = true; - kind = diag::err_preserve_enum_value_invalid; - } - ReturnUnsignedInt = false; - } else if (BuiltinID == BPF::BI__builtin_btf_type_id) { - ReturnUnsignedInt = false; - } - - if (InvalidArg) { - Diag(Arg->getBeginLoc(), kind) << 1 << Arg->getSourceRange(); - return true; - } - - if (ReturnUnsignedInt) - TheCall->setType(Context.UnsignedIntTy); - else - TheCall->setType(Context.UnsignedLongTy); - return false; -} - -bool Sema::CheckHexagonBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall) { - struct ArgInfo { - uint8_t OpNum; - bool IsSigned; - uint8_t BitWidth; - uint8_t Align; - }; - struct BuiltinInfo { - unsigned BuiltinID; - ArgInfo Infos[2]; - }; - - static BuiltinInfo Infos[] = { - { Hexagon::BI__builtin_circ_ldd, {{ 3, true, 4, 3 }} }, - { Hexagon::BI__builtin_circ_ldw, {{ 3, true, 4, 2 }} }, - { Hexagon::BI__builtin_circ_ldh, {{ 3, true, 4, 1 }} }, - { Hexagon::BI__builtin_circ_lduh, {{ 3, true, 4, 1 }} }, - { Hexagon::BI__builtin_circ_ldb, {{ 3, true, 4, 0 }} }, - { Hexagon::BI__builtin_circ_ldub, {{ 3, true, 4, 0 }} }, - { Hexagon::BI__builtin_circ_std, {{ 3, true, 4, 3 }} }, - { Hexagon::BI__builtin_circ_stw, {{ 3, true, 4, 2 }} }, - { Hexagon::BI__builtin_circ_sth, {{ 3, true, 4, 1 }} }, - { Hexagon::BI__builtin_circ_sthhi, {{ 3, true, 4, 1 }} }, - { Hexagon::BI__builtin_circ_stb, {{ 3, true, 4, 0 }} }, - - { Hexagon::BI__builtin_HEXAGON_L2_loadrub_pci, {{ 1, true, 4, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_L2_loadrb_pci, {{ 1, true, 4, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_L2_loadruh_pci, {{ 1, true, 4, 1 }} }, - { Hexagon::BI__builtin_HEXAGON_L2_loadrh_pci, {{ 1, true, 4, 1 }} }, - { Hexagon::BI__builtin_HEXAGON_L2_loadri_pci, {{ 1, true, 4, 2 }} }, - { Hexagon::BI__builtin_HEXAGON_L2_loadrd_pci, {{ 1, true, 4, 3 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_storerb_pci, {{ 1, true, 4, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_storerh_pci, {{ 1, true, 4, 1 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_storerf_pci, {{ 1, true, 4, 1 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_storeri_pci, {{ 1, true, 4, 2 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_storerd_pci, {{ 1, true, 4, 3 }} }, - - { Hexagon::BI__builtin_HEXAGON_A2_combineii, {{ 1, true, 8, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_A2_tfrih, {{ 1, false, 16, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_A2_tfril, {{ 1, false, 16, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_A2_tfrpi, {{ 0, true, 8, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_A4_bitspliti, {{ 1, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_A4_cmpbeqi, {{ 1, false, 8, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_A4_cmpbgti, {{ 1, true, 8, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_A4_cround_ri, {{ 1, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_A4_round_ri, {{ 1, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_A4_round_ri_sat, {{ 1, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_A4_vcmpbeqi, {{ 1, false, 8, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_A4_vcmpbgti, {{ 1, true, 8, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_A4_vcmpbgtui, {{ 1, false, 7, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_A4_vcmpheqi, {{ 1, true, 8, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_A4_vcmphgti, {{ 1, true, 8, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_A4_vcmphgtui, {{ 1, false, 7, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_A4_vcmpweqi, {{ 1, true, 8, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_A4_vcmpwgti, {{ 1, true, 8, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_A4_vcmpwgtui, {{ 1, false, 7, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_C2_bitsclri, {{ 1, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_C2_muxii, {{ 2, true, 8, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_C4_nbitsclri, {{ 1, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_F2_dfclass, {{ 1, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_F2_dfimm_n, {{ 0, false, 10, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_F2_dfimm_p, {{ 0, false, 10, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_F2_sfclass, {{ 1, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_F2_sfimm_n, {{ 0, false, 10, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_F2_sfimm_p, {{ 0, false, 10, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_M4_mpyri_addi, {{ 2, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_M4_mpyri_addr_u2, {{ 1, false, 6, 2 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_addasl_rrri, {{ 2, false, 3, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asl_i_p_acc, {{ 2, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asl_i_p_and, {{ 2, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asl_i_p, {{ 1, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asl_i_p_nac, {{ 2, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asl_i_p_or, {{ 2, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asl_i_p_xacc, {{ 2, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asl_i_r_acc, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asl_i_r_and, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asl_i_r, {{ 1, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asl_i_r_nac, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asl_i_r_or, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asl_i_r_sat, {{ 1, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asl_i_r_xacc, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asl_i_vh, {{ 1, false, 4, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asl_i_vw, {{ 1, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asr_i_p_acc, {{ 2, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asr_i_p_and, {{ 2, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asr_i_p, {{ 1, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asr_i_p_nac, {{ 2, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asr_i_p_or, {{ 2, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asr_i_p_rnd_goodsyntax, - {{ 1, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asr_i_p_rnd, {{ 1, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asr_i_r_acc, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asr_i_r_and, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asr_i_r, {{ 1, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asr_i_r_nac, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asr_i_r_or, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asr_i_r_rnd_goodsyntax, - {{ 1, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asr_i_r_rnd, {{ 1, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asr_i_svw_trun, {{ 1, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asr_i_vh, {{ 1, false, 4, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_asr_i_vw, {{ 1, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_clrbit_i, {{ 1, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_extractu, {{ 1, false, 5, 0 }, - { 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_extractup, {{ 1, false, 6, 0 }, - { 2, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_insert, {{ 2, false, 5, 0 }, - { 3, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_insertp, {{ 2, false, 6, 0 }, - { 3, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_p_acc, {{ 2, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_p_and, {{ 2, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_p, {{ 1, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_p_nac, {{ 2, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_p_or, {{ 2, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_p_xacc, {{ 2, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_r_acc, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_r_and, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_r, {{ 1, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_r_nac, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_r_or, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_r_xacc, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_vh, {{ 1, false, 4, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_vw, {{ 1, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_setbit_i, {{ 1, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_tableidxb_goodsyntax, - {{ 2, false, 4, 0 }, - { 3, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_tableidxd_goodsyntax, - {{ 2, false, 4, 0 }, - { 3, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_tableidxh_goodsyntax, - {{ 2, false, 4, 0 }, - { 3, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_tableidxw_goodsyntax, - {{ 2, false, 4, 0 }, - { 3, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_togglebit_i, {{ 1, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_tstbit_i, {{ 1, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_valignib, {{ 2, false, 3, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S2_vspliceib, {{ 2, false, 3, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S4_addi_asl_ri, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S4_addi_lsr_ri, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S4_andi_asl_ri, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S4_andi_lsr_ri, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S4_clbaddi, {{ 1, true , 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S4_clbpaddi, {{ 1, true, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S4_extract, {{ 1, false, 5, 0 }, - { 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S4_extractp, {{ 1, false, 6, 0 }, - { 2, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S4_lsli, {{ 0, true, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S4_ntstbit_i, {{ 1, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S4_ori_asl_ri, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S4_ori_lsr_ri, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S4_subi_asl_ri, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S4_subi_lsr_ri, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S4_vrcrotate_acc, {{ 3, false, 2, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S4_vrcrotate, {{ 2, false, 2, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S5_asrhub_rnd_sat_goodsyntax, - {{ 1, false, 4, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S5_asrhub_sat, {{ 1, false, 4, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S5_vasrhrnd_goodsyntax, - {{ 1, false, 4, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p, {{ 1, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_acc, {{ 2, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_and, {{ 2, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_nac, {{ 2, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_or, {{ 2, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_xacc, {{ 2, false, 6, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r, {{ 1, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_acc, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_and, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_nac, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_or, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_xacc, {{ 2, false, 5, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_valignbi, {{ 2, false, 3, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_valignbi_128B, {{ 2, false, 3, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_vlalignbi, {{ 2, false, 3, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_vlalignbi_128B, {{ 2, false, 3, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusi, {{ 2, false, 1, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusi_128B, {{ 2, false, 1, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusi_acc, {{ 3, false, 1, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusi_acc_128B, - {{ 3, false, 1, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubi, {{ 2, false, 1, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubi_128B, {{ 2, false, 1, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubi_acc, {{ 3, false, 1, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubi_acc_128B, - {{ 3, false, 1, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_vrsadubi, {{ 2, false, 1, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_vrsadubi_128B, {{ 2, false, 1, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_vrsadubi_acc, {{ 3, false, 1, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_vrsadubi_acc_128B, - {{ 3, false, 1, 0 }} }, - - { Hexagon::BI__builtin_HEXAGON_V6_v6mpyhubs10, {{ 2, false, 2, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_v6mpyhubs10_128B, - {{ 2, false, 2, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_v6mpyhubs10_vxx, - {{ 3, false, 2, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_v6mpyhubs10_vxx_128B, - {{ 3, false, 2, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_v6mpyvubs10, {{ 2, false, 2, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_v6mpyvubs10_128B, - {{ 2, false, 2, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_v6mpyvubs10_vxx, - {{ 3, false, 2, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_v6mpyvubs10_vxx_128B, - {{ 3, false, 2, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_vlutvvbi, {{ 2, false, 3, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_vlutvvbi_128B, {{ 2, false, 3, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb_oracci, {{ 3, false, 3, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb_oracci_128B, - {{ 3, false, 3, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_vlutvwhi, {{ 2, false, 3, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_vlutvwhi_128B, {{ 2, false, 3, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh_oracci, {{ 3, false, 3, 0 }} }, - { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh_oracci_128B, - {{ 3, false, 3, 0 }} }, - }; - - // Use a dynamically initialized static to sort the table exactly once on - // first run. - static const bool SortOnce = - (llvm::sort(Infos, - [](const BuiltinInfo &LHS, const BuiltinInfo &RHS) { - return LHS.BuiltinID < RHS.BuiltinID; - }), - true); - (void)SortOnce; - - const BuiltinInfo *F = llvm::partition_point( - Infos, [=](const BuiltinInfo &BI) { return BI.BuiltinID < BuiltinID; }); - if (F == std::end(Infos) || F->BuiltinID != BuiltinID) - return false; - - bool Error = false; - - for (const ArgInfo &A : F->Infos) { - // Ignore empty ArgInfo elements. - if (A.BitWidth == 0) - continue; - - int32_t Min = A.IsSigned ? -(1 << (A.BitWidth - 1)) : 0; - int32_t Max = (1 << (A.IsSigned ? A.BitWidth - 1 : A.BitWidth)) - 1; - if (!A.Align) { - Error |= BuiltinConstantArgRange(TheCall, A.OpNum, Min, Max); - } else { - unsigned M = 1 << A.Align; - Min *= M; - Max *= M; - Error |= BuiltinConstantArgRange(TheCall, A.OpNum, Min, Max); - Error |= BuiltinConstantArgMultiple(TheCall, A.OpNum, M); - } - } - return Error; -} - -bool Sema::CheckHexagonBuiltinFunctionCall(unsigned BuiltinID, - CallExpr *TheCall) { - return CheckHexagonBuiltinArgument(BuiltinID, TheCall); -} - -bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, - unsigned BuiltinID, - CallExpr *TheCall) { - switch (BuiltinID) { - default: - break; - // Basic intrinsics. - case LoongArch::BI__builtin_loongarch_cacop_d: - case LoongArch::BI__builtin_loongarch_cacop_w: { - BuiltinConstantArgRange(TheCall, 0, 0, llvm::maxUIntN(5)); - BuiltinConstantArgRange(TheCall, 2, llvm::minIntN(12), llvm::maxIntN(12)); - break; - } - case LoongArch::BI__builtin_loongarch_break: - case LoongArch::BI__builtin_loongarch_dbar: - case LoongArch::BI__builtin_loongarch_ibar: - case LoongArch::BI__builtin_loongarch_syscall: - // Check if immediate is in [0, 32767]. - return BuiltinConstantArgRange(TheCall, 0, 0, 32767); - case LoongArch::BI__builtin_loongarch_csrrd_w: - case LoongArch::BI__builtin_loongarch_csrrd_d: - return BuiltinConstantArgRange(TheCall, 0, 0, 16383); - case LoongArch::BI__builtin_loongarch_csrwr_w: - case LoongArch::BI__builtin_loongarch_csrwr_d: - return BuiltinConstantArgRange(TheCall, 1, 0, 16383); - case LoongArch::BI__builtin_loongarch_csrxchg_w: - case LoongArch::BI__builtin_loongarch_csrxchg_d: - return BuiltinConstantArgRange(TheCall, 2, 0, 16383); - case LoongArch::BI__builtin_loongarch_lddir_d: - case LoongArch::BI__builtin_loongarch_ldpte_d: - return BuiltinConstantArgRange(TheCall, 1, 0, 31); - case LoongArch::BI__builtin_loongarch_movfcsr2gr: - case LoongArch::BI__builtin_loongarch_movgr2fcsr: - return BuiltinConstantArgRange(TheCall, 0, 0, llvm::maxUIntN(2)); - - // LSX intrinsics. - case LoongArch::BI__builtin_lsx_vbitclri_b: - case LoongArch::BI__builtin_lsx_vbitrevi_b: - case LoongArch::BI__builtin_lsx_vbitseti_b: - case LoongArch::BI__builtin_lsx_vsat_b: - case LoongArch::BI__builtin_lsx_vsat_bu: - case LoongArch::BI__builtin_lsx_vslli_b: - case LoongArch::BI__builtin_lsx_vsrai_b: - case LoongArch::BI__builtin_lsx_vsrari_b: - case LoongArch::BI__builtin_lsx_vsrli_b: - case LoongArch::BI__builtin_lsx_vsllwil_h_b: - case LoongArch::BI__builtin_lsx_vsllwil_hu_bu: - case LoongArch::BI__builtin_lsx_vrotri_b: - case LoongArch::BI__builtin_lsx_vsrlri_b: - return BuiltinConstantArgRange(TheCall, 1, 0, 7); - case LoongArch::BI__builtin_lsx_vbitclri_h: - case LoongArch::BI__builtin_lsx_vbitrevi_h: - case LoongArch::BI__builtin_lsx_vbitseti_h: - case LoongArch::BI__builtin_lsx_vsat_h: - case LoongArch::BI__builtin_lsx_vsat_hu: - case LoongArch::BI__builtin_lsx_vslli_h: - case LoongArch::BI__builtin_lsx_vsrai_h: - case LoongArch::BI__builtin_lsx_vsrari_h: - case LoongArch::BI__builtin_lsx_vsrli_h: - case LoongArch::BI__builtin_lsx_vsllwil_w_h: - case LoongArch::BI__builtin_lsx_vsllwil_wu_hu: - case LoongArch::BI__builtin_lsx_vrotri_h: - case LoongArch::BI__builtin_lsx_vsrlri_h: - return BuiltinConstantArgRange(TheCall, 1, 0, 15); - case LoongArch::BI__builtin_lsx_vssrarni_b_h: - case LoongArch::BI__builtin_lsx_vssrarni_bu_h: - case LoongArch::BI__builtin_lsx_vssrani_b_h: - case LoongArch::BI__builtin_lsx_vssrani_bu_h: - case LoongArch::BI__builtin_lsx_vsrarni_b_h: - case LoongArch::BI__builtin_lsx_vsrlni_b_h: - case LoongArch::BI__builtin_lsx_vsrlrni_b_h: - case LoongArch::BI__builtin_lsx_vssrlni_b_h: - case LoongArch::BI__builtin_lsx_vssrlni_bu_h: - case LoongArch::BI__builtin_lsx_vssrlrni_b_h: - case LoongArch::BI__builtin_lsx_vssrlrni_bu_h: - case LoongArch::BI__builtin_lsx_vsrani_b_h: - return BuiltinConstantArgRange(TheCall, 2, 0, 15); - case LoongArch::BI__builtin_lsx_vslei_bu: - case LoongArch::BI__builtin_lsx_vslei_hu: - case LoongArch::BI__builtin_lsx_vslei_wu: - case LoongArch::BI__builtin_lsx_vslei_du: - case LoongArch::BI__builtin_lsx_vslti_bu: - case LoongArch::BI__builtin_lsx_vslti_hu: - case LoongArch::BI__builtin_lsx_vslti_wu: - case LoongArch::BI__builtin_lsx_vslti_du: - case LoongArch::BI__builtin_lsx_vmaxi_bu: - case LoongArch::BI__builtin_lsx_vmaxi_hu: - case LoongArch::BI__builtin_lsx_vmaxi_wu: - case LoongArch::BI__builtin_lsx_vmaxi_du: - case LoongArch::BI__builtin_lsx_vmini_bu: - case LoongArch::BI__builtin_lsx_vmini_hu: - case LoongArch::BI__builtin_lsx_vmini_wu: - case LoongArch::BI__builtin_lsx_vmini_du: - case LoongArch::BI__builtin_lsx_vaddi_bu: - case LoongArch::BI__builtin_lsx_vaddi_hu: - case LoongArch::BI__builtin_lsx_vaddi_wu: - case LoongArch::BI__builtin_lsx_vaddi_du: - case LoongArch::BI__builtin_lsx_vbitclri_w: - case LoongArch::BI__builtin_lsx_vbitrevi_w: - case LoongArch::BI__builtin_lsx_vbitseti_w: - case LoongArch::BI__builtin_lsx_vsat_w: - case LoongArch::BI__builtin_lsx_vsat_wu: - case LoongArch::BI__builtin_lsx_vslli_w: - case LoongArch::BI__builtin_lsx_vsrai_w: - case LoongArch::BI__builtin_lsx_vsrari_w: - case LoongArch::BI__builtin_lsx_vsrli_w: - case LoongArch::BI__builtin_lsx_vsllwil_d_w: - case LoongArch::BI__builtin_lsx_vsllwil_du_wu: - case LoongArch::BI__builtin_lsx_vsrlri_w: - case LoongArch::BI__builtin_lsx_vrotri_w: - case LoongArch::BI__builtin_lsx_vsubi_bu: - case LoongArch::BI__builtin_lsx_vsubi_hu: - case LoongArch::BI__builtin_lsx_vbsrl_v: - case LoongArch::BI__builtin_lsx_vbsll_v: - case LoongArch::BI__builtin_lsx_vsubi_wu: - case LoongArch::BI__builtin_lsx_vsubi_du: - return BuiltinConstantArgRange(TheCall, 1, 0, 31); - case LoongArch::BI__builtin_lsx_vssrarni_h_w: - case LoongArch::BI__builtin_lsx_vssrarni_hu_w: - case LoongArch::BI__builtin_lsx_vssrani_h_w: - case LoongArch::BI__builtin_lsx_vssrani_hu_w: - case LoongArch::BI__builtin_lsx_vsrarni_h_w: - case LoongArch::BI__builtin_lsx_vsrani_h_w: - case LoongArch::BI__builtin_lsx_vfrstpi_b: - case LoongArch::BI__builtin_lsx_vfrstpi_h: - case LoongArch::BI__builtin_lsx_vsrlni_h_w: - case LoongArch::BI__builtin_lsx_vsrlrni_h_w: - case LoongArch::BI__builtin_lsx_vssrlni_h_w: - case LoongArch::BI__builtin_lsx_vssrlni_hu_w: - case LoongArch::BI__builtin_lsx_vssrlrni_h_w: - case LoongArch::BI__builtin_lsx_vssrlrni_hu_w: - return BuiltinConstantArgRange(TheCall, 2, 0, 31); - case LoongArch::BI__builtin_lsx_vbitclri_d: - case LoongArch::BI__builtin_lsx_vbitrevi_d: - case LoongArch::BI__builtin_lsx_vbitseti_d: - case LoongArch::BI__builtin_lsx_vsat_d: - case LoongArch::BI__builtin_lsx_vsat_du: - case LoongArch::BI__builtin_lsx_vslli_d: - case LoongArch::BI__builtin_lsx_vsrai_d: - case LoongArch::BI__builtin_lsx_vsrli_d: - case LoongArch::BI__builtin_lsx_vsrari_d: - case LoongArch::BI__builtin_lsx_vrotri_d: - case LoongArch::BI__builtin_lsx_vsrlri_d: - return BuiltinConstantArgRange(TheCall, 1, 0, 63); - case LoongArch::BI__builtin_lsx_vssrarni_w_d: - case LoongArch::BI__builtin_lsx_vssrarni_wu_d: - case LoongArch::BI__builtin_lsx_vssrani_w_d: - case LoongArch::BI__builtin_lsx_vssrani_wu_d: - case LoongArch::BI__builtin_lsx_vsrarni_w_d: - case LoongArch::BI__builtin_lsx_vsrlni_w_d: - case LoongArch::BI__builtin_lsx_vsrlrni_w_d: - case LoongArch::BI__builtin_lsx_vssrlni_w_d: - case LoongArch::BI__builtin_lsx_vssrlni_wu_d: - case LoongArch::BI__builtin_lsx_vssrlrni_w_d: - case LoongArch::BI__builtin_lsx_vssrlrni_wu_d: - case LoongArch::BI__builtin_lsx_vsrani_w_d: - return BuiltinConstantArgRange(TheCall, 2, 0, 63); - case LoongArch::BI__builtin_lsx_vssrarni_d_q: - case LoongArch::BI__builtin_lsx_vssrarni_du_q: - case LoongArch::BI__builtin_lsx_vssrani_d_q: - case LoongArch::BI__builtin_lsx_vssrani_du_q: - case LoongArch::BI__builtin_lsx_vsrarni_d_q: - case LoongArch::BI__builtin_lsx_vssrlni_d_q: - case LoongArch::BI__builtin_lsx_vssrlni_du_q: - case LoongArch::BI__builtin_lsx_vssrlrni_d_q: - case LoongArch::BI__builtin_lsx_vssrlrni_du_q: - case LoongArch::BI__builtin_lsx_vsrani_d_q: - case LoongArch::BI__builtin_lsx_vsrlrni_d_q: - case LoongArch::BI__builtin_lsx_vsrlni_d_q: - return BuiltinConstantArgRange(TheCall, 2, 0, 127); - case LoongArch::BI__builtin_lsx_vseqi_b: - case LoongArch::BI__builtin_lsx_vseqi_h: - case LoongArch::BI__builtin_lsx_vseqi_w: - case LoongArch::BI__builtin_lsx_vseqi_d: - case LoongArch::BI__builtin_lsx_vslti_b: - case LoongArch::BI__builtin_lsx_vslti_h: - case LoongArch::BI__builtin_lsx_vslti_w: - case LoongArch::BI__builtin_lsx_vslti_d: - case LoongArch::BI__builtin_lsx_vslei_b: - case LoongArch::BI__builtin_lsx_vslei_h: - case LoongArch::BI__builtin_lsx_vslei_w: - case LoongArch::BI__builtin_lsx_vslei_d: - case LoongArch::BI__builtin_lsx_vmaxi_b: - case LoongArch::BI__builtin_lsx_vmaxi_h: - case LoongArch::BI__builtin_lsx_vmaxi_w: - case LoongArch::BI__builtin_lsx_vmaxi_d: - case LoongArch::BI__builtin_lsx_vmini_b: - case LoongArch::BI__builtin_lsx_vmini_h: - case LoongArch::BI__builtin_lsx_vmini_w: - case LoongArch::BI__builtin_lsx_vmini_d: - return BuiltinConstantArgRange(TheCall, 1, -16, 15); - case LoongArch::BI__builtin_lsx_vandi_b: - case LoongArch::BI__builtin_lsx_vnori_b: - case LoongArch::BI__builtin_lsx_vori_b: - case LoongArch::BI__builtin_lsx_vshuf4i_b: - case LoongArch::BI__builtin_lsx_vshuf4i_h: - case LoongArch::BI__builtin_lsx_vshuf4i_w: - case LoongArch::BI__builtin_lsx_vxori_b: - return BuiltinConstantArgRange(TheCall, 1, 0, 255); - case LoongArch::BI__builtin_lsx_vbitseli_b: - case LoongArch::BI__builtin_lsx_vshuf4i_d: - case LoongArch::BI__builtin_lsx_vextrins_b: - case LoongArch::BI__builtin_lsx_vextrins_h: - case LoongArch::BI__builtin_lsx_vextrins_w: - case LoongArch::BI__builtin_lsx_vextrins_d: - case LoongArch::BI__builtin_lsx_vpermi_w: - return BuiltinConstantArgRange(TheCall, 2, 0, 255); - case LoongArch::BI__builtin_lsx_vpickve2gr_b: - case LoongArch::BI__builtin_lsx_vpickve2gr_bu: - case LoongArch::BI__builtin_lsx_vreplvei_b: - return BuiltinConstantArgRange(TheCall, 1, 0, 15); - case LoongArch::BI__builtin_lsx_vinsgr2vr_b: - return BuiltinConstantArgRange(TheCall, 2, 0, 15); - case LoongArch::BI__builtin_lsx_vpickve2gr_h: - case LoongArch::BI__builtin_lsx_vpickve2gr_hu: - case LoongArch::BI__builtin_lsx_vreplvei_h: - return BuiltinConstantArgRange(TheCall, 1, 0, 7); - case LoongArch::BI__builtin_lsx_vinsgr2vr_h: - return BuiltinConstantArgRange(TheCall, 2, 0, 7); - case LoongArch::BI__builtin_lsx_vpickve2gr_w: - case LoongArch::BI__builtin_lsx_vpickve2gr_wu: - case LoongArch::BI__builtin_lsx_vreplvei_w: - return BuiltinConstantArgRange(TheCall, 1, 0, 3); - case LoongArch::BI__builtin_lsx_vinsgr2vr_w: - return BuiltinConstantArgRange(TheCall, 2, 0, 3); - case LoongArch::BI__builtin_lsx_vpickve2gr_d: - case LoongArch::BI__builtin_lsx_vpickve2gr_du: - case LoongArch::BI__builtin_lsx_vreplvei_d: - return BuiltinConstantArgRange(TheCall, 1, 0, 1); - case LoongArch::BI__builtin_lsx_vinsgr2vr_d: - return BuiltinConstantArgRange(TheCall, 2, 0, 1); - case LoongArch::BI__builtin_lsx_vstelm_b: - return BuiltinConstantArgRange(TheCall, 2, -128, 127) || - BuiltinConstantArgRange(TheCall, 3, 0, 15); - case LoongArch::BI__builtin_lsx_vstelm_h: - return BuiltinConstantArgRange(TheCall, 2, -256, 254) || - BuiltinConstantArgRange(TheCall, 3, 0, 7); - case LoongArch::BI__builtin_lsx_vstelm_w: - return BuiltinConstantArgRange(TheCall, 2, -512, 508) || - BuiltinConstantArgRange(TheCall, 3, 0, 3); - case LoongArch::BI__builtin_lsx_vstelm_d: - return BuiltinConstantArgRange(TheCall, 2, -1024, 1016) || - BuiltinConstantArgRange(TheCall, 3, 0, 1); - case LoongArch::BI__builtin_lsx_vldrepl_b: - case LoongArch::BI__builtin_lsx_vld: - return BuiltinConstantArgRange(TheCall, 1, -2048, 2047); - case LoongArch::BI__builtin_lsx_vldrepl_h: - return BuiltinConstantArgRange(TheCall, 1, -2048, 2046); - case LoongArch::BI__builtin_lsx_vldrepl_w: - return BuiltinConstantArgRange(TheCall, 1, -2048, 2044); - case LoongArch::BI__builtin_lsx_vldrepl_d: - return BuiltinConstantArgRange(TheCall, 1, -2048, 2040); - case LoongArch::BI__builtin_lsx_vst: - return BuiltinConstantArgRange(TheCall, 2, -2048, 2047); - case LoongArch::BI__builtin_lsx_vldi: - return BuiltinConstantArgRange(TheCall, 0, -4096, 4095); - case LoongArch::BI__builtin_lsx_vrepli_b: - case LoongArch::BI__builtin_lsx_vrepli_h: - case LoongArch::BI__builtin_lsx_vrepli_w: - case LoongArch::BI__builtin_lsx_vrepli_d: - return BuiltinConstantArgRange(TheCall, 0, -512, 511); - - // LASX intrinsics. - case LoongArch::BI__builtin_lasx_xvbitclri_b: - case LoongArch::BI__builtin_lasx_xvbitrevi_b: - case LoongArch::BI__builtin_lasx_xvbitseti_b: - case LoongArch::BI__builtin_lasx_xvsat_b: - case LoongArch::BI__builtin_lasx_xvsat_bu: - case LoongArch::BI__builtin_lasx_xvslli_b: - case LoongArch::BI__builtin_lasx_xvsrai_b: - case LoongArch::BI__builtin_lasx_xvsrari_b: - case LoongArch::BI__builtin_lasx_xvsrli_b: - case LoongArch::BI__builtin_lasx_xvsllwil_h_b: - case LoongArch::BI__builtin_lasx_xvsllwil_hu_bu: - case LoongArch::BI__builtin_lasx_xvrotri_b: - case LoongArch::BI__builtin_lasx_xvsrlri_b: - return BuiltinConstantArgRange(TheCall, 1, 0, 7); - case LoongArch::BI__builtin_lasx_xvbitclri_h: - case LoongArch::BI__builtin_lasx_xvbitrevi_h: - case LoongArch::BI__builtin_lasx_xvbitseti_h: - case LoongArch::BI__builtin_lasx_xvsat_h: - case LoongArch::BI__builtin_lasx_xvsat_hu: - case LoongArch::BI__builtin_lasx_xvslli_h: - case LoongArch::BI__builtin_lasx_xvsrai_h: - case LoongArch::BI__builtin_lasx_xvsrari_h: - case LoongArch::BI__builtin_lasx_xvsrli_h: - case LoongArch::BI__builtin_lasx_xvsllwil_w_h: - case LoongArch::BI__builtin_lasx_xvsllwil_wu_hu: - case LoongArch::BI__builtin_lasx_xvrotri_h: - case LoongArch::BI__builtin_lasx_xvsrlri_h: - return BuiltinConstantArgRange(TheCall, 1, 0, 15); - case LoongArch::BI__builtin_lasx_xvssrarni_b_h: - case LoongArch::BI__builtin_lasx_xvssrarni_bu_h: - case LoongArch::BI__builtin_lasx_xvssrani_b_h: - case LoongArch::BI__builtin_lasx_xvssrani_bu_h: - case LoongArch::BI__builtin_lasx_xvsrarni_b_h: - case LoongArch::BI__builtin_lasx_xvsrlni_b_h: - case LoongArch::BI__builtin_lasx_xvsrlrni_b_h: - case LoongArch::BI__builtin_lasx_xvssrlni_b_h: - case LoongArch::BI__builtin_lasx_xvssrlni_bu_h: - case LoongArch::BI__builtin_lasx_xvssrlrni_b_h: - case LoongArch::BI__builtin_lasx_xvssrlrni_bu_h: - case LoongArch::BI__builtin_lasx_xvsrani_b_h: - return BuiltinConstantArgRange(TheCall, 2, 0, 15); - case LoongArch::BI__builtin_lasx_xvslei_bu: - case LoongArch::BI__builtin_lasx_xvslei_hu: - case LoongArch::BI__builtin_lasx_xvslei_wu: - case LoongArch::BI__builtin_lasx_xvslei_du: - case LoongArch::BI__builtin_lasx_xvslti_bu: - case LoongArch::BI__builtin_lasx_xvslti_hu: - case LoongArch::BI__builtin_lasx_xvslti_wu: - case LoongArch::BI__builtin_lasx_xvslti_du: - case LoongArch::BI__builtin_lasx_xvmaxi_bu: - case LoongArch::BI__builtin_lasx_xvmaxi_hu: - case LoongArch::BI__builtin_lasx_xvmaxi_wu: - case LoongArch::BI__builtin_lasx_xvmaxi_du: - case LoongArch::BI__builtin_lasx_xvmini_bu: - case LoongArch::BI__builtin_lasx_xvmini_hu: - case LoongArch::BI__builtin_lasx_xvmini_wu: - case LoongArch::BI__builtin_lasx_xvmini_du: - case LoongArch::BI__builtin_lasx_xvaddi_bu: - case LoongArch::BI__builtin_lasx_xvaddi_hu: - case LoongArch::BI__builtin_lasx_xvaddi_wu: - case LoongArch::BI__builtin_lasx_xvaddi_du: - case LoongArch::BI__builtin_lasx_xvbitclri_w: - case LoongArch::BI__builtin_lasx_xvbitrevi_w: - case LoongArch::BI__builtin_lasx_xvbitseti_w: - case LoongArch::BI__builtin_lasx_xvsat_w: - case LoongArch::BI__builtin_lasx_xvsat_wu: - case LoongArch::BI__builtin_lasx_xvslli_w: - case LoongArch::BI__builtin_lasx_xvsrai_w: - case LoongArch::BI__builtin_lasx_xvsrari_w: - case LoongArch::BI__builtin_lasx_xvsrli_w: - case LoongArch::BI__builtin_lasx_xvsllwil_d_w: - case LoongArch::BI__builtin_lasx_xvsllwil_du_wu: - case LoongArch::BI__builtin_lasx_xvsrlri_w: - case LoongArch::BI__builtin_lasx_xvrotri_w: - case LoongArch::BI__builtin_lasx_xvsubi_bu: - case LoongArch::BI__builtin_lasx_xvsubi_hu: - case LoongArch::BI__builtin_lasx_xvsubi_wu: - case LoongArch::BI__builtin_lasx_xvsubi_du: - case LoongArch::BI__builtin_lasx_xvbsrl_v: - case LoongArch::BI__builtin_lasx_xvbsll_v: - return BuiltinConstantArgRange(TheCall, 1, 0, 31); - case LoongArch::BI__builtin_lasx_xvssrarni_h_w: - case LoongArch::BI__builtin_lasx_xvssrarni_hu_w: - case LoongArch::BI__builtin_lasx_xvssrani_h_w: - case LoongArch::BI__builtin_lasx_xvssrani_hu_w: - case LoongArch::BI__builtin_lasx_xvsrarni_h_w: - case LoongArch::BI__builtin_lasx_xvsrani_h_w: - case LoongArch::BI__builtin_lasx_xvfrstpi_b: - case LoongArch::BI__builtin_lasx_xvfrstpi_h: - case LoongArch::BI__builtin_lasx_xvsrlni_h_w: - case LoongArch::BI__builtin_lasx_xvsrlrni_h_w: - case LoongArch::BI__builtin_lasx_xvssrlni_h_w: - case LoongArch::BI__builtin_lasx_xvssrlni_hu_w: - case LoongArch::BI__builtin_lasx_xvssrlrni_h_w: - case LoongArch::BI__builtin_lasx_xvssrlrni_hu_w: - return BuiltinConstantArgRange(TheCall, 2, 0, 31); - case LoongArch::BI__builtin_lasx_xvbitclri_d: - case LoongArch::BI__builtin_lasx_xvbitrevi_d: - case LoongArch::BI__builtin_lasx_xvbitseti_d: - case LoongArch::BI__builtin_lasx_xvsat_d: - case LoongArch::BI__builtin_lasx_xvsat_du: - case LoongArch::BI__builtin_lasx_xvslli_d: - case LoongArch::BI__builtin_lasx_xvsrai_d: - case LoongArch::BI__builtin_lasx_xvsrli_d: - case LoongArch::BI__builtin_lasx_xvsrari_d: - case LoongArch::BI__builtin_lasx_xvrotri_d: - case LoongArch::BI__builtin_lasx_xvsrlri_d: - return BuiltinConstantArgRange(TheCall, 1, 0, 63); - case LoongArch::BI__builtin_lasx_xvssrarni_w_d: - case LoongArch::BI__builtin_lasx_xvssrarni_wu_d: - case LoongArch::BI__builtin_lasx_xvssrani_w_d: - case LoongArch::BI__builtin_lasx_xvssrani_wu_d: - case LoongArch::BI__builtin_lasx_xvsrarni_w_d: - case LoongArch::BI__builtin_lasx_xvsrlni_w_d: - case LoongArch::BI__builtin_lasx_xvsrlrni_w_d: - case LoongArch::BI__builtin_lasx_xvssrlni_w_d: - case LoongArch::BI__builtin_lasx_xvssrlni_wu_d: - case LoongArch::BI__builtin_lasx_xvssrlrni_w_d: - case LoongArch::BI__builtin_lasx_xvssrlrni_wu_d: - case LoongArch::BI__builtin_lasx_xvsrani_w_d: - return BuiltinConstantArgRange(TheCall, 2, 0, 63); - case LoongArch::BI__builtin_lasx_xvssrarni_d_q: - case LoongArch::BI__builtin_lasx_xvssrarni_du_q: - case LoongArch::BI__builtin_lasx_xvssrani_d_q: - case LoongArch::BI__builtin_lasx_xvssrani_du_q: - case LoongArch::BI__builtin_lasx_xvsrarni_d_q: - case LoongArch::BI__builtin_lasx_xvssrlni_d_q: - case LoongArch::BI__builtin_lasx_xvssrlni_du_q: - case LoongArch::BI__builtin_lasx_xvssrlrni_d_q: - case LoongArch::BI__builtin_lasx_xvssrlrni_du_q: - case LoongArch::BI__builtin_lasx_xvsrani_d_q: - case LoongArch::BI__builtin_lasx_xvsrlni_d_q: - case LoongArch::BI__builtin_lasx_xvsrlrni_d_q: - return BuiltinConstantArgRange(TheCall, 2, 0, 127); - case LoongArch::BI__builtin_lasx_xvseqi_b: - case LoongArch::BI__builtin_lasx_xvseqi_h: - case LoongArch::BI__builtin_lasx_xvseqi_w: - case LoongArch::BI__builtin_lasx_xvseqi_d: - case LoongArch::BI__builtin_lasx_xvslti_b: - case LoongArch::BI__builtin_lasx_xvslti_h: - case LoongArch::BI__builtin_lasx_xvslti_w: - case LoongArch::BI__builtin_lasx_xvslti_d: - case LoongArch::BI__builtin_lasx_xvslei_b: - case LoongArch::BI__builtin_lasx_xvslei_h: - case LoongArch::BI__builtin_lasx_xvslei_w: - case LoongArch::BI__builtin_lasx_xvslei_d: - case LoongArch::BI__builtin_lasx_xvmaxi_b: - case LoongArch::BI__builtin_lasx_xvmaxi_h: - case LoongArch::BI__builtin_lasx_xvmaxi_w: - case LoongArch::BI__builtin_lasx_xvmaxi_d: - case LoongArch::BI__builtin_lasx_xvmini_b: - case LoongArch::BI__builtin_lasx_xvmini_h: - case LoongArch::BI__builtin_lasx_xvmini_w: - case LoongArch::BI__builtin_lasx_xvmini_d: - return BuiltinConstantArgRange(TheCall, 1, -16, 15); - case LoongArch::BI__builtin_lasx_xvandi_b: - case LoongArch::BI__builtin_lasx_xvnori_b: - case LoongArch::BI__builtin_lasx_xvori_b: - case LoongArch::BI__builtin_lasx_xvshuf4i_b: - case LoongArch::BI__builtin_lasx_xvshuf4i_h: - case LoongArch::BI__builtin_lasx_xvshuf4i_w: - case LoongArch::BI__builtin_lasx_xvxori_b: - case LoongArch::BI__builtin_lasx_xvpermi_d: - return BuiltinConstantArgRange(TheCall, 1, 0, 255); - case LoongArch::BI__builtin_lasx_xvbitseli_b: - case LoongArch::BI__builtin_lasx_xvshuf4i_d: - case LoongArch::BI__builtin_lasx_xvextrins_b: - case LoongArch::BI__builtin_lasx_xvextrins_h: - case LoongArch::BI__builtin_lasx_xvextrins_w: - case LoongArch::BI__builtin_lasx_xvextrins_d: - case LoongArch::BI__builtin_lasx_xvpermi_q: - case LoongArch::BI__builtin_lasx_xvpermi_w: - return BuiltinConstantArgRange(TheCall, 2, 0, 255); - case LoongArch::BI__builtin_lasx_xvrepl128vei_b: - return BuiltinConstantArgRange(TheCall, 1, 0, 15); - case LoongArch::BI__builtin_lasx_xvrepl128vei_h: - case LoongArch::BI__builtin_lasx_xvpickve2gr_w: - case LoongArch::BI__builtin_lasx_xvpickve2gr_wu: - case LoongArch::BI__builtin_lasx_xvpickve_w_f: - case LoongArch::BI__builtin_lasx_xvpickve_w: - return BuiltinConstantArgRange(TheCall, 1, 0, 7); - case LoongArch::BI__builtin_lasx_xvinsgr2vr_w: - case LoongArch::BI__builtin_lasx_xvinsve0_w: - return BuiltinConstantArgRange(TheCall, 2, 0, 7); - case LoongArch::BI__builtin_lasx_xvrepl128vei_w: - case LoongArch::BI__builtin_lasx_xvpickve2gr_d: - case LoongArch::BI__builtin_lasx_xvpickve2gr_du: - case LoongArch::BI__builtin_lasx_xvpickve_d_f: - case LoongArch::BI__builtin_lasx_xvpickve_d: - return BuiltinConstantArgRange(TheCall, 1, 0, 3); - case LoongArch::BI__builtin_lasx_xvinsve0_d: - case LoongArch::BI__builtin_lasx_xvinsgr2vr_d: - return BuiltinConstantArgRange(TheCall, 2, 0, 3); - case LoongArch::BI__builtin_lasx_xvstelm_b: - return BuiltinConstantArgRange(TheCall, 2, -128, 127) || - BuiltinConstantArgRange(TheCall, 3, 0, 31); - case LoongArch::BI__builtin_lasx_xvstelm_h: - return BuiltinConstantArgRange(TheCall, 2, -256, 254) || - BuiltinConstantArgRange(TheCall, 3, 0, 15); - case LoongArch::BI__builtin_lasx_xvstelm_w: - return BuiltinConstantArgRange(TheCall, 2, -512, 508) || - BuiltinConstantArgRange(TheCall, 3, 0, 7); - case LoongArch::BI__builtin_lasx_xvstelm_d: - return BuiltinConstantArgRange(TheCall, 2, -1024, 1016) || - BuiltinConstantArgRange(TheCall, 3, 0, 3); - case LoongArch::BI__builtin_lasx_xvrepl128vei_d: - return BuiltinConstantArgRange(TheCall, 1, 0, 1); - case LoongArch::BI__builtin_lasx_xvldrepl_b: - case LoongArch::BI__builtin_lasx_xvld: - return BuiltinConstantArgRange(TheCall, 1, -2048, 2047); - case LoongArch::BI__builtin_lasx_xvldrepl_h: - return BuiltinConstantArgRange(TheCall, 1, -2048, 2046); - case LoongArch::BI__builtin_lasx_xvldrepl_w: - return BuiltinConstantArgRange(TheCall, 1, -2048, 2044); - case LoongArch::BI__builtin_lasx_xvldrepl_d: - return BuiltinConstantArgRange(TheCall, 1, -2048, 2040); - case LoongArch::BI__builtin_lasx_xvst: - return BuiltinConstantArgRange(TheCall, 2, -2048, 2047); - case LoongArch::BI__builtin_lasx_xvldi: - return BuiltinConstantArgRange(TheCall, 0, -4096, 4095); - case LoongArch::BI__builtin_lasx_xvrepli_b: - case LoongArch::BI__builtin_lasx_xvrepli_h: - case LoongArch::BI__builtin_lasx_xvrepli_w: - case LoongArch::BI__builtin_lasx_xvrepli_d: - return BuiltinConstantArgRange(TheCall, 0, -512, 511); - } - return false; -} - -bool Sema::CheckMipsBuiltinFunctionCall(const TargetInfo &TI, - unsigned BuiltinID, CallExpr *TheCall) { - return CheckMipsBuiltinCpu(TI, BuiltinID, TheCall) || - CheckMipsBuiltinArgument(BuiltinID, TheCall); -} - -bool Sema::CheckMipsBuiltinCpu(const TargetInfo &TI, unsigned BuiltinID, - CallExpr *TheCall) { - - if (Mips::BI__builtin_mips_addu_qb <= BuiltinID && - BuiltinID <= Mips::BI__builtin_mips_lwx) { - if (!TI.hasFeature("dsp")) - return Diag(TheCall->getBeginLoc(), diag::err_mips_builtin_requires_dsp); - } - - if (Mips::BI__builtin_mips_absq_s_qb <= BuiltinID && - BuiltinID <= Mips::BI__builtin_mips_subuh_r_qb) { - if (!TI.hasFeature("dspr2")) - return Diag(TheCall->getBeginLoc(), - diag::err_mips_builtin_requires_dspr2); - } - - if (Mips::BI__builtin_msa_add_a_b <= BuiltinID && - BuiltinID <= Mips::BI__builtin_msa_xori_b) { - if (!TI.hasFeature("msa")) - return Diag(TheCall->getBeginLoc(), diag::err_mips_builtin_requires_msa); - } - - return false; -} - -// CheckMipsBuiltinArgument - Checks the constant value passed to the -// intrinsic is correct. The switch statement is ordered by DSP, MSA. The -// ordering for DSP is unspecified. MSA is ordered by the data format used -// by the underlying instruction i.e., df/m, df/n and then by size. -// -// FIXME: The size tests here should instead be tablegen'd along with the -// definitions from include/clang/Basic/BuiltinsMips.def. -// FIXME: GCC is strict on signedness for some of these intrinsics, we should -// be too. -bool Sema::CheckMipsBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall) { - unsigned i = 0, l = 0, u = 0, m = 0; - switch (BuiltinID) { - default: return false; - case Mips::BI__builtin_mips_wrdsp: i = 1; l = 0; u = 63; break; - case Mips::BI__builtin_mips_rddsp: i = 0; l = 0; u = 63; break; - case Mips::BI__builtin_mips_append: i = 2; l = 0; u = 31; break; - case Mips::BI__builtin_mips_balign: i = 2; l = 0; u = 3; break; - case Mips::BI__builtin_mips_precr_sra_ph_w: i = 2; l = 0; u = 31; break; - case Mips::BI__builtin_mips_precr_sra_r_ph_w: i = 2; l = 0; u = 31; break; - case Mips::BI__builtin_mips_prepend: i = 2; l = 0; u = 31; break; - // MSA intrinsics. Instructions (which the intrinsics maps to) which use the - // df/m field. - // These intrinsics take an unsigned 3 bit immediate. - case Mips::BI__builtin_msa_bclri_b: - case Mips::BI__builtin_msa_bnegi_b: - case Mips::BI__builtin_msa_bseti_b: - case Mips::BI__builtin_msa_sat_s_b: - case Mips::BI__builtin_msa_sat_u_b: - case Mips::BI__builtin_msa_slli_b: - case Mips::BI__builtin_msa_srai_b: - case Mips::BI__builtin_msa_srari_b: - case Mips::BI__builtin_msa_srli_b: - case Mips::BI__builtin_msa_srlri_b: i = 1; l = 0; u = 7; break; - case Mips::BI__builtin_msa_binsli_b: - case Mips::BI__builtin_msa_binsri_b: i = 2; l = 0; u = 7; break; - // These intrinsics take an unsigned 4 bit immediate. - case Mips::BI__builtin_msa_bclri_h: - case Mips::BI__builtin_msa_bnegi_h: - case Mips::BI__builtin_msa_bseti_h: - case Mips::BI__builtin_msa_sat_s_h: - case Mips::BI__builtin_msa_sat_u_h: - case Mips::BI__builtin_msa_slli_h: - case Mips::BI__builtin_msa_srai_h: - case Mips::BI__builtin_msa_srari_h: - case Mips::BI__builtin_msa_srli_h: - case Mips::BI__builtin_msa_srlri_h: i = 1; l = 0; u = 15; break; - case Mips::BI__builtin_msa_binsli_h: - case Mips::BI__builtin_msa_binsri_h: i = 2; l = 0; u = 15; break; - // These intrinsics take an unsigned 5 bit immediate. - // The first block of intrinsics actually have an unsigned 5 bit field, - // not a df/n field. - case Mips::BI__builtin_msa_cfcmsa: - case Mips::BI__builtin_msa_ctcmsa: i = 0; l = 0; u = 31; break; - case Mips::BI__builtin_msa_clei_u_b: - case Mips::BI__builtin_msa_clei_u_h: - case Mips::BI__builtin_msa_clei_u_w: - case Mips::BI__builtin_msa_clei_u_d: - case Mips::BI__builtin_msa_clti_u_b: - case Mips::BI__builtin_msa_clti_u_h: - case Mips::BI__builtin_msa_clti_u_w: - case Mips::BI__builtin_msa_clti_u_d: - case Mips::BI__builtin_msa_maxi_u_b: - case Mips::BI__builtin_msa_maxi_u_h: - case Mips::BI__builtin_msa_maxi_u_w: - case Mips::BI__builtin_msa_maxi_u_d: - case Mips::BI__builtin_msa_mini_u_b: - case Mips::BI__builtin_msa_mini_u_h: - case Mips::BI__builtin_msa_mini_u_w: - case Mips::BI__builtin_msa_mini_u_d: - case Mips::BI__builtin_msa_addvi_b: - case Mips::BI__builtin_msa_addvi_h: - case Mips::BI__builtin_msa_addvi_w: - case Mips::BI__builtin_msa_addvi_d: - case Mips::BI__builtin_msa_bclri_w: - case Mips::BI__builtin_msa_bnegi_w: - case Mips::BI__builtin_msa_bseti_w: - case Mips::BI__builtin_msa_sat_s_w: - case Mips::BI__builtin_msa_sat_u_w: - case Mips::BI__builtin_msa_slli_w: - case Mips::BI__builtin_msa_srai_w: - case Mips::BI__builtin_msa_srari_w: - case Mips::BI__builtin_msa_srli_w: - case Mips::BI__builtin_msa_srlri_w: - case Mips::BI__builtin_msa_subvi_b: - case Mips::BI__builtin_msa_subvi_h: - case Mips::BI__builtin_msa_subvi_w: - case Mips::BI__builtin_msa_subvi_d: i = 1; l = 0; u = 31; break; - case Mips::BI__builtin_msa_binsli_w: - case Mips::BI__builtin_msa_binsri_w: i = 2; l = 0; u = 31; break; - // These intrinsics take an unsigned 6 bit immediate. - case Mips::BI__builtin_msa_bclri_d: - case Mips::BI__builtin_msa_bnegi_d: - case Mips::BI__builtin_msa_bseti_d: - case Mips::BI__builtin_msa_sat_s_d: - case Mips::BI__builtin_msa_sat_u_d: - case Mips::BI__builtin_msa_slli_d: - case Mips::BI__builtin_msa_srai_d: - case Mips::BI__builtin_msa_srari_d: - case Mips::BI__builtin_msa_srli_d: - case Mips::BI__builtin_msa_srlri_d: i = 1; l = 0; u = 63; break; - case Mips::BI__builtin_msa_binsli_d: - case Mips::BI__builtin_msa_binsri_d: i = 2; l = 0; u = 63; break; - // These intrinsics take a signed 5 bit immediate. - case Mips::BI__builtin_msa_ceqi_b: - case Mips::BI__builtin_msa_ceqi_h: - case Mips::BI__builtin_msa_ceqi_w: - case Mips::BI__builtin_msa_ceqi_d: - case Mips::BI__builtin_msa_clti_s_b: - case Mips::BI__builtin_msa_clti_s_h: - case Mips::BI__builtin_msa_clti_s_w: - case Mips::BI__builtin_msa_clti_s_d: - case Mips::BI__builtin_msa_clei_s_b: - case Mips::BI__builtin_msa_clei_s_h: - case Mips::BI__builtin_msa_clei_s_w: - case Mips::BI__builtin_msa_clei_s_d: - case Mips::BI__builtin_msa_maxi_s_b: - case Mips::BI__builtin_msa_maxi_s_h: - case Mips::BI__builtin_msa_maxi_s_w: - case Mips::BI__builtin_msa_maxi_s_d: - case Mips::BI__builtin_msa_mini_s_b: - case Mips::BI__builtin_msa_mini_s_h: - case Mips::BI__builtin_msa_mini_s_w: - case Mips::BI__builtin_msa_mini_s_d: i = 1; l = -16; u = 15; break; - // These intrinsics take an unsigned 8 bit immediate. - case Mips::BI__builtin_msa_andi_b: - case Mips::BI__builtin_msa_nori_b: - case Mips::BI__builtin_msa_ori_b: - case Mips::BI__builtin_msa_shf_b: - case Mips::BI__builtin_msa_shf_h: - case Mips::BI__builtin_msa_shf_w: - case Mips::BI__builtin_msa_xori_b: i = 1; l = 0; u = 255; break; - case Mips::BI__builtin_msa_bseli_b: - case Mips::BI__builtin_msa_bmnzi_b: - case Mips::BI__builtin_msa_bmzi_b: i = 2; l = 0; u = 255; break; - // df/n format - // These intrinsics take an unsigned 4 bit immediate. - case Mips::BI__builtin_msa_copy_s_b: - case Mips::BI__builtin_msa_copy_u_b: - case Mips::BI__builtin_msa_insve_b: - case Mips::BI__builtin_msa_splati_b: i = 1; l = 0; u = 15; break; - case Mips::BI__builtin_msa_sldi_b: i = 2; l = 0; u = 15; break; - // These intrinsics take an unsigned 3 bit immediate. - case Mips::BI__builtin_msa_copy_s_h: - case Mips::BI__builtin_msa_copy_u_h: - case Mips::BI__builtin_msa_insve_h: - case Mips::BI__builtin_msa_splati_h: i = 1; l = 0; u = 7; break; - case Mips::BI__builtin_msa_sldi_h: i = 2; l = 0; u = 7; break; - // These intrinsics take an unsigned 2 bit immediate. - case Mips::BI__builtin_msa_copy_s_w: - case Mips::BI__builtin_msa_copy_u_w: - case Mips::BI__builtin_msa_insve_w: - case Mips::BI__builtin_msa_splati_w: i = 1; l = 0; u = 3; break; - case Mips::BI__builtin_msa_sldi_w: i = 2; l = 0; u = 3; break; - // These intrinsics take an unsigned 1 bit immediate. - case Mips::BI__builtin_msa_copy_s_d: - case Mips::BI__builtin_msa_copy_u_d: - case Mips::BI__builtin_msa_insve_d: - case Mips::BI__builtin_msa_splati_d: i = 1; l = 0; u = 1; break; - case Mips::BI__builtin_msa_sldi_d: i = 2; l = 0; u = 1; break; - // Memory offsets and immediate loads. - // These intrinsics take a signed 10 bit immediate. - case Mips::BI__builtin_msa_ldi_b: i = 0; l = -128; u = 255; break; - case Mips::BI__builtin_msa_ldi_h: - case Mips::BI__builtin_msa_ldi_w: - case Mips::BI__builtin_msa_ldi_d: i = 0; l = -512; u = 511; break; - case Mips::BI__builtin_msa_ld_b: i = 1; l = -512; u = 511; m = 1; break; - case Mips::BI__builtin_msa_ld_h: i = 1; l = -1024; u = 1022; m = 2; break; - case Mips::BI__builtin_msa_ld_w: i = 1; l = -2048; u = 2044; m = 4; break; - case Mips::BI__builtin_msa_ld_d: i = 1; l = -4096; u = 4088; m = 8; break; - case Mips::BI__builtin_msa_ldr_d: i = 1; l = -4096; u = 4088; m = 8; break; - case Mips::BI__builtin_msa_ldr_w: i = 1; l = -2048; u = 2044; m = 4; break; - case Mips::BI__builtin_msa_st_b: i = 2; l = -512; u = 511; m = 1; break; - case Mips::BI__builtin_msa_st_h: i = 2; l = -1024; u = 1022; m = 2; break; - case Mips::BI__builtin_msa_st_w: i = 2; l = -2048; u = 2044; m = 4; break; - case Mips::BI__builtin_msa_st_d: i = 2; l = -4096; u = 4088; m = 8; break; - case Mips::BI__builtin_msa_str_d: i = 2; l = -4096; u = 4088; m = 8; break; - case Mips::BI__builtin_msa_str_w: i = 2; l = -2048; u = 2044; m = 4; break; - } - - if (!m) - return BuiltinConstantArgRange(TheCall, i, l, u); - - return BuiltinConstantArgRange(TheCall, i, l, u) || - BuiltinConstantArgMultiple(TheCall, i, m); -} - -/// DecodePPCMMATypeFromStr - This decodes one PPC MMA type descriptor from Str, -/// advancing the pointer over the consumed characters. The decoded type is -/// returned. If the decoded type represents a constant integer with a -/// constraint on its value then Mask is set to that value. The type descriptors -/// used in Str are specific to PPC MMA builtins and are documented in the file -/// defining the PPC builtins. -static QualType DecodePPCMMATypeFromStr(ASTContext &Context, const char *&Str, - unsigned &Mask) { - bool RequireICE = false; - ASTContext::GetBuiltinTypeError Error = ASTContext::GE_None; - switch (*Str++) { - case 'V': - return Context.getVectorType(Context.UnsignedCharTy, 16, - VectorKind::AltiVecVector); - case 'i': { - char *End; - unsigned size = strtoul(Str, &End, 10); - assert(End != Str && "Missing constant parameter constraint"); - Str = End; - Mask = size; - return Context.IntTy; - } - case 'W': { - char *End; - unsigned size = strtoul(Str, &End, 10); - assert(End != Str && "Missing PowerPC MMA type size"); - Str = End; - QualType Type; - switch (size) { - #define PPC_VECTOR_TYPE(typeName, Id, size) \ - case size: Type = Context.Id##Ty; break; - #include "clang/Basic/PPCTypes.def" - default: llvm_unreachable("Invalid PowerPC MMA vector type"); - } - bool CheckVectorArgs = false; - while (!CheckVectorArgs) { - switch (*Str++) { - case '*': - Type = Context.getPointerType(Type); - break; - case 'C': - Type = Type.withConst(); - break; - default: - CheckVectorArgs = true; - --Str; - break; - } - } - return Type; - } - default: - return Context.DecodeTypeStr(--Str, Context, Error, RequireICE, true); - } -} - -static bool isPPC_64Builtin(unsigned BuiltinID) { - // These builtins only work on PPC 64bit targets. - switch (BuiltinID) { - case PPC::BI__builtin_divde: - case PPC::BI__builtin_divdeu: - case PPC::BI__builtin_bpermd: - case PPC::BI__builtin_pdepd: - case PPC::BI__builtin_pextd: - case PPC::BI__builtin_ppc_ldarx: - case PPC::BI__builtin_ppc_stdcx: - case PPC::BI__builtin_ppc_tdw: - case PPC::BI__builtin_ppc_trapd: - case PPC::BI__builtin_ppc_cmpeqb: - case PPC::BI__builtin_ppc_setb: - case PPC::BI__builtin_ppc_mulhd: - case PPC::BI__builtin_ppc_mulhdu: - case PPC::BI__builtin_ppc_maddhd: - case PPC::BI__builtin_ppc_maddhdu: - case PPC::BI__builtin_ppc_maddld: - case PPC::BI__builtin_ppc_load8r: - case PPC::BI__builtin_ppc_store8r: - case PPC::BI__builtin_ppc_insert_exp: - case PPC::BI__builtin_ppc_extract_sig: - case PPC::BI__builtin_ppc_addex: - case PPC::BI__builtin_darn: - case PPC::BI__builtin_darn_raw: - case PPC::BI__builtin_ppc_compare_and_swaplp: - case PPC::BI__builtin_ppc_fetch_and_addlp: - case PPC::BI__builtin_ppc_fetch_and_andlp: - case PPC::BI__builtin_ppc_fetch_and_orlp: - case PPC::BI__builtin_ppc_fetch_and_swaplp: - return true; - } - return false; -} - /// Returns true if the argument consists of one contiguous run of 1s with any /// number of 0s on either side. The 1s are allowed to wrap from LSB to MSB, so /// 0x000FFF0, 0x0000FFFF, 0xFF0000FF, 0x0 are all runs. 0x0F0F0000 is not, @@ -5287,182 +3322,6 @@ bool Sema::ValueIsRunOfOnes(CallExpr *TheCall, unsigned ArgNum) { << ArgNum << Arg->getSourceRange(); } -bool Sema::CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, - CallExpr *TheCall) { - unsigned i = 0, l = 0, u = 0; - bool IsTarget64Bit = TI.getTypeWidth(TI.getIntPtrType()) == 64; - llvm::APSInt Result; - - if (isPPC_64Builtin(BuiltinID) && !IsTarget64Bit) - return Diag(TheCall->getBeginLoc(), diag::err_64_bit_builtin_32_bit_tgt) - << TheCall->getSourceRange(); - - switch (BuiltinID) { - default: return false; - case PPC::BI__builtin_altivec_crypto_vshasigmaw: - case PPC::BI__builtin_altivec_crypto_vshasigmad: - return BuiltinConstantArgRange(TheCall, 1, 0, 1) || - BuiltinConstantArgRange(TheCall, 2, 0, 15); - case PPC::BI__builtin_altivec_dss: - return BuiltinConstantArgRange(TheCall, 0, 0, 3); - case PPC::BI__builtin_tbegin: - case PPC::BI__builtin_tend: - return BuiltinConstantArgRange(TheCall, 0, 0, 1); - case PPC::BI__builtin_tsr: - return BuiltinConstantArgRange(TheCall, 0, 0, 7); - case PPC::BI__builtin_tabortwc: - case PPC::BI__builtin_tabortdc: - return BuiltinConstantArgRange(TheCall, 0, 0, 31); - case PPC::BI__builtin_tabortwci: - case PPC::BI__builtin_tabortdci: - return BuiltinConstantArgRange(TheCall, 0, 0, 31) || - BuiltinConstantArgRange(TheCall, 2, 0, 31); - // According to GCC 'Basic PowerPC Built-in Functions Available on ISA 2.05', - // __builtin_(un)pack_longdouble are available only if long double uses IBM - // extended double representation. - case PPC::BI__builtin_unpack_longdouble: - if (BuiltinConstantArgRange(TheCall, 1, 0, 1)) - return true; - [[fallthrough]]; - case PPC::BI__builtin_pack_longdouble: - if (&TI.getLongDoubleFormat() != &llvm::APFloat::PPCDoubleDouble()) - return Diag(TheCall->getBeginLoc(), diag::err_ppc_builtin_requires_abi) - << "ibmlongdouble"; - return false; - case PPC::BI__builtin_altivec_dst: - case PPC::BI__builtin_altivec_dstt: - case PPC::BI__builtin_altivec_dstst: - case PPC::BI__builtin_altivec_dststt: - return BuiltinConstantArgRange(TheCall, 2, 0, 3); - case PPC::BI__builtin_vsx_xxpermdi: - case PPC::BI__builtin_vsx_xxsldwi: - return BuiltinVSX(TheCall); - case PPC::BI__builtin_unpack_vector_int128: - return BuiltinConstantArgRange(TheCall, 1, 0, 1); - case PPC::BI__builtin_altivec_vgnb: - return BuiltinConstantArgRange(TheCall, 1, 2, 7); - case PPC::BI__builtin_vsx_xxeval: - return BuiltinConstantArgRange(TheCall, 3, 0, 255); - case PPC::BI__builtin_altivec_vsldbi: - return BuiltinConstantArgRange(TheCall, 2, 0, 7); - case PPC::BI__builtin_altivec_vsrdbi: - return BuiltinConstantArgRange(TheCall, 2, 0, 7); - case PPC::BI__builtin_vsx_xxpermx: - return BuiltinConstantArgRange(TheCall, 3, 0, 7); - case PPC::BI__builtin_ppc_tw: - case PPC::BI__builtin_ppc_tdw: - return BuiltinConstantArgRange(TheCall, 2, 1, 31); - case PPC::BI__builtin_ppc_cmprb: - return BuiltinConstantArgRange(TheCall, 0, 0, 1); - // For __rlwnm, __rlwimi and __rldimi, the last parameter mask must - // be a constant that represents a contiguous bit field. - case PPC::BI__builtin_ppc_rlwnm: - return ValueIsRunOfOnes(TheCall, 2); - case PPC::BI__builtin_ppc_rlwimi: - return BuiltinConstantArgRange(TheCall, 2, 0, 31) || - ValueIsRunOfOnes(TheCall, 3); - case PPC::BI__builtin_ppc_rldimi: - return BuiltinConstantArgRange(TheCall, 2, 0, 63) || - ValueIsRunOfOnes(TheCall, 3); - case PPC::BI__builtin_ppc_addex: { - if (BuiltinConstantArgRange(TheCall, 2, 0, 3)) - return true; - // Output warning for reserved values 1 to 3. - int ArgValue = - TheCall->getArg(2)->getIntegerConstantExpr(Context)->getSExtValue(); - if (ArgValue != 0) - Diag(TheCall->getBeginLoc(), diag::warn_argument_undefined_behaviour) - << ArgValue; - return false; - } - case PPC::BI__builtin_ppc_mtfsb0: - case PPC::BI__builtin_ppc_mtfsb1: - return BuiltinConstantArgRange(TheCall, 0, 0, 31); - case PPC::BI__builtin_ppc_mtfsf: - return BuiltinConstantArgRange(TheCall, 0, 0, 255); - case PPC::BI__builtin_ppc_mtfsfi: - return BuiltinConstantArgRange(TheCall, 0, 0, 7) || - BuiltinConstantArgRange(TheCall, 1, 0, 15); - case PPC::BI__builtin_ppc_alignx: - return BuiltinConstantArgPower2(TheCall, 0); - case PPC::BI__builtin_ppc_rdlam: - return ValueIsRunOfOnes(TheCall, 2); - case PPC::BI__builtin_vsx_ldrmb: - case PPC::BI__builtin_vsx_strmb: - return BuiltinConstantArgRange(TheCall, 1, 1, 16); - case PPC::BI__builtin_altivec_vcntmbb: - case PPC::BI__builtin_altivec_vcntmbh: - case PPC::BI__builtin_altivec_vcntmbw: - case PPC::BI__builtin_altivec_vcntmbd: - return BuiltinConstantArgRange(TheCall, 1, 0, 1); - case PPC::BI__builtin_vsx_xxgenpcvbm: - case PPC::BI__builtin_vsx_xxgenpcvhm: - case PPC::BI__builtin_vsx_xxgenpcvwm: - case PPC::BI__builtin_vsx_xxgenpcvdm: - return BuiltinConstantArgRange(TheCall, 1, 0, 3); - case PPC::BI__builtin_ppc_test_data_class: { - // Check if the first argument of the __builtin_ppc_test_data_class call is - // valid. The argument must be 'float' or 'double' or '__float128'. - QualType ArgType = TheCall->getArg(0)->getType(); - if (ArgType != QualType(Context.FloatTy) && - ArgType != QualType(Context.DoubleTy) && - ArgType != QualType(Context.Float128Ty)) - return Diag(TheCall->getBeginLoc(), - diag::err_ppc_invalid_test_data_class_type); - return BuiltinConstantArgRange(TheCall, 1, 0, 127); - } - case PPC::BI__builtin_ppc_maxfe: - case PPC::BI__builtin_ppc_minfe: - case PPC::BI__builtin_ppc_maxfl: - case PPC::BI__builtin_ppc_minfl: - case PPC::BI__builtin_ppc_maxfs: - case PPC::BI__builtin_ppc_minfs: { - if (Context.getTargetInfo().getTriple().isOSAIX() && - (BuiltinID == PPC::BI__builtin_ppc_maxfe || - BuiltinID == PPC::BI__builtin_ppc_minfe)) - return Diag(TheCall->getBeginLoc(), diag::err_target_unsupported_type) - << "builtin" << true << 128 << QualType(Context.LongDoubleTy) - << false << Context.getTargetInfo().getTriple().str(); - // Argument type should be exact. - QualType ArgType = QualType(Context.LongDoubleTy); - if (BuiltinID == PPC::BI__builtin_ppc_maxfl || - BuiltinID == PPC::BI__builtin_ppc_minfl) - ArgType = QualType(Context.DoubleTy); - else if (BuiltinID == PPC::BI__builtin_ppc_maxfs || - BuiltinID == PPC::BI__builtin_ppc_minfs) - ArgType = QualType(Context.FloatTy); - for (unsigned I = 0, E = TheCall->getNumArgs(); I < E; ++I) - if (TheCall->getArg(I)->getType() != ArgType) - return Diag(TheCall->getBeginLoc(), - diag::err_typecheck_convert_incompatible) - << TheCall->getArg(I)->getType() << ArgType << 1 << 0 << 0; - return false; - } -#define CUSTOM_BUILTIN(Name, Intr, Types, Acc, Feature) \ - case PPC::BI__builtin_##Name: \ - return BuiltinPPCMMACall(TheCall, BuiltinID, Types); -#include "clang/Basic/BuiltinsPPC.def" - } - return BuiltinConstantArgRange(TheCall, i, l, u); -} - -// Check if the given type is a non-pointer PPC MMA type. This function is used -// in Sema to prevent invalid uses of restricted PPC MMA types. -bool Sema::CheckPPCMMAType(QualType Type, SourceLocation TypeLoc) { - if (Type->isPointerType() || Type->isArrayType()) - return false; - - QualType CoreType = Type.getCanonicalType().getUnqualifiedType(); -#define PPC_VECTOR_TYPE(Name, Id, Size) || CoreType == Context.Id##Ty - if (false -#include "clang/Basic/PPCTypes.def" - ) { - Diag(TypeLoc, diag::err_ppc_invalid_use_mma_type); - return true; - } - return false; -} - // Helper function for CheckHLSLBuiltinFunctionCall bool CheckVectorElementCallArgs(Sema *S, CallExpr *TheCall) { assert(TheCall->getNumArgs() > 1); @@ -5685,201 +3544,6 @@ bool Sema::CheckHLSLBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { return false; } -bool Sema::CheckAMDGCNBuiltinFunctionCall(unsigned BuiltinID, - CallExpr *TheCall) { - // position of memory order and scope arguments in the builtin - unsigned OrderIndex, ScopeIndex; - switch (BuiltinID) { - case AMDGPU::BI__builtin_amdgcn_global_load_lds: { - constexpr const int SizeIdx = 2; - llvm::APSInt Size; - Expr *ArgExpr = TheCall->getArg(SizeIdx); - ExprResult R = VerifyIntegerConstantExpression(ArgExpr, &Size); - if (R.isInvalid()) - return true; - switch (Size.getSExtValue()) { - case 1: - case 2: - case 4: - return false; - default: - Diag(ArgExpr->getExprLoc(), - diag::err_amdgcn_global_load_lds_size_invalid_value) - << ArgExpr->getSourceRange(); - Diag(ArgExpr->getExprLoc(), - diag::note_amdgcn_global_load_lds_size_valid_value) - << ArgExpr->getSourceRange(); - return true; - } - } - case AMDGPU::BI__builtin_amdgcn_get_fpenv: - case AMDGPU::BI__builtin_amdgcn_set_fpenv: - return false; - case AMDGPU::BI__builtin_amdgcn_atomic_inc32: - case AMDGPU::BI__builtin_amdgcn_atomic_inc64: - case AMDGPU::BI__builtin_amdgcn_atomic_dec32: - case AMDGPU::BI__builtin_amdgcn_atomic_dec64: - OrderIndex = 2; - ScopeIndex = 3; - break; - case AMDGPU::BI__builtin_amdgcn_fence: - OrderIndex = 0; - ScopeIndex = 1; - break; - default: - return false; - } - - ExprResult Arg = TheCall->getArg(OrderIndex); - auto ArgExpr = Arg.get(); - Expr::EvalResult ArgResult; - - if (!ArgExpr->EvaluateAsInt(ArgResult, Context)) - return Diag(ArgExpr->getExprLoc(), diag::err_typecheck_expect_int) - << ArgExpr->getType(); - auto Ord = ArgResult.Val.getInt().getZExtValue(); - - // Check validity of memory ordering as per C11 / C++11's memody model. - // Only fence needs check. Atomic dec/inc allow all memory orders. - if (!llvm::isValidAtomicOrderingCABI(Ord)) - return Diag(ArgExpr->getBeginLoc(), - diag::warn_atomic_op_has_invalid_memory_order) - << 0 << ArgExpr->getSourceRange(); - switch (static_cast<llvm::AtomicOrderingCABI>(Ord)) { - case llvm::AtomicOrderingCABI::relaxed: - case llvm::AtomicOrderingCABI::consume: - if (BuiltinID == AMDGPU::BI__builtin_amdgcn_fence) - return Diag(ArgExpr->getBeginLoc(), - diag::warn_atomic_op_has_invalid_memory_order) - << 0 << ArgExpr->getSourceRange(); - break; - case llvm::AtomicOrderingCABI::acquire: - case llvm::AtomicOrderingCABI::release: - case llvm::AtomicOrderingCABI::acq_rel: - case llvm::AtomicOrderingCABI::seq_cst: - break; - } - - Arg = TheCall->getArg(ScopeIndex); - ArgExpr = Arg.get(); - Expr::EvalResult ArgResult1; - // Check that sync scope is a constant literal - if (!ArgExpr->EvaluateAsConstantExpr(ArgResult1, Context)) - return Diag(ArgExpr->getExprLoc(), diag::err_expr_not_string_literal) - << ArgExpr->getType(); - - return false; -} - -bool Sema::CheckSystemZBuiltinFunctionCall(unsigned BuiltinID, - CallExpr *TheCall) { - if (BuiltinID == SystemZ::BI__builtin_tabort) { - Expr *Arg = TheCall->getArg(0); - if (std::optional<llvm::APSInt> AbortCode = - Arg->getIntegerConstantExpr(Context)) - if (AbortCode->getSExtValue() >= 0 && AbortCode->getSExtValue() < 256) - return Diag(Arg->getBeginLoc(), diag::err_systemz_invalid_tabort_code) - << Arg->getSourceRange(); - } - - // For intrinsics which take an immediate value as part of the instruction, - // range check them here. - unsigned i = 0, l = 0, u = 0; - switch (BuiltinID) { - default: return false; - case SystemZ::BI__builtin_s390_lcbb: i = 1; l = 0; u = 15; break; - case SystemZ::BI__builtin_s390_verimb: - case SystemZ::BI__builtin_s390_verimh: - case SystemZ::BI__builtin_s390_verimf: - case SystemZ::BI__builtin_s390_verimg: i = 3; l = 0; u = 255; break; - case SystemZ::BI__builtin_s390_vfaeb: - case SystemZ::BI__builtin_s390_vfaeh: - case SystemZ::BI__builtin_s390_vfaef: - case SystemZ::BI__builtin_s390_vfaebs: - case SystemZ::BI__builtin_s390_vfaehs: - case SystemZ::BI__builtin_s390_vfaefs: - case SystemZ::BI__builtin_s390_vfaezb: - case SystemZ::BI__builtin_s390_vfaezh: - case SystemZ::BI__builtin_s390_vfaezf: - case SystemZ::BI__builtin_s390_vfaezbs: - case SystemZ::BI__builtin_s390_vfaezhs: - case SystemZ::BI__builtin_s390_vfaezfs: i = 2; l = 0; u = 15; break; - case SystemZ::BI__builtin_s390_vfisb: - case SystemZ::BI__builtin_s390_vfidb: - return BuiltinConstantArgRange(TheCall, 1, 0, 15) || - BuiltinConstantArgRange(TheCall, 2, 0, 15); - case SystemZ::BI__builtin_s390_vftcisb: - case SystemZ::BI__builtin_s390_vftcidb: i = 1; l = 0; u = 4095; break; - case SystemZ::BI__builtin_s390_vlbb: i = 1; l = 0; u = 15; break; - case SystemZ::BI__builtin_s390_vpdi: i = 2; l = 0; u = 15; break; - case SystemZ::BI__builtin_s390_vsldb: i = 2; l = 0; u = 15; break; - case SystemZ::BI__builtin_s390_vstrcb: - case SystemZ::BI__builtin_s390_vstrch: - case SystemZ::BI__builtin_s390_vstrcf: - case SystemZ::BI__builtin_s390_vstrczb: - case SystemZ::BI__builtin_s390_vstrczh: - case SystemZ::BI__builtin_s390_vstrczf: - case SystemZ::BI__builtin_s390_vstrcbs: - case SystemZ::BI__builtin_s390_vstrchs: - case SystemZ::BI__builtin_s390_vstrcfs: - case SystemZ::BI__builtin_s390_vstrczbs: - case SystemZ::BI__builtin_s390_vstrczhs: - case SystemZ::BI__builtin_s390_vstrczfs: i = 3; l = 0; u = 15; break; - case SystemZ::BI__builtin_s390_vmslg: i = 3; l = 0; u = 15; break; - case SystemZ::BI__builtin_s390_vfminsb: - case SystemZ::BI__builtin_s390_vfmaxsb: - case SystemZ::BI__builtin_s390_vfmindb: - case SystemZ::BI__builtin_s390_vfmaxdb: i = 2; l = 0; u = 15; break; - case SystemZ::BI__builtin_s390_vsld: i = 2; l = 0; u = 7; break; - case SystemZ::BI__builtin_s390_vsrd: i = 2; l = 0; u = 7; break; - case SystemZ::BI__builtin_s390_vclfnhs: - case SystemZ::BI__builtin_s390_vclfnls: - case SystemZ::BI__builtin_s390_vcfn: - case SystemZ::BI__builtin_s390_vcnf: i = 1; l = 0; u = 15; break; - case SystemZ::BI__builtin_s390_vcrnfs: i = 2; l = 0; u = 15; break; - } - return BuiltinConstantArgRange(TheCall, i, l, u); -} - -bool Sema::CheckWebAssemblyBuiltinFunctionCall(const TargetInfo &TI, - unsigned BuiltinID, - CallExpr *TheCall) { - switch (BuiltinID) { - case WebAssembly::BI__builtin_wasm_ref_null_extern: - return BuiltinWasmRefNullExtern(TheCall); - case WebAssembly::BI__builtin_wasm_ref_null_func: - return BuiltinWasmRefNullFunc(TheCall); - case WebAssembly::BI__builtin_wasm_table_get: - return BuiltinWasmTableGet(TheCall); - case WebAssembly::BI__builtin_wasm_table_set: - return BuiltinWasmTableSet(TheCall); - case WebAssembly::BI__builtin_wasm_table_size: - return BuiltinWasmTableSize(TheCall); - case WebAssembly::BI__builtin_wasm_table_grow: - return BuiltinWasmTableGrow(TheCall); - case WebAssembly::BI__builtin_wasm_table_fill: - return BuiltinWasmTableFill(TheCall); - case WebAssembly::BI__builtin_wasm_table_copy: - return BuiltinWasmTableCopy(TheCall); - } - - return false; -} - -bool Sema::CheckNVPTXBuiltinFunctionCall(const TargetInfo &TI, - unsigned BuiltinID, - CallExpr *TheCall) { - switch (BuiltinID) { - case NVPTX::BI__nvvm_cp_async_ca_shared_global_4: - case NVPTX::BI__nvvm_cp_async_ca_shared_global_8: - case NVPTX::BI__nvvm_cp_async_ca_shared_global_16: - case NVPTX::BI__nvvm_cp_async_cg_shared_global_16: - return checkArgCountAtMost(TheCall, 3); - } - - return false; -} - /// Given a FunctionDecl's FormatAttr, attempts to populate the FomatStringInfo /// parameter with the FormatAttr's correct format_idx and firstDataArg. /// Returns true when the format fits the function and the FormatStringInfo has @@ -6107,40 +3771,6 @@ static void CheckNonNullArguments(Sema &S, } } -// 16 byte ByVal alignment not due to a vector member is not honoured by XL -// on AIX. Emit a warning here that users are generating binary incompatible -// code to be safe. -// Here we try to get information about the alignment of the struct member -// from the struct passed to the caller function. We only warn when the struct -// is passed byval, hence the series of checks and early returns if we are a not -// passing a struct byval. -void Sema::checkAIXMemberAlignment(SourceLocation Loc, const Expr *Arg) { - const auto *ICE = dyn_cast<ImplicitCastExpr>(Arg->IgnoreParens()); - if (!ICE) - return; - - const auto *DR = dyn_cast<DeclRefExpr>(ICE->getSubExpr()); - if (!DR) - return; - - const auto *PD = dyn_cast<ParmVarDecl>(DR->getDecl()); - if (!PD || !PD->getType()->isRecordType()) - return; - - QualType ArgType = Arg->getType(); - for (const FieldDecl *FD : - ArgType->castAs<RecordType>()->getDecl()->fields()) { - if (const auto *AA = FD->getAttr<AlignedAttr>()) { - CharUnits Alignment = - Context.toCharUnitsFromBits(AA->getAlignment(Context)); - if (Alignment.getQuantity() == 16) { - Diag(FD->getLocation(), diag::warn_not_xl_compatible) << FD; - Diag(Loc, diag::note_misaligned_member_used_here) << PD; - } - } - } -} - /// Warn if a pointer or reference argument passed to a function points to an /// object that is less aligned than the parameter. This can happen when /// creating a typedef with a lower alignment than the original type and then @@ -6257,7 +3887,7 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto, FDecl->hasLinkage() && FDecl->getFormalLinkage() != Linkage::Internal && CallType == VariadicDoesNotApply) - checkAIXMemberAlignment((Arg->getExprLoc()), Arg); + PPC().checkAIXMemberAlignment((Arg->getExprLoc()), Arg); QualType ParamTy = Proto->getParamType(ArgIdx); if (ParamTy->isSizelessVectorType()) @@ -6293,10 +3923,10 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto, bool IsCalleeStreamingCompatible = ExtInfo.AArch64SMEAttributes & FunctionType::SME_PStateSMCompatibleMask; - ArmStreamingType CallerFnType = getArmStreamingFnType(CallerFD); + SemaARM::ArmStreamingType CallerFnType = getArmStreamingFnType(CallerFD); if (!IsCalleeStreamingCompatible && - (CallerFnType == ArmStreamingCompatible || - ((CallerFnType == ArmStreaming) ^ IsCalleeStreaming))) { + (CallerFnType == SemaARM::ArmStreamingCompatible || + ((CallerFnType == SemaARM::ArmStreaming) ^ IsCalleeStreaming))) { if (IsScalableArg) Diag(Loc, diag::warn_sme_streaming_pass_return_vl_to_non_streaming) << /*IsArg=*/true; @@ -7159,35 +4789,6 @@ static bool checkBuiltinArgument(Sema &S, CallExpr *E, unsigned ArgIndex) { return false; } -bool Sema::BuiltinWasmRefNullExtern(CallExpr *TheCall) { - if (TheCall->getNumArgs() != 0) - return true; - - TheCall->setType(Context.getWebAssemblyExternrefType()); - - return false; -} - -bool Sema::BuiltinWasmRefNullFunc(CallExpr *TheCall) { - if (TheCall->getNumArgs() != 0) { - Diag(TheCall->getBeginLoc(), diag::err_typecheck_call_too_many_args) - << 0 /*function call*/ << /*expected*/ 0 << TheCall->getNumArgs() - << /*is non object*/ 0; - return true; - } - - // This custom type checking code ensures that the nodes are as expected - // in order to later on generate the necessary builtin. - QualType Pointee = Context.getFunctionType(Context.VoidTy, {}, {}); - QualType Type = Context.getPointerType(Pointee); - Pointee = Context.getAddrSpaceQualType(Pointee, LangAS::wasm_funcref); - Type = Context.getAttributedType(attr::WebAssemblyFuncref, Type, - Context.getPointerType(Pointee)); - TheCall->setType(Type); - - return false; -} - /// We have a call to a function like __sync_fetch_and_add, which is an /// overloaded function based on the pointer type of its first argument. /// The main BuildCallExpr routines have already promoted the types of @@ -8063,55 +5664,6 @@ bool Sema::BuiltinComplex(CallExpr *TheCall) { return false; } -// Customized Sema Checking for VSX builtins that have the following signature: -// vector [...] builtinName(vector [...], vector [...], const int); -// Which takes the same type of vectors (any legal vector type) for the first -// two arguments and takes compile time constant for the third argument. -// Example builtins are : -// vector double vec_xxpermdi(vector double, vector double, int); -// vector short vec_xxsldwi(vector short, vector short, int); -bool Sema::BuiltinVSX(CallExpr *TheCall) { - unsigned ExpectedNumArgs = 3; - if (checkArgCount(TheCall, ExpectedNumArgs)) - return true; - - // Check the third argument is a compile time constant - if (!TheCall->getArg(2)->isIntegerConstantExpr(Context)) - return Diag(TheCall->getBeginLoc(), - diag::err_vsx_builtin_nonconstant_argument) - << 3 /* argument index */ << TheCall->getDirectCallee() - << SourceRange(TheCall->getArg(2)->getBeginLoc(), - TheCall->getArg(2)->getEndLoc()); - - QualType Arg1Ty = TheCall->getArg(0)->getType(); - QualType Arg2Ty = TheCall->getArg(1)->getType(); - - // Check the type of argument 1 and argument 2 are vectors. - SourceLocation BuiltinLoc = TheCall->getBeginLoc(); - if ((!Arg1Ty->isVectorType() && !Arg1Ty->isDependentType()) || - (!Arg2Ty->isVectorType() && !Arg2Ty->isDependentType())) { - return Diag(BuiltinLoc, diag::err_vec_builtin_non_vector) - << TheCall->getDirectCallee() << /*isMorethantwoArgs*/ false - << SourceRange(TheCall->getArg(0)->getBeginLoc(), - TheCall->getArg(1)->getEndLoc()); - } - - // Check the first two arguments are the same type. - if (!Context.hasSameUnqualifiedType(Arg1Ty, Arg2Ty)) { - return Diag(BuiltinLoc, diag::err_vec_builtin_incompatible_vector) - << TheCall->getDirectCallee() << /*isMorethantwoArgs*/ false - << SourceRange(TheCall->getArg(0)->getBeginLoc(), - TheCall->getArg(1)->getEndLoc()); - } - - // When default clang type checking is turned off and the customized type - // checking is used, the returning type of the function must be explicitly - // set. Otherwise it is _Bool by default. - TheCall->setType(Arg1Ty); - - return false; -} - /// BuiltinShuffleVector - Handle __builtin_shufflevector. // This is declared to take (...), so we have to check everything. ExprResult Sema::BuiltinShuffleVector(CallExpr *TheCall) { @@ -8629,360 +6181,6 @@ bool Sema::BuiltinConstantArgShiftedByteOrXXFF(CallExpr *TheCall, int ArgNum, << Arg->getSourceRange(); } -/// BuiltinARMMemoryTaggingCall - Handle calls of memory tagging extensions -bool Sema::BuiltinARMMemoryTaggingCall(unsigned BuiltinID, CallExpr *TheCall) { - if (BuiltinID == AArch64::BI__builtin_arm_irg) { - if (checkArgCount(TheCall, 2)) - return true; - Expr *Arg0 = TheCall->getArg(0); - Expr *Arg1 = TheCall->getArg(1); - - ExprResult FirstArg = DefaultFunctionArrayLvalueConversion(Arg0); - if (FirstArg.isInvalid()) - return true; - QualType FirstArgType = FirstArg.get()->getType(); - if (!FirstArgType->isAnyPointerType()) - return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer) - << "first" << FirstArgType << Arg0->getSourceRange(); - TheCall->setArg(0, FirstArg.get()); - - ExprResult SecArg = DefaultLvalueConversion(Arg1); - if (SecArg.isInvalid()) - return true; - QualType SecArgType = SecArg.get()->getType(); - if (!SecArgType->isIntegerType()) - return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_integer) - << "second" << SecArgType << Arg1->getSourceRange(); - - // Derive the return type from the pointer argument. - TheCall->setType(FirstArgType); - return false; - } - - if (BuiltinID == AArch64::BI__builtin_arm_addg) { - if (checkArgCount(TheCall, 2)) - return true; - - Expr *Arg0 = TheCall->getArg(0); - ExprResult FirstArg = DefaultFunctionArrayLvalueConversion(Arg0); - if (FirstArg.isInvalid()) - return true; - QualType FirstArgType = FirstArg.get()->getType(); - if (!FirstArgType->isAnyPointerType()) - return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer) - << "first" << FirstArgType << Arg0->getSourceRange(); - TheCall->setArg(0, FirstArg.get()); - - // Derive the return type from the pointer argument. - TheCall->setType(FirstArgType); - - // Second arg must be an constant in range [0,15] - return BuiltinConstantArgRange(TheCall, 1, 0, 15); - } - - if (BuiltinID == AArch64::BI__builtin_arm_gmi) { - if (checkArgCount(TheCall, 2)) - return true; - Expr *Arg0 = TheCall->getArg(0); - Expr *Arg1 = TheCall->getArg(1); - - ExprResult FirstArg = DefaultFunctionArrayLvalueConversion(Arg0); - if (FirstArg.isInvalid()) - return true; - QualType FirstArgType = FirstArg.get()->getType(); - if (!FirstArgType->isAnyPointerType()) - return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer) - << "first" << FirstArgType << Arg0->getSourceRange(); - - QualType SecArgType = Arg1->getType(); - if (!SecArgType->isIntegerType()) - return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_integer) - << "second" << SecArgType << Arg1->getSourceRange(); - TheCall->setType(Context.IntTy); - return false; - } - - if (BuiltinID == AArch64::BI__builtin_arm_ldg || - BuiltinID == AArch64::BI__builtin_arm_stg) { - if (checkArgCount(TheCall, 1)) - return true; - Expr *Arg0 = TheCall->getArg(0); - ExprResult FirstArg = DefaultFunctionArrayLvalueConversion(Arg0); - if (FirstArg.isInvalid()) - return true; - - QualType FirstArgType = FirstArg.get()->getType(); - if (!FirstArgType->isAnyPointerType()) - return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer) - << "first" << FirstArgType << Arg0->getSourceRange(); - TheCall->setArg(0, FirstArg.get()); - - // Derive the return type from the pointer argument. - if (BuiltinID == AArch64::BI__builtin_arm_ldg) - TheCall->setType(FirstArgType); - return false; - } - - if (BuiltinID == AArch64::BI__builtin_arm_subp) { - Expr *ArgA = TheCall->getArg(0); - Expr *ArgB = TheCall->getArg(1); - - ExprResult ArgExprA = DefaultFunctionArrayLvalueConversion(ArgA); - ExprResult ArgExprB = DefaultFunctionArrayLvalueConversion(ArgB); - - if (ArgExprA.isInvalid() || ArgExprB.isInvalid()) - return true; - - QualType ArgTypeA = ArgExprA.get()->getType(); - QualType ArgTypeB = ArgExprB.get()->getType(); - - auto isNull = [&] (Expr *E) -> bool { - return E->isNullPointerConstant( - Context, Expr::NPC_ValueDependentIsNotNull); }; - - // argument should be either a pointer or null - if (!ArgTypeA->isAnyPointerType() && !isNull(ArgA)) - return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_null_or_pointer) - << "first" << ArgTypeA << ArgA->getSourceRange(); - - if (!ArgTypeB->isAnyPointerType() && !isNull(ArgB)) - return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_null_or_pointer) - << "second" << ArgTypeB << ArgB->getSourceRange(); - - // Ensure Pointee types are compatible - if (ArgTypeA->isAnyPointerType() && !isNull(ArgA) && - ArgTypeB->isAnyPointerType() && !isNull(ArgB)) { - QualType pointeeA = ArgTypeA->getPointeeType(); - QualType pointeeB = ArgTypeB->getPointeeType(); - if (!Context.typesAreCompatible( - Context.getCanonicalType(pointeeA).getUnqualifiedType(), - Context.getCanonicalType(pointeeB).getUnqualifiedType())) { - return Diag(TheCall->getBeginLoc(), diag::err_typecheck_sub_ptr_compatible) - << ArgTypeA << ArgTypeB << ArgA->getSourceRange() - << ArgB->getSourceRange(); - } - } - - // at least one argument should be pointer type - if (!ArgTypeA->isAnyPointerType() && !ArgTypeB->isAnyPointerType()) - return Diag(TheCall->getBeginLoc(), diag::err_memtag_any2arg_pointer) - << ArgTypeA << ArgTypeB << ArgA->getSourceRange(); - - if (isNull(ArgA)) // adopt type of the other pointer - ArgExprA = ImpCastExprToType(ArgExprA.get(), ArgTypeB, CK_NullToPointer); - - if (isNull(ArgB)) - ArgExprB = ImpCastExprToType(ArgExprB.get(), ArgTypeA, CK_NullToPointer); - - TheCall->setArg(0, ArgExprA.get()); - TheCall->setArg(1, ArgExprB.get()); - TheCall->setType(Context.LongLongTy); - return false; - } - assert(false && "Unhandled ARM MTE intrinsic"); - return true; -} - -/// BuiltinARMSpecialReg - Handle a check if argument ArgNum of CallExpr -/// TheCall is an ARM/AArch64 special register string literal. -bool Sema::BuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall, - int ArgNum, unsigned ExpectedFieldNum, - bool AllowName) { - bool IsARMBuiltin = BuiltinID == ARM::BI__builtin_arm_rsr64 || - BuiltinID == ARM::BI__builtin_arm_wsr64 || - BuiltinID == ARM::BI__builtin_arm_rsr || - BuiltinID == ARM::BI__builtin_arm_rsrp || - BuiltinID == ARM::BI__builtin_arm_wsr || - BuiltinID == ARM::BI__builtin_arm_wsrp; - bool IsAArch64Builtin = BuiltinID == AArch64::BI__builtin_arm_rsr64 || - BuiltinID == AArch64::BI__builtin_arm_wsr64 || - BuiltinID == AArch64::BI__builtin_arm_rsr128 || - BuiltinID == AArch64::BI__builtin_arm_wsr128 || - BuiltinID == AArch64::BI__builtin_arm_rsr || - BuiltinID == AArch64::BI__builtin_arm_rsrp || - BuiltinID == AArch64::BI__builtin_arm_wsr || - BuiltinID == AArch64::BI__builtin_arm_wsrp; - assert((IsARMBuiltin || IsAArch64Builtin) && "Unexpected ARM builtin."); - - // We can't check the value of a dependent argument. - Expr *Arg = TheCall->getArg(ArgNum); - if (Arg->isTypeDependent() || Arg->isValueDependent()) - return false; - - // Check if the argument is a string literal. - if (!isa<StringLiteral>(Arg->IgnoreParenImpCasts())) - return Diag(TheCall->getBeginLoc(), diag::err_expr_not_string_literal) - << Arg->getSourceRange(); - - // Check the type of special register given. - StringRef Reg = cast<StringLiteral>(Arg->IgnoreParenImpCasts())->getString(); - SmallVector<StringRef, 6> Fields; - Reg.split(Fields, ":"); - - if (Fields.size() != ExpectedFieldNum && !(AllowName && Fields.size() == 1)) - return Diag(TheCall->getBeginLoc(), diag::err_arm_invalid_specialreg) - << Arg->getSourceRange(); - - // If the string is the name of a register then we cannot check that it is - // valid here but if the string is of one the forms described in ACLE then we - // can check that the supplied fields are integers and within the valid - // ranges. - if (Fields.size() > 1) { - bool FiveFields = Fields.size() == 5; - - bool ValidString = true; - if (IsARMBuiltin) { - ValidString &= Fields[0].starts_with_insensitive("cp") || - Fields[0].starts_with_insensitive("p"); - if (ValidString) - Fields[0] = Fields[0].drop_front( - Fields[0].starts_with_insensitive("cp") ? 2 : 1); - - ValidString &= Fields[2].starts_with_insensitive("c"); - if (ValidString) - Fields[2] = Fields[2].drop_front(1); - - if (FiveFields) { - ValidString &= Fields[3].starts_with_insensitive("c"); - if (ValidString) - Fields[3] = Fields[3].drop_front(1); - } - } - - SmallVector<int, 5> Ranges; - if (FiveFields) - Ranges.append({IsAArch64Builtin ? 1 : 15, 7, 15, 15, 7}); - else - Ranges.append({15, 7, 15}); - - for (unsigned i=0; i<Fields.size(); ++i) { - int IntField; - ValidString &= !Fields[i].getAsInteger(10, IntField); - ValidString &= (IntField >= 0 && IntField <= Ranges[i]); - } - - if (!ValidString) - return Diag(TheCall->getBeginLoc(), diag::err_arm_invalid_specialreg) - << Arg->getSourceRange(); - } else if (IsAArch64Builtin && Fields.size() == 1) { - // This code validates writes to PSTATE registers. - - // Not a write. - if (TheCall->getNumArgs() != 2) - return false; - - // The 128-bit system register accesses do not touch PSTATE. - if (BuiltinID == AArch64::BI__builtin_arm_rsr128 || - BuiltinID == AArch64::BI__builtin_arm_wsr128) - return false; - - // These are the named PSTATE accesses using "MSR (immediate)" instructions, - // along with the upper limit on the immediates allowed. - auto MaxLimit = llvm::StringSwitch<std::optional<unsigned>>(Reg) - .CaseLower("spsel", 15) - .CaseLower("daifclr", 15) - .CaseLower("daifset", 15) - .CaseLower("pan", 15) - .CaseLower("uao", 15) - .CaseLower("dit", 15) - .CaseLower("ssbs", 15) - .CaseLower("tco", 15) - .CaseLower("allint", 1) - .CaseLower("pm", 1) - .Default(std::nullopt); - - // If this is not a named PSTATE, just continue without validating, as this - // will be lowered to an "MSR (register)" instruction directly - if (!MaxLimit) - return false; - - // Here we only allow constants in the range for that pstate, as required by - // the ACLE. - // - // While clang also accepts the names of system registers in its ACLE - // intrinsics, we prevent this with the PSTATE names used in MSR (immediate) - // as the value written via a register is different to the value used as an - // immediate to have the same effect. e.g., for the instruction `msr tco, - // x0`, it is bit 25 of register x0 that is written into PSTATE.TCO, but - // with `msr tco, #imm`, it is bit 0 of xN that is written into PSTATE.TCO. - // - // If a programmer wants to codegen the MSR (register) form of `msr tco, - // xN`, they can still do so by specifying the register using five - // colon-separated numbers in a string. - return BuiltinConstantArgRange(TheCall, 1, 0, *MaxLimit); - } - - return false; -} - -/// BuiltinPPCMMACall - Check the call to a PPC MMA builtin for validity. -/// Emit an error and return true on failure; return false on success. -/// TypeStr is a string containing the type descriptor of the value returned by -/// the builtin and the descriptors of the expected type of the arguments. -bool Sema::BuiltinPPCMMACall(CallExpr *TheCall, unsigned BuiltinID, - const char *TypeStr) { - - assert((TypeStr[0] != '\0') && - "Invalid types in PPC MMA builtin declaration"); - - unsigned Mask = 0; - unsigned ArgNum = 0; - - // The first type in TypeStr is the type of the value returned by the - // builtin. So we first read that type and change the type of TheCall. - QualType type = DecodePPCMMATypeFromStr(Context, TypeStr, Mask); - TheCall->setType(type); - - while (*TypeStr != '\0') { - Mask = 0; - QualType ExpectedType = DecodePPCMMATypeFromStr(Context, TypeStr, Mask); - if (ArgNum >= TheCall->getNumArgs()) { - ArgNum++; - break; - } - - Expr *Arg = TheCall->getArg(ArgNum); - QualType PassedType = Arg->getType(); - QualType StrippedRVType = PassedType.getCanonicalType(); - - // Strip Restrict/Volatile qualifiers. - if (StrippedRVType.isRestrictQualified() || - StrippedRVType.isVolatileQualified()) - StrippedRVType = StrippedRVType.getCanonicalType().getUnqualifiedType(); - - // The only case where the argument type and expected type are allowed to - // mismatch is if the argument type is a non-void pointer (or array) and - // expected type is a void pointer. - if (StrippedRVType != ExpectedType) - if (!(ExpectedType->isVoidPointerType() && - (StrippedRVType->isPointerType() || StrippedRVType->isArrayType()))) - return Diag(Arg->getBeginLoc(), - diag::err_typecheck_convert_incompatible) - << PassedType << ExpectedType << 1 << 0 << 0; - - // If the value of the Mask is not 0, we have a constraint in the size of - // the integer argument so here we ensure the argument is a constant that - // is in the valid range. - if (Mask != 0 && BuiltinConstantArgRange(TheCall, ArgNum, 0, Mask, true)) - return true; - - ArgNum++; - } - - // In case we exited early from the previous loop, there are other types to - // read from TypeStr. So we need to read them all to ensure we have the right - // number of arguments in TheCall and if it is not the case, to display a - // better error message. - while (*TypeStr != '\0') { - (void) DecodePPCMMATypeFromStr(Context, TypeStr, Mask); - ArgNum++; - } - if (checkArgCount(TheCall, ArgNum)) - return true; - - return false; -} - /// BuiltinLongjmp - Handle __builtin_longjmp(void *env[5], int val). /// This checks that the target supports __builtin_longjmp and /// that val is a constant 1. @@ -12712,7 +9910,7 @@ Sema::CheckReturnValExpr(Expr *RetValExp, QualType lhsType, // PPC MMA non-pointer types are not allowed as return type. Checking the type // here prevent the user from using a PPC MMA type as trailing return type. if (Context.getTargetInfo().getTriple().isPPC64()) - CheckPPCMMAType(RetValExp->getType(), ReturnLoc); + PPC().CheckPPCMMAType(RetValExp->getType(), ReturnLoc); } /// Check for comparisons of floating-point values using == and !=. Issue a @@ -18390,168 +15588,6 @@ ExprResult Sema::BuiltinMatrixColumnMajorStore(CallExpr *TheCall, return CallResult; } -/// Checks the argument at the given index is a WebAssembly table and if it -/// is, sets ElTy to the element type. -static bool CheckWasmBuiltinArgIsTable(Sema &S, CallExpr *E, unsigned ArgIndex, - QualType &ElTy) { - Expr *ArgExpr = E->getArg(ArgIndex); - const auto *ATy = dyn_cast<ArrayType>(ArgExpr->getType()); - if (!ATy || !ATy->getElementType().isWebAssemblyReferenceType()) { - return S.Diag(ArgExpr->getBeginLoc(), - diag::err_wasm_builtin_arg_must_be_table_type) - << ArgIndex + 1 << ArgExpr->getSourceRange(); - } - ElTy = ATy->getElementType(); - return false; -} - -/// Checks the argument at the given index is an integer. -static bool CheckWasmBuiltinArgIsInteger(Sema &S, CallExpr *E, - unsigned ArgIndex) { - Expr *ArgExpr = E->getArg(ArgIndex); - if (!ArgExpr->getType()->isIntegerType()) { - return S.Diag(ArgExpr->getBeginLoc(), - diag::err_wasm_builtin_arg_must_be_integer_type) - << ArgIndex + 1 << ArgExpr->getSourceRange(); - } - return false; -} - -/// Check that the first argument is a WebAssembly table, and the second -/// is an index to use as index into the table. -bool Sema::BuiltinWasmTableGet(CallExpr *TheCall) { - if (checkArgCount(TheCall, 2)) - return true; - - QualType ElTy; - if (CheckWasmBuiltinArgIsTable(*this, TheCall, 0, ElTy)) - return true; - - if (CheckWasmBuiltinArgIsInteger(*this, TheCall, 1)) - return true; - - // If all is well, we set the type of TheCall to be the type of the - // element of the table. - // i.e. a table.get on an externref table has type externref, - // or whatever the type of the table element is. - TheCall->setType(ElTy); - - return false; -} - -/// Check that the first argumnet is a WebAssembly table, the second is -/// an index to use as index into the table and the third is the reference -/// type to set into the table. -bool Sema::BuiltinWasmTableSet(CallExpr *TheCall) { - if (checkArgCount(TheCall, 3)) - return true; - - QualType ElTy; - if (CheckWasmBuiltinArgIsTable(*this, TheCall, 0, ElTy)) - return true; - - if (CheckWasmBuiltinArgIsInteger(*this, TheCall, 1)) - return true; - - if (!Context.hasSameType(ElTy, TheCall->getArg(2)->getType())) - return true; - - return false; -} - -/// Check that the argument is a WebAssembly table. -bool Sema::BuiltinWasmTableSize(CallExpr *TheCall) { - if (checkArgCount(TheCall, 1)) - return true; - - QualType ElTy; - if (CheckWasmBuiltinArgIsTable(*this, TheCall, 0, ElTy)) - return true; - - return false; -} - -/// Check that the first argument is a WebAssembly table, the second is the -/// value to use for new elements (of a type matching the table type), the -/// third value is an integer. -bool Sema::BuiltinWasmTableGrow(CallExpr *TheCall) { - if (checkArgCount(TheCall, 3)) - return true; - - QualType ElTy; - if (CheckWasmBuiltinArgIsTable(*this, TheCall, 0, ElTy)) - return true; - - Expr *NewElemArg = TheCall->getArg(1); - if (!Context.hasSameType(ElTy, NewElemArg->getType())) { - return Diag(NewElemArg->getBeginLoc(), - diag::err_wasm_builtin_arg_must_match_table_element_type) - << 2 << 1 << NewElemArg->getSourceRange(); - } - - if (CheckWasmBuiltinArgIsInteger(*this, TheCall, 2)) - return true; - - return false; -} - -/// Check that the first argument is a WebAssembly table, the second is an -/// integer, the third is the value to use to fill the table (of a type -/// matching the table type), and the fourth is an integer. -bool Sema::BuiltinWasmTableFill(CallExpr *TheCall) { - if (checkArgCount(TheCall, 4)) - return true; - - QualType ElTy; - if (CheckWasmBuiltinArgIsTable(*this, TheCall, 0, ElTy)) - return true; - - if (CheckWasmBuiltinArgIsInteger(*this, TheCall, 1)) - return true; - - Expr *NewElemArg = TheCall->getArg(2); - if (!Context.hasSameType(ElTy, NewElemArg->getType())) { - return Diag(NewElemArg->getBeginLoc(), - diag::err_wasm_builtin_arg_must_match_table_element_type) - << 3 << 1 << NewElemArg->getSourceRange(); - } - - if (CheckWasmBuiltinArgIsInteger(*this, TheCall, 3)) - return true; - - return false; -} - -/// Check that the first argument is a WebAssembly table, the second is also a -/// WebAssembly table (of the same element type), and the third to fifth -/// arguments are integers. -bool Sema::BuiltinWasmTableCopy(CallExpr *TheCall) { - if (checkArgCount(TheCall, 5)) - return true; - - QualType XElTy; - if (CheckWasmBuiltinArgIsTable(*this, TheCall, 0, XElTy)) - return true; - - QualType YElTy; - if (CheckWasmBuiltinArgIsTable(*this, TheCall, 1, YElTy)) - return true; - - Expr *TableYArg = TheCall->getArg(1); - if (!Context.hasSameType(XElTy, YElTy)) { - return Diag(TableYArg->getBeginLoc(), - diag::err_wasm_builtin_arg_must_match_table_element_type) - << 2 << 1 << TableYArg->getSourceRange(); - } - - for (int I = 2; I <= 4; I++) { - if (CheckWasmBuiltinArgIsInteger(*this, TheCall, I)) - return true; - } - - return false; -} - /// \brief Enforce the bounds of a TCB /// CheckTCBEnforcement - Enforces that every function in a named TCB only /// directly calls other functions in the same TCB as marked by the enforce_tcb |