Skip to content

[AArch64] Add option -msve-streaming-vector-bits= . #144611

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 0 additions & 9 deletions clang/include/clang/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/LangOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
9 changes: 8 additions & 1 deletion clang/include/clang/Basic/TargetInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why can't we add IsArmStreamingFunction to LangOpts? It it weird to add a target-specific parameter to a common hook.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LangOpts is global. IsArmStreamingFunction is context-dependent: it depends on whether we're currently analyzing a function marked __arm_streaming/etc.

We could reorganize the code, maybe... like, move some bits of the implementation into AST. But I'm not sure that really helps.

llvm::StringMap<bool> *FeatureMap = nullptr) const {
return std::nullopt;
}
Expand Down
19 changes: 19 additions & 0 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -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=">,
Expand All @@ -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]>,
Expand Down
9 changes: 9 additions & 0 deletions clang/include/clang/Sema/SemaARM.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
85 changes: 2 additions & 83 deletions clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10443,92 +10443,11 @@ bool ASTContext::areCompatibleVectorTypes(QualType FirstVec,
return false;
}

/// getSVETypeSize - Return SVE vector or predicate register size.
static uint64_t getSVETypeSize(ASTContext &Context, const BuiltinType *Ty) {
assert(Ty->isSveVLSBuiltinType() && "Invalid SVE Type");
if (Ty->getKind() == BuiltinType::SveBool ||
Ty->getKind() == BuiltinType::SveCount)
return (Context.getLangOpts().VScaleMin * 128) / Context.getCharWidth();
return Context.getLangOpts().VScaleMin * 128;
}

bool ASTContext::areCompatibleSveTypes(QualType FirstType,
QualType SecondType) {
auto IsValidCast = [this](QualType FirstType, QualType SecondType) {
if (const auto *BT = FirstType->getAs<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");
auto VScale =
Context.getTargetInfo().getVScaleRange(Context.getLangOpts(), false);
auto VScale = Context.getTargetInfo().getVScaleRange(
Context.getLangOpts(), TargetInfo::ArmStreamingKind::NotStreaming);
if (!VScale)
return 0;

Expand Down
3 changes: 2 additions & 1 deletion clang/lib/AST/ItaniumMangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
13 changes: 10 additions & 3 deletions clang/lib/Basic/Targets/AArch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -820,16 +820,23 @@ AArch64TargetInfo::getTargetBuiltins() const {

std::optional<std::pair<unsigned, unsigned>>
AArch64TargetInfo::getVScaleRange(const LangOptions &LangOpts,
bool IsArmStreamingFunction,
ArmStreamingKind IsArmStreamingFunction,
llvm::StringMap<bool> *FeatureMap) const {
if (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 == ArmStreamingKind::Streaming &&
(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);

if (IsArmStreamingFunction &&
if (IsArmStreamingFunction == ArmStreamingKind::Streaming &&
(hasFeature("sme") || (FeatureMap && (FeatureMap->lookup("sme")))))
return std::pair<unsigned, unsigned>(1, 16);

Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Basic/Targets/AArch64.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Basic/Targets/RISCV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down Expand Up @@ -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;
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Basic/Targets/RISCV.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
10 changes: 8 additions & 2 deletions clang/lib/CodeGen/CodeGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/CodeGen/Targets/RISCV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down
29 changes: 21 additions & 8 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1666,30 +1666,43 @@ 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" ||
Val == "2048" || Val == "128+" || Val == "256+" || Val == "512+" ||
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);

Expand Down
5 changes: 5 additions & 0 deletions clang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down
Loading
Loading