diff options
author | Eli Friedman <efriedma@quicinc.com> | 2025-07-03 13:44:38 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-07-03 13:44:38 -0700 |
commit | 2aa0f0a3bd541278b04efcc717e7aa94ef4c1308 (patch) | |
tree | bad6cb83b2366c8e0ae9e46cd18f4187a460c5f6 /clang/lib | |
parent | 3c13257f32f5669510860f5f40851e28270f36b3 (diff) | |
download | llvm-2aa0f0a3bd541278b04efcc717e7aa94ef4c1308.zip llvm-2aa0f0a3bd541278b04efcc717e7aa94ef4c1308.tar.gz llvm-2aa0f0a3bd541278b04efcc717e7aa94ef4c1308.tar.bz2 |
[AArch64] Add option -msve-streaming-vector-bits= . (#144611)
This is similar to -msve-vector-bits, but for streaming mode: it
constrains the legal values of "vscale", allowing optimizations based on
that constraint.
This also fixes conversions between SVE vectors and fixed-width vectors
in streaming functions with -msve-vector-bits and
-msve-streaming-vector-bits.
This rejects any use of arm_sve_vector_bits types in streaming
functions; if it becomes relevant, we could add
arm_sve_streaming_vector_bits types in the future.
This doesn't touch the __ARM_FEATURE_SVE_BITS define.
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/AST/ASTContext.cpp | 4 | ||||
-rw-r--r-- | clang/lib/AST/ItaniumMangle.cpp | 3 | ||||
-rw-r--r-- | clang/lib/Basic/Targets/AArch64.cpp | 28 | ||||
-rw-r--r-- | clang/lib/Basic/Targets/AArch64.h | 2 | ||||
-rw-r--r-- | clang/lib/Basic/Targets/RISCV.cpp | 4 | ||||
-rw-r--r-- | clang/lib/Basic/Targets/RISCV.h | 2 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenFunction.cpp | 10 | ||||
-rw-r--r-- | clang/lib/CodeGen/Targets/RISCV.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Driver/ToolChains/Clang.cpp | 26 | ||||
-rw-r--r-- | clang/lib/Frontend/CompilerInvocation.cpp | 5 | ||||
-rw-r--r-- | clang/lib/Sema/Sema.cpp | 18 | ||||
-rw-r--r-- | clang/lib/Sema/SemaARM.cpp | 53 | ||||
-rw-r--r-- | clang/lib/Sema/SemaType.cpp | 4 |
13 files changed, 129 insertions, 32 deletions
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index b13bdd5..679812a 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -10513,8 +10513,8 @@ bool ASTContext::areCompatibleVectorTypes(QualType FirstVec, /// 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 84936b72..8a1d4e8 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 e57feafe..72d2e5f 100644 --- a/clang/lib/Basic/Targets/AArch64.cpp +++ b/clang/lib/Basic/Targets/AArch64.cpp @@ -750,16 +750,36 @@ AArch64TargetInfo::getTargetBuiltins() const { std::optional<std::pair<unsigned, unsigned>> AArch64TargetInfo::getVScaleRange(const LangOptions &LangOpts, - bool IsArmStreamingFunction, + ArmStreamingKind Mode, llvm::StringMap<bool> *FeatureMap) const { - if (LangOpts.VScaleMin || LangOpts.VScaleMax) + if (Mode == ArmStreamingKind::NotStreaming && + (LangOpts.VScaleMin || LangOpts.VScaleMax)) return std::pair<unsigned, unsigned>( - LangOpts.VScaleMin ? LangOpts.VScaleMin : 1, LangOpts.VScaleMax); + LangOpts.VScaleMin ? LangOpts.VScaleMin : 1, + LangOpts.VScaleMax ? LangOpts.VScaleMax : 16); + + if (Mode == ArmStreamingKind::Streaming && + (LangOpts.VScaleStreamingMin || LangOpts.VScaleStreamingMax)) + return std::pair<unsigned, unsigned>( + LangOpts.VScaleStreamingMin ? LangOpts.VScaleStreamingMin : 1, + LangOpts.VScaleStreamingMax ? LangOpts.VScaleStreamingMax : 16); + + if (Mode == ArmStreamingKind::StreamingCompatible && + ((LangOpts.VScaleMin && LangOpts.VScaleStreamingMin) || + (LangOpts.VScaleMax && LangOpts.VScaleStreamingMax))) { + unsigned Min = + std::min(LangOpts.VScaleMin ? LangOpts.VScaleMin : 1, + LangOpts.VScaleStreamingMin ? LangOpts.VScaleStreamingMin : 1); + unsigned Max = std::max( + LangOpts.VScaleMax ? LangOpts.VScaleMax : 16, + LangOpts.VScaleStreamingMax ? LangOpts.VScaleStreamingMax : 16); + return std::pair(Min, Max); + } if (hasFeature("sve") || (FeatureMap && (FeatureMap->lookup("sve")))) return std::pair<unsigned, unsigned>(1, 16); - if (IsArmStreamingFunction && + if (Mode == ArmStreamingKind::Streaming && (hasFeature("sme") || (FeatureMap && (FeatureMap->lookup("sme"))))) return std::pair<unsigned, unsigned>(1, 16); diff --git a/clang/lib/Basic/Targets/AArch64.h b/clang/lib/Basic/Targets/AArch64.h index 56adfa9..f4277e9 100644 --- a/clang/lib/Basic/Targets/AArch64.h +++ b/clang/lib/Basic/Targets/AArch64.h @@ -196,7 +196,7 @@ public: llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const override; std::optional<std::pair<unsigned, unsigned>> - getVScaleRange(const LangOptions &LangOpts, bool IsArmStreamingFunction, + getVScaleRange(const LangOptions &LangOpts, ArmStreamingKind Mode, llvm::StringMap<bool> *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 2098449..8a28c07 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<std::pair<unsigned, unsigned>> RISCVTargetInfo::getVScaleRange(const LangOptions &LangOpts, - bool IsArmStreamingFunction, + ArmStreamingKind IsArmStreamingFunction, llvm::StringMap<bool> *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 0b36c9d..8d629ab 100644 --- a/clang/lib/Basic/Targets/RISCV.h +++ b/clang/lib/Basic/Targets/RISCV.h @@ -99,7 +99,7 @@ public: const std::vector<std::string> &FeaturesVec) const override; std::optional<std::pair<unsigned, unsigned>> - getVScaleRange(const LangOptions &LangOpts, bool IsArmStreamingFunction, + getVScaleRange(const LangOptions &LangOpts, ArmStreamingKind Mode, llvm::StringMap<bool> *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 70a0979..776a646 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -1109,10 +1109,16 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, // Add vscale_range attribute if appropriate. llvm::StringMap<bool> 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<FunctionProtoType>()) + if (T->getAArch64SMEAttributes() & + FunctionType::SME_PStateSMCompatibleMask) + IsArmStreaming = TargetInfo::ArmStreamingKind::StreamingCompatible; + + if (IsArmStreamingFunction(FD, true)) + IsArmStreaming = TargetInfo::ArmStreamingKind::Streaming; } std::optional<std::pair<unsigned, unsigned>> VScaleRange = getContext().getTargetInfo().getVScaleRange(getLangOpts(), IsArmStreaming, diff --git a/clang/lib/CodeGen/Targets/RISCV.cpp b/clang/lib/CodeGen/Targets/RISCV.cpp index 14d4cee..cc3d487 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 42323b2..71d4f0a 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -1668,7 +1668,8 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args, } // Handle -msve_vector_bits=<bits> - if (Arg *A = Args.getLastArg(options::OPT_msve_vector_bits_EQ)) { + auto HandleVectorBits = [&](Arg *A, StringRef VScaleMin, + StringRef VScaleMax) { StringRef Val = A->getValue(); const Driver &D = getToolChain().getDriver(); if (Val == "128" || Val == "256" || Val == "512" || Val == "1024" || @@ -1676,22 +1677,31 @@ 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"); 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"); + 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, "-mvscale-min=", "-mvscale-max="); + if (Arg *A = Args.getLastArg(options::OPT_msve_streaming_vector_bits_EQ)) + HandleVectorBits(A, "-mvscale-streaming-min=", "-mvscale-streaming-max="); AddAAPCSVolatileBitfieldArgs(Args, CmdArgs); diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 0a9e364..9b3200b 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -4620,6 +4620,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/Sema.cpp b/clang/lib/Sema/Sema.cpp index dfc5a27..56608e9 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -2261,6 +2261,24 @@ void Sema::checkTypeSupport(QualType Ty, SourceLocation Loc, ValueDecl *D) { } } } + + if (auto *VT = Ty->getAs<VectorType>(); + VT && FD && + (VT->getVectorKind() == VectorKind::SveFixedLengthData || + VT->getVectorKind() == VectorKind::SveFixedLengthPredicate) && + (LangOpts.VScaleMin != LangOpts.VScaleStreamingMin || + LangOpts.VScaleMax != LangOpts.VScaleStreamingMax)) { + if (IsArmStreamingFunction(FD, /*IncludeLocallyStreaming=*/true)) { + Diag(Loc, diag::err_sve_fixed_vector_in_streaming_function) + << Ty << /*Streaming*/ 0; + } else if (const auto *FTy = FD->getType()->getAs<FunctionProtoType>()) { + if (FTy->getAArch64SMEAttributes() & + FunctionType::SME_PStateSMCompatibleMask) { + Diag(Loc, diag::err_sve_fixed_vector_in_streaming_function) + << Ty << /*StreamingCompatible*/ 1; + } + } + } }; CheckType(Ty); diff --git a/clang/lib/Sema/SemaARM.cpp b/clang/lib/Sema/SemaARM.cpp index b7dca8d..76318a0 100644 --- a/clang/lib/Sema/SemaARM.cpp +++ b/clang/lib/Sema/SemaARM.cpp @@ -1410,21 +1410,41 @@ void SemaARM::CheckSMEFunctionDefAttributes(const FunctionDecl *FD) { } /// getSVETypeSize - Return SVE vector or predicate register size. -static uint64_t getSVETypeSize(ASTContext &Context, const BuiltinType *Ty) { +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 (Context.getLangOpts().VScaleMin * 128) / Context.getCharWidth(); - return Context.getLangOpts().VScaleMin * 128; + return (VScale * 128) / Context.getCharWidth(); + return VScale * 128; } bool SemaARM::areCompatibleSveTypes(QualType FirstType, QualType SecondType) { - auto IsValidCast = [this](QualType FirstType, QualType SecondType) { + bool IsStreaming = false; + if (getLangOpts().VScaleMin != getLangOpts().VScaleStreamingMin || + getLangOpts().VScaleMax != getLangOpts().VScaleStreamingMax) { + 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<FunctionProtoType>()) { + 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<BuiltinType>()) { if (const auto *VT = SecondType->getAs<VectorType>()) { - ASTContext &Context = getASTContext(); // 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) @@ -1432,7 +1452,7 @@ bool SemaARM::areCompatibleSveTypes(QualType FirstType, QualType SecondType) { FirstType->getSveEltType(Context); else if (VT->getVectorKind() == VectorKind::Generic) return Context.getTypeSize(SecondType) == - getSVETypeSize(Context, BT) && + getSVETypeSize(Context, BT, IsStreaming) && Context.hasSameType( VT->getElementType(), Context.getBuiltinVectorTypeInfo(BT).ElementType); @@ -1447,7 +1467,23 @@ bool SemaARM::areCompatibleSveTypes(QualType FirstType, QualType SecondType) { bool SemaARM::areLaxCompatibleSveTypes(QualType FirstType, QualType SecondType) { - auto IsLaxCompatible = [this](QualType FirstType, QualType SecondType) { + bool IsStreaming = false; + if (getLangOpts().VScaleMin != getLangOpts().VScaleStreamingMin || + getLangOpts().VScaleMax != getLangOpts().VScaleStreamingMax) { + 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<FunctionProtoType>()) + 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<BuiltinType>(); if (!BT) return false; @@ -1471,7 +1507,8 @@ bool SemaARM::areLaxCompatibleSveTypes(QualType FirstType, // 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)) + Context.getTypeSize(SecondType) != + getSVETypeSize(Context, BT, IsStreaming)) return false; // If -flax-vector-conversions=all is specified, the types are diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 785d7b8..88aa63d 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; |