[clang] [AArch64] Add option -msve-streaming-vector-bits= . (PR #144611)
Eli Friedman via cfe-commits
cfe-commits at lists.llvm.org
Wed Jun 25 10:32:13 PDT 2025
https://github.com/efriedma-quic updated https://github.com/llvm/llvm-project/pull/144611
>From c28804a471a9fe6be24479ffbfd7d4aa6c774125 Mon Sep 17 00:00:00 2001
From: Eli Friedman <efriedma at quicinc.com>
Date: Tue, 17 Jun 2025 11:48:47 -0700
Subject: [PATCH 1/5] [AArch64] Add option -msve-streaming-vector-bits= .
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 currently doesn't touch the __ARM_FEATURE_SVE_BITS define or the
arm_sve_vector_bits attribute.
---
clang/include/clang/AST/ASTContext.h | 9 --
clang/include/clang/Basic/LangOptions.def | 3 +
clang/include/clang/Driver/Options.td | 19 ++++
clang/include/clang/Sema/SemaARM.h | 9 ++
clang/lib/AST/ASTContext.cpp | 81 ----------------
clang/lib/Basic/Targets/AArch64.cpp | 8 +-
clang/lib/Driver/ToolChains/Clang.cpp | 29 ++++--
clang/lib/Frontend/CompilerInvocation.cpp | 5 +
clang/lib/Sema/SemaARM.cpp | 97 +++++++++++++++++++
clang/lib/Sema/SemaChecking.cpp | 16 +--
clang/lib/Sema/SemaExpr.cpp | 5 +-
clang/lib/Sema/SemaOverload.cpp | 9 +-
.../arm-sve-vector-bits-vscale-range.c | 58 ++++++++---
clang/test/Driver/aarch64-sve-vector-bits.c | 4 +
...rch64-streaming-sve-vector-conversions.cpp | 53 ++++++++++
15 files changed, 277 insertions(+), 128 deletions(-)
create mode 100644 clang/test/SemaCXX/aarch64-streaming-sve-vector-conversions.cpp
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<ASTContext> {
/// 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/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<m_aarch64_Fe
Visibility<[ClangOption, FlangOption]>,
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<m_aarch64_Features_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<LangOpts<"VScaleMax">>;
+def mvscale_streaming_min_EQ
+ : Joined<["-"], "mvscale-streaming-min=">,
+ Visibility<[CC1Option, FC1Option]>,
+ HelpText<"Specify the vscale minimum. Defaults to \"1\". (AArch64 only)">,
+ MarshallingInfoInt<LangOpts<"VScaleStreamingMin">>;
+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<LangOpts<"VScaleStreamingMax">>;
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..d785b5a5006cc 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -10443,87 +10443,6 @@ 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<BuiltinType>()) {
- if (const auto *VT = SecondType->getAs<VectorType>()) {
- // 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<BuiltinType>();
- if (!BT)
- return false;
-
- const auto *VecTy = SecondType->getAs<VectorType>();
- 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");
diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp
index e8abdf9aafd82..c5935390137b1 100644
--- a/clang/lib/Basic/Targets/AArch64.cpp
+++ b/clang/lib/Basic/Targets/AArch64.cpp
@@ -822,10 +822,16 @@ std::optional<std::pair<unsigned, unsigned>>
AArch64TargetInfo::getVScaleRange(const LangOptions &LangOpts,
bool IsArmStreamingFunction,
llvm::StringMap<bool> *FeatureMap) const {
- if (LangOpts.VScaleMin || LangOpts.VScaleMax)
+ if (!IsArmStreamingFunction && (LangOpts.VScaleMin || LangOpts.VScaleMax))
return std::pair<unsigned, unsigned>(
LangOpts.VScaleMin ? LangOpts.VScaleMin : 1, LangOpts.VScaleMax);
+ if (IsArmStreamingFunction &&
+ (LangOpts.VScaleStreamingMin || LangOpts.VScaleStreamingMax))
+ return std::pair<unsigned, unsigned>(
+ LangOpts.VScaleStreamingMin ? LangOpts.VScaleStreamingMin : 1,
+ LangOpts.VScaleStreamingMax);
+
if (hasFeature("sve") || (FeatureMap && (FeatureMap->lookup("sve"))))
return std::pair<unsigned, unsigned>(1, 16);
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=<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..ec892a5d82421 100644
--- a/clang/lib/Sema/SemaARM.cpp
+++ b/clang/lib/Sema/SemaARM.cpp
@@ -1409,4 +1409,101 @@ 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))
+ 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>()) {
+ // 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))
+ if (IsArmStreamingFunction(FD, /*IncludeLocallyStreaming=*/true))
+ IsStreaming = true;
+
+ auto IsLaxCompatible = [&](QualType FirstType, QualType SecondType) {
+ const auto *BT = FirstType->getAs<BuiltinType>();
+ if (!BT)
+ return false;
+
+ const auto *VecTy = SecondType->getAs<VectorType>();
+ 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<VectorType>(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/test/CodeGen/arm-sve-vector-bits-vscale-range.c b/clang/test/CodeGen/arm-sve-vector-bits-vscale-range.c
index bd424172a1865..47e745aece191 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,50 @@
-// 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-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-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-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-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-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-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-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 -D#VBITS=1 --check-prefixes=CHECK-NOMAX,CHECK-NOSTREAMING
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +sme -mvscale-min=2 -emit-llvm -o - %s | \
+// RUN: FileCheck %s -D#VBITS=2 --check-prefixes=CHECK-NOMAX,CHECK-NOSTREAMING
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +sme -mvscale-min=4 -emit-llvm -o - %s | \
+// RUN: FileCheck %s -D#VBITS=4 --check-prefixes=CHECK-NOMAX,CHECK-NOSTREAMING
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +sme -mvscale-min=8 -emit-llvm -o - %s | \
+// RUN: FileCheck %s -D#VBITS=8 --check-prefixes=CHECK-NOMAX,CHECK-NOSTREAMING
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +sme -mvscale-min=16 -emit-llvm -o - %s | \
+// RUN: FileCheck %s -D#VBITS=16 --check-prefixes=CHECK-NOMAX,CHECK-NOSTREAMING
+// 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-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-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-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-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-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-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-NONE,CHECK-STREAMING-NOMAX -D#STREAMINGVBITS=4
// CHECK-LABEL: @func() #0
+// CHECK-LABEL: @func2() #1
// CHECK: 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) {{.*}} }
void func(void) {}
+__arm_locally_streaming void func2(void) {}
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..7498aaa9982f9
--- /dev/null
+++ b/clang/test/SemaCXX/aarch64-streaming-sve-vector-conversions.cpp
@@ -0,0 +1,53 @@
+// 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 <arm_sve.h>
+
+#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}}
+}
>From cb8936f185ae113905221a685ec84f226d817b70 Mon Sep 17 00:00:00 2001
From: Eli Friedman <efriedma at quicinc.com>
Date: Wed, 18 Jun 2025 17:09:06 -0700
Subject: [PATCH 2/5] Fix interaction with streaming-compatible functions.
---
clang/include/clang/Basic/TargetInfo.h | 9 +++-
clang/lib/AST/ASTContext.cpp | 4 +-
clang/lib/AST/ItaniumMangle.cpp | 3 +-
clang/lib/Basic/Targets/AArch64.cpp | 9 ++--
clang/lib/Basic/Targets/AArch64.h | 3 +-
clang/lib/Basic/Targets/RISCV.cpp | 4 +-
clang/lib/Basic/Targets/RISCV.h | 3 +-
clang/lib/CodeGen/CodeGenFunction.cpp | 10 ++++-
clang/lib/CodeGen/Targets/RISCV.cpp | 2 +-
clang/lib/Sema/SemaARM.cpp | 21 ++++++++-
clang/lib/Sema/SemaType.cpp | 4 +-
.../arm-sve-vector-bits-vscale-range.c | 43 ++++++++++---------
...rch64-streaming-sve-vector-conversions.cpp | 16 +++++++
13 files changed, 92 insertions(+), 39 deletions(-)
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<Builtin::InfosShard> getTargetBuiltins() const = 0;
+ enum class ArmStreamingKind {
+ NotStreaming,
+ StreamingCompatible,
+ Streaming,
+ };
+
/// Returns target-specific min and max values VScale_Range.
virtual std::optional<std::pair<unsigned, unsigned>>
- getVScaleRange(const LangOptions &LangOpts, bool IsArmStreamingFunction,
+ getVScaleRange(const LangOptions &LangOpts,
+ ArmStreamingKind IsArmStreamingFunction,
llvm::StringMap<bool> *FeatureMap = nullptr) const {
return std::nullopt;
}
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index d785b5a5006cc..07c70ea770d66 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -10446,8 +10446,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 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 c5935390137b1..2e4234f0b5fae 100644
--- a/clang/lib/Basic/Targets/AArch64.cpp
+++ b/clang/lib/Basic/Targets/AArch64.cpp
@@ -820,13 +820,14 @@ AArch64TargetInfo::getTargetBuiltins() const {
std::optional<std::pair<unsigned, unsigned>>
AArch64TargetInfo::getVScaleRange(const LangOptions &LangOpts,
- bool IsArmStreamingFunction,
+ ArmStreamingKind IsArmStreamingFunction,
llvm::StringMap<bool> *FeatureMap) const {
- if (!IsArmStreamingFunction && (LangOpts.VScaleMin || LangOpts.VScaleMax))
+ if (IsArmStreamingFunction == ArmStreamingKind::NotStreaming &&
+ (LangOpts.VScaleMin || LangOpts.VScaleMax))
return std::pair<unsigned, unsigned>(
LangOpts.VScaleMin ? LangOpts.VScaleMin : 1, LangOpts.VScaleMax);
- if (IsArmStreamingFunction &&
+ if (IsArmStreamingFunction == ArmStreamingKind::Streaming &&
(LangOpts.VScaleStreamingMin || LangOpts.VScaleStreamingMax))
return std::pair<unsigned, unsigned>(
LangOpts.VScaleStreamingMin ? LangOpts.VScaleStreamingMin : 1,
@@ -835,7 +836,7 @@ AArch64TargetInfo::getVScaleRange(const LangOptions &LangOpts,
if (hasFeature("sve") || (FeatureMap && (FeatureMap->lookup("sve"))))
return std::pair<unsigned, unsigned>(1, 16);
- if (IsArmStreamingFunction &&
+ if (IsArmStreamingFunction == 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 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<Builtin::InfosShard> getTargetBuiltins() const override;
std::optional<std::pair<unsigned, unsigned>>
- getVScaleRange(const LangOptions &LangOpts, bool IsArmStreamingFunction,
+ getVScaleRange(const LangOptions &LangOpts,
+ ArmStreamingKind IsArmStreamingFunction,
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 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<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 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<std::string> &FeaturesVec) const override;
std::optional<std::pair<unsigned, unsigned>>
- getVScaleRange(const LangOptions &LangOpts, bool IsArmStreamingFunction,
+ getVScaleRange(const LangOptions &LangOpts,
+ ArmStreamingKind IsArmStreamingFunction,
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 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<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 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/Sema/SemaARM.cpp b/clang/lib/Sema/SemaARM.cpp
index ec892a5d82421..dd52400cf77ce 100644
--- a/clang/lib/Sema/SemaARM.cpp
+++ b/clang/lib/Sema/SemaARM.cpp
@@ -1423,9 +1423,18 @@ static uint64_t getSVETypeSize(ASTContext &Context, const BuiltinType *Ty,
bool SemaARM::areCompatibleSveTypes(QualType FirstType, QualType SecondType) {
bool IsStreaming = false;
- if (const FunctionDecl *FD = SemaRef.getCurFunctionDecl(/*AllowLambda=*/true))
+ 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>()) {
@@ -1455,9 +1464,17 @@ bool SemaARM::areCompatibleSveTypes(QualType FirstType, QualType SecondType) {
bool SemaARM::areLaxCompatibleSveTypes(QualType FirstType,
QualType SecondType) {
bool IsStreaming = false;
- if (const FunctionDecl *FD = SemaRef.getCurFunctionDecl(/*AllowLambda=*/true))
+ 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>();
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 47e745aece191..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,50 +1,53 @@
// 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-NOSTREAMING -D#VBITS=1
+// 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-NOSTREAMING -D#VBITS=2
+// 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-NOSTREAMING -D#VBITS=4
+// 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-NOSTREAMING -D#VBITS=8
+// 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-NOSTREAMING -D#VBITS=16
+// 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-NOSTREAMING -D#VBITS=1
+// 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-NOSTREAMING -D#VBITS=2
+// 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 -D#VBITS=1 --check-prefixes=CHECK-NOMAX,CHECK-NOSTREAMING
+// 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 -D#VBITS=2 --check-prefixes=CHECK-NOMAX,CHECK-NOSTREAMING
+// 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 -D#VBITS=4 --check-prefixes=CHECK-NOMAX,CHECK-NOSTREAMING
+// 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 -D#VBITS=8 --check-prefixes=CHECK-NOMAX,CHECK-NOSTREAMING
+// 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 -D#VBITS=16 --check-prefixes=CHECK-NOMAX,CHECK-NOSTREAMING
+// 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-UNBOUNDED,CHECK-NOSTREAMING
+// 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-UNBOUNDED,CHECK-NOSTREAMING
+// 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-NONE,CHECK-NOSTREAMING
+// 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-NONE,CHECK-NOSTREAMING
+// 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-NONE,CHECK-STREAMING -D#STREAMINGVBITS=1
+// 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-NONE,CHECK-STREAMING -D#STREAMINGVBITS=4
+// 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-NONE,CHECK-STREAMING-NOMAX -D#STREAMINGVBITS=4
+// RUN: FileCheck %s --check-prefixes=CHECK,CHECK-NONE,CHECK-STREAMING-NOMAX -D#STREAMINGVBITS=4
// CHECK-LABEL: @func() #0
// CHECK-LABEL: @func2() #1
-// CHECK: attributes #0 = { {{.*}} vscale_range([[#VBITS]],[[#VBITS]]) {{.*}} }
+// 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/SemaCXX/aarch64-streaming-sve-vector-conversions.cpp b/clang/test/SemaCXX/aarch64-streaming-sve-vector-conversions.cpp
index 7498aaa9982f9..1520e2b572ce6 100644
--- a/clang/test/SemaCXX/aarch64-streaming-sve-vector-conversions.cpp
+++ b/clang/test/SemaCXX/aarch64-streaming-sve-vector-conversions.cpp
@@ -51,3 +51,19 @@ __arm_locally_streaming void streaming_fixed() {
*(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}}
+}
+
>From b772f08bda474d7206ebc5da9c85415314d97569 Mon Sep 17 00:00:00 2001
From: Eli Friedman <efriedma at quicinc.com>
Date: Mon, 23 Jun 2025 15:46:11 -0700
Subject: [PATCH 3/5] Address review comments.
---
.../clang/Basic/DiagnosticSemaKinds.td | 3 +
clang/lib/Basic/Targets/AArch64.cpp | 14 ++++-
clang/lib/Driver/ToolChains/Clang.cpp | 11 ++--
clang/lib/Sema/Sema.cpp | 15 +++++
.../arm-sve-vector-bits-vscale-range.c | 59 +++++++++++--------
clang/test/Sema/attr-arm-sve-vector-bits.c | 31 ++++++++--
6 files changed, 96 insertions(+), 37 deletions(-)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 0f77083dac9df..d5d8b6226d72d 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3317,6 +3317,9 @@ def err_sve_vector_in_non_sve_target : Error<
"SVE vector type %0 cannot be used in a target without sve">;
def err_sve_vector_in_non_streaming_function : Error<
"SVE vector type %0 cannot be used in a non-streaming function">;
+def err_sve_fixed_vector_in_streaming_function
+ : Error<"fixed width SVE vector type %0 cannot be used in a "
+ "%select{streaming|streaming-compatible}1 function">;
def err_attribute_riscv_rvv_bits_unsupported : Error<
"%0 is only supported when '-mrvv-vector-bits=<bits>' is specified with a "
"value of \"zvl\" or a power 2 in the range [64,65536]">;
diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp
index 2e4234f0b5fae..3dde076d608f9 100644
--- a/clang/lib/Basic/Targets/AArch64.cpp
+++ b/clang/lib/Basic/Targets/AArch64.cpp
@@ -825,13 +825,23 @@ AArch64TargetInfo::getVScaleRange(const LangOptions &LangOpts,
if (IsArmStreamingFunction == 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 (IsArmStreamingFunction == ArmStreamingKind::Streaming &&
(LangOpts.VScaleStreamingMin || LangOpts.VScaleStreamingMax))
return std::pair<unsigned, unsigned>(
LangOpts.VScaleStreamingMin ? LangOpts.VScaleStreamingMin : 1,
- LangOpts.VScaleStreamingMax);
+ LangOpts.VScaleStreamingMax ? LangOpts.VScaleStreamingMax : 16);
+
+ if (IsArmStreamingFunction == 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);
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 24ec25601881f..d23c8ae9ff893 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -1666,7 +1666,8 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args,
}
// Handle -msve_vector_bits=<bits>
- auto HandleVectorBits = [&](Arg *A, bool Streaming) {
+ 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" ||
@@ -1677,8 +1678,6 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args,
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(VScaleMax + llvm::Twine(Bits / 128)));
}
@@ -1687,8 +1686,6 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args,
(void)Invalid;
assert(!Invalid && "Failed to parse value");
- StringRef VScaleMin =
- Streaming ? "-mvscale-streaming-min=" : "-mvscale-min=";
CmdArgs.push_back(
Args.MakeArgString(VScaleMin + llvm::Twine(Bits / 128)));
} else if (Val == "scalable") {
@@ -1700,9 +1697,9 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args,
}
};
if (Arg *A = Args.getLastArg(options::OPT_msve_vector_bits_EQ))
- HandleVectorBits(A, /*Streaming*/ false);
+ HandleVectorBits(A, "-mvscale-min=", "-mvscale-max=");
if (Arg *A = Args.getLastArg(options::OPT_msve_streaming_vector_bits_EQ))
- HandleVectorBits(A, /*Streaming*/ true);
+ HandleVectorBits(A, "-mvscale-streaming-min=", "-mvscale-streaming-max=");
AddAAPCSVolatileBitfieldArgs(Args, CmdArgs);
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 9826abc0c3b40..afcf846cf5260 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -2270,6 +2270,21 @@ 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)) {
+ if (IsArmStreamingFunction(FD, /*IncludeLocallyStreaming=*/true)) {
+ Diag(Loc, diag::err_sve_fixed_vector_in_streaming_function) << Ty << 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 << 1;
+ }
+ }
+ }
};
CheckType(Ty);
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 252d40e7d1f75..98548749a04d6 100644
--- a/clang/test/CodeGen/arm-sve-vector-bits-vscale-range.c
+++ b/clang/test/CodeGen/arm-sve-vector-bits-vscale-range.c
@@ -1,53 +1,66 @@
// 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: FileCheck %s --check-prefixes=CHECK,CHECK-MINMAX,CHECK-NOSTREAMING,CHECK-NOCOMPATIBLE -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: FileCheck %s --check-prefixes=CHECK,CHECK-MINMAX,CHECK-NOSTREAMING,CHECK-NOCOMPATIBLE -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: FileCheck %s --check-prefixes=CHECK,CHECK-MINMAX,CHECK-NOSTREAMING,CHECK-NOCOMPATIBLE -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: FileCheck %s --check-prefixes=CHECK,CHECK-MINMAX,CHECK-NOSTREAMING,CHECK-NOCOMPATIBLE -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: FileCheck %s --check-prefixes=CHECK,CHECK-MINMAX,CHECK-NOSTREAMING,CHECK-NOCOMPATIBLE -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: FileCheck %s --check-prefixes=CHECK,CHECK-MINMAX,CHECK-NOSTREAMING,CHECK-NOCOMPATIBLE -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: FileCheck %s --check-prefixes=CHECK,CHECK-MINMAX,CHECK-NOSTREAMING,CHECK-NOCOMPATIBLE -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: FileCheck %s --check-prefixes=CHECK,CHECK-NOMAX,CHECK-NOSTREAMING,CHECK-NOCOMPATIBLE -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: FileCheck %s --check-prefixes=CHECK,CHECK-NOMAX,CHECK-NOSTREAMING,CHECK-NOCOMPATIBLE -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: FileCheck %s --check-prefixes=CHECK,CHECK-NOMAX,CHECK-NOSTREAMING,CHECK-NOCOMPATIBLE -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: FileCheck %s --check-prefixes=CHECK,CHECK-NOMAX,CHECK-NOSTREAMING,CHECK-NOCOMPATIBLE -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: FileCheck %s --check-prefixes=CHECK,CHECK-NOMAX,CHECK-NOSTREAMING,CHECK-NOCOMPATIBLE -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: FileCheck %s --check-prefixes=CHECK,CHECK-UNBOUNDED,CHECK-NOSTREAMING,CHECK-NOCOMPATIBLE
// 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: FileCheck %s --check-prefixes=CHECK,CHECK-UNBOUNDED,CHECK-NOSTREAMING,CHECK-NOCOMPATIBLE
// 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: FileCheck %s --check-prefixes=CHECK,CHECK-NONE,CHECK-NOSTREAMING,CHECK-NOCOMPATIBLE
// 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: FileCheck %s --check-prefixes=CHECK,CHECK-NONE,CHECK-NOSTREAMING,CHECK-NOCOMPATIBLE
// 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: FileCheck %s --check-prefixes=CHECK,CHECK-NONE,CHECK-STREAMING,CHECK-NOCOMPATIBLE -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: FileCheck %s --check-prefixes=CHECK,CHECK-NONE,CHECK-STREAMING,CHECK-NOCOMPATIBLE -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
+// RUN: FileCheck %s --check-prefixes=CHECK,CHECK-NONE,CHECK-STREAMING-NOMAX,CHECK-NOCOMPATIBLE -D#STREAMINGVBITS=4
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +sme -target-feature +sme -mvscale-min=2 -mvscale-streaming-min=4 -emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=CHECK,CHECK-NOMAX,CHECK-STREAMING-NOMAX,CHECK-COMPATIBLE-NOMAX -D#VBITS=2 -D#STREAMINGVBITS=4
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +sme -target-feature +sme -mvscale-max=2 -mvscale-streaming-max=4 -emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=CHECK,CHECK-NOMIN,CHECK-STREAMING-NOMIN,CHECK-COMPATIBLE-NOMIN -D#VBITS=2 -D#STREAMINGVBITS=4
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +sme -target-feature +sme \
+// RUN: -mvscale-min=2 -mvscale-streaming-min=4 -mvscale-max=2 -mvscale-streaming-max=4 -emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=CHECK,CHECK-MINMAX,CHECK-STREAMING,CHECK-COMPATIBLE -D#VBITS=2 -D#STREAMINGVBITS=4
+
// CHECK-LABEL: @func() #0
// 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-NOMAX: attributes #0 = { {{.*}} vscale_range([[#VBITS]],16) {{.*}} }
+// CHECK-NOMIN: attributes #0 = { {{.*}} vscale_range(1,[[#VBITS]]) {{.*}} }
+// CHECK-UNBOUNDED: attributes #0 = { {{.*}} vscale_range(1,16) {{.*}} }
// 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-STREAMING-NOMAX: attributes #1 = { {{.*}} vscale_range([[#STREAMINGVBITS]],16)
+// CHECK-STREAMING-NOMIN: attributes #1 = { {{.*}} vscale_range(1,[[#STREAMINGVBITS]]) {{.*}} }
// CHECK-NOSTREAMING: attributes #1 = { {{.*}} vscale_range(1,16) {{.*}} }
-// CHECK: attributes #2 = { {{.*}} vscale_range(1,16) {{.*}} }
+// CHECK-NOCOMPATIBLE: attributes #2 = { {{.*}} vscale_range(1,16) {{.*}} }
+// CHECK-COMPATIBLE: attributes #2 = { {{.*}} vscale_range([[#VBITS]],[[#STREAMINGVBITS]]) {{.*}} }
+// CHECK-COMPATIBLE-NOMAX: attributes #2 = { {{.*}} vscale_range([[#VBITS]],16) {{.*}} }
+// CHECK-COMPATIBLE-NOMIN: attributes #2 = { {{.*}} vscale_range(1,[[#STREAMINGVBITS]]) {{.*}} }
void func(void) {}
__arm_locally_streaming void func2(void) {}
void func3(void) __arm_streaming_compatible {}
diff --git a/clang/test/Sema/attr-arm-sve-vector-bits.c b/clang/test/Sema/attr-arm-sve-vector-bits.c
index d34b13a74df6d..5993a5beaafef 100644
--- a/clang/test/Sema/attr-arm-sve-vector-bits.c
+++ b/clang/test/Sema/attr-arm-sve-vector-bits.c
@@ -1,8 +1,8 @@
-// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +bf16 -ffreestanding -fsyntax-only -verify -mvscale-min=1 -mvscale-max=1 %s
-// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +bf16 -ffreestanding -fsyntax-only -verify -mvscale-min=2 -mvscale-max=2 %s
-// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +bf16 -ffreestanding -fsyntax-only -verify -mvscale-min=4 -mvscale-max=4 %s
-// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +bf16 -ffreestanding -fsyntax-only -verify -mvscale-min=8 -mvscale-max=8 %s
-// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +bf16 -ffreestanding -fsyntax-only -verify -mvscale-min=16 -mvscale-max=16 %s
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +bf16 -target-feature +sme -ffreestanding -fsyntax-only -verify -mvscale-min=1 -mvscale-max=1 %s
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +bf16 -target-feature +sme -ffreestanding -fsyntax-only -verify -mvscale-min=2 -mvscale-max=2 %s
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +bf16 -target-feature +sme -ffreestanding -fsyntax-only -verify -mvscale-min=4 -mvscale-max=4 %s
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +bf16 -target-feature +sme -ffreestanding -fsyntax-only -verify -mvscale-min=8 -mvscale-max=8 %s
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +bf16 -target-feature +sme -ffreestanding -fsyntax-only -verify -mvscale-min=16 -mvscale-max=16 %s
#include <stdint.h>
@@ -382,3 +382,24 @@ TEST_INT_OPS(fixed_uint64_t)
TEST_OPS(fixed_float16_t)
TEST_OPS(fixed_float32_t)
TEST_OPS(fixed_float64_t)
+
+// --------------------------------------------------------------------------//
+// Streaming
+__arm_locally_streaming void locally_streaming() {
+ svint8_t t1 = extern_int8; // expected-error {{cannot be used in a streaming function}}
+ svbool_t t2 = extern_bool; // expected-error {{cannot be used in a streaming function}}
+ void* t3 = extern_int8_ptr;
+}
+void streaming(void) __arm_streaming {
+ svint8_t t1 = extern_int8; // expected-error {{cannot be used in a streaming function}}
+ svbool_t t2 = extern_bool; // expected-error {{cannot be used in a streaming function}}
+ void* t3 = extern_int8_ptr;
+}
+void streaming_compatible(void) __arm_streaming_compatible {
+ svint8_t t1 = extern_int8; // expected-error {{cannot be used in a streaming-compatible function}} \
+ // expected-error {{initializing}}
+ svbool_t t2 = extern_bool; // expected-error {{cannot be used in a streaming-compatible function}} \
+ // expected-error {{initializing}}
+ void* t3 = extern_int8_ptr;
+}
+__arm_locally_streaming void locally_streaming_arg(fixed_int8_t x) {} // expected-error {{cannot be used in a streaming function}}
>From 67405658d0b01bf4460810920e91ccc2d19bf62a Mon Sep 17 00:00:00 2001
From: Eli Friedman <efriedma at quicinc.com>
Date: Mon, 23 Jun 2025 15:50:22 -0700
Subject: [PATCH 4/5] Fix formatting
---
clang/lib/Basic/Targets/AArch64.cpp | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp
index 3dde076d608f9..0bfb27b3cb2fb 100644
--- a/clang/lib/Basic/Targets/AArch64.cpp
+++ b/clang/lib/Basic/Targets/AArch64.cpp
@@ -825,7 +825,8 @@ AArch64TargetInfo::getVScaleRange(const LangOptions &LangOpts,
if (IsArmStreamingFunction == ArmStreamingKind::NotStreaming &&
(LangOpts.VScaleMin || LangOpts.VScaleMax))
return std::pair<unsigned, unsigned>(
- LangOpts.VScaleMin ? LangOpts.VScaleMin : 1, LangOpts.VScaleMax ? LangOpts.VScaleMax : 16);
+ LangOpts.VScaleMin ? LangOpts.VScaleMin : 1,
+ LangOpts.VScaleMax ? LangOpts.VScaleMax : 16);
if (IsArmStreamingFunction == ArmStreamingKind::Streaming &&
(LangOpts.VScaleStreamingMin || LangOpts.VScaleStreamingMax))
@@ -836,10 +837,12 @@ AArch64TargetInfo::getVScaleRange(const LangOptions &LangOpts,
if (IsArmStreamingFunction == 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);
+ 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);
}
>From fb4a10d202affa7c036d37e6b7981bdfff2e10a8 Mon Sep 17 00:00:00 2001
From: Eli Friedman <efriedma at quicinc.com>
Date: Wed, 25 Jun 2025 10:30:09 -0700
Subject: [PATCH 5/5] Address review comments.
Fix variable names, allow fixed-width types in streaming functions if
the streaming and non-streaming widths are the same.
---
clang/include/clang/Basic/TargetInfo.h | 3 +-
clang/lib/Basic/Targets/AArch64.cpp | 10 ++---
clang/lib/Basic/Targets/AArch64.h | 3 +-
clang/lib/Basic/Targets/RISCV.h | 3 +-
clang/lib/Sema/Sema.cpp | 4 +-
clang/lib/Sema/SemaARM.cpp | 45 +++++++++++++---------
clang/test/Sema/attr-arm-sve-vector-bits.c | 28 +++++++-------
7 files changed, 51 insertions(+), 45 deletions(-)
diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h
index 00e6f88d648ca..88d74faa4dd4c 100644
--- a/clang/include/clang/Basic/TargetInfo.h
+++ b/clang/include/clang/Basic/TargetInfo.h
@@ -1042,8 +1042,7 @@ class TargetInfo : public TransferrableTargetInfo,
/// Returns target-specific min and max values VScale_Range.
virtual std::optional<std::pair<unsigned, unsigned>>
- getVScaleRange(const LangOptions &LangOpts,
- ArmStreamingKind IsArmStreamingFunction,
+ getVScaleRange(const LangOptions &LangOpts, ArmStreamingKind Mode,
llvm::StringMap<bool> *FeatureMap = nullptr) const {
return std::nullopt;
}
diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp
index 041c5bc638d12..74529a46181bb 100644
--- a/clang/lib/Basic/Targets/AArch64.cpp
+++ b/clang/lib/Basic/Targets/AArch64.cpp
@@ -823,21 +823,21 @@ AArch64TargetInfo::getTargetBuiltins() const {
std::optional<std::pair<unsigned, unsigned>>
AArch64TargetInfo::getVScaleRange(const LangOptions &LangOpts,
- ArmStreamingKind IsArmStreamingFunction,
+ ArmStreamingKind Mode,
llvm::StringMap<bool> *FeatureMap) const {
- if (IsArmStreamingFunction == ArmStreamingKind::NotStreaming &&
+ if (Mode == ArmStreamingKind::NotStreaming &&
(LangOpts.VScaleMin || LangOpts.VScaleMax))
return std::pair<unsigned, unsigned>(
LangOpts.VScaleMin ? LangOpts.VScaleMin : 1,
LangOpts.VScaleMax ? LangOpts.VScaleMax : 16);
- if (IsArmStreamingFunction == ArmStreamingKind::Streaming &&
+ if (Mode == ArmStreamingKind::Streaming &&
(LangOpts.VScaleStreamingMin || LangOpts.VScaleStreamingMax))
return std::pair<unsigned, unsigned>(
LangOpts.VScaleStreamingMin ? LangOpts.VScaleStreamingMin : 1,
LangOpts.VScaleStreamingMax ? LangOpts.VScaleStreamingMax : 16);
- if (IsArmStreamingFunction == ArmStreamingKind::StreamingCompatible &&
+ if (Mode == ArmStreamingKind::StreamingCompatible &&
((LangOpts.VScaleMin && LangOpts.VScaleStreamingMin) ||
(LangOpts.VScaleMax && LangOpts.VScaleStreamingMax))) {
unsigned Min =
@@ -852,7 +852,7 @@ AArch64TargetInfo::getVScaleRange(const LangOptions &LangOpts,
if (hasFeature("sve") || (FeatureMap && (FeatureMap->lookup("sve"))))
return std::pair<unsigned, unsigned>(1, 16);
- if (IsArmStreamingFunction == ArmStreamingKind::Streaming &&
+ 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 aba9422349497..e80e1a68f5284 100644
--- a/clang/lib/Basic/Targets/AArch64.h
+++ b/clang/lib/Basic/Targets/AArch64.h
@@ -198,8 +198,7 @@ class LLVM_LIBRARY_VISIBILITY AArch64TargetInfo : public TargetInfo {
llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const override;
std::optional<std::pair<unsigned, unsigned>>
- getVScaleRange(const LangOptions &LangOpts,
- ArmStreamingKind 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.h b/clang/lib/Basic/Targets/RISCV.h
index 2779538e5b741..8d629abab7bec 100644
--- a/clang/lib/Basic/Targets/RISCV.h
+++ b/clang/lib/Basic/Targets/RISCV.h
@@ -99,8 +99,7 @@ class RISCVTargetInfo : public TargetInfo {
const std::vector<std::string> &FeaturesVec) const override;
std::optional<std::pair<unsigned, unsigned>>
- getVScaleRange(const LangOptions &LangOpts,
- ArmStreamingKind 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/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index f2cabbf0a015d..79cbdebc046b3 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -2265,7 +2265,9 @@ 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)) {
+ 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 << 0;
} else if (const auto *FTy = FD->getType()->getAs<FunctionProtoType>()) {
diff --git a/clang/lib/Sema/SemaARM.cpp b/clang/lib/Sema/SemaARM.cpp
index dd52400cf77ce..f8b3c5e12187c 100644
--- a/clang/lib/Sema/SemaARM.cpp
+++ b/clang/lib/Sema/SemaARM.cpp
@@ -1423,16 +1423,20 @@ static uint64_t getSVETypeSize(ASTContext &Context, const BuiltinType *Ty,
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<FunctionProtoType>())
- if (T->getAArch64SMEAttributes() &
- FunctionType::SME_PStateSMCompatibleMask)
- return false;
+ if (LangOpts.VScaleMin != LangOpts.VScaleStreamingMin ||
+ LangOpts.VScaleMax != LangOpts.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;
+ if (IsArmStreamingFunction(FD, /*IncludeLocallyStreaming=*/true))
+ IsStreaming = true;
+ }
}
auto IsValidCast = [&](QualType FirstType, QualType SecondType) {
@@ -1464,16 +1468,19 @@ bool SemaARM::areCompatibleSveTypes(QualType FirstType, QualType SecondType) {
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<FunctionProtoType>())
- if (T->getAArch64SMEAttributes() &
- FunctionType::SME_PStateSMCompatibleMask)
- return false;
-
- if (IsArmStreamingFunction(FD, /*IncludeLocallyStreaming=*/true))
- IsStreaming = true;
+ if (LangOpts.VScaleMin != LangOpts.VScaleStreamingMin ||
+ LangOpts.VScaleMax != LangOpts.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) {
diff --git a/clang/test/Sema/attr-arm-sve-vector-bits.c b/clang/test/Sema/attr-arm-sve-vector-bits.c
index 5993a5beaafef..447addb4d5d33 100644
--- a/clang/test/Sema/attr-arm-sve-vector-bits.c
+++ b/clang/test/Sema/attr-arm-sve-vector-bits.c
@@ -1,8 +1,8 @@
-// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +bf16 -target-feature +sme -ffreestanding -fsyntax-only -verify -mvscale-min=1 -mvscale-max=1 %s
-// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +bf16 -target-feature +sme -ffreestanding -fsyntax-only -verify -mvscale-min=2 -mvscale-max=2 %s
-// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +bf16 -target-feature +sme -ffreestanding -fsyntax-only -verify -mvscale-min=4 -mvscale-max=4 %s
-// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +bf16 -target-feature +sme -ffreestanding -fsyntax-only -verify -mvscale-min=8 -mvscale-max=8 %s
-// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +bf16 -target-feature +sme -ffreestanding -fsyntax-only -verify -mvscale-min=16 -mvscale-max=16 %s
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +bf16 -target-feature +sme -ffreestanding -fsyntax-only -verify=expected,streamingdifferent -mvscale-min=1 -mvscale-max=1 %s
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +bf16 -target-feature +sme -ffreestanding -fsyntax-only -verify=expected,streamingdifferent -mvscale-min=2 -mvscale-max=2 -mvscale-streaming-min=2 %s
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +bf16 -target-feature +sme -ffreestanding -fsyntax-only -verify=expected -mvscale-min=4 -mvscale-max=4 -mvscale-streaming-min=4 -mvscale-streaming-max=4 %s
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +bf16 -target-feature +sme -ffreestanding -fsyntax-only -verify=expected,streamingdifferent -mvscale-min=8 -mvscale-max=8 -mvscale-streaming-min=4 -mvscale-streaming-max=8 %s
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +bf16 -target-feature +sme -ffreestanding -fsyntax-only -verify=expected,streamingdifferent -mvscale-min=16 -mvscale-max=16 %s
#include <stdint.h>
@@ -386,20 +386,20 @@ TEST_OPS(fixed_float64_t)
// --------------------------------------------------------------------------//
// Streaming
__arm_locally_streaming void locally_streaming() {
- svint8_t t1 = extern_int8; // expected-error {{cannot be used in a streaming function}}
- svbool_t t2 = extern_bool; // expected-error {{cannot be used in a streaming function}}
+ svint8_t t1 = extern_int8; // streamingdifferent-error {{cannot be used in a streaming function}}
+ svbool_t t2 = extern_bool; // streamingdifferent-error {{cannot be used in a streaming function}}
void* t3 = extern_int8_ptr;
}
void streaming(void) __arm_streaming {
- svint8_t t1 = extern_int8; // expected-error {{cannot be used in a streaming function}}
- svbool_t t2 = extern_bool; // expected-error {{cannot be used in a streaming function}}
+ svint8_t t1 = extern_int8; // streamingdifferent-error {{cannot be used in a streaming function}}
+ svbool_t t2 = extern_bool; // streamingdifferent-error {{cannot be used in a streaming function}}
void* t3 = extern_int8_ptr;
}
void streaming_compatible(void) __arm_streaming_compatible {
- svint8_t t1 = extern_int8; // expected-error {{cannot be used in a streaming-compatible function}} \
- // expected-error {{initializing}}
- svbool_t t2 = extern_bool; // expected-error {{cannot be used in a streaming-compatible function}} \
- // expected-error {{initializing}}
+ svint8_t t1 = extern_int8; // streamingdifferent-error {{cannot be used in a streaming-compatible function}} \
+ // streamingdifferent-error {{initializing}}
+ svbool_t t2 = extern_bool; // streamingdifferent-error {{cannot be used in a streaming-compatible function}} \
+ // streamingdifferent-error {{initializing}}
void* t3 = extern_int8_ptr;
}
-__arm_locally_streaming void locally_streaming_arg(fixed_int8_t x) {} // expected-error {{cannot be used in a streaming function}}
+__arm_locally_streaming void locally_streaming_arg(fixed_int8_t x) {} // streamingdifferent-error {{cannot be used in a streaming function}}
More information about the cfe-commits
mailing list