[RISCV] Add the zvl extension according to the v1.0 spec

`zvl` is the new standard vector extension that specifies the minimum vector length of the vector extension.
The `zvl` extension is related to the `zve` extension and other updates that are added in v1.0.

According to https://github.com/riscv-non-isa/riscv-c-api-doc/pull/21,
Clang defines macro `__riscv_v_min_vlen` for `zvl` and it can be used for applications that uses the vector extension.
LLVM checks whether the option `riscv-v-vector-bits-min` (if specified) matches the `zvl*` extension specified.

Reviewed By: craig.topper

Differential Revision: https://reviews.llvm.org/D108694
This commit is contained in:
eopXD 2021-10-23 03:18:24 -07:00
parent 35d00fdc10
commit 26bb1b1dab
10 changed files with 231 additions and 16 deletions

View File

@ -125,6 +125,7 @@ void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("__riscv_xlen", Is64Bit ? "64" : "32");
StringRef CodeModel = getTargetOpts().CodeModel;
unsigned FLen = ISAInfo->getFLen();
unsigned MinVLen = ISAInfo->getMinVLen();
if (CodeModel == "default")
CodeModel = "small";
@ -176,6 +177,9 @@ void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("__riscv_fsqrt");
}
if (MinVLen)
Builder.defineMacro("__riscv_v_min_vlen", Twine(MinVLen));
if (ISAInfo->hasExtension("c"))
Builder.defineMacro("__riscv_compressed");

View File

@ -434,3 +434,17 @@
// RUN: %clang -target riscv32-unknown-elf -march=rv32izvlsseg0p10 -menable-experimental-extensions -### %s -c 2>&1 | \
// RUN: FileCheck -check-prefix=RV32-EXPERIMENTAL-ZVLSSEG-GOODVERS %s
// RV32-EXPERIMENTAL-ZVLSSEG-GOODVERS: "-target-feature" "+experimental-zvlsseg"
// RUN: %clang -target riscv32-unknown-elf -march=rv32izvl32b0p10 -### %s -c 2>&1 | \
// RUN: FileCheck -check-prefix=RV32-EXPERIMENTAL-ZVL-NOFLAG %s
// RV32-EXPERIMENTAL-ZVL-NOFLAG: error: invalid arch name 'rv32izvl32b0p10'
// RV32-EXPERIMENTAL-ZVL-NOFLAG: requires '-menable-experimental-extensions'
// RUN: %clang -target riscv32-unknown-elf -march=rv32izvl32b0p1 -menable-experimental-extensions -### %s -c 2>&1 | \
// RUN: FileCheck -check-prefix=RV32-EXPERIMENTAL-ZVL-BADVERS %s
// RV32-EXPERIMENTAL-ZVL-BADVERS: error: invalid arch name 'rv32izvl32b0p1'
// RV32-EXPERIMENTAL-ZVL-BADVERS: unsupported version number 0.1 for experimental extension
// RUN: %clang -target riscv32-unknown-elf -march=rv32izvl32b0p10 -menable-experimental-extensions -### %s -c 2>&1 | \
// RUN: FileCheck -check-prefix=RV32-EXPERIMENTAL-ZVL-GOODVERS %s
// RV32-EXPERIMENTAL-ZVL-GOODVERS: "-target-feature" "+experimental-zvl32b"

View File

@ -243,3 +243,53 @@
// RUN: -march=rv64izfh1p0 -x c -E -dM %s \
// RUN: -o - | FileCheck --check-prefix=CHECK-ZFH-EXT %s
// CHECK-ZFH-EXT: __riscv_zfh 10000
// RUN: %clang -target riscv32-unknown-linux-gnu -menable-experimental-extensions \
// RUN: -march=rv64iv0p10 -x c -E -dM %s -o - \
// RUN: | FileCheck --check-prefix=CHECK-V-MINVLEN %s
// CHECK-V-MINVLEN: __riscv_v_min_vlen 128
// RUN: %clang -target riscv32-unknown-linux-gnu -menable-experimental-extensions \
// RUN: -march=rv64iv0p10_zvl256b0p10 -x c -E -dM %s -o - \
// RUN: | FileCheck --check-prefix=CHECK-ZVL256b %s
// CHECK-ZVL256b: __riscv_v_min_vlen 256
// RUN: %clang -target riscv32-unknown-linux-gnu -menable-experimental-extensions \
// RUN: -march=rv64iv0p10_zvl512b0p10 -x c -E -dM %s -o - \
// RUN: | FileCheck --check-prefix=CHECK-ZVL512b %s
// CHECK-ZVL512b: __riscv_v_min_vlen 512
// RUN: %clang -target riscv32-unknown-linux-gnu -menable-experimental-extensions \
// RUN: -march=rv64iv0p10_zvl1024b0p10 -x c -E -dM %s -o - \
// RUN: | FileCheck --check-prefix=CHECK-ZVL1024b %s
// CHECK-ZVL1024b: __riscv_v_min_vlen 1024
// RUN: %clang -target riscv32-unknown-linux-gnu -menable-experimental-extensions \
// RUN: -march=rv64iv0p10_zvl2048b0p10 -x c -E -dM %s -o - \
// RUN: | FileCheck --check-prefix=CHECK-ZVL2048b %s
// CHECK-ZVL2048b: __riscv_v_min_vlen 2048
// RUN: %clang -target riscv32-unknown-linux-gnu -menable-experimental-extensions \
// RUN: -march=rv64iv0p10_zvl4096b0p10 -x c -E -dM %s -o - \
// RUN: | FileCheck --check-prefix=CHECK-ZVL4096b %s
// CHECK-ZVL4096b: __riscv_v_min_vlen 4096
// RUN: %clang -target riscv32-unknown-linux-gnu -menable-experimental-extensions \
// RUN: -march=rv64iv0p10_zvl8192b0p10 -x c -E -dM %s -o - \
// RUN: | FileCheck --check-prefix=CHECK-ZVL8192b %s
// CHECK-ZVL8192b: __riscv_v_min_vlen 8192
// RUN: %clang -target riscv32-unknown-linux-gnu -menable-experimental-extensions \
// RUN: -march=rv64iv0p10_zvl16384b0p10 -x c -E -dM %s -o - \
// RUN: | FileCheck --check-prefix=CHECK-ZVL16384b %s
// CHECK-ZVL16384b: __riscv_v_min_vlen 16384
// RUN: %clang -target riscv32-unknown-linux-gnu -menable-experimental-extensions \
// RUN: -march=rv64iv0p10_zvl32768b0p10 -x c -E -dM %s -o - \
// RUN: | FileCheck --check-prefix=CHECK-ZVL32768b %s
// CHECK-ZVL32768b: __riscv_v_min_vlen 32768
// RUN: %clang -target riscv32-unknown-linux-gnu -menable-experimental-extensions \
// RUN: -march=rv64iv0p10_zvl65536b0p10 -x c -E -dM %s -o - \
// RUN: | FileCheck --check-prefix=CHECK-ZVL65536b %s
// CHECK-ZVL65536b: __riscv_v_min_vlen 65536

View File

@ -61,6 +61,7 @@ public:
unsigned getXLen() const { return XLen; };
unsigned getFLen() const { return FLen; };
unsigned getMinVLen() const { return MinVLen; }
bool hasExtension(StringRef Ext) const;
std::string toString() const;
@ -71,10 +72,11 @@ public:
unsigned MinorVersion);
private:
RISCVISAInfo(unsigned XLen) : XLen(XLen), FLen(0) {}
RISCVISAInfo(unsigned XLen) : XLen(XLen), FLen(0), MinVLen(0) {}
unsigned XLen;
unsigned FLen;
unsigned MinVLen;
OrderedExtensionMap Exts;
@ -85,6 +87,7 @@ private:
void updateImplication();
void updateFLen();
void updateMinVLen();
};
} // namespace llvm

View File

@ -9,6 +9,7 @@
#include "llvm/Support/RISCVISAInfo.h"
#include "llvm/ADT/None.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Errc.h"
@ -66,6 +67,18 @@ static const RISCVSupportedExtension SupportedExperimentalExtensions[] = {
{"zbt", RISCVExtensionVersion{0, 93}},
{"zvlsseg", RISCVExtensionVersion{0, 10}},
{"zvl32b", RISCVExtensionVersion{0, 10}},
{"zvl64b", RISCVExtensionVersion{0, 10}},
{"zvl128b", RISCVExtensionVersion{0, 10}},
{"zvl256b", RISCVExtensionVersion{0, 10}},
{"zvl512b", RISCVExtensionVersion{0, 10}},
{"zvl1024b", RISCVExtensionVersion{0, 10}},
{"zvl2048b", RISCVExtensionVersion{0, 10}},
{"zvl4096b", RISCVExtensionVersion{0, 10}},
{"zvl8192b", RISCVExtensionVersion{0, 10}},
{"zvl16384b", RISCVExtensionVersion{0, 10}},
{"zvl32768b", RISCVExtensionVersion{0, 10}},
{"zvl65536b", RISCVExtensionVersion{0, 10}},
};
static bool stripExperimentalPrefix(StringRef &Ext) {
@ -435,6 +448,7 @@ RISCVISAInfo::parseFeatures(unsigned XLen,
ISAInfo->updateImplication();
ISAInfo->updateFLen();
ISAInfo->updateMinVLen();
if (Error Result = ISAInfo->checkDependency())
return std::move(Result);
@ -658,6 +672,7 @@ RISCVISAInfo::parseArchString(StringRef Arch, bool EnableExperimentalExtension,
ISAInfo->updateImplication();
ISAInfo->updateFLen();
ISAInfo->updateMinVLen();
if (Error Result = ISAInfo->checkDependency())
return std::move(Result);
@ -691,8 +706,19 @@ Error RISCVISAInfo::checkDependency() {
return Error::success();
}
static const char *ImpliedExtsV[] = {"zvlsseg"};
static const char *ImpliedExtsV[] = {"zvlsseg", "zvl128b"};
static const char *ImpliedExtsZfh[] = {"zfhmin"};
static const char *ImpliedExtsZvl65536b[] = {"zvl32768b"};
static const char *ImpliedExtsZvl32768b[] = {"zvl16384b"};
static const char *ImpliedExtsZvl16384b[] = {"zvl8192b"};
static const char *ImpliedExtsZvl8192b[] = {"zvl4096b"};
static const char *ImpliedExtsZvl4096b[] = {"zvl2048b"};
static const char *ImpliedExtsZvl2048b[] = {"zvl1024b"};
static const char *ImpliedExtsZvl1024b[] = {"zvl512b"};
static const char *ImpliedExtsZvl512b[] = {"zvl256b"};
static const char *ImpliedExtsZvl256b[] = {"zvl128b"};
static const char *ImpliedExtsZvl128b[] = {"zvl64b"};
static const char *ImpliedExtsZvl64b[] = {"zvl32b"};
struct ImpliedExtsEntry {
StringLiteral Name;
@ -708,6 +734,17 @@ struct ImpliedExtsEntry {
static constexpr ImpliedExtsEntry ImpliedExts[] = {
{{"v"}, {ImpliedExtsV}},
{{"zfh"}, {ImpliedExtsZfh}},
{{"zvl1024b"}, {ImpliedExtsZvl1024b}},
{{"zvl128b"}, {ImpliedExtsZvl128b}},
{{"zvl16384b"}, {ImpliedExtsZvl16384b}},
{{"zvl2048b"}, {ImpliedExtsZvl2048b}},
{{"zvl256b"}, {ImpliedExtsZvl256b}},
{{"zvl32768b"}, {ImpliedExtsZvl32768b}},
{{"zvl4096b"}, {ImpliedExtsZvl4096b}},
{{"zvl512b"}, {ImpliedExtsZvl512b}},
{{"zvl64b"}, {ImpliedExtsZvl64b}},
{{"zvl65536b"}, {ImpliedExtsZvl65536b}},
{{"zvl8192b"}, {ImpliedExtsZvl8192b}},
};
void RISCVISAInfo::updateImplication() {
@ -722,12 +759,25 @@ void RISCVISAInfo::updateImplication() {
}
assert(llvm::is_sorted(ImpliedExts) && "Table not sorted by Name");
for (auto &Ext : Exts) {
auto I = llvm::lower_bound(ImpliedExts, Ext.first);
if (I != std::end(ImpliedExts) && I->Name == Ext.first) {
for (auto &ImpliedExt : I->Exts) {
// This loop may execute over 1 iteration since implication can be layered
// Exits loop if no more implication is applied
SmallSetVector<StringRef, 16> WorkList;
for (auto &Ext : Exts)
WorkList.insert(Ext.first);
while (!WorkList.empty()) {
StringRef ExtName = WorkList.pop_back_val();
auto I = llvm::lower_bound(ImpliedExts, ExtName);
if (I != std::end(ImpliedExts) && I->Name == ExtName) {
for (const char *ImpliedExt : I->Exts) {
if (WorkList.count(ImpliedExt))
continue;
if (Exts.count(ImpliedExt))
continue;
auto Version = findDefaultVersion(ImpliedExt);
addExtension(ImpliedExt, Version->Major, Version->Minor);
WorkList.insert(ImpliedExt);
}
}
}
@ -742,6 +792,18 @@ void RISCVISAInfo::updateFLen() {
FLen = 32;
}
void RISCVISAInfo::updateMinVLen() {
for (auto Ext : Exts) {
StringRef ExtName = Ext.first;
bool IsZvlExt = ExtName.consume_front("zvl") && ExtName.consume_back("b");
if (IsZvlExt) {
unsigned ZvlLen;
if (!ExtName.getAsInteger(10, ZvlLen))
MinVLen = std::max(MinVLen, ZvlLen);
}
}
}
std::string RISCVISAInfo::toString() const {
std::string Buffer;
raw_string_ostream Arch(Buffer);

View File

@ -150,9 +150,21 @@ def HasRVCHints : Predicate<"Subtarget->enableRVCHintInstrs()">,
AssemblerPredicate<(all_of(not FeatureNoRVCHints)),
"RVC Hint Instructions">;
def FeatureStdExtZvl32b : SubtargetFeature<"experimental-zvl32b", "ZvlLen", "ExtZvl::Zvl32b",
"'Zvl' (Minimum Vector Length) 32">;
foreach i = { 6-15 } in {
defvar I = !shl(1, i);
def FeatureStdExtZvl#I#b :
SubtargetFeature<"experimental-zvl"#I#"b", "ZvlLen", "ExtZvl::Zvl"#I#"b",
"'Zvl' (Minimum Vector Length) "#I,
[!cast<SubtargetFeature>("FeatureStdExtZvl"#!srl(I, 1)#"b")]>;
}
def FeatureStdExtV
: SubtargetFeature<"experimental-v", "HasStdExtV", "true",
"'V' (Vector Instructions)">;
"'V' (Vector Instructions)",
[FeatureStdExtZvl128b]>;
def HasStdExtV : Predicate<"Subtarget->hasStdExtV()">,
AssemblerPredicate<(all_of FeatureStdExtV),
"'V' (Vector Instructions)">;

View File

@ -18,6 +18,7 @@
#include "RISCVRegisterBankInfo.h"
#include "RISCVTargetMachine.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Support/ErrorHandling.h"
using namespace llvm;
@ -140,7 +141,15 @@ unsigned RISCVSubtarget::getMaxRVVVectorSizeInBits() const {
"Tried to get vector length without Zve or V extension support!");
if (RVVVectorBitsMax == 0)
return 0;
assert(RVVVectorBitsMax >= 128 && RVVVectorBitsMax <= 65536 &&
// ZvlLen specifies the minimum required vlen. The upper bound provided by
// riscv-v-vector-bits-max should be no less than it.
if (RVVVectorBitsMax < ZvlLen)
report_fatal_error("riscv-v-vector-bits-max specified is lower "
"than the Zvl*b limitation");
// FIXME: Change to >= 32 when VLEN = 32 is supported
assert(RVVVectorBitsMax >= 64 && RVVVectorBitsMax <= 65536 &&
isPowerOf2_32(RVVVectorBitsMax) &&
"V extension requires vector length to be in the range of 128 to "
"65536 and a power of 2!");
@ -152,10 +161,17 @@ unsigned RISCVSubtarget::getMaxRVVVectorSizeInBits() const {
}
unsigned RISCVSubtarget::getMinRVVVectorSizeInBits() const {
// ZvlLen specifies the minimum required vlen. The lower bound provided by
// riscv-v-vector-bits-min should be no less than it.
if (RVVVectorBitsMin != 0 && RVVVectorBitsMin < ZvlLen)
report_fatal_error("riscv-v-vector-bits-min specified is lower "
"than the Zvl*b limitation");
assert(hasVInstructions() &&
"Tried to get vector length without Zve or V extension support!");
// FIXME: Change to >= 32 when VLEN = 32 is supported
assert((RVVVectorBitsMin == 0 ||
(RVVVectorBitsMin >= 128 && RVVVectorBitsMax <= 65536 &&
(RVVVectorBitsMin >= 64 && RVVVectorBitsMax <= 65536 &&
isPowerOf2_32(RVVVectorBitsMin))) &&
"V extension requires vector length to be in the range of 128 to "
"65536 and a power of 2!");

View File

@ -34,6 +34,22 @@ class StringRef;
class RISCVSubtarget : public RISCVGenSubtargetInfo {
public:
enum ExtZvl : unsigned {
NotSet = 0,
Zvl32b = 32,
Zvl64b = 64,
Zvl128b = 128,
Zvl256b = 256,
Zvl512b = 512,
Zvl1024b = 1024,
Zvl2048b = 2048,
Zvl4096b = 4096,
Zvl8192b = 8192,
Zvl16384b = 16384,
Zvl32768b = 32768,
Zvl65536b = 65536
};
enum RISCVProcFamilyEnum : uint8_t {
Others,
SiFive7,
@ -69,6 +85,7 @@ private:
bool EnableRVCHintInstrs = true;
bool EnableSaveRestore = false;
unsigned XLen = 32;
ExtZvl ZvlLen = ExtZvl::NotSet;
MVT XLenVT = MVT::i32;
uint8_t MaxInterleaveFactor = 2;
RISCVABI::ABI TargetABI = RISCVABI::ABI_Unknown;
@ -134,6 +151,7 @@ public:
bool hasStdExtZbt() const { return HasStdExtZbt; }
bool hasStdExtV() const { return HasStdExtV; }
bool hasStdExtZvlsseg() const { return HasStdExtZvlsseg; }
bool hasStdExtZvl() const { return ZvlLen != ExtZvl::NotSet; }
bool hasStdExtZfhmin() const { return HasStdExtZfhmin; }
bool hasStdExtZfh() const { return HasStdExtZfh; }
bool is64Bit() const { return HasRV64; }

View File

@ -40,7 +40,7 @@
; RV32F: .attribute 5, "rv32i2p0_f2p0"
; RV32D: .attribute 5, "rv32i2p0_f2p0_d2p0"
; RV32C: .attribute 5, "rv32i2p0_c2p0"
; RV32V: .attribute 5, "rv32i2p0_v0p10_zvlsseg0p10"
; RV32V: .attribute 5, "rv32i2p0_v0p10_zvamo0p10_zvl128b0p10_zvl32b0p10_zvl64b0p10_zvlsseg0p10"
; RV32ZFHMIN: .attribute 5, "rv32i2p0_f2p0_zfhmin1p0"
; RV32ZFH: .attribute 5, "rv32i2p0_f2p0_zfh1p0_zfhmin1p0"
; RV32ZBA: .attribute 5, "rv32i2p0_zba1p0"
@ -53,7 +53,7 @@
; RV32ZBR: .attribute 5, "rv32i2p0_zbr0p93"
; RV32ZBS: .attribute 5, "rv32i2p0_zbs1p0"
; RV32ZBT: .attribute 5, "rv32i2p0_zbt0p93"
; RV32COMBINED: .attribute 5, "rv32i2p0_f2p0_v0p10_zfh1p0_zfhmin1p0_zbb1p0_zvlsseg0p10"
; RV32COMBINED: .attribute 5, "rv32i2p0_f2p0_v0p10_zfh1p0_zfhmin1p0_zbb1p0_zvamo0p10_zvl128b0p10_zvl32b0p10_zvl64b0p10_zvlsseg0p10"
; RV64M: .attribute 5, "rv64i2p0_m2p0"
; RV64A: .attribute 5, "rv64i2p0_a2p0"
@ -72,8 +72,8 @@
; RV64ZBR: .attribute 5, "rv64i2p0_zbr0p93"
; RV64ZBS: .attribute 5, "rv64i2p0_zbs1p0"
; RV64ZBT: .attribute 5, "rv64i2p0_zbt0p93"
; RV64V: .attribute 5, "rv64i2p0_v0p10_zvlsseg0p10"
; RV64COMBINED: .attribute 5, "rv64i2p0_f2p0_v0p10_zfh1p0_zfhmin1p0_zbb1p0_zvlsseg0p10"
; RV64V: .attribute 5, "rv64i2p0_v0p10_zvamo0p10_zvl128b0p10_zvl32b0p10_zvl64b0p10_zvlsseg0p10"
; RV64COMBINED: .attribute 5, "rv64i2p0_f2p0_v0p10_zfh1p0_zfhmin1p0_zbb1p0_zvamo0p10_zvl128b0p10_zvl32b0p10_zvl64b0p10_zvlsseg0p10"
define i32 @addi(i32 %a) {

View File

@ -36,7 +36,7 @@
## Experimental extensions require version string to be explicitly specified
.attribute arch, "rv32iv0p10"
# CHECK: attribute 5, "rv32i2p0_v0p10_zvlsseg0p10"
# CHECK: attribute 5, "rv32i2p0_v0p10_zvl128b0p10_zvl32b0p10_zvl64b0p10_zvlsseg0p10"
.attribute arch, "rv32izba1p0"
# CHECK: attribute 5, "rv32i2p0_zba1p0"
@ -74,5 +74,41 @@
.attribute arch, "rv32ifzfh1p0"
# CHECK: attribute 5, "rv32i2p0_f2p0_zfh1p0_zfhmin1p0"
.attribute arch, "rv32iv0p10zvlsseg0p10"
# CHECK: attribute 5, "rv32i2p0_v0p10_zvlsseg0p10"
.attribute arch, "rv32iv0p10_zvlsseg0p10"
# CHECK: attribute 5, "rv32i2p0_v0p10_zvl128b0p10_zvl32b0p10_zvl64b0p10_zvlsseg0p10"
.attribute arch, "rv32iv0p10zvl32b0p10"
# CHECK: attribute 5, "rv32i2p0_v0p10_zvl128b0p10_zvl32b0p10_zvl64b0p10_zvlsseg0p10"
.attribute arch, "rv32iv0p10zvl64b0p10"
# CHECK: attribute 5, "rv32i2p0_v0p10_zvl128b0p10_zvl32b0p10_zvl64b0p10_zvlsseg0p10"
.attribute arch, "rv32iv0p10zvl128b0p10"
# CHECK: attribute 5, "rv32i2p0_v0p10_zvl128b0p10_zvl32b0p10_zvl64b0p10_zvlsseg0p10"
.attribute arch, "rv32iv0p10zvl256b0p10"
# CHECK: attribute 5, "rv32i2p0_v0p10_zvl128b0p10_zvl256b0p10_zvl32b0p10_zvl64b0p10_zvlsseg0p10"
.attribute arch, "rv32iv0p10zvl512b0p10"
# CHECK: attribute 5, "rv32i2p0_v0p10_zvl128b0p10_zvl256b0p10_zvl32b0p10_zvl512b0p10_zvl64b0p10_zvlsseg0p10"
.attribute arch, "rv32iv0p10zvl1024b0p10"
# CHECK: attribute 5, "rv32i2p0_v0p10_zvl1024b0p10_zvl128b0p10_zvl256b0p10_zvl32b0p10_zvl512b0p10_zvl64b0p10_zvlsseg0p10"
.attribute arch, "rv32iv0p10zvl2048b0p10"
# CHECK: attribute 5, "rv32i2p0_v0p10_zvl1024b0p10_zvl128b0p10_zvl2048b0p10_zvl256b0p10_zvl32b0p10_zvl512b0p10_zvl64b0p10_zvlsseg0p10"
.attribute arch, "rv32iv0p10zvl4096b0p10"
# CHECK: attribute 5, "rv32i2p0_v0p10_zvl1024b0p10_zvl128b0p10_zvl2048b0p10_zvl256b0p10_zvl32b0p10_zvl4096b0p10_zvl512b0p10_zvl64b0p10_zvlsseg0p10"
.attribute arch, "rv32iv0p10zvl8192b0p10"
# CHECK: attribute 5, "rv32i2p0_v0p10_zvl1024b0p10_zvl128b0p10_zvl2048b0p10_zvl256b0p10_zvl32b0p10_zvl4096b0p10_zvl512b0p10_zvl64b0p10_zvl8192b0p10_zvlsseg0p10"
.attribute arch, "rv32iv0p10zvl16384b0p10"
# CHECK: attribute 5, "rv32i2p0_v0p10_zvl1024b0p10_zvl128b0p10_zvl16384b0p10_zvl2048b0p10_zvl256b0p10_zvl32b0p10_zvl4096b0p10_zvl512b0p10_zvl64b0p10_zvl8192b0p10_zvlsseg0p10"
.attribute arch, "rv32iv0p10zvl32768b0p10"
# CHECK: attribute 5, "rv32i2p0_v0p10_zvl1024b0p10_zvl128b0p10_zvl16384b0p10_zvl2048b0p10_zvl256b0p10_zvl32768b0p10_zvl32b0p10_zvl4096b0p10_zvl512b0p10_zvl64b0p10_zvl8192b0p10_zvlsseg0p10"
.attribute arch, "rv32iv0p10zvl65536b0p10"
# CHECK: attribute 5, "rv32i2p0_v0p10_zvl1024b0p10_zvl128b0p10_zvl16384b0p10_zvl2048b0p10_zvl256b0p10_zvl32768b0p10_zvl32b0p10_zvl4096b0p10_zvl512b0p10_zvl64b0p10_zvl65536b0p10_zvl8192b0p10_zvlsseg0p10"