blob: bede4e64696c55cba39c2fe142328e3e860b09d3 [file] [log] [blame] [edit]
//===-- unittests/RISCVISAInfoTest.cpp ------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "llvm/TargetParser/RISCVISAInfo.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/Testing/Support/Error.h"
#include "gtest/gtest.h"
using ::testing::ElementsAre;
using namespace llvm;
bool operator==(const RISCVISAUtils::ExtensionVersion &A,
const RISCVISAUtils::ExtensionVersion &B) {
return A.Major == B.Major && A.Minor == B.Minor;
}
TEST(ParseNormalizedArchString, RejectsInvalidChars) {
for (StringRef Input : {"RV32", "rV64", "rv32i2P0", "rv64i2p0_A2p0",
"rv32e2.0", "rva20u64+zbc"}) {
EXPECT_EQ(
toString(RISCVISAInfo::parseNormalizedArchString(Input).takeError()),
"string may only contain [a-z0-9_]");
}
}
TEST(ParseNormalizedArchString, RejectsInvalidBaseISA) {
for (StringRef Input : {"rv32", "rv64", "rv32j", "rv65i"}) {
EXPECT_EQ(
toString(RISCVISAInfo::parseNormalizedArchString(Input).takeError()),
"arch string must begin with valid base ISA");
}
}
TEST(ParseNormalizedArchString, RejectsMalformedInputs) {
for (StringRef Input : {"rv64e2p", "rv32i", "rv64ip1"}) {
EXPECT_EQ(
toString(RISCVISAInfo::parseNormalizedArchString(Input).takeError()),
"extension lacks version in expected format");
}
for (StringRef Input : {"rv64i2p0_", "rv32i2p0__a2p0"}) {
EXPECT_EQ(
toString(RISCVISAInfo::parseNormalizedArchString(Input).takeError()),
"extension name missing after separator '_'");
}
}
TEST(ParseNormalizedArchString, RejectsOnlyVersion) {
for (StringRef Input : {"rv64i2p0_1p0", "rv32i2p0_1p0"}) {
EXPECT_EQ(
toString(RISCVISAInfo::parseNormalizedArchString(Input).takeError()),
"missing extension name");
}
}
TEST(ParseNormalizedArchString, RejectsBadZ) {
for (StringRef Input : {"rv64i2p0_z1p0", "rv32i2p0_z2a1p0"}) {
EXPECT_EQ(
toString(RISCVISAInfo::parseNormalizedArchString(Input).takeError()),
"'z' must be followed by a letter");
}
}
TEST(ParseNormalizedArchString, RejectsBadS) {
for (StringRef Input : {"rv64i2p0_s1p0", "rv32i2p0_s2a1p0"}) {
EXPECT_EQ(
toString(RISCVISAInfo::parseNormalizedArchString(Input).takeError()),
"'s' must be followed by a letter");
}
}
TEST(ParseNormalizedArchString, RejectsBadX) {
for (StringRef Input : {"rv64i2p0_x1p0", "rv32i2p0_x2a1p0"}) {
EXPECT_EQ(
toString(RISCVISAInfo::parseNormalizedArchString(Input).takeError()),
"'x' must be followed by a letter");
}
}
TEST(ParseNormalizedArchString, DuplicateExtension) {
for (StringRef Input : {"rv64i2p0_a2p0_a1p0"}) {
EXPECT_EQ(
toString(RISCVISAInfo::parseNormalizedArchString(Input).takeError()),
"duplicate extension 'a'");
}
}
TEST(ParseNormalizedArchString, AcceptsValidBaseISAsAndSetsXLen) {
auto MaybeRV32I = RISCVISAInfo::parseNormalizedArchString("rv32i2p0");
ASSERT_THAT_EXPECTED(MaybeRV32I, Succeeded());
RISCVISAInfo &InfoRV32I = **MaybeRV32I;
EXPECT_EQ(InfoRV32I.getExtensions().size(), 1UL);
EXPECT_TRUE(InfoRV32I.getExtensions().at("i") ==
(RISCVISAUtils::ExtensionVersion{2, 0}));
EXPECT_EQ(InfoRV32I.getXLen(), 32U);
auto MaybeRV32E = RISCVISAInfo::parseNormalizedArchString("rv32e2p0");
ASSERT_THAT_EXPECTED(MaybeRV32E, Succeeded());
RISCVISAInfo &InfoRV32E = **MaybeRV32E;
EXPECT_EQ(InfoRV32E.getExtensions().size(), 1UL);
EXPECT_TRUE(InfoRV32E.getExtensions().at("e") ==
(RISCVISAUtils::ExtensionVersion{2, 0}));
EXPECT_EQ(InfoRV32E.getXLen(), 32U);
auto MaybeRV64I = RISCVISAInfo::parseNormalizedArchString("rv64i2p0");
ASSERT_THAT_EXPECTED(MaybeRV64I, Succeeded());
RISCVISAInfo &InfoRV64I = **MaybeRV64I;
EXPECT_EQ(InfoRV64I.getExtensions().size(), 1UL);
EXPECT_TRUE(InfoRV64I.getExtensions().at("i") ==
(RISCVISAUtils::ExtensionVersion{2, 0}));
EXPECT_EQ(InfoRV64I.getXLen(), 64U);
auto MaybeRV64E = RISCVISAInfo::parseNormalizedArchString("rv64e2p0");
ASSERT_THAT_EXPECTED(MaybeRV64E, Succeeded());
RISCVISAInfo &InfoRV64E = **MaybeRV64E;
EXPECT_EQ(InfoRV64E.getExtensions().size(), 1UL);
EXPECT_TRUE(InfoRV64E.getExtensions().at("e") ==
(RISCVISAUtils::ExtensionVersion{2, 0}));
EXPECT_EQ(InfoRV64E.getXLen(), 64U);
}
TEST(ParseNormalizedArchString, AcceptsArbitraryExtensionsAndVersions) {
auto MaybeISAInfo = RISCVISAInfo::parseNormalizedArchString(
"rv64i5p1_m3p2_zmadeup11p12_sfoo2p0_xbar3p0");
ASSERT_THAT_EXPECTED(MaybeISAInfo, Succeeded());
RISCVISAInfo &Info = **MaybeISAInfo;
EXPECT_EQ(Info.getExtensions().size(), 5UL);
EXPECT_TRUE(Info.getExtensions().at("i") ==
(RISCVISAUtils::ExtensionVersion{5, 1}));
EXPECT_TRUE(Info.getExtensions().at("m") ==
(RISCVISAUtils::ExtensionVersion{3, 2}));
EXPECT_TRUE(Info.getExtensions().at("zmadeup") ==
(RISCVISAUtils::ExtensionVersion{11, 12}));
EXPECT_TRUE(Info.getExtensions().at("sfoo") ==
(RISCVISAUtils::ExtensionVersion{2, 0}));
EXPECT_TRUE(Info.getExtensions().at("xbar") ==
(RISCVISAUtils::ExtensionVersion{3, 0}));
}
TEST(ParseNormalizedArchString, UpdatesFLenMinVLenMaxELen) {
auto MaybeISAInfo = RISCVISAInfo::parseNormalizedArchString(
"rv64i2p0_d2p0_zvl64b1p0_zve64d1p0");
ASSERT_THAT_EXPECTED(MaybeISAInfo, Succeeded());
RISCVISAInfo &Info = **MaybeISAInfo;
EXPECT_EQ(Info.getXLen(), 64U);
EXPECT_EQ(Info.getFLen(), 64U);
EXPECT_EQ(Info.getMinVLen(), 64U);
EXPECT_EQ(Info.getMaxELen(), 64U);
EXPECT_EQ(Info.getMaxELenFp(), 64U);
}
TEST(ParseNormalizedArchString, AcceptsUnknownMultiletter) {
auto MaybeISAInfo = RISCVISAInfo::parseNormalizedArchString(
"rv64i2p0_f2p0_d2p0_zicsr2p0_ykk1p0");
ASSERT_THAT_EXPECTED(MaybeISAInfo, Succeeded());
RISCVISAInfo &Info = **MaybeISAInfo;
EXPECT_EQ(Info.toString(), "rv64i2p0_f2p0_d2p0_zicsr2p0_ykk1p0");
}
TEST(ParseArchString, RejectsInvalidChars) {
for (StringRef Input : {"RV32", "rV64", "rv32i2P0", "rv64i2p0_A2p0"}) {
EXPECT_EQ(toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
"string may only contain [a-z0-9_]");
}
}
TEST(ParseArchString, RejectsInvalidBaseISA) {
for (StringRef Input : {"rv32", "rv64", "rv65i"}) {
EXPECT_EQ(toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
"string must begin with rv32{i,e,g}, rv64{i,e,g}, or a supported "
"profile name");
}
for (StringRef Input : {"rv32j", "rv32_i"}) {
EXPECT_EQ(toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
"first letter after 'rv32' should be 'e', 'i' or 'g'");
}
EXPECT_EQ(toString(RISCVISAInfo::parseArchString("rv64k", true).takeError()),
"first letter after 'rv64' should be 'e', 'i' or 'g'");
}
TEST(ParseArchString, RejectsUnsupportedBaseISA) {
for (StringRef Input : {"rv128i", "rv128g"}) {
EXPECT_EQ(toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
"string must begin with rv32{i,e,g}, rv64{i,e,g}, or a supported "
"profile name");
}
}
TEST(ParseArchString, AcceptsSupportedBaseISAsAndSetsXLenAndFLen) {
auto MaybeRV32I = RISCVISAInfo::parseArchString("rv32i", true);
ASSERT_THAT_EXPECTED(MaybeRV32I, Succeeded());
RISCVISAInfo &InfoRV32I = **MaybeRV32I;
const auto &ExtsRV32I = InfoRV32I.getExtensions();
EXPECT_EQ(ExtsRV32I.size(), 1UL);
EXPECT_TRUE(ExtsRV32I.at("i") == (RISCVISAUtils::ExtensionVersion{2, 1}));
EXPECT_EQ(InfoRV32I.getXLen(), 32U);
EXPECT_EQ(InfoRV32I.getFLen(), 0U);
EXPECT_EQ(InfoRV32I.getMinVLen(), 0U);
EXPECT_EQ(InfoRV32I.getMaxELen(), 0U);
EXPECT_EQ(InfoRV32I.getMaxELenFp(), 0U);
auto MaybeRV32E = RISCVISAInfo::parseArchString("rv32e", true);
ASSERT_THAT_EXPECTED(MaybeRV32E, Succeeded());
RISCVISAInfo &InfoRV32E = **MaybeRV32E;
const auto &ExtsRV32E = InfoRV32E.getExtensions();
EXPECT_EQ(ExtsRV32E.size(), 1UL);
EXPECT_TRUE(ExtsRV32E.at("e") == (RISCVISAUtils::ExtensionVersion{2, 0}));
EXPECT_EQ(InfoRV32E.getXLen(), 32U);
EXPECT_EQ(InfoRV32E.getFLen(), 0U);
EXPECT_EQ(InfoRV32E.getMinVLen(), 0U);
EXPECT_EQ(InfoRV32E.getMaxELen(), 0U);
EXPECT_EQ(InfoRV32E.getMaxELenFp(), 0U);
auto MaybeRV32G = RISCVISAInfo::parseArchString("rv32g", true);
ASSERT_THAT_EXPECTED(MaybeRV32G, Succeeded());
RISCVISAInfo &InfoRV32G = **MaybeRV32G;
const auto &ExtsRV32G = InfoRV32G.getExtensions();
EXPECT_EQ(ExtsRV32G.size(), 8UL);
EXPECT_TRUE(ExtsRV32G.at("i") == (RISCVISAUtils::ExtensionVersion{2, 1}));
EXPECT_TRUE(ExtsRV32G.at("m") == (RISCVISAUtils::ExtensionVersion{2, 0}));
EXPECT_TRUE(ExtsRV32G.at("a") == (RISCVISAUtils::ExtensionVersion{2, 1}));
EXPECT_TRUE(ExtsRV32G.at("f") == (RISCVISAUtils::ExtensionVersion{2, 2}));
EXPECT_TRUE(ExtsRV32G.at("d") == (RISCVISAUtils::ExtensionVersion{2, 2}));
EXPECT_TRUE(ExtsRV32G.at("zicsr") == (RISCVISAUtils::ExtensionVersion{2, 0}));
EXPECT_TRUE(ExtsRV32G.at("zifencei") ==
(RISCVISAUtils::ExtensionVersion{2, 0}));
EXPECT_TRUE(ExtsRV32G.at("zmmul") == (RISCVISAUtils::ExtensionVersion{1, 0}));
EXPECT_EQ(InfoRV32G.getXLen(), 32U);
EXPECT_EQ(InfoRV32G.getFLen(), 64U);
EXPECT_EQ(InfoRV32G.getMinVLen(), 0U);
EXPECT_EQ(InfoRV32G.getMaxELen(), 0U);
EXPECT_EQ(InfoRV32G.getMaxELenFp(), 0U);
auto MaybeRV64I = RISCVISAInfo::parseArchString("rv64i", true);
ASSERT_THAT_EXPECTED(MaybeRV64I, Succeeded());
RISCVISAInfo &InfoRV64I = **MaybeRV64I;
const auto &ExtsRV64I = InfoRV64I.getExtensions();
EXPECT_EQ(ExtsRV64I.size(), 1UL);
EXPECT_TRUE(ExtsRV64I.at("i") == (RISCVISAUtils::ExtensionVersion{2, 1}));
EXPECT_EQ(InfoRV64I.getXLen(), 64U);
EXPECT_EQ(InfoRV64I.getFLen(), 0U);
EXPECT_EQ(InfoRV64I.getMinVLen(), 0U);
EXPECT_EQ(InfoRV64I.getMaxELen(), 0U);
EXPECT_EQ(InfoRV64I.getMaxELenFp(), 0U);
auto MaybeRV64E = RISCVISAInfo::parseArchString("rv64e", true);
ASSERT_THAT_EXPECTED(MaybeRV64E, Succeeded());
RISCVISAInfo &InfoRV64E = **MaybeRV64E;
const auto &ExtsRV64E = InfoRV64E.getExtensions();
EXPECT_EQ(ExtsRV64E.size(), 1UL);
EXPECT_TRUE(ExtsRV64E.at("e") == (RISCVISAUtils::ExtensionVersion{2, 0}));
EXPECT_EQ(InfoRV64E.getXLen(), 64U);
EXPECT_EQ(InfoRV64E.getFLen(), 0U);
EXPECT_EQ(InfoRV64E.getMinVLen(), 0U);
EXPECT_EQ(InfoRV64E.getMaxELen(), 0U);
EXPECT_EQ(InfoRV64E.getMaxELenFp(), 0U);
auto MaybeRV64G = RISCVISAInfo::parseArchString("rv64g", true);
ASSERT_THAT_EXPECTED(MaybeRV64G, Succeeded());
RISCVISAInfo &InfoRV64G = **MaybeRV64G;
const auto &ExtsRV64G = InfoRV64G.getExtensions();
EXPECT_EQ(ExtsRV64G.size(), 8UL);
EXPECT_TRUE(ExtsRV64G.at("i") == (RISCVISAUtils::ExtensionVersion{2, 1}));
EXPECT_TRUE(ExtsRV64G.at("m") == (RISCVISAUtils::ExtensionVersion{2, 0}));
EXPECT_TRUE(ExtsRV64G.at("a") == (RISCVISAUtils::ExtensionVersion{2, 1}));
EXPECT_TRUE(ExtsRV64G.at("f") == (RISCVISAUtils::ExtensionVersion{2, 2}));
EXPECT_TRUE(ExtsRV64G.at("d") == (RISCVISAUtils::ExtensionVersion{2, 2}));
EXPECT_TRUE(ExtsRV64G.at("zicsr") == (RISCVISAUtils::ExtensionVersion{2, 0}));
EXPECT_TRUE(ExtsRV64G.at("zifencei") ==
(RISCVISAUtils::ExtensionVersion{2, 0}));
EXPECT_TRUE(ExtsRV32G.at("zmmul") == (RISCVISAUtils::ExtensionVersion{1, 0}));
EXPECT_EQ(InfoRV64G.getXLen(), 64U);
EXPECT_EQ(InfoRV64G.getFLen(), 64U);
EXPECT_EQ(InfoRV64G.getMinVLen(), 0U);
EXPECT_EQ(InfoRV64G.getMaxELen(), 0U);
EXPECT_EQ(InfoRV64G.getMaxELenFp(), 0U);
auto MaybeRV64GCV = RISCVISAInfo::parseArchString("rv64gcv", true);
ASSERT_THAT_EXPECTED(MaybeRV64GCV, Succeeded());
RISCVISAInfo &InfoRV64GCV = **MaybeRV64GCV;
const auto &ExtsRV64GCV = InfoRV64GCV.getExtensions();
EXPECT_EQ(ExtsRV64GCV.size(), 18UL);
EXPECT_TRUE(ExtsRV64GCV.at("i") == (RISCVISAUtils::ExtensionVersion{2, 1}));
EXPECT_TRUE(ExtsRV64GCV.at("m") == (RISCVISAUtils::ExtensionVersion{2, 0}));
EXPECT_TRUE(ExtsRV64GCV.at("a") == (RISCVISAUtils::ExtensionVersion{2, 1}));
EXPECT_TRUE(ExtsRV64GCV.at("f") == (RISCVISAUtils::ExtensionVersion{2, 2}));
EXPECT_TRUE(ExtsRV64GCV.at("d") == (RISCVISAUtils::ExtensionVersion{2, 2}));
EXPECT_TRUE(ExtsRV64GCV.at("c") == (RISCVISAUtils::ExtensionVersion{2, 0}));
EXPECT_TRUE(ExtsRV64GCV.at("zicsr") == (RISCVISAUtils::ExtensionVersion{2, 0}));
EXPECT_TRUE(ExtsRV64GCV.at("zifencei") ==
(RISCVISAUtils::ExtensionVersion{2, 0}));
EXPECT_TRUE(ExtsRV32G.at("zmmul") == (RISCVISAUtils::ExtensionVersion{1, 0}));
EXPECT_TRUE(ExtsRV64GCV.at("v") == (RISCVISAUtils::ExtensionVersion{1, 0}));
EXPECT_TRUE(ExtsRV64GCV.at("zve32x") == (RISCVISAUtils::ExtensionVersion{1, 0}));
EXPECT_TRUE(ExtsRV64GCV.at("zve32f") == (RISCVISAUtils::ExtensionVersion{1, 0}));
EXPECT_TRUE(ExtsRV64GCV.at("zve64x") == (RISCVISAUtils::ExtensionVersion{1, 0}));
EXPECT_TRUE(ExtsRV64GCV.at("zve64f") == (RISCVISAUtils::ExtensionVersion{1, 0}));
EXPECT_TRUE(ExtsRV64GCV.at("zve64d") == (RISCVISAUtils::ExtensionVersion{1, 0}));
EXPECT_TRUE(ExtsRV64GCV.at("zvl32b") == (RISCVISAUtils::ExtensionVersion{1, 0}));
EXPECT_TRUE(ExtsRV64GCV.at("zvl64b") == (RISCVISAUtils::ExtensionVersion{1, 0}));
EXPECT_TRUE(ExtsRV64GCV.at("zvl128b") == (RISCVISAUtils::ExtensionVersion{1, 0}));
EXPECT_EQ(InfoRV64GCV.getXLen(), 64U);
EXPECT_EQ(InfoRV64GCV.getFLen(), 64U);
EXPECT_EQ(InfoRV64GCV.getMinVLen(), 128U);
EXPECT_EQ(InfoRV64GCV.getMaxELen(), 64U);
EXPECT_EQ(InfoRV64GCV.getMaxELenFp(), 64U);
}
TEST(ParseArchString, RejectsUnrecognizedExtensionNamesByDefault) {
EXPECT_EQ(
toString(
RISCVISAInfo::parseArchString("rv32i_zmadeup", true).takeError()),
"unsupported standard user-level extension 'zmadeup'");
EXPECT_EQ(
toString(
RISCVISAInfo::parseArchString("rv64g_smadeup", true).takeError()),
"unsupported standard supervisor-level extension 'smadeup'");
EXPECT_EQ(
toString(
RISCVISAInfo::parseArchString("rv64g_xmadeup", true).takeError()),
"unsupported non-standard user-level extension 'xmadeup'");
EXPECT_EQ(
toString(
RISCVISAInfo::parseArchString("rv32i_zmadeup1p0", true).takeError()),
"unsupported standard user-level extension 'zmadeup'");
EXPECT_EQ(
toString(
RISCVISAInfo::parseArchString("rv64g_smadeup1p0", true).takeError()),
"unsupported standard supervisor-level extension 'smadeup'");
EXPECT_EQ(
toString(
RISCVISAInfo::parseArchString("rv64g_xmadeup1p0", true).takeError()),
"unsupported non-standard user-level extension 'xmadeup'");
}
TEST(ParseArchString, AcceptsVersionInLongOrShortForm) {
for (StringRef Input : {"rv64i2p1"}) {
auto MaybeISAInfo = RISCVISAInfo::parseArchString(Input, true);
ASSERT_THAT_EXPECTED(MaybeISAInfo, Succeeded());
const auto &Exts = (*MaybeISAInfo)->getExtensions();
EXPECT_TRUE(Exts.at("i") == (RISCVISAUtils::ExtensionVersion{2, 1}));
}
for (StringRef Input : {"rv32i_zfinx1", "rv32i_zfinx1p0"}) {
auto MaybeISAInfo = RISCVISAInfo::parseArchString(Input, true);
ASSERT_THAT_EXPECTED(MaybeISAInfo, Succeeded());
const auto &Exts = (*MaybeISAInfo)->getExtensions();
EXPECT_TRUE(Exts.at("zfinx") == (RISCVISAUtils::ExtensionVersion{1, 0}));
}
}
TEST(ParseArchString, RejectsUnrecognizedExtensionVersionsByDefault) {
EXPECT_EQ(
toString(RISCVISAInfo::parseArchString("rv64i2p", true).takeError()),
"minor version number missing after 'p' for extension 'i'");
EXPECT_EQ(
toString(RISCVISAInfo::parseArchString("rv64i1p0", true).takeError()),
"unsupported version number 1.0 for extension 'i'");
EXPECT_EQ(
toString(RISCVISAInfo::parseArchString("rv64i9p9", true).takeError()),
"unsupported version number 9.9 for extension 'i'");
EXPECT_EQ(
toString(RISCVISAInfo::parseArchString("rv32im0p1", true).takeError()),
"unsupported version number 0.1 for extension 'm'");
EXPECT_EQ(toString(RISCVISAInfo::parseArchString("rv32izifencei10p10", true)
.takeError()),
"unsupported version number 10.10 for extension 'zifencei'");
}
TEST(ParseArchString, AcceptsUnderscoreSplittingExtensions) {
for (StringRef Input : {"rv32imafdczifencei", "rv32i_m_a_f_d_c_zifencei"}) {
auto MaybeISAInfo = RISCVISAInfo::parseArchString(Input, true);
ASSERT_THAT_EXPECTED(MaybeISAInfo, Succeeded());
const auto &Exts = (*MaybeISAInfo)->getExtensions();
EXPECT_EQ(Exts.size(), 9UL);
EXPECT_EQ(Exts.count("i"), 1U);
EXPECT_EQ(Exts.count("m"), 1U);
EXPECT_EQ(Exts.count("a"), 1U);
EXPECT_EQ(Exts.count("f"), 1U);
EXPECT_EQ(Exts.count("d"), 1U);
EXPECT_EQ(Exts.count("c"), 1U);
EXPECT_EQ(Exts.count("zicsr"), 1U);
EXPECT_EQ(Exts.count("zifencei"), 1U);
EXPECT_EQ(Exts.count("zmmul"), 1U);
}
}
TEST(ParseArchString, AcceptsRelaxSingleLetterExtensions) {
for (StringRef Input :
{"rv32imfad", "rv32im_fa_d", "rv32im2p0fad", "rv32i2p1m2p0fad"}) {
auto MaybeISAInfo = RISCVISAInfo::parseArchString(Input, true);
ASSERT_THAT_EXPECTED(MaybeISAInfo, Succeeded());
const auto &Exts = (*MaybeISAInfo)->getExtensions();
EXPECT_EQ(Exts.size(), 7UL);
EXPECT_EQ(Exts.count("i"), 1U);
EXPECT_EQ(Exts.count("m"), 1U);
EXPECT_EQ(Exts.count("f"), 1U);
EXPECT_EQ(Exts.count("a"), 1U);
EXPECT_EQ(Exts.count("d"), 1U);
EXPECT_EQ(Exts.count("zicsr"), 1U);
EXPECT_EQ(Exts.count("zmmul"), 1U);
}
}
TEST(ParseArchString, AcceptsRelaxMixedLetterExtensions) {
for (StringRef Input :
{"rv32i_zihintntl_m_a_f_d_svinval", "rv32izihintntl_mafdsvinval",
"rv32i_zihintntl_mafd_svinval"}) {
auto MaybeISAInfo = RISCVISAInfo::parseArchString(Input, true);
ASSERT_THAT_EXPECTED(MaybeISAInfo, Succeeded());
const auto &Exts = (*MaybeISAInfo)->getExtensions();
EXPECT_EQ(Exts.size(), 9UL);
EXPECT_EQ(Exts.count("i"), 1U);
EXPECT_EQ(Exts.count("m"), 1U);
EXPECT_EQ(Exts.count("a"), 1U);
EXPECT_EQ(Exts.count("f"), 1U);
EXPECT_EQ(Exts.count("d"), 1U);
EXPECT_EQ(Exts.count("zihintntl"), 1U);
EXPECT_EQ(Exts.count("svinval"), 1U);
EXPECT_EQ(Exts.count("zicsr"), 1U);
EXPECT_EQ(Exts.count("zmmul"), 1U);
}
}
TEST(ParseArchString, AcceptsAmbiguousFromRelaxExtensions) {
for (StringRef Input : {"rv32i_zba_m", "rv32izba_m", "rv32izba1p0_m2p0"}) {
auto MaybeISAInfo = RISCVISAInfo::parseArchString(Input, true);
ASSERT_THAT_EXPECTED(MaybeISAInfo, Succeeded());
const auto &Exts = (*MaybeISAInfo)->getExtensions();
EXPECT_EQ(Exts.size(), 4UL);
EXPECT_EQ(Exts.count("i"), 1U);
EXPECT_EQ(Exts.count("zba"), 1U);
EXPECT_EQ(Exts.count("m"), 1U);
EXPECT_EQ(Exts.count("zmmul"), 1U);
}
for (StringRef Input :
{"rv32ia_zba_m", "rv32iazba_m", "rv32ia2p1zba1p0_m2p0"}) {
auto MaybeISAInfo = RISCVISAInfo::parseArchString(Input, true);
ASSERT_THAT_EXPECTED(MaybeISAInfo, Succeeded());
const auto &Exts = (*MaybeISAInfo)->getExtensions();
EXPECT_EQ(Exts.size(), 5UL);
EXPECT_EQ(Exts.count("i"), 1U);
EXPECT_EQ(Exts.count("zba"), 1U);
EXPECT_EQ(Exts.count("m"), 1U);
EXPECT_EQ(Exts.count("a"), 1U);
EXPECT_EQ(Exts.count("zmmul"), 1U);
}
}
TEST(ParseArchString, RejectsRelaxExtensionsNotStartWithEorIorG) {
EXPECT_EQ(
toString(RISCVISAInfo::parseArchString("rv32zba_im", true).takeError()),
"first letter after 'rv32' should be 'e', 'i' or 'g'");
}
TEST(ParseArchString,
RejectsMultiLetterExtensionFollowBySingleLetterExtensions) {
for (StringRef Input : {"rv32izbam", "rv32i_zbam"})
EXPECT_EQ(toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
"unsupported standard user-level extension 'zbam'");
EXPECT_EQ(
toString(RISCVISAInfo::parseArchString("rv32izbai_m", true).takeError()),
"unsupported standard user-level extension 'zbai'");
EXPECT_EQ(
toString(RISCVISAInfo::parseArchString("rv32izbaim", true).takeError()),
"unsupported standard user-level extension 'zbaim'");
EXPECT_EQ(
toString(
RISCVISAInfo::parseArchString("rv32i_zba1p0m", true).takeError()),
"unsupported standard user-level extension 'zba1p0m'");
}
TEST(ParseArchString, RejectsDoubleOrTrailingUnderscore) {
EXPECT_EQ(
toString(RISCVISAInfo::parseArchString("rv64i__m", true).takeError()),
"extension name missing after separator '_'");
for (StringRef Input :
{"rv32ezicsr__zifencei", "rv32i_", "rv32izicsr_", "rv64im_"}) {
EXPECT_EQ(toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
"extension name missing after separator '_'");
}
}
TEST(ParseArchString, RejectsDuplicateExtensionNames) {
EXPECT_EQ(toString(RISCVISAInfo::parseArchString("rv64ii", true).takeError()),
"invalid standard user-level extension 'i'");
EXPECT_EQ(toString(RISCVISAInfo::parseArchString("rv32ee", true).takeError()),
"invalid standard user-level extension 'e'");
EXPECT_EQ(
toString(RISCVISAInfo::parseArchString("rv64imm", true).takeError()),
"duplicated standard user-level extension 'm'");
EXPECT_EQ(
toString(
RISCVISAInfo::parseArchString("rv32i_zicsr_zicsr", true).takeError()),
"duplicated standard user-level extension 'zicsr'");
}
TEST(ParseArchString,
RejectsExperimentalExtensionsIfNotEnableExperimentalExtension) {
EXPECT_EQ(
toString(RISCVISAInfo::parseArchString("rv64izalasr", false).takeError()),
"requires '-menable-experimental-extensions' for experimental extension "
"'zalasr'");
}
TEST(ParseArchString,
AcceptsExperimentalExtensionsIfEnableExperimentalExtension) {
// Note: If zalasr becomes none-experimental, this test will need
// updating (and unfortunately, it will still pass). The failure of
// RejectsExperimentalExtensionsIfNotEnableExperimentalExtension will
// hopefully serve as a reminder to update.
auto MaybeISAInfo = RISCVISAInfo::parseArchString("rv64izalasr", true, false);
ASSERT_THAT_EXPECTED(MaybeISAInfo, Succeeded());
const auto &Exts = (*MaybeISAInfo)->getExtensions();
EXPECT_EQ(Exts.size(), 2UL);
EXPECT_EQ(Exts.count("zalasr"), 1U);
auto MaybeISAInfo2 = RISCVISAInfo::parseArchString("rv64izalasr0p1", true);
ASSERT_THAT_EXPECTED(MaybeISAInfo2, Succeeded());
const auto &Exts2 = (*MaybeISAInfo2)->getExtensions();
EXPECT_EQ(Exts2.size(), 2UL);
EXPECT_EQ(Exts2.count("zalasr"), 1U);
}
TEST(ParseArchString,
RequiresExplicitVersionNumberForExperimentalExtensionByDefault) {
EXPECT_EQ(
toString(RISCVISAInfo::parseArchString("rv64izalasr", true).takeError()),
"experimental extension requires explicit version number `zalasr`");
}
TEST(ParseArchString,
AcceptsUnrecognizedVersionIfNotExperimentalExtensionVersionCheck) {
auto MaybeISAInfo =
RISCVISAInfo::parseArchString("rv64izalasr9p9", true, false);
ASSERT_THAT_EXPECTED(MaybeISAInfo, Succeeded());
const auto &Exts = (*MaybeISAInfo)->getExtensions();
EXPECT_EQ(Exts.size(), 2UL);
EXPECT_TRUE(Exts.at("zalasr") == (RISCVISAUtils::ExtensionVersion{9, 9}));
}
TEST(ParseArchString, RejectsUnrecognizedVersionForExperimentalExtension) {
EXPECT_EQ(
toString(
RISCVISAInfo::parseArchString("rv64izalasr9p9", true).takeError()),
"unsupported version number 9.9 for experimental extension 'zalasr' "
"(this compiler supports 0.1)");
}
TEST(ParseArchString, RejectsExtensionVersionForG) {
for (StringRef Input : {"rv32g1c", "rv64g2p0"}) {
EXPECT_EQ(toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
"version not supported for 'g'");
}
}
TEST(ParseArchString, AddsImpliedExtensions) {
// Does not attempt to exhaustively test all implications.
auto MaybeRV64ID = RISCVISAInfo::parseArchString("rv64id", true);
ASSERT_THAT_EXPECTED(MaybeRV64ID, Succeeded());
const auto &ExtsRV64ID = (*MaybeRV64ID)->getExtensions();
EXPECT_EQ(ExtsRV64ID.size(), 4UL);
EXPECT_EQ(ExtsRV64ID.count("i"), 1U);
EXPECT_EQ(ExtsRV64ID.count("f"), 1U);
EXPECT_EQ(ExtsRV64ID.count("d"), 1U);
EXPECT_EQ(ExtsRV64ID.count("zicsr"), 1U);
auto MaybeRV32IZKN = RISCVISAInfo::parseArchString("rv64izkn", true);
ASSERT_THAT_EXPECTED(MaybeRV32IZKN, Succeeded());
const auto &ExtsRV32IZKN = (*MaybeRV32IZKN)->getExtensions();
EXPECT_EQ(ExtsRV32IZKN.size(), 8UL);
EXPECT_EQ(ExtsRV32IZKN.count("i"), 1U);
EXPECT_EQ(ExtsRV32IZKN.count("zbkb"), 1U);
EXPECT_EQ(ExtsRV32IZKN.count("zbkc"), 1U);
EXPECT_EQ(ExtsRV32IZKN.count("zbkx"), 1U);
EXPECT_EQ(ExtsRV32IZKN.count("zkne"), 1U);
EXPECT_EQ(ExtsRV32IZKN.count("zknd"), 1U);
EXPECT_EQ(ExtsRV32IZKN.count("zknh"), 1U);
EXPECT_EQ(ExtsRV32IZKN.count("zkn"), 1U);
}
TEST(ParseArchString, RejectsConflictingExtensions) {
for (StringRef Input : {"rv32ifzfinx", "rv64gzdinx"}) {
EXPECT_EQ(toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
"'f' and 'zfinx' extensions are incompatible");
}
for (StringRef Input : {"rv32idc_zcmp1p0", "rv64idc_zcmp1p0"}) {
EXPECT_EQ(toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
"'zcmp' extension is incompatible with 'c' extension when 'd' "
"extension is enabled");
}
for (StringRef Input : {"rv32id_zcd1p0_zcmp1p0", "rv64id_zcd1p0_zcmp1p0"}) {
EXPECT_EQ(toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
"'zcmp' extension is incompatible with 'zcd' extension when 'd' "
"extension is enabled");
}
for (StringRef Input : {"rv32idc_zcmt1p0", "rv64idc_zcmt1p0"}) {
EXPECT_EQ(toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
"'zcmt' extension is incompatible with 'c' extension when 'd' "
"extension is enabled");
}
for (StringRef Input : {"rv32id_zcd1p0_zcmt1p0", "rv64id_zcd1p0_zcmt1p0"}) {
EXPECT_EQ(toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
"'zcmt' extension is incompatible with 'zcd' extension when 'd' "
"extension is enabled");
}
for (StringRef Input : {"rv64if_zcf"}) {
EXPECT_EQ(toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
"'zcf' is only supported for 'rv32'");
}
}
TEST(ParseArchString, RejectsUnrecognizedProfileNames) {
for (StringRef Input : {"rvi23u99", "rvz23u64", "rva99u32"}) {
EXPECT_EQ(toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
"string must begin with rv32{i,e,g}, rv64{i,e,g}, or a supported "
"profile name");
}
}
TEST(ParseArchString, RejectsProfilesWithUnseparatedExtraExtensions) {
for (StringRef Input : {"rvi20u32m", "rvi20u64c"}) {
EXPECT_EQ(toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
"additional extensions must be after separator '_'");
}
}
TEST(ParseArchString, AcceptsBareProfileNames) {
auto MaybeRVA20U64 = RISCVISAInfo::parseArchString("rva20u64", true);
ASSERT_THAT_EXPECTED(MaybeRVA20U64, Succeeded());
const auto &Exts = (*MaybeRVA20U64)->getExtensions();
EXPECT_EQ(Exts.size(), 14UL);
EXPECT_EQ(Exts.count("i"), 1U);
EXPECT_EQ(Exts.count("m"), 1U);
EXPECT_EQ(Exts.count("f"), 1U);
EXPECT_EQ(Exts.count("a"), 1U);
EXPECT_EQ(Exts.count("d"), 1U);
EXPECT_EQ(Exts.count("c"), 1U);
EXPECT_EQ(Exts.count("za128rs"), 1U);
EXPECT_EQ(Exts.count("zicntr"), 1U);
EXPECT_EQ(Exts.count("ziccif"), 1U);
EXPECT_EQ(Exts.count("zicsr"), 1U);
EXPECT_EQ(Exts.count("ziccrse"), 1U);
EXPECT_EQ(Exts.count("ziccamoa"), 1U);
EXPECT_EQ(Exts.count("zicclsm"), 1U);
EXPECT_EQ(Exts.count("zmmul"), 1U);
auto MaybeRVA23U64 = RISCVISAInfo::parseArchString("rva23u64", true);
ASSERT_THAT_EXPECTED(MaybeRVA23U64, Succeeded());
EXPECT_GT((*MaybeRVA23U64)->getExtensions().size(), 13UL);
}
TEST(ParseArchSTring, AcceptsProfileNamesWithSeparatedAdditionalExtensions) {
auto MaybeRVI20U64 = RISCVISAInfo::parseArchString("rvi20u64_m_zba", true);
ASSERT_THAT_EXPECTED(MaybeRVI20U64, Succeeded());
const auto &Exts = (*MaybeRVI20U64)->getExtensions();
EXPECT_EQ(Exts.size(), 4UL);
EXPECT_EQ(Exts.count("i"), 1U);
EXPECT_EQ(Exts.count("m"), 1U);
EXPECT_EQ(Exts.count("zba"), 1U);
EXPECT_EQ(Exts.count("zmmul"), 1U);
}
TEST(ParseArchString,
RejectsProfilesWithAdditionalExtensionsGivenAlreadyInProfile) {
// This test was added to document the current behaviour. Discussion isn't
// believed to have taken place about if this is desirable or not.
EXPECT_EQ(
toString(
RISCVISAInfo::parseArchString("rva20u64_zicntr", true).takeError()),
"duplicated standard user-level extension 'zicntr'");
}
TEST(ParseArchString,
RejectsExperimentalProfilesIfEnableExperimentalExtensionsNotSet) {
EXPECT_EQ(
toString(RISCVISAInfo::parseArchString("rva23u64", false).takeError()),
"requires '-menable-experimental-extensions' for profile 'rva23u64'");
}
TEST(ToFeatures, IIsDroppedAndExperimentalExtensionsArePrefixed) {
auto MaybeISAInfo1 =
RISCVISAInfo::parseArchString("rv64im_zalasr", true, false);
ASSERT_THAT_EXPECTED(MaybeISAInfo1, Succeeded());
EXPECT_THAT((*MaybeISAInfo1)->toFeatures(),
ElementsAre("+m", "+zmmul", "+experimental-zalasr"));
auto MaybeISAInfo2 = RISCVISAInfo::parseArchString(
"rv32e_zalasr_xventanacondops", true, false);
ASSERT_THAT_EXPECTED(MaybeISAInfo2, Succeeded());
EXPECT_THAT((*MaybeISAInfo2)->toFeatures(),
ElementsAre("+e", "+experimental-zalasr", "+xventanacondops"));
}
TEST(ToFeatures, UnsupportedExtensionsAreDropped) {
auto MaybeISAInfo =
RISCVISAInfo::parseNormalizedArchString("rv64i2p0_m2p0_xmadeup1p0");
ASSERT_THAT_EXPECTED(MaybeISAInfo, Succeeded());
EXPECT_THAT((*MaybeISAInfo)->toFeatures(), ElementsAre("+m"));
}
TEST(ToFeatures, UnsupportedExtensionsAreKeptIfIgnoreUnknownIsFalse) {
auto MaybeISAInfo =
RISCVISAInfo::parseNormalizedArchString("rv64i2p0_m2p0_xmadeup1p0");
ASSERT_THAT_EXPECTED(MaybeISAInfo, Succeeded());
EXPECT_THAT((*MaybeISAInfo)->toFeatures(false, false),
ElementsAre("+m", "+xmadeup"));
}
TEST(ToFeatures, AddAllExtensionsAddsNegativeExtensions) {
auto MaybeISAInfo = RISCVISAInfo::parseNormalizedArchString("rv64i2p0_m2p0");
ASSERT_THAT_EXPECTED(MaybeISAInfo, Succeeded());
auto Features = (*MaybeISAInfo)->toFeatures(true);
EXPECT_GT(Features.size(), 1UL);
EXPECT_EQ(Features.front(), "+m");
// Every feature after should be a negative feature
for (auto &NegativeExt : llvm::drop_begin(Features))
EXPECT_TRUE(NegativeExt.substr(0, 1) == "-");
}
TEST(OrderedExtensionMap, ExtensionsAreCorrectlyOrdered) {
RISCVISAUtils::OrderedExtensionMap Exts;
for (auto ExtName : {"y", "l", "m", "c", "i", "xfoo", "xbar", "sfoo", "sbar",
"zmfoo", "zzfoo", "zfinx", "zicsr"})
Exts[ExtName] = {1, 0};
std::vector<std::string> ExtNames;
for (const auto &Ext : Exts)
ExtNames.push_back(Ext.first);
// FIXME: 'l' and 'y' should be ordered after 'i', 'm', 'c'.
EXPECT_THAT(ExtNames,
ElementsAre("i", "m", "l", "c", "y", "zicsr", "zmfoo", "zfinx",
"zzfoo", "sbar", "sfoo", "xbar", "xfoo"));
}
TEST(ParseArchString, ZceImplication) {
auto MaybeRV32IZce = RISCVISAInfo::parseArchString("rv32izce", true);
ASSERT_THAT_EXPECTED(MaybeRV32IZce, Succeeded());
const auto &ExtsRV32IZce = (*MaybeRV32IZce)->getExtensions();
EXPECT_EQ(ExtsRV32IZce.size(), 7UL);
EXPECT_EQ(ExtsRV32IZce.count("i"), 1U);
EXPECT_EQ(ExtsRV32IZce.count("zicsr"), 1U);
EXPECT_EQ(ExtsRV32IZce.count("zca"), 1U);
EXPECT_EQ(ExtsRV32IZce.count("zcb"), 1U);
EXPECT_EQ(ExtsRV32IZce.count("zce"), 1U);
EXPECT_EQ(ExtsRV32IZce.count("zcmp"), 1U);
EXPECT_EQ(ExtsRV32IZce.count("zcmt"), 1U);
auto MaybeRV32IFZce = RISCVISAInfo::parseArchString("rv32ifzce", true);
ASSERT_THAT_EXPECTED(MaybeRV32IFZce, Succeeded());
const auto &ExtsRV32IFZce = (*MaybeRV32IFZce)->getExtensions();
EXPECT_EQ(ExtsRV32IFZce.size(), 9UL);
EXPECT_EQ(ExtsRV32IFZce.count("i"), 1U);
EXPECT_EQ(ExtsRV32IFZce.count("zicsr"), 1U);
EXPECT_EQ(ExtsRV32IFZce.count("f"), 1U);
EXPECT_EQ(ExtsRV32IFZce.count("zca"), 1U);
EXPECT_EQ(ExtsRV32IFZce.count("zcb"), 1U);
EXPECT_EQ(ExtsRV32IFZce.count("zce"), 1U);
EXPECT_EQ(ExtsRV32IFZce.count("zcf"), 1U);
EXPECT_EQ(ExtsRV32IFZce.count("zcmp"), 1U);
EXPECT_EQ(ExtsRV32IFZce.count("zcmt"), 1U);
auto MaybeRV32IDZce = RISCVISAInfo::parseArchString("rv32idzce", true);
ASSERT_THAT_EXPECTED(MaybeRV32IDZce, Succeeded());
const auto &ExtsRV32IDZce = (*MaybeRV32IDZce)->getExtensions();
EXPECT_EQ(ExtsRV32IDZce.size(), 10UL);
EXPECT_EQ(ExtsRV32IDZce.count("i"), 1U);
EXPECT_EQ(ExtsRV32IDZce.count("zicsr"), 1U);
EXPECT_EQ(ExtsRV32IDZce.count("f"), 1U);
EXPECT_EQ(ExtsRV32IDZce.count("d"), 1U);
EXPECT_EQ(ExtsRV32IDZce.count("zca"), 1U);
EXPECT_EQ(ExtsRV32IDZce.count("zcb"), 1U);
EXPECT_EQ(ExtsRV32IDZce.count("zce"), 1U);
EXPECT_EQ(ExtsRV32IDZce.count("zcf"), 1U);
EXPECT_EQ(ExtsRV32IDZce.count("zcmp"), 1U);
EXPECT_EQ(ExtsRV32IDZce.count("zcmt"), 1U);
auto MaybeRV64IZce = RISCVISAInfo::parseArchString("rv64izce", true);
ASSERT_THAT_EXPECTED(MaybeRV64IZce, Succeeded());
const auto &ExtsRV64IZce = (*MaybeRV64IZce)->getExtensions();
EXPECT_EQ(ExtsRV64IZce.size(), 7UL);
EXPECT_EQ(ExtsRV64IZce.count("i"), 1U);
EXPECT_EQ(ExtsRV64IZce.count("zicsr"), 1U);
EXPECT_EQ(ExtsRV64IZce.count("zca"), 1U);
EXPECT_EQ(ExtsRV64IZce.count("zcb"), 1U);
EXPECT_EQ(ExtsRV64IZce.count("zce"), 1U);
EXPECT_EQ(ExtsRV64IZce.count("zcmp"), 1U);
EXPECT_EQ(ExtsRV64IZce.count("zcmt"), 1U);
auto MaybeRV64IFZce = RISCVISAInfo::parseArchString("rv64ifzce", true);
ASSERT_THAT_EXPECTED(MaybeRV64IFZce, Succeeded());
const auto &ExtsRV64IFZce = (*MaybeRV64IFZce)->getExtensions();
EXPECT_EQ(ExtsRV64IFZce.size(), 8UL);
EXPECT_EQ(ExtsRV64IFZce.count("i"), 1U);
EXPECT_EQ(ExtsRV64IFZce.count("zicsr"), 1U);
EXPECT_EQ(ExtsRV64IFZce.count("f"), 1U);
EXPECT_EQ(ExtsRV64IFZce.count("zca"), 1U);
EXPECT_EQ(ExtsRV64IFZce.count("zcb"), 1U);
EXPECT_EQ(ExtsRV64IFZce.count("zce"), 1U);
EXPECT_EQ(ExtsRV64IFZce.count("zcmp"), 1U);
EXPECT_EQ(ExtsRV64IFZce.count("zcmt"), 1U);
EXPECT_EQ(ExtsRV64IFZce.count("zca"), 1U);
EXPECT_EQ(ExtsRV64IFZce.count("zcb"), 1U);
EXPECT_EQ(ExtsRV64IFZce.count("zce"), 1U);
EXPECT_EQ(ExtsRV64IFZce.count("zcmp"), 1U);
EXPECT_EQ(ExtsRV64IFZce.count("zcmt"), 1U);
auto MaybeRV64IDZce = RISCVISAInfo::parseArchString("rv64idzce", true);
ASSERT_THAT_EXPECTED(MaybeRV64IDZce, Succeeded());
const auto &ExtsRV64IDZce = (*MaybeRV64IDZce)->getExtensions();
EXPECT_EQ(ExtsRV64IDZce.size(), 9UL);
EXPECT_EQ(ExtsRV64IDZce.count("i"), 1U);
EXPECT_EQ(ExtsRV64IDZce.count("zicsr"), 1U);
EXPECT_EQ(ExtsRV64IDZce.count("f"), 1U);
EXPECT_EQ(ExtsRV64IDZce.count("d"), 1U);
EXPECT_EQ(ExtsRV64IDZce.count("zca"), 1U);
EXPECT_EQ(ExtsRV64IDZce.count("zcb"), 1U);
EXPECT_EQ(ExtsRV64IDZce.count("zce"), 1U);
EXPECT_EQ(ExtsRV64IDZce.count("zcmp"), 1U);
EXPECT_EQ(ExtsRV64IDZce.count("zcmt"), 1U);
}
TEST(isSupportedExtensionWithVersion, AcceptsSingleExtensionWithVersion) {
EXPECT_TRUE(RISCVISAInfo::isSupportedExtensionWithVersion("zbb1p0"));
EXPECT_FALSE(RISCVISAInfo::isSupportedExtensionWithVersion("zbb"));
EXPECT_FALSE(RISCVISAInfo::isSupportedExtensionWithVersion("zfoo1p0"));
EXPECT_FALSE(RISCVISAInfo::isSupportedExtensionWithVersion("zfoo"));
EXPECT_FALSE(RISCVISAInfo::isSupportedExtensionWithVersion(""));
EXPECT_FALSE(RISCVISAInfo::isSupportedExtensionWithVersion("c2p0zbb1p0"));
}
TEST(getTargetFeatureForExtension, RetrieveTargetFeatureFromOneExt) {
EXPECT_EQ(RISCVISAInfo::getTargetFeatureForExtension("zbb"), "zbb");
EXPECT_EQ(RISCVISAInfo::getTargetFeatureForExtension("ztso1p0"), "ztso");
EXPECT_EQ(RISCVISAInfo::getTargetFeatureForExtension("ztso"), "ztso");
EXPECT_EQ(RISCVISAInfo::getTargetFeatureForExtension("zihintntl1234p4321"),
"");
EXPECT_EQ(RISCVISAInfo::getTargetFeatureForExtension("zfoo"), "");
EXPECT_EQ(RISCVISAInfo::getTargetFeatureForExtension(""), "");
EXPECT_EQ(RISCVISAInfo::getTargetFeatureForExtension("zbbzihintntl"), "");
}
TEST(RiscvExtensionsHelp, CheckExtensions) {
// clang-format off
std::string ExpectedOutput =
R"(All available -march extensions for RISC-V
Name Version Description
i 2.1 This is a long dummy description
e 2.0
m 2.0
a 2.1
f 2.2
d 2.2
c 2.0
b 1.0
v 1.0
h 1.0
zic64b 1.0
zicbom 1.0
zicbop 1.0
zicboz 1.0
ziccamoa 1.0
ziccif 1.0
zicclsm 1.0
ziccrse 1.0
zicntr 2.0
zicond 1.0
zicsr 2.0
zifencei 2.0
zihintntl 1.0
zihintpause 2.0
zihpm 2.0
zimop 1.0
zmmul 1.0
za128rs 1.0
za64rs 1.0
zaamo 1.0
zabha 1.0
zalrsc 1.0
zama16b 1.0
zawrs 1.0
zfa 1.0
zfbfmin 1.0
zfh 1.0
zfhmin 1.0
zfinx 1.0
zdinx 1.0
zca 1.0
zcb 1.0
zcd 1.0
zce 1.0
zcf 1.0
zcmop 1.0
zcmp 1.0
zcmt 1.0
zba 1.0
zbb 1.0
zbc 1.0
zbkb 1.0
zbkc 1.0
zbkx 1.0
zbs 1.0
zk 1.0
zkn 1.0
zknd 1.0
zkne 1.0
zknh 1.0
zkr 1.0
zks 1.0
zksed 1.0
zksh 1.0
zkt 1.0
ztso 1.0
zvbb 1.0
zvbc 1.0
zve32f 1.0
zve32x 1.0
zve64d 1.0
zve64f 1.0
zve64x 1.0
zvfbfmin 1.0
zvfbfwma 1.0
zvfh 1.0
zvfhmin 1.0
zvkb 1.0
zvkg 1.0
zvkn 1.0
zvknc 1.0
zvkned 1.0
zvkng 1.0
zvknha 1.0
zvknhb 1.0
zvks 1.0
zvksc 1.0
zvksed 1.0
zvksg 1.0
zvksh 1.0
zvkt 1.0
zvl1024b 1.0
zvl128b 1.0
zvl16384b 1.0
zvl2048b 1.0
zvl256b 1.0
zvl32768b 1.0
zvl32b 1.0
zvl4096b 1.0
zvl512b 1.0
zvl64b 1.0
zvl65536b 1.0
zvl8192b 1.0
zhinx 1.0
zhinxmin 1.0
shcounterenw 1.0
shgatpa 1.0
shtvala 1.0
shvsatpa 1.0
shvstvala 1.0
shvstvecd 1.0
smaia 1.0
smcdeleg 1.0
smcsrind 1.0
smepmp 1.0
smstateen 1.0
ssaia 1.0
ssccfg 1.0
ssccptr 1.0
sscofpmf 1.0
sscounterenw 1.0
sscsrind 1.0
ssstateen 1.0
ssstrict 1.0
sstc 1.0
sstvala 1.0
sstvecd 1.0
ssu64xl 1.0
svade 1.0
svadu 1.0
svbare 1.0
svinval 1.0
svnapot 1.0
svpbmt 1.0
xcvalu 1.0
xcvbi 1.0
xcvbitmanip 1.0
xcvelw 1.0
xcvmac 1.0
xcvmem 1.0
xcvsimd 1.0
xsfcease 1.0
xsfvcp 1.0
xsfvfnrclipxfqf 1.0
xsfvfwmaccqqq 1.0
xsfvqmaccdod 1.0
xsfvqmaccqoq 1.0
xsifivecdiscarddlone 1.0
xsifivecflushdlone 1.0
xtheadba 1.0
xtheadbb 1.0
xtheadbs 1.0
xtheadcmo 1.0
xtheadcondmov 1.0
xtheadfmemidx 1.0
xtheadmac 1.0
xtheadmemidx 1.0
xtheadmempair 1.0
xtheadsync 1.0
xtheadvdot 1.0
xventanacondops 1.0
xwchc 2.2
Experimental extensions
zicfilp 1.0 This is a long dummy description
zicfiss 1.0
zacas 1.0
zalasr 0.1
smmpm 1.0
smnpm 1.0
ssnpm 1.0
sspm 1.0
ssqosid 1.0
supm 1.0
Supported Profiles
rva20s64
rva20u64
rva22s64
rva22u64
rvi20u32
rvi20u64
Experimental Profiles
rva23s64
rva23u64
rvb23s64
rvb23u64
rvm23u32
Use -march to specify the target's extension.
For example, clang -march=rv32i_v1p0)";
// clang-format on
StringMap<StringRef> DummyMap;
DummyMap["i"] = "This is a long dummy description";
DummyMap["experimental-zicfilp"] = "This is a long dummy description";
outs().flush();
testing::internal::CaptureStdout();
RISCVISAInfo::printSupportedExtensions(DummyMap);
outs().flush();
std::string CapturedOutput = testing::internal::GetCapturedStdout();
EXPECT_TRUE([](std::string &Captured, std::string &Expected) {
return Captured.find(Expected) != std::string::npos;
}(CapturedOutput, ExpectedOutput));
}
TEST(TargetParserTest, RISCVPrintEnabledExtensions) {
// clang-format off
std::string ExpectedOutput =
R"(Extensions enabled for the given RISC-V target
Name Version Description
i 2.1 'I' (Base Integer Instruction Set)
Experimental extensions
zicfilp 1.0 'Zicfilp' (Landing pad)
ISA String: rv64i2p1_zicfilp1p0_zicsr2p0
)";
// clang-format on
StringMap<StringRef> DescMap;
DescMap["i"] = "'I' (Base Integer Instruction Set)";
DescMap["experimental-zicfilp"] = "'Zicfilp' (Landing pad)";
std::set<StringRef> EnabledExtensions = {"i", "experimental-zicfilp"};
outs().flush();
testing::internal::CaptureStdout();
RISCVISAInfo::printEnabledExtensions(/*IsRV64=*/true, EnabledExtensions,
DescMap);
outs().flush();
std::string CapturedOutput = testing::internal::GetCapturedStdout();
EXPECT_EQ(CapturedOutput, ExpectedOutput);
}