aboutsummaryrefslogtreecommitdiff
path: root/clang/lib
diff options
context:
space:
mode:
authorEli Friedman <efriedma@quicinc.com>2025-07-03 13:44:38 -0700
committerGitHub <noreply@github.com>2025-07-03 13:44:38 -0700
commit2aa0f0a3bd541278b04efcc717e7aa94ef4c1308 (patch)
treebad6cb83b2366c8e0ae9e46cd18f4187a460c5f6 /clang/lib
parent3c13257f32f5669510860f5f40851e28270f36b3 (diff)
downloadllvm-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.cpp4
-rw-r--r--clang/lib/AST/ItaniumMangle.cpp3
-rw-r--r--clang/lib/Basic/Targets/AArch64.cpp28
-rw-r--r--clang/lib/Basic/Targets/AArch64.h2
-rw-r--r--clang/lib/Basic/Targets/RISCV.cpp4
-rw-r--r--clang/lib/Basic/Targets/RISCV.h2
-rw-r--r--clang/lib/CodeGen/CodeGenFunction.cpp10
-rw-r--r--clang/lib/CodeGen/Targets/RISCV.cpp2
-rw-r--r--clang/lib/Driver/ToolChains/Clang.cpp26
-rw-r--r--clang/lib/Frontend/CompilerInvocation.cpp5
-rw-r--r--clang/lib/Sema/Sema.cpp18
-rw-r--r--clang/lib/Sema/SemaARM.cpp53
-rw-r--r--clang/lib/Sema/SemaType.cpp4
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;