Skip to content

Commit c28804a

Browse files
committed
[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.
1 parent b1f5e26 commit c28804a

File tree

15 files changed

+277
-128
lines changed

15 files changed

+277
-128
lines changed

clang/include/clang/AST/ASTContext.h

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2486,15 +2486,6 @@ class ASTContext : public RefCountedBase<ASTContext> {
24862486
/// types.
24872487
bool areCompatibleVectorTypes(QualType FirstVec, QualType SecondVec);
24882488

2489-
/// Return true if the given types are an SVE builtin and a VectorType that
2490-
/// is a fixed-length representation of the SVE builtin for a specific
2491-
/// vector-length.
2492-
bool areCompatibleSveTypes(QualType FirstType, QualType SecondType);
2493-
2494-
/// Return true if the given vector types are lax-compatible SVE vector types,
2495-
/// false otherwise.
2496-
bool areLaxCompatibleSveTypes(QualType FirstType, QualType SecondType);
2497-
24982489
/// Return true if the given types are an RISC-V vector builtin type and a
24992490
/// VectorType that is a fixed-length representation of the RISC-V vector
25002491
/// builtin type for a specific vector-length.

clang/include/clang/Basic/LangOptions.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,9 @@ LANGOPT(OmitVTableRTTI, 1, 0,
503503
LANGOPT(VScaleMin, 32, 0, "Minimum vscale value")
504504
LANGOPT(VScaleMax, 32, 0, "Maximum vscale value")
505505

506+
LANGOPT(VScaleStreamingMin, 32, 0, "Minimum streaming vscale value")
507+
LANGOPT(VScaleStreamingMax, 32, 0, "Maximum streaming vscale value")
508+
506509
ENUM_LANGOPT(ExtendIntArgs, ExtendArgsKind, 1, ExtendArgsKind::ExtendTo32,
507510
"Controls how scalar integer arguments are extended in calls "
508511
"to unprototyped and varargs functions")

clang/include/clang/Driver/Options.td

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5173,6 +5173,14 @@ def msve_vector_bits_EQ : Joined<["-"], "msve-vector-bits=">, Group<m_aarch64_Fe
51735173
Visibility<[ClangOption, FlangOption]>,
51745174
HelpText<"Specify the size in bits of an SVE vector register. Defaults to the"
51755175
" vector length agnostic value of \"scalable\". (AArch64 only)">;
5176+
def msve_streaming_vector_bits_EQ
5177+
: Joined<["-"], "msve-streaming-vector-bits=">,
5178+
Group<m_aarch64_Features_Group>,
5179+
Visibility<[ClangOption, FlangOption]>,
5180+
HelpText<
5181+
"Specify the size in bits of an SVE vector register in streaming "
5182+
"mode. Defaults to the vector length agnostic value of "
5183+
"\"scalable\". (AArch64 only)">;
51765184
} // let Flags = [TargetSpecific]
51775185

51785186
def mvscale_min_EQ : Joined<["-"], "mvscale-min=">,
@@ -5184,6 +5192,17 @@ def mvscale_max_EQ : Joined<["-"], "mvscale-max=">,
51845192
HelpText<"Specify the vscale maximum. Defaults to the"
51855193
" vector length agnostic value of \"0\". (AArch64/RISC-V only)">,
51865194
MarshallingInfoInt<LangOpts<"VScaleMax">>;
5195+
def mvscale_streaming_min_EQ
5196+
: Joined<["-"], "mvscale-streaming-min=">,
5197+
Visibility<[CC1Option, FC1Option]>,
5198+
HelpText<"Specify the vscale minimum. Defaults to \"1\". (AArch64 only)">,
5199+
MarshallingInfoInt<LangOpts<"VScaleStreamingMin">>;
5200+
def mvscale_streaming_max_EQ
5201+
: Joined<["-"], "mvscale-streaming-max=">,
5202+
Visibility<[CC1Option, FC1Option]>,
5203+
HelpText<"Specify the vscale maximum. Defaults to the"
5204+
" vector length agnostic value of \"0\". (AArch64 only)">,
5205+
MarshallingInfoInt<LangOpts<"VScaleStreamingMax">>;
51875206

51885207
def msign_return_address_EQ : Joined<["-"], "msign-return-address=">,
51895208
Visibility<[ClangOption, CC1Option]>,

clang/include/clang/Sema/SemaARM.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,15 @@ class SemaARM : public SemaBase {
8282
void handleInterruptSaveFPAttr(Decl *D, const ParsedAttr &AL);
8383

8484
void CheckSMEFunctionDefAttributes(const FunctionDecl *FD);
85+
86+
/// Return true if the given types are an SVE builtin and a VectorType that
87+
/// is a fixed-length representation of the SVE builtin for a specific
88+
/// vector-length.
89+
bool areCompatibleSveTypes(QualType FirstType, QualType SecondType);
90+
91+
/// Return true if the given vector types are lax-compatible SVE vector types,
92+
/// false otherwise.
93+
bool areLaxCompatibleSveTypes(QualType FirstType, QualType SecondType);
8594
};
8695

8796
SemaARM::ArmStreamingType getArmStreamingFnType(const FunctionDecl *FD);

clang/lib/AST/ASTContext.cpp

Lines changed: 0 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -10443,87 +10443,6 @@ bool ASTContext::areCompatibleVectorTypes(QualType FirstVec,
1044310443
return false;
1044410444
}
1044510445

10446-
/// getSVETypeSize - Return SVE vector or predicate register size.
10447-
static uint64_t getSVETypeSize(ASTContext &Context, const BuiltinType *Ty) {
10448-
assert(Ty->isSveVLSBuiltinType() && "Invalid SVE Type");
10449-
if (Ty->getKind() == BuiltinType::SveBool ||
10450-
Ty->getKind() == BuiltinType::SveCount)
10451-
return (Context.getLangOpts().VScaleMin * 128) / Context.getCharWidth();
10452-
return Context.getLangOpts().VScaleMin * 128;
10453-
}
10454-
10455-
bool ASTContext::areCompatibleSveTypes(QualType FirstType,
10456-
QualType SecondType) {
10457-
auto IsValidCast = [this](QualType FirstType, QualType SecondType) {
10458-
if (const auto *BT = FirstType->getAs<BuiltinType>()) {
10459-
if (const auto *VT = SecondType->getAs<VectorType>()) {
10460-
// Predicates have the same representation as uint8 so we also have to
10461-
// check the kind to make these types incompatible.
10462-
if (VT->getVectorKind() == VectorKind::SveFixedLengthPredicate)
10463-
return BT->getKind() == BuiltinType::SveBool;
10464-
else if (VT->getVectorKind() == VectorKind::SveFixedLengthData)
10465-
return VT->getElementType().getCanonicalType() ==
10466-
FirstType->getSveEltType(*this);
10467-
else if (VT->getVectorKind() == VectorKind::Generic)
10468-
return getTypeSize(SecondType) == getSVETypeSize(*this, BT) &&
10469-
hasSameType(VT->getElementType(),
10470-
getBuiltinVectorTypeInfo(BT).ElementType);
10471-
}
10472-
}
10473-
return false;
10474-
};
10475-
10476-
return IsValidCast(FirstType, SecondType) ||
10477-
IsValidCast(SecondType, FirstType);
10478-
}
10479-
10480-
bool ASTContext::areLaxCompatibleSveTypes(QualType FirstType,
10481-
QualType SecondType) {
10482-
auto IsLaxCompatible = [this](QualType FirstType, QualType SecondType) {
10483-
const auto *BT = FirstType->getAs<BuiltinType>();
10484-
if (!BT)
10485-
return false;
10486-
10487-
const auto *VecTy = SecondType->getAs<VectorType>();
10488-
if (VecTy && (VecTy->getVectorKind() == VectorKind::SveFixedLengthData ||
10489-
VecTy->getVectorKind() == VectorKind::Generic)) {
10490-
const LangOptions::LaxVectorConversionKind LVCKind =
10491-
getLangOpts().getLaxVectorConversions();
10492-
10493-
// Can not convert between sve predicates and sve vectors because of
10494-
// different size.
10495-
if (BT->getKind() == BuiltinType::SveBool &&
10496-
VecTy->getVectorKind() == VectorKind::SveFixedLengthData)
10497-
return false;
10498-
10499-
// If __ARM_FEATURE_SVE_BITS != N do not allow GNU vector lax conversion.
10500-
// "Whenever __ARM_FEATURE_SVE_BITS==N, GNUT implicitly
10501-
// converts to VLAT and VLAT implicitly converts to GNUT."
10502-
// ACLE Spec Version 00bet6, 3.7.3.2. Behavior common to vectors and
10503-
// predicates.
10504-
if (VecTy->getVectorKind() == VectorKind::Generic &&
10505-
getTypeSize(SecondType) != getSVETypeSize(*this, BT))
10506-
return false;
10507-
10508-
// If -flax-vector-conversions=all is specified, the types are
10509-
// certainly compatible.
10510-
if (LVCKind == LangOptions::LaxVectorConversionKind::All)
10511-
return true;
10512-
10513-
// If -flax-vector-conversions=integer is specified, the types are
10514-
// compatible if the elements are integer types.
10515-
if (LVCKind == LangOptions::LaxVectorConversionKind::Integer)
10516-
return VecTy->getElementType().getCanonicalType()->isIntegerType() &&
10517-
FirstType->getSveEltType(*this)->isIntegerType();
10518-
}
10519-
10520-
return false;
10521-
};
10522-
10523-
return IsLaxCompatible(FirstType, SecondType) ||
10524-
IsLaxCompatible(SecondType, FirstType);
10525-
}
10526-
1052710446
/// getRVVTypeSize - Return RVV vector register size.
1052810447
static uint64_t getRVVTypeSize(ASTContext &Context, const BuiltinType *Ty) {
1052910448
assert(Ty->isRVVVLSBuiltinType() && "Invalid RVV Type");

clang/lib/Basic/Targets/AArch64.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -822,10 +822,16 @@ std::optional<std::pair<unsigned, unsigned>>
822822
AArch64TargetInfo::getVScaleRange(const LangOptions &LangOpts,
823823
bool IsArmStreamingFunction,
824824
llvm::StringMap<bool> *FeatureMap) const {
825-
if (LangOpts.VScaleMin || LangOpts.VScaleMax)
825+
if (!IsArmStreamingFunction && (LangOpts.VScaleMin || LangOpts.VScaleMax))
826826
return std::pair<unsigned, unsigned>(
827827
LangOpts.VScaleMin ? LangOpts.VScaleMin : 1, LangOpts.VScaleMax);
828828

829+
if (IsArmStreamingFunction &&
830+
(LangOpts.VScaleStreamingMin || LangOpts.VScaleStreamingMax))
831+
return std::pair<unsigned, unsigned>(
832+
LangOpts.VScaleStreamingMin ? LangOpts.VScaleStreamingMin : 1,
833+
LangOpts.VScaleStreamingMax);
834+
829835
if (hasFeature("sve") || (FeatureMap && (FeatureMap->lookup("sve"))))
830836
return std::pair<unsigned, unsigned>(1, 16);
831837

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1666,30 +1666,43 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args,
16661666
}
16671667

16681668
// Handle -msve_vector_bits=<bits>
1669-
if (Arg *A = Args.getLastArg(options::OPT_msve_vector_bits_EQ)) {
1669+
auto HandleVectorBits = [&](Arg *A, bool Streaming) {
16701670
StringRef Val = A->getValue();
16711671
const Driver &D = getToolChain().getDriver();
16721672
if (Val == "128" || Val == "256" || Val == "512" || Val == "1024" ||
16731673
Val == "2048" || Val == "128+" || Val == "256+" || Val == "512+" ||
16741674
Val == "1024+" || Val == "2048+") {
16751675
unsigned Bits = 0;
16761676
if (!Val.consume_back("+")) {
1677-
bool Invalid = Val.getAsInteger(10, Bits); (void)Invalid;
1677+
bool Invalid = Val.getAsInteger(10, Bits);
1678+
(void)Invalid;
16781679
assert(!Invalid && "Failed to parse value");
1680+
StringRef VScaleMax =
1681+
Streaming ? "-mvscale-streaming-max=" : "-mvscale-max=";
16791682
CmdArgs.push_back(
1680-
Args.MakeArgString("-mvscale-max=" + llvm::Twine(Bits / 128)));
1683+
Args.MakeArgString(VScaleMax + llvm::Twine(Bits / 128)));
16811684
}
16821685

1683-
bool Invalid = Val.getAsInteger(10, Bits); (void)Invalid;
1686+
bool Invalid = Val.getAsInteger(10, Bits);
1687+
(void)Invalid;
16841688
assert(!Invalid && "Failed to parse value");
1689+
1690+
StringRef VScaleMin =
1691+
Streaming ? "-mvscale-streaming-min=" : "-mvscale-min=";
16851692
CmdArgs.push_back(
1686-
Args.MakeArgString("-mvscale-min=" + llvm::Twine(Bits / 128)));
1687-
// Silently drop requests for vector-length agnostic code as it's implied.
1688-
} else if (Val != "scalable")
1693+
Args.MakeArgString(VScaleMin + llvm::Twine(Bits / 128)));
1694+
} else if (Val == "scalable") {
1695+
// Silently drop requests for vector-length agnostic code as it's implied.
1696+
} else {
16891697
// Handle the unsupported values passed to msve-vector-bits.
16901698
D.Diag(diag::err_drv_unsupported_option_argument)
16911699
<< A->getSpelling() << Val;
1692-
}
1700+
}
1701+
};
1702+
if (Arg *A = Args.getLastArg(options::OPT_msve_vector_bits_EQ))
1703+
HandleVectorBits(A, /*Streaming*/ false);
1704+
if (Arg *A = Args.getLastArg(options::OPT_msve_streaming_vector_bits_EQ))
1705+
HandleVectorBits(A, /*Streaming*/ true);
16931706

16941707
AddAAPCSVolatileBitfieldArgs(Args, CmdArgs);
16951708

clang/lib/Frontend/CompilerInvocation.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4558,6 +4558,11 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
45584558
if (StringRef(A->getValue()).getAsInteger(10, VScaleMin) || VScaleMin == 0)
45594559
Diags.Report(diag::err_cc1_unbounded_vscale_min);
45604560
}
4561+
if (Arg *A = Args.getLastArg(options::OPT_mvscale_streaming_min_EQ)) {
4562+
unsigned VScaleMin;
4563+
if (StringRef(A->getValue()).getAsInteger(10, VScaleMin) || VScaleMin == 0)
4564+
Diags.Report(diag::err_cc1_unbounded_vscale_min);
4565+
}
45614566

45624567
if (const Arg *A = Args.getLastArg(OPT_frandomize_layout_seed_file_EQ)) {
45634568
std::ifstream SeedFile(A->getValue(0));

clang/lib/Sema/SemaARM.cpp

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1409,4 +1409,101 @@ void SemaARM::CheckSMEFunctionDefAttributes(const FunctionDecl *FD) {
14091409
}
14101410
}
14111411

1412+
/// getSVETypeSize - Return SVE vector or predicate register size.
1413+
static uint64_t getSVETypeSize(ASTContext &Context, const BuiltinType *Ty,
1414+
bool IsStreaming) {
1415+
assert(Ty->isSveVLSBuiltinType() && "Invalid SVE Type");
1416+
uint64_t VScale = IsStreaming ? Context.getLangOpts().VScaleStreamingMin
1417+
: Context.getLangOpts().VScaleMin;
1418+
if (Ty->getKind() == BuiltinType::SveBool ||
1419+
Ty->getKind() == BuiltinType::SveCount)
1420+
return (VScale * 128) / Context.getCharWidth();
1421+
return VScale * 128;
1422+
}
1423+
1424+
bool SemaARM::areCompatibleSveTypes(QualType FirstType, QualType SecondType) {
1425+
bool IsStreaming = false;
1426+
if (const FunctionDecl *FD = SemaRef.getCurFunctionDecl(/*AllowLambda=*/true))
1427+
if (IsArmStreamingFunction(FD, /*IncludeLocallyStreaming=*/true))
1428+
IsStreaming = true;
1429+
auto IsValidCast = [&](QualType FirstType, QualType SecondType) {
1430+
if (const auto *BT = FirstType->getAs<BuiltinType>()) {
1431+
if (const auto *VT = SecondType->getAs<VectorType>()) {
1432+
// Predicates have the same representation as uint8 so we also have to
1433+
// check the kind to make these types incompatible.
1434+
ASTContext &Context = getASTContext();
1435+
if (VT->getVectorKind() == VectorKind::SveFixedLengthPredicate)
1436+
return BT->getKind() == BuiltinType::SveBool;
1437+
else if (VT->getVectorKind() == VectorKind::SveFixedLengthData)
1438+
return VT->getElementType().getCanonicalType() ==
1439+
FirstType->getSveEltType(Context);
1440+
else if (VT->getVectorKind() == VectorKind::Generic)
1441+
return Context.getTypeSize(SecondType) ==
1442+
getSVETypeSize(Context, BT, IsStreaming) &&
1443+
Context.hasSameType(
1444+
VT->getElementType(),
1445+
Context.getBuiltinVectorTypeInfo(BT).ElementType);
1446+
}
1447+
}
1448+
return false;
1449+
};
1450+
1451+
return IsValidCast(FirstType, SecondType) ||
1452+
IsValidCast(SecondType, FirstType);
1453+
}
1454+
1455+
bool SemaARM::areLaxCompatibleSveTypes(QualType FirstType,
1456+
QualType SecondType) {
1457+
bool IsStreaming = false;
1458+
if (const FunctionDecl *FD = SemaRef.getCurFunctionDecl(/*AllowLambda=*/true))
1459+
if (IsArmStreamingFunction(FD, /*IncludeLocallyStreaming=*/true))
1460+
IsStreaming = true;
1461+
1462+
auto IsLaxCompatible = [&](QualType FirstType, QualType SecondType) {
1463+
const auto *BT = FirstType->getAs<BuiltinType>();
1464+
if (!BT)
1465+
return false;
1466+
1467+
const auto *VecTy = SecondType->getAs<VectorType>();
1468+
if (VecTy && (VecTy->getVectorKind() == VectorKind::SveFixedLengthData ||
1469+
VecTy->getVectorKind() == VectorKind::Generic)) {
1470+
const LangOptions::LaxVectorConversionKind LVCKind =
1471+
getLangOpts().getLaxVectorConversions();
1472+
ASTContext &Context = getASTContext();
1473+
1474+
// Can not convert between sve predicates and sve vectors because of
1475+
// different size.
1476+
if (BT->getKind() == BuiltinType::SveBool &&
1477+
VecTy->getVectorKind() == VectorKind::SveFixedLengthData)
1478+
return false;
1479+
1480+
// If __ARM_FEATURE_SVE_BITS != N do not allow GNU vector lax conversion.
1481+
// "Whenever __ARM_FEATURE_SVE_BITS==N, GNUT implicitly
1482+
// converts to VLAT and VLAT implicitly converts to GNUT."
1483+
// ACLE Spec Version 00bet6, 3.7.3.2. Behavior common to vectors and
1484+
// predicates.
1485+
if (VecTy->getVectorKind() == VectorKind::Generic &&
1486+
Context.getTypeSize(SecondType) !=
1487+
getSVETypeSize(Context, BT, IsStreaming))
1488+
return false;
1489+
1490+
// If -flax-vector-conversions=all is specified, the types are
1491+
// certainly compatible.
1492+
if (LVCKind == LangOptions::LaxVectorConversionKind::All)
1493+
return true;
1494+
1495+
// If -flax-vector-conversions=integer is specified, the types are
1496+
// compatible if the elements are integer types.
1497+
if (LVCKind == LangOptions::LaxVectorConversionKind::Integer)
1498+
return VecTy->getElementType().getCanonicalType()->isIntegerType() &&
1499+
FirstType->getSveEltType(Context)->isIntegerType();
1500+
}
1501+
1502+
return false;
1503+
};
1504+
1505+
return IsLaxCompatible(FirstType, SecondType) ||
1506+
IsLaxCompatible(SecondType, FirstType);
1507+
}
1508+
14121509
} // namespace clang

clang/lib/Sema/SemaChecking.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12057,10 +12057,10 @@ void Sema::CheckImplicitConversion(Expr *E, QualType T, SourceLocation CC,
1205712057
// Strip vector types.
1205812058
if (isa<VectorType>(Source)) {
1205912059
if (Target->isSveVLSBuiltinType() &&
12060-
(Context.areCompatibleSveTypes(QualType(Target, 0),
12061-
QualType(Source, 0)) ||
12062-
Context.areLaxCompatibleSveTypes(QualType(Target, 0),
12063-
QualType(Source, 0))))
12060+
(ARM().areCompatibleSveTypes(QualType(Target, 0),
12061+
QualType(Source, 0)) ||
12062+
ARM().areLaxCompatibleSveTypes(QualType(Target, 0),
12063+
QualType(Source, 0))))
1206412064
return;
1206512065

1206612066
if (Target->isRVVVLSBuiltinType() &&
@@ -12120,10 +12120,10 @@ void Sema::CheckImplicitConversion(Expr *E, QualType T, SourceLocation CC,
1212012120
const Type *OriginalTarget = Context.getCanonicalType(T).getTypePtr();
1212112121
// Handle conversion from scalable to fixed when msve-vector-bits is
1212212122
// specified
12123-
if (Context.areCompatibleSveTypes(QualType(OriginalTarget, 0),
12124-
QualType(Source, 0)) ||
12125-
Context.areLaxCompatibleSveTypes(QualType(OriginalTarget, 0),
12126-
QualType(Source, 0)))
12123+
if (ARM().areCompatibleSveTypes(QualType(OriginalTarget, 0),
12124+
QualType(Source, 0)) ||
12125+
ARM().areLaxCompatibleSveTypes(QualType(OriginalTarget, 0),
12126+
QualType(Source, 0)))
1212712127
return;
1212812128

1212912129
// If the vector cast is cast between two vectors of the same size, it is

0 commit comments

Comments
 (0)