Skip to content
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,
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,
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit:

Suggested change
ArmStreamingKind IsArmStreamingFunction,
ArmStreamingKind Mode,

(here and in other places)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Just "Mode" on its own seems sort of confusing? Not sure what a better name is, though.

Copy link
Member

Choose a reason for hiding this comment

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

I think calling the enum ArmStreamingMode and the parameter StreamingMode would be okay ("StreamingKind" is a little inconsistent as everywhere else this is referred to as the streaming mode).

Copy link
Collaborator

Choose a reason for hiding this comment

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

My primary objection is that IsArmStreamingFunction suggests the type is a bool, but is instead an enum with more than 2 values.

Because the variable is of type ArmStreamingKind and is compared everywhere to enums named 'Streaming' 'StreamingCompatible' and 'NotStreaming', I think Mode is clear enough of a name. @MacDue's suggestion to use StreamingMode is also confusing because "streaming [SVE] mode" is another way of saying that PSTATE.SM=1.

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