diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 3abb49312255a..64d4c5547341e 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -2486,15 +2486,6 @@ class ASTContext : public RefCountedBase { /// types. bool areCompatibleVectorTypes(QualType FirstVec, QualType SecondVec); - /// Return true if the given types are an SVE builtin and a VectorType that - /// is a fixed-length representation of the SVE builtin for a specific - /// vector-length. - bool areCompatibleSveTypes(QualType FirstType, QualType SecondType); - - /// Return true if the given vector types are lax-compatible SVE vector types, - /// false otherwise. - bool areLaxCompatibleSveTypes(QualType FirstType, QualType SecondType); - /// Return true if the given types are an RISC-V vector builtin type and a /// VectorType that is a fixed-length representation of the RISC-V vector /// builtin type for a specific vector-length. diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index 789761c1f3647..8054be1bb4e88 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -503,6 +503,9 @@ LANGOPT(OmitVTableRTTI, 1, 0, LANGOPT(VScaleMin, 32, 0, "Minimum vscale value") LANGOPT(VScaleMax, 32, 0, "Maximum vscale value") +LANGOPT(VScaleStreamingMin, 32, 0, "Minimum streaming vscale value") +LANGOPT(VScaleStreamingMax, 32, 0, "Maximum streaming vscale value") + ENUM_LANGOPT(ExtendIntArgs, ExtendArgsKind, 1, ExtendArgsKind::ExtendTo32, "Controls how scalar integer arguments are extended in calls " "to unprototyped and varargs functions") diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h index c3bce6e807f34..00e6f88d648ca 100644 --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -1034,9 +1034,16 @@ class TargetInfo : public TransferrableTargetInfo, /// set of primary and secondary targets. virtual llvm::SmallVector getTargetBuiltins() const = 0; + enum class ArmStreamingKind { + NotStreaming, + StreamingCompatible, + Streaming, + }; + /// Returns target-specific min and max values VScale_Range. virtual std::optional> - getVScaleRange(const LangOptions &LangOpts, bool IsArmStreamingFunction, + getVScaleRange(const LangOptions &LangOpts, + ArmStreamingKind IsArmStreamingFunction, llvm::StringMap *FeatureMap = nullptr) const { return std::nullopt; } diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 152df89118a6a..2e8d5b18483d7 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -5173,6 +5173,14 @@ def msve_vector_bits_EQ : Joined<["-"], "msve-vector-bits=">, Group, HelpText<"Specify the size in bits of an SVE vector register. Defaults to the" " vector length agnostic value of \"scalable\". (AArch64 only)">; +def msve_streaming_vector_bits_EQ + : Joined<["-"], "msve-streaming-vector-bits=">, + Group, + Visibility<[ClangOption, FlangOption]>, + HelpText< + "Specify the size in bits of an SVE vector register in streaming " + "mode. Defaults to the vector length agnostic value of " + "\"scalable\". (AArch64 only)">; } // let Flags = [TargetSpecific] def mvscale_min_EQ : Joined<["-"], "mvscale-min=">, @@ -5184,6 +5192,17 @@ def mvscale_max_EQ : Joined<["-"], "mvscale-max=">, HelpText<"Specify the vscale maximum. Defaults to the" " vector length agnostic value of \"0\". (AArch64/RISC-V only)">, MarshallingInfoInt>; +def mvscale_streaming_min_EQ + : Joined<["-"], "mvscale-streaming-min=">, + Visibility<[CC1Option, FC1Option]>, + HelpText<"Specify the vscale minimum. Defaults to \"1\". (AArch64 only)">, + MarshallingInfoInt>; +def mvscale_streaming_max_EQ + : Joined<["-"], "mvscale-streaming-max=">, + Visibility<[CC1Option, FC1Option]>, + HelpText<"Specify the vscale maximum. Defaults to the" + " vector length agnostic value of \"0\". (AArch64 only)">, + MarshallingInfoInt>; def msign_return_address_EQ : Joined<["-"], "msign-return-address=">, Visibility<[ClangOption, CC1Option]>, diff --git a/clang/include/clang/Sema/SemaARM.h b/clang/include/clang/Sema/SemaARM.h index ce79e94ebdd9b..788a7abf5f9c1 100644 --- a/clang/include/clang/Sema/SemaARM.h +++ b/clang/include/clang/Sema/SemaARM.h @@ -82,6 +82,15 @@ class SemaARM : public SemaBase { void handleInterruptSaveFPAttr(Decl *D, const ParsedAttr &AL); void CheckSMEFunctionDefAttributes(const FunctionDecl *FD); + + /// Return true if the given types are an SVE builtin and a VectorType that + /// is a fixed-length representation of the SVE builtin for a specific + /// vector-length. + bool areCompatibleSveTypes(QualType FirstType, QualType SecondType); + + /// Return true if the given vector types are lax-compatible SVE vector types, + /// false otherwise. + bool areLaxCompatibleSveTypes(QualType FirstType, QualType SecondType); }; SemaARM::ArmStreamingType getArmStreamingFnType(const FunctionDecl *FD); diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 4d44f23c0f503..07c70ea770d66 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -10443,92 +10443,11 @@ bool ASTContext::areCompatibleVectorTypes(QualType FirstVec, return false; } -/// getSVETypeSize - Return SVE vector or predicate register size. -static uint64_t getSVETypeSize(ASTContext &Context, const BuiltinType *Ty) { - assert(Ty->isSveVLSBuiltinType() && "Invalid SVE Type"); - if (Ty->getKind() == BuiltinType::SveBool || - Ty->getKind() == BuiltinType::SveCount) - return (Context.getLangOpts().VScaleMin * 128) / Context.getCharWidth(); - return Context.getLangOpts().VScaleMin * 128; -} - -bool ASTContext::areCompatibleSveTypes(QualType FirstType, - QualType SecondType) { - auto IsValidCast = [this](QualType FirstType, QualType SecondType) { - if (const auto *BT = FirstType->getAs()) { - if (const auto *VT = SecondType->getAs()) { - // Predicates have the same representation as uint8 so we also have to - // check the kind to make these types incompatible. - if (VT->getVectorKind() == VectorKind::SveFixedLengthPredicate) - return BT->getKind() == BuiltinType::SveBool; - else if (VT->getVectorKind() == VectorKind::SveFixedLengthData) - return VT->getElementType().getCanonicalType() == - FirstType->getSveEltType(*this); - else if (VT->getVectorKind() == VectorKind::Generic) - return getTypeSize(SecondType) == getSVETypeSize(*this, BT) && - hasSameType(VT->getElementType(), - getBuiltinVectorTypeInfo(BT).ElementType); - } - } - return false; - }; - - return IsValidCast(FirstType, SecondType) || - IsValidCast(SecondType, FirstType); -} - -bool ASTContext::areLaxCompatibleSveTypes(QualType FirstType, - QualType SecondType) { - auto IsLaxCompatible = [this](QualType FirstType, QualType SecondType) { - const auto *BT = FirstType->getAs(); - if (!BT) - return false; - - const auto *VecTy = SecondType->getAs(); - if (VecTy && (VecTy->getVectorKind() == VectorKind::SveFixedLengthData || - VecTy->getVectorKind() == VectorKind::Generic)) { - const LangOptions::LaxVectorConversionKind LVCKind = - getLangOpts().getLaxVectorConversions(); - - // Can not convert between sve predicates and sve vectors because of - // different size. - if (BT->getKind() == BuiltinType::SveBool && - VecTy->getVectorKind() == VectorKind::SveFixedLengthData) - return false; - - // If __ARM_FEATURE_SVE_BITS != N do not allow GNU vector lax conversion. - // "Whenever __ARM_FEATURE_SVE_BITS==N, GNUT implicitly - // converts to VLAT and VLAT implicitly converts to GNUT." - // ACLE Spec Version 00bet6, 3.7.3.2. Behavior common to vectors and - // predicates. - if (VecTy->getVectorKind() == VectorKind::Generic && - getTypeSize(SecondType) != getSVETypeSize(*this, BT)) - return false; - - // If -flax-vector-conversions=all is specified, the types are - // certainly compatible. - if (LVCKind == LangOptions::LaxVectorConversionKind::All) - return true; - - // If -flax-vector-conversions=integer is specified, the types are - // compatible if the elements are integer types. - if (LVCKind == LangOptions::LaxVectorConversionKind::Integer) - return VecTy->getElementType().getCanonicalType()->isIntegerType() && - FirstType->getSveEltType(*this)->isIntegerType(); - } - - return false; - }; - - return IsLaxCompatible(FirstType, SecondType) || - IsLaxCompatible(SecondType, FirstType); -} - /// getRVVTypeSize - Return RVV vector register size. static uint64_t getRVVTypeSize(ASTContext &Context, const BuiltinType *Ty) { assert(Ty->isRVVVLSBuiltinType() && "Invalid RVV Type"); - auto VScale = - Context.getTargetInfo().getVScaleRange(Context.getLangOpts(), false); + auto VScale = Context.getTargetInfo().getVScaleRange( + Context.getLangOpts(), TargetInfo::ArmStreamingKind::NotStreaming); if (!VScale) return 0; diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index ecf5be220439b..40da699f052f9 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -4273,7 +4273,8 @@ void CXXNameMangler::mangleRISCVFixedRVVVectorType(const VectorType *T) { // Apend the LMUL suffix. auto VScale = getASTContext().getTargetInfo().getVScaleRange( - getASTContext().getLangOpts(), false); + getASTContext().getLangOpts(), + TargetInfo::ArmStreamingKind::NotStreaming); unsigned VLen = VScale->first * llvm::RISCV::RVVBitsPerBlock; if (T->getVectorKind() == VectorKind::RVVFixedLengthData) { diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp index e8abdf9aafd82..2e4234f0b5fae 100644 --- a/clang/lib/Basic/Targets/AArch64.cpp +++ b/clang/lib/Basic/Targets/AArch64.cpp @@ -820,16 +820,23 @@ AArch64TargetInfo::getTargetBuiltins() const { std::optional> AArch64TargetInfo::getVScaleRange(const LangOptions &LangOpts, - bool IsArmStreamingFunction, + ArmStreamingKind IsArmStreamingFunction, llvm::StringMap *FeatureMap) const { - if (LangOpts.VScaleMin || LangOpts.VScaleMax) + if (IsArmStreamingFunction == ArmStreamingKind::NotStreaming && + (LangOpts.VScaleMin || LangOpts.VScaleMax)) return std::pair( LangOpts.VScaleMin ? LangOpts.VScaleMin : 1, LangOpts.VScaleMax); + if (IsArmStreamingFunction == ArmStreamingKind::Streaming && + (LangOpts.VScaleStreamingMin || LangOpts.VScaleStreamingMax)) + return std::pair( + LangOpts.VScaleStreamingMin ? LangOpts.VScaleStreamingMin : 1, + LangOpts.VScaleStreamingMax); + if (hasFeature("sve") || (FeatureMap && (FeatureMap->lookup("sve")))) return std::pair(1, 16); - if (IsArmStreamingFunction && + if (IsArmStreamingFunction == ArmStreamingKind::Streaming && (hasFeature("sme") || (FeatureMap && (FeatureMap->lookup("sme"))))) return std::pair(1, 16); diff --git a/clang/lib/Basic/Targets/AArch64.h b/clang/lib/Basic/Targets/AArch64.h index a4c65361105e4..6dc96ad6cb3d2 100644 --- a/clang/lib/Basic/Targets/AArch64.h +++ b/clang/lib/Basic/Targets/AArch64.h @@ -197,7 +197,8 @@ class LLVM_LIBRARY_VISIBILITY AArch64TargetInfo : public TargetInfo { llvm::SmallVector getTargetBuiltins() const override; std::optional> - getVScaleRange(const LangOptions &LangOpts, bool IsArmStreamingFunction, + getVScaleRange(const LangOptions &LangOpts, + ArmStreamingKind IsArmStreamingFunction, llvm::StringMap *FeatureMap = nullptr) const override; bool doesFeatureAffectCodeGen(StringRef Name) const override; bool validateCpuSupports(StringRef FeatureStr) const override; diff --git a/clang/lib/Basic/Targets/RISCV.cpp b/clang/lib/Basic/Targets/RISCV.cpp index 2098449dd83a3..8a28c0788aad7 100644 --- a/clang/lib/Basic/Targets/RISCV.cpp +++ b/clang/lib/Basic/Targets/RISCV.cpp @@ -222,7 +222,7 @@ void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts, // Currently we support the v1.0 RISC-V V intrinsics. Builder.defineMacro("__riscv_v_intrinsic", Twine(getVersionValue(1, 0))); - auto VScale = getVScaleRange(Opts, false); + auto VScale = getVScaleRange(Opts, ArmStreamingKind::NotStreaming); if (VScale && VScale->first && VScale->first == VScale->second) Builder.defineMacro("__riscv_v_fixed_vlen", Twine(VScale->first * llvm::RISCV::RVVBitsPerBlock)); @@ -367,7 +367,7 @@ bool RISCVTargetInfo::initFeatureMap( std::optional> RISCVTargetInfo::getVScaleRange(const LangOptions &LangOpts, - bool IsArmStreamingFunction, + ArmStreamingKind IsArmStreamingFunction, llvm::StringMap *FeatureMap) const { // RISCV::RVVBitsPerBlock is 64. unsigned VScaleMin = ISAInfo->getMinVLen() / llvm::RISCV::RVVBitsPerBlock; diff --git a/clang/lib/Basic/Targets/RISCV.h b/clang/lib/Basic/Targets/RISCV.h index 0b36c9d5d9cc8..2779538e5b741 100644 --- a/clang/lib/Basic/Targets/RISCV.h +++ b/clang/lib/Basic/Targets/RISCV.h @@ -99,7 +99,8 @@ class RISCVTargetInfo : public TargetInfo { const std::vector &FeaturesVec) const override; std::optional> - getVScaleRange(const LangOptions &LangOpts, bool IsArmStreamingFunction, + getVScaleRange(const LangOptions &LangOpts, + ArmStreamingKind IsArmStreamingFunction, llvm::StringMap *FeatureMap = nullptr) const override; bool hasFeature(StringRef Feature) const override; diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 56562002e7194..52707a1fd9f75 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -1108,10 +1108,16 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, // Add vscale_range attribute if appropriate. llvm::StringMap FeatureMap; - bool IsArmStreaming = false; + auto IsArmStreaming = TargetInfo::ArmStreamingKind::NotStreaming; if (FD) { getContext().getFunctionFeatureMap(FeatureMap, FD); - IsArmStreaming = IsArmStreamingFunction(FD, true); + if (const auto *T = FD->getType()->getAs()) + if (T->getAArch64SMEAttributes() & + FunctionType::SME_PStateSMCompatibleMask) + IsArmStreaming = TargetInfo::ArmStreamingKind::StreamingCompatible; + + if (IsArmStreamingFunction(FD, true)) + IsArmStreaming = TargetInfo::ArmStreamingKind::Streaming; } std::optional> VScaleRange = getContext().getTargetInfo().getVScaleRange(getLangOpts(), IsArmStreaming, diff --git a/clang/lib/CodeGen/Targets/RISCV.cpp b/clang/lib/CodeGen/Targets/RISCV.cpp index 14d4cee7c61d3..cc3d487da83b5 100644 --- a/clang/lib/CodeGen/Targets/RISCV.cpp +++ b/clang/lib/CodeGen/Targets/RISCV.cpp @@ -544,7 +544,7 @@ ABIArgInfo RISCVABIInfo::coerceVLSVector(QualType Ty, unsigned ABIVLen) const { assert(VT->getElementType()->isBuiltinType() && "expected builtin type!"); auto VScale = getContext().getTargetInfo().getVScaleRange( - getContext().getLangOpts(), false); + getContext().getLangOpts(), TargetInfo::ArmStreamingKind::NotStreaming); unsigned NumElts = VT->getNumElements(); llvm::Type *EltType = llvm::Type::getInt1Ty(getVMContext()); diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 1d11be1d82be8..24ec25601881f 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -1666,7 +1666,7 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args, } // Handle -msve_vector_bits= - if (Arg *A = Args.getLastArg(options::OPT_msve_vector_bits_EQ)) { + auto HandleVectorBits = [&](Arg *A, bool Streaming) { StringRef Val = A->getValue(); const Driver &D = getToolChain().getDriver(); if (Val == "128" || Val == "256" || Val == "512" || Val == "1024" || @@ -1674,22 +1674,35 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args, Val == "1024+" || Val == "2048+") { unsigned Bits = 0; if (!Val.consume_back("+")) { - bool Invalid = Val.getAsInteger(10, Bits); (void)Invalid; + bool Invalid = Val.getAsInteger(10, Bits); + (void)Invalid; assert(!Invalid && "Failed to parse value"); + StringRef VScaleMax = + Streaming ? "-mvscale-streaming-max=" : "-mvscale-max="; CmdArgs.push_back( - Args.MakeArgString("-mvscale-max=" + llvm::Twine(Bits / 128))); + Args.MakeArgString(VScaleMax + llvm::Twine(Bits / 128))); } - bool Invalid = Val.getAsInteger(10, Bits); (void)Invalid; + bool Invalid = Val.getAsInteger(10, Bits); + (void)Invalid; assert(!Invalid && "Failed to parse value"); + + StringRef VScaleMin = + Streaming ? "-mvscale-streaming-min=" : "-mvscale-min="; CmdArgs.push_back( - Args.MakeArgString("-mvscale-min=" + llvm::Twine(Bits / 128))); - // Silently drop requests for vector-length agnostic code as it's implied. - } else if (Val != "scalable") + Args.MakeArgString(VScaleMin + llvm::Twine(Bits / 128))); + } else if (Val == "scalable") { + // Silently drop requests for vector-length agnostic code as it's implied. + } else { // Handle the unsupported values passed to msve-vector-bits. D.Diag(diag::err_drv_unsupported_option_argument) << A->getSpelling() << Val; - } + } + }; + if (Arg *A = Args.getLastArg(options::OPT_msve_vector_bits_EQ)) + HandleVectorBits(A, /*Streaming*/ false); + if (Arg *A = Args.getLastArg(options::OPT_msve_streaming_vector_bits_EQ)) + HandleVectorBits(A, /*Streaming*/ true); AddAAPCSVolatileBitfieldArgs(Args, CmdArgs); diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 2c02719121c73..b3334b1bc560a 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -4558,6 +4558,11 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args, if (StringRef(A->getValue()).getAsInteger(10, VScaleMin) || VScaleMin == 0) Diags.Report(diag::err_cc1_unbounded_vscale_min); } + if (Arg *A = Args.getLastArg(options::OPT_mvscale_streaming_min_EQ)) { + unsigned VScaleMin; + if (StringRef(A->getValue()).getAsInteger(10, VScaleMin) || VScaleMin == 0) + Diags.Report(diag::err_cc1_unbounded_vscale_min); + } if (const Arg *A = Args.getLastArg(OPT_frandomize_layout_seed_file_EQ)) { std::ifstream SeedFile(A->getValue(0)); diff --git a/clang/lib/Sema/SemaARM.cpp b/clang/lib/Sema/SemaARM.cpp index e992a1012fde0..dd52400cf77ce 100644 --- a/clang/lib/Sema/SemaARM.cpp +++ b/clang/lib/Sema/SemaARM.cpp @@ -1409,4 +1409,118 @@ void SemaARM::CheckSMEFunctionDefAttributes(const FunctionDecl *FD) { } } +/// getSVETypeSize - Return SVE vector or predicate register size. +static uint64_t getSVETypeSize(ASTContext &Context, const BuiltinType *Ty, + bool IsStreaming) { + assert(Ty->isSveVLSBuiltinType() && "Invalid SVE Type"); + uint64_t VScale = IsStreaming ? Context.getLangOpts().VScaleStreamingMin + : Context.getLangOpts().VScaleMin; + if (Ty->getKind() == BuiltinType::SveBool || + Ty->getKind() == BuiltinType::SveCount) + return (VScale * 128) / Context.getCharWidth(); + return VScale * 128; +} + +bool SemaARM::areCompatibleSveTypes(QualType FirstType, QualType SecondType) { + bool IsStreaming = false; + if (const FunctionDecl *FD = + SemaRef.getCurFunctionDecl(/*AllowLambda=*/true)) { + // For streaming-compatible functions, we don't know vector length. + if (const auto *T = FD->getType()->getAs()) + if (T->getAArch64SMEAttributes() & + FunctionType::SME_PStateSMCompatibleMask) + return false; + + if (IsArmStreamingFunction(FD, /*IncludeLocallyStreaming=*/true)) + IsStreaming = true; + } + + auto IsValidCast = [&](QualType FirstType, QualType SecondType) { + if (const auto *BT = FirstType->getAs()) { + if (const auto *VT = SecondType->getAs()) { + // Predicates have the same representation as uint8 so we also have to + // check the kind to make these types incompatible. + ASTContext &Context = getASTContext(); + if (VT->getVectorKind() == VectorKind::SveFixedLengthPredicate) + return BT->getKind() == BuiltinType::SveBool; + else if (VT->getVectorKind() == VectorKind::SveFixedLengthData) + return VT->getElementType().getCanonicalType() == + FirstType->getSveEltType(Context); + else if (VT->getVectorKind() == VectorKind::Generic) + return Context.getTypeSize(SecondType) == + getSVETypeSize(Context, BT, IsStreaming) && + Context.hasSameType( + VT->getElementType(), + Context.getBuiltinVectorTypeInfo(BT).ElementType); + } + } + return false; + }; + + return IsValidCast(FirstType, SecondType) || + IsValidCast(SecondType, FirstType); +} + +bool SemaARM::areLaxCompatibleSveTypes(QualType FirstType, + QualType SecondType) { + bool IsStreaming = false; + if (const FunctionDecl *FD = + SemaRef.getCurFunctionDecl(/*AllowLambda=*/true)) { + // For streaming-compatible functions, we don't know vector length. + if (const auto *T = FD->getType()->getAs()) + if (T->getAArch64SMEAttributes() & + FunctionType::SME_PStateSMCompatibleMask) + return false; + + if (IsArmStreamingFunction(FD, /*IncludeLocallyStreaming=*/true)) + IsStreaming = true; + } + + auto IsLaxCompatible = [&](QualType FirstType, QualType SecondType) { + const auto *BT = FirstType->getAs(); + if (!BT) + return false; + + const auto *VecTy = SecondType->getAs(); + if (VecTy && (VecTy->getVectorKind() == VectorKind::SveFixedLengthData || + VecTy->getVectorKind() == VectorKind::Generic)) { + const LangOptions::LaxVectorConversionKind LVCKind = + getLangOpts().getLaxVectorConversions(); + ASTContext &Context = getASTContext(); + + // Can not convert between sve predicates and sve vectors because of + // different size. + if (BT->getKind() == BuiltinType::SveBool && + VecTy->getVectorKind() == VectorKind::SveFixedLengthData) + return false; + + // If __ARM_FEATURE_SVE_BITS != N do not allow GNU vector lax conversion. + // "Whenever __ARM_FEATURE_SVE_BITS==N, GNUT implicitly + // converts to VLAT and VLAT implicitly converts to GNUT." + // ACLE Spec Version 00bet6, 3.7.3.2. Behavior common to vectors and + // predicates. + if (VecTy->getVectorKind() == VectorKind::Generic && + Context.getTypeSize(SecondType) != + getSVETypeSize(Context, BT, IsStreaming)) + return false; + + // If -flax-vector-conversions=all is specified, the types are + // certainly compatible. + if (LVCKind == LangOptions::LaxVectorConversionKind::All) + return true; + + // If -flax-vector-conversions=integer is specified, the types are + // compatible if the elements are integer types. + if (LVCKind == LangOptions::LaxVectorConversionKind::Integer) + return VecTy->getElementType().getCanonicalType()->isIntegerType() && + FirstType->getSveEltType(Context)->isIntegerType(); + } + + return false; + }; + + return IsLaxCompatible(FirstType, SecondType) || + IsLaxCompatible(SecondType, FirstType); +} + } // namespace clang diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 8f8e1ceb7197e..bae4cc67da98f 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -12057,10 +12057,10 @@ void Sema::CheckImplicitConversion(Expr *E, QualType T, SourceLocation CC, // Strip vector types. if (isa(Source)) { if (Target->isSveVLSBuiltinType() && - (Context.areCompatibleSveTypes(QualType(Target, 0), - QualType(Source, 0)) || - Context.areLaxCompatibleSveTypes(QualType(Target, 0), - QualType(Source, 0)))) + (ARM().areCompatibleSveTypes(QualType(Target, 0), + QualType(Source, 0)) || + ARM().areLaxCompatibleSveTypes(QualType(Target, 0), + QualType(Source, 0)))) return; if (Target->isRVVVLSBuiltinType() && @@ -12120,10 +12120,10 @@ void Sema::CheckImplicitConversion(Expr *E, QualType T, SourceLocation CC, const Type *OriginalTarget = Context.getCanonicalType(T).getTypePtr(); // Handle conversion from scalable to fixed when msve-vector-bits is // specified - if (Context.areCompatibleSveTypes(QualType(OriginalTarget, 0), - QualType(Source, 0)) || - Context.areLaxCompatibleSveTypes(QualType(OriginalTarget, 0), - QualType(Source, 0))) + if (ARM().areCompatibleSveTypes(QualType(OriginalTarget, 0), + QualType(Source, 0)) || + ARM().areLaxCompatibleSveTypes(QualType(OriginalTarget, 0), + QualType(Source, 0))) return; // If the vector cast is cast between two vectors of the same size, it is diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index c7abbbd6993de..087db40573ef6 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -51,6 +51,7 @@ #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" +#include "clang/Sema/SemaARM.h" #include "clang/Sema/SemaCUDA.h" #include "clang/Sema/SemaFixItUtils.h" #include "clang/Sema/SemaHLSL.h" @@ -9533,8 +9534,8 @@ AssignConvertType Sema::CheckAssignmentConstraints(QualType LHSType, // Allow assignments between fixed-length and sizeless SVE vectors. if ((LHSType->isSVESizelessBuiltinType() && RHSType->isVectorType()) || (LHSType->isVectorType() && RHSType->isSVESizelessBuiltinType())) - if (Context.areCompatibleSveTypes(LHSType, RHSType) || - Context.areLaxCompatibleSveTypes(LHSType, RHSType)) { + if (ARM().areCompatibleSveTypes(LHSType, RHSType) || + ARM().areLaxCompatibleSveTypes(LHSType, RHSType)) { Kind = CK_BitCast; return AssignConvertType::Compatible; } diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 89e86f49a3ca8..4d5964c1a93b0 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -30,6 +30,7 @@ #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Overload.h" +#include "clang/Sema/SemaARM.h" #include "clang/Sema/SemaCUDA.h" #include "clang/Sema/SemaObjC.h" #include "clang/Sema/Template.h" @@ -2180,8 +2181,8 @@ static bool IsVectorConversion(Sema &S, QualType FromType, QualType ToType, if (ToType->isSVESizelessBuiltinType() || FromType->isSVESizelessBuiltinType()) - if (S.Context.areCompatibleSveTypes(FromType, ToType) || - S.Context.areLaxCompatibleSveTypes(FromType, ToType)) { + if (S.ARM().areCompatibleSveTypes(FromType, ToType) || + S.ARM().areLaxCompatibleSveTypes(FromType, ToType)) { ICK = ICK_SVE_Vector_Conversion; return true; } @@ -4735,9 +4736,9 @@ CompareStandardConversionSequences(Sema &S, SourceLocation Loc, if (SCS1.Second == ICK_SVE_Vector_Conversion && SCS2.Second == ICK_SVE_Vector_Conversion) { bool SCS1IsCompatibleSVEVectorConversion = - S.Context.areCompatibleSveTypes(SCS1.getFromType(), SCS1.getToType(2)); + S.ARM().areCompatibleSveTypes(SCS1.getFromType(), SCS1.getToType(2)); bool SCS2IsCompatibleSVEVectorConversion = - S.Context.areCompatibleSveTypes(SCS2.getFromType(), SCS2.getToType(2)); + S.ARM().areCompatibleSveTypes(SCS2.getFromType(), SCS2.getToType(2)); if (SCS1IsCompatibleSVEVectorConversion != SCS2IsCompatibleSVEVectorConversion) diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index a0cd2d1615243..2039d27b32464 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -8522,8 +8522,8 @@ static void HandleRISCVRVVVectorBitsTypeAttr(QualType &CurType, return; } - auto VScale = - S.Context.getTargetInfo().getVScaleRange(S.getLangOpts(), false); + auto VScale = S.Context.getTargetInfo().getVScaleRange( + S.getLangOpts(), TargetInfo::ArmStreamingKind::NotStreaming); if (!VScale || !VScale->first || VScale->first != VScale->second) { S.Diag(Attr.getLoc(), diag::err_attribute_riscv_rvv_bits_unsupported) << Attr; diff --git a/clang/test/CodeGen/arm-sve-vector-bits-vscale-range.c b/clang/test/CodeGen/arm-sve-vector-bits-vscale-range.c index bd424172a1865..252d40e7d1f75 100644 --- a/clang/test/CodeGen/arm-sve-vector-bits-vscale-range.c +++ b/clang/test/CodeGen/arm-sve-vector-bits-vscale-range.c @@ -1,22 +1,53 @@ -// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -mvscale-min=1 -mvscale-max=1 -emit-llvm -o - %s | FileCheck %s -D#VBITS=1 -// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -mvscale-min=2 -mvscale-max=2 -emit-llvm -o - %s | FileCheck %s -D#VBITS=2 -// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -mvscale-min=4 -mvscale-max=4 -emit-llvm -o - %s | FileCheck %s -D#VBITS=4 -// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -mvscale-min=8 -mvscale-max=8 -emit-llvm -o - %s | FileCheck %s -D#VBITS=8 -// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -mvscale-min=16 -mvscale-max=16 -emit-llvm -o - %s | FileCheck %s -D#VBITS=16 -// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve2 -mvscale-min=1 -mvscale-max=1 -emit-llvm -o - %s | FileCheck %s -D#VBITS=1 -// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve2 -mvscale-min=2 -mvscale-max=2 -emit-llvm -o - %s | FileCheck %s -D#VBITS=2 -// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -mvscale-min=1 -emit-llvm -o - %s | FileCheck %s -D#VBITS=1 --check-prefix=CHECK-NOMAX -// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -mvscale-min=2 -emit-llvm -o - %s | FileCheck %s -D#VBITS=2 --check-prefix=CHECK-NOMAX -// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -mvscale-min=4 -emit-llvm -o - %s | FileCheck %s -D#VBITS=4 --check-prefix=CHECK-NOMAX -// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -mvscale-min=8 -emit-llvm -o - %s | FileCheck %s -D#VBITS=8 --check-prefix=CHECK-NOMAX -// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -mvscale-min=16 -emit-llvm -o - %s | FileCheck %s -D#VBITS=16 --check-prefix=CHECK-NOMAX -// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve2 -mvscale-min=1 -mvscale-max=0 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-UNBOUNDED -// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -mvscale-min=1 -mvscale-max=0 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-UNBOUNDED -// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-NONE +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +sme -mvscale-min=1 -mvscale-max=1 -emit-llvm -o - %s | \ +// RUN: FileCheck %s --check-prefixes=CHECK,CHECK-MINMAX,CHECK-NOSTREAMING -D#VBITS=1 +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +sme -mvscale-min=2 -mvscale-max=2 -emit-llvm -o - %s | \ +// RUN: FileCheck %s --check-prefixes=CHECK,CHECK-MINMAX,CHECK-NOSTREAMING -D#VBITS=2 +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +sme -mvscale-min=4 -mvscale-max=4 -emit-llvm -o - %s | \ +// RUN: FileCheck %s --check-prefixes=CHECK,CHECK-MINMAX,CHECK-NOSTREAMING -D#VBITS=4 +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +sme -mvscale-min=8 -mvscale-max=8 -emit-llvm -o - %s | \ +// RUN: FileCheck %s --check-prefixes=CHECK,CHECK-MINMAX,CHECK-NOSTREAMING -D#VBITS=8 +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +sme -mvscale-min=16 -mvscale-max=16 -emit-llvm -o - %s | \ +// RUN: FileCheck %s --check-prefixes=CHECK,CHECK-MINMAX,CHECK-NOSTREAMING -D#VBITS=16 +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve2 -target-feature +sme -mvscale-min=1 -mvscale-max=1 -emit-llvm -o - %s | \ +// RUN: FileCheck %s --check-prefixes=CHECK,CHECK-MINMAX,CHECK-NOSTREAMING -D#VBITS=1 +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve2 -target-feature +sme -mvscale-min=2 -mvscale-max=2 -emit-llvm -o - %s | \ +// RUN: FileCheck %s --check-prefixes=CHECK,CHECK-MINMAX,CHECK-NOSTREAMING -D#VBITS=2 +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +sme -mvscale-min=1 -emit-llvm -o - %s | \ +// RUN: FileCheck %s --check-prefixes=CHECK,CHECK-NOMAX,CHECK-NOSTREAMING -D#VBITS=1 +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +sme -mvscale-min=2 -emit-llvm -o - %s | \ +// RUN: FileCheck %s --check-prefixes=CHECK,CHECK-NOMAX,CHECK-NOSTREAMING -D#VBITS=2 +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +sme -mvscale-min=4 -emit-llvm -o - %s | \ +// RUN: FileCheck %s --check-prefixes=CHECK,CHECK-NOMAX,CHECK-NOSTREAMING -D#VBITS=4 +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +sme -mvscale-min=8 -emit-llvm -o - %s | \ +// RUN: FileCheck %s --check-prefixes=CHECK,CHECK-NOMAX,CHECK-NOSTREAMING -D#VBITS=8 +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +sme -mvscale-min=16 -emit-llvm -o - %s | \ +// RUN: FileCheck %s --check-prefixes=CHECK,CHECK-NOMAX,CHECK-NOSTREAMING -D#VBITS=16 +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve2 -target-feature +sme -mvscale-min=1 -mvscale-max=0 -emit-llvm -o - %s | \ +// RUN: FileCheck %s --check-prefixes=CHECK,CHECK-UNBOUNDED,CHECK-NOSTREAMING +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +sme -mvscale-min=1 -mvscale-max=0 -emit-llvm -o - %s | \ +// RUN: FileCheck %s --check-prefixes=CHECK,CHECK-UNBOUNDED,CHECK-NOSTREAMING +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +sme -emit-llvm -o - %s | \ +// RUN: FileCheck %s --check-prefixes=CHECK,CHECK-NONE,CHECK-NOSTREAMING +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +sme -target-feature +sme -emit-llvm -o - %s | \ +// RUN: FileCheck %s --check-prefixes=CHECK,CHECK-NONE,CHECK-NOSTREAMING +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +sme -target-feature +sme -mvscale-streaming-min=1 -mvscale-streaming-max=1 -emit-llvm -o - %s | \ +// RUN: FileCheck %s --check-prefixes=CHECK,CHECK-NONE,CHECK-STREAMING -D#STREAMINGVBITS=1 +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +sme -target-feature +sme -mvscale-streaming-min=4 -mvscale-streaming-max=4 -emit-llvm -o - %s | \ +// RUN: FileCheck %s --check-prefixes=CHECK,CHECK-NONE,CHECK-STREAMING -D#STREAMINGVBITS=4 +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +sme -target-feature +sme -mvscale-streaming-min=4 -emit-llvm -o - %s | \ +// RUN: FileCheck %s --check-prefixes=CHECK,CHECK-NONE,CHECK-STREAMING-NOMAX -D#STREAMINGVBITS=4 // CHECK-LABEL: @func() #0 -// CHECK: attributes #0 = { {{.*}} vscale_range([[#VBITS]],[[#VBITS]]) {{.*}} } +// CHECK-LABEL: @func2() #1 +// CHECK-LABEL: @func3() #2 +// CHECK-MINMAX: attributes #0 = { {{.*}} vscale_range([[#VBITS]],[[#VBITS]]) {{.*}} } // CHECK-NOMAX: attributes #0 = { {{.*}} vscale_range([[#VBITS]],0) {{.*}} } // CHECK-UNBOUNDED: attributes #0 = { {{.*}} vscale_range(1,0) {{.*}} } // CHECK-NONE: attributes #0 = { {{.*}} vscale_range(1,16) {{.*}} } +// CHECK-STREAMING: attributes #1 = { {{.*}} vscale_range([[#STREAMINGVBITS]],[[#STREAMINGVBITS]]) +// CHECK-STREAMING-NOMAX: attributes #1 = { {{.*}} vscale_range([[#STREAMINGVBITS]],0) +// CHECK-NOSTREAMING: attributes #1 = { {{.*}} vscale_range(1,16) {{.*}} } +// CHECK: attributes #2 = { {{.*}} vscale_range(1,16) {{.*}} } void func(void) {} +__arm_locally_streaming void func2(void) {} +void func3(void) __arm_streaming_compatible {} diff --git a/clang/test/Driver/aarch64-sve-vector-bits.c b/clang/test/Driver/aarch64-sve-vector-bits.c index 535b0f157019a..f54cd94764bfb 100644 --- a/clang/test/Driver/aarch64-sve-vector-bits.c +++ b/clang/test/Driver/aarch64-sve-vector-bits.c @@ -24,6 +24,8 @@ // RUN: -msve-vector-bits=2048+ 2>&1 | FileCheck --check-prefix=CHECK-2048P %s // RUN: %clang -c %s -### --target=aarch64-none-linux-gnu -march=armv8-a+sve \ // RUN: -msve-vector-bits=scalable 2>&1 | FileCheck --check-prefix=CHECK-SCALABLE %s +// RUN: %clang -c %s -### --target=aarch64-none-linux-gnu -march=armv8-a+sve+sme \ +// RUN: -msve-streaming-vector-bits=128 2>&1 | FileCheck --check-prefix=STREAMING-128 %s // CHECK-128: "-mvscale-max=1" "-mvscale-min=1" // CHECK-256: "-mvscale-max=2" "-mvscale-min=2" @@ -44,6 +46,8 @@ // CHECK-SCALABLE-NOT: "-mvscale-min= // CHECK-SCALABLE-NOT: "-mvscale-max= +// STREAMING-128: "-mvscale-streaming-max=1" "-mvscale-streaming-min=1" + // Error out if an unsupported value is passed to -msve-vector-bits. // ----------------------------------------------------------------------------- // RUN: not %clang -c %s -### --target=aarch64-none-linux-gnu -march=armv8-a+sve \ diff --git a/clang/test/SemaCXX/aarch64-streaming-sve-vector-conversions.cpp b/clang/test/SemaCXX/aarch64-streaming-sve-vector-conversions.cpp new file mode 100644 index 0000000000000..1520e2b572ce6 --- /dev/null +++ b/clang/test/SemaCXX/aarch64-streaming-sve-vector-conversions.cpp @@ -0,0 +1,69 @@ +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +sme -mvscale-min=1 -mvscale-max=1 -mvscale-streaming-min=2 -mvscale-streaming-max=2 -flax-vector-conversions=integer -ffreestanding -fsyntax-only -verify %s +// REQUIRES: aarch64-registered-target + +#include + +#define SVE_BITS 128 +#define SVE_FIXED_ATTR __attribute__((arm_sve_vector_bits(SVE_BITS))) +#define GNU_FIXED_ATTR __attribute__((vector_size(SVE_BITS / 8))) +#define GNU_BOOL_FIXED_ATTR __attribute__((vector_size(SVE_BITS / 64))) +#define STREAMING_BITS 256 +#define GNU_FIXED_STREAMING_ATTR __attribute__((vector_size(STREAMING_BITS / 8))) +#define GNU_BOOL_FIXED_STREAMING_ATTR __attribute__((vector_size(STREAMING_BITS / 64))) + +typedef svfloat32_t sve_fixed_float32_t SVE_FIXED_ATTR; +typedef svint32_t sve_fixed_int32_t SVE_FIXED_ATTR; +typedef svbool_t sve_fixed_bool_t SVE_FIXED_ATTR; +typedef float gnu_fixed_float32_t GNU_FIXED_ATTR; +typedef int gnu_fixed_int32_t GNU_FIXED_ATTR; +typedef int8_t gnu_fixed_bool_t GNU_BOOL_FIXED_ATTR; + +typedef float gnu_fixed_float32_t_streaming GNU_FIXED_STREAMING_ATTR; +typedef int gnu_fixed_int32_t_streaming GNU_FIXED_STREAMING_ATTR; +typedef int8_t gnu_fixed_bool_t_streaming GNU_BOOL_FIXED_STREAMING_ATTR; + +void sve_fixed() { + gnu_fixed_int32_t fi; + gnu_fixed_float32_t_streaming fi_wrong; + gnu_fixed_float32_t ff; + gnu_fixed_float32_t_streaming ff_wrong; + gnu_fixed_bool_t fb; + gnu_fixed_bool_t_streaming fb_wrong; + *(volatile svint32_t*)0 = fi; + *(volatile svint32_t*)0 = fi_wrong; // expected-error {{incompatible}} + *(volatile svfloat32_t*)0 = ff; + *(volatile svfloat32_t*)0 = ff_wrong; // expected-error {{incompatible}} + *(volatile svbool_t*)0 = fb; + *(volatile svbool_t*)0 = fb_wrong; // expected-error {{incompatible}} +} + +__arm_locally_streaming void streaming_fixed() { + gnu_fixed_int32_t_streaming fi; + gnu_fixed_float32_t fi_wrong; + gnu_fixed_float32_t_streaming ff; + gnu_fixed_float32_t ff_wrong; + gnu_fixed_bool_t_streaming fb; + gnu_fixed_bool_t fb_wrong; + *(volatile svint32_t*)0 = fi; + *(volatile svint32_t*)0 = fi_wrong; // expected-error {{incompatible}} + *(volatile svfloat32_t*)0 = ff; + *(volatile svfloat32_t*)0 = ff_wrong; // expected-error {{incompatible}} + *(volatile svbool_t*)0 = fb; + *(volatile svbool_t*)0 = fb_wrong; // expected-error {{incompatible}} +} + +void streaming_compatible() __arm_streaming_compatible { + gnu_fixed_int32_t fi_ns; + gnu_fixed_float32_t_streaming fi_s; + gnu_fixed_float32_t ff_ns; + gnu_fixed_float32_t_streaming ff_s; + gnu_fixed_bool_t fb_ns; + gnu_fixed_bool_t_streaming fb_s; + *(volatile svint32_t*)0 = fi_ns; // expected-error {{incompatible}} + *(volatile svint32_t*)0 = fi_s; // expected-error {{incompatible}} + *(volatile svfloat32_t*)0 = ff_ns; // expected-error {{incompatible}} + *(volatile svfloat32_t*)0 = ff_s; // expected-error {{incompatible}} + *(volatile svbool_t*)0 = fb_ns; // expected-error {{incompatible}} + *(volatile svbool_t*)0 = fb_s; // expected-error {{incompatible}} +} + pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy