diff --git a/clang/lib/Basic/Targets/RISCV.cpp b/clang/lib/Basic/Targets/RISCV.cpp --- a/clang/lib/Basic/Targets/RISCV.cpp +++ b/clang/lib/Basic/Targets/RISCV.cpp @@ -125,6 +125,7 @@ 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 @@ Builder.defineMacro("__riscv_fsqrt"); } + if (MinVLen) + Builder.defineMacro("__riscv_v_min_vlen", Twine(MinVLen)); + if (ISAInfo->hasExtension("c")) Builder.defineMacro("__riscv_compressed"); diff --git a/clang/test/CodeGen/RISCV/riscv-metadata.c b/clang/test/CodeGen/RISCV/riscv-metadata.c --- a/clang/test/CodeGen/RISCV/riscv-metadata.c +++ b/clang/test/CodeGen/RISCV/riscv-metadata.c @@ -1,9 +1,9 @@ // RUN: %clang_cc1 -triple riscv32 -target-abi ilp32 -emit-llvm -o - %s | FileCheck -check-prefix=ILP32 %s // RUN: %clang_cc1 -triple riscv32 -target-feature +f -target-abi ilp32f -emit-llvm -o - %s | FileCheck -check-prefix=ILP32F %s -// RUN: %clang_cc1 -triple riscv32 -target-feature +d -target-abi ilp32d -emit-llvm -o - %s | FileCheck -check-prefix=ILP32D %s +// RUN: %clang_cc1 -triple riscv32 -target-feature +d -target-feature +f -target-abi ilp32d -emit-llvm -o - %s | FileCheck -check-prefix=ILP32D %s // RUN: %clang_cc1 -triple riscv64 -target-abi lp64 -emit-llvm -o - %s | FileCheck -check-prefix=LP64 %s // RUN: %clang_cc1 -triple riscv64 -target-feature +f -target-abi lp64f -emit-llvm -o - %s | FileCheck -check-prefix=LP64F %s -// RUN: %clang_cc1 -triple riscv64 -target-feature +d -target-abi lp64d -emit-llvm -o - %s | FileCheck -check-prefix=LP64D %s +// RUN: %clang_cc1 -triple riscv64 -target-feature +d -target-feature +f -target-abi lp64d -emit-llvm -o - %s | FileCheck -check-prefix=LP64D %s // ILP32: !{{[0-9]+}} = !{i32 1, !"target-abi", !"ilp32"} // ILP32F: !{{[0-9]+}} = !{i32 1, !"target-abi", !"ilp32f"} diff --git a/clang/test/CodeGen/RISCV/riscv32-ilp32-ilp32f-ilp32d-abi.c b/clang/test/CodeGen/RISCV/riscv32-ilp32-ilp32f-ilp32d-abi.c --- a/clang/test/CodeGen/RISCV/riscv32-ilp32-ilp32f-ilp32d-abi.c +++ b/clang/test/CodeGen/RISCV/riscv32-ilp32-ilp32f-ilp32d-abi.c @@ -3,7 +3,7 @@ // RUN: | FileCheck %s -check-prefixes=CHECK,CHECK-FORCEINT128 // RUN: %clang_cc1 -triple riscv32 -target-feature +f -target-abi ilp32f -emit-llvm %s -o - \ // RUN: | FileCheck %s -// RUN: %clang_cc1 -triple riscv32 -target-feature +d -target-abi ilp32d -emit-llvm %s -o - \ +// RUN: %clang_cc1 -triple riscv32 -target-feature +d -target-feature +f -target-abi ilp32d -emit-llvm %s -o - \ // RUN: | FileCheck %s // This file contains test cases that will have the same output for the ilp32, diff --git a/clang/test/CodeGen/RISCV/riscv32-ilp32d-abi.c b/clang/test/CodeGen/RISCV/riscv32-ilp32d-abi.c --- a/clang/test/CodeGen/RISCV/riscv32-ilp32d-abi.c +++ b/clang/test/CodeGen/RISCV/riscv32-ilp32d-abi.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -triple riscv32 -target-feature +d -target-abi ilp32d -emit-llvm %s -o - \ +// RUN: %clang_cc1 -triple riscv32 -target-feature +d -target-feature +f -target-abi ilp32d -emit-llvm %s -o - \ // RUN: | FileCheck %s #include diff --git a/clang/test/CodeGen/RISCV/riscv32-ilp32f-ilp32d-abi.c b/clang/test/CodeGen/RISCV/riscv32-ilp32f-ilp32d-abi.c --- a/clang/test/CodeGen/RISCV/riscv32-ilp32f-ilp32d-abi.c +++ b/clang/test/CodeGen/RISCV/riscv32-ilp32f-ilp32d-abi.c @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -triple riscv32 -target-feature +f -target-abi ilp32f -emit-llvm %s -o - \ // RUN: | FileCheck %s -// RUN: %clang_cc1 -triple riscv32 -target-feature +d -target-abi ilp32d -emit-llvm %s -o - \ +// RUN: %clang_cc1 -triple riscv32 -target-feature +d -target-feature +f -target-abi ilp32d -emit-llvm %s -o - \ // RUN: | FileCheck %s #include diff --git a/clang/test/CodeGen/RISCV/riscv64-lp64-lp64f-lp64d-abi.c b/clang/test/CodeGen/RISCV/riscv64-lp64-lp64f-lp64d-abi.c --- a/clang/test/CodeGen/RISCV/riscv64-lp64-lp64f-lp64d-abi.c +++ b/clang/test/CodeGen/RISCV/riscv64-lp64-lp64f-lp64d-abi.c @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -triple riscv64 -emit-llvm %s -o - | FileCheck %s // RUN: %clang_cc1 -triple riscv64 -target-feature +f -target-abi lp64f -emit-llvm %s -o - \ // RUN: | FileCheck %s -// RUN: %clang_cc1 -triple riscv64 -target-feature +d -target-abi lp64d -emit-llvm %s -o - \ +// RUN: %clang_cc1 -triple riscv64 -target-feature +d -target-feature +f -target-abi lp64d -emit-llvm %s -o - \ // RUN: | FileCheck %s // This file contains test cases that will have the same output for the lp64, diff --git a/clang/test/CodeGen/RISCV/riscv64-lp64d-abi.c b/clang/test/CodeGen/RISCV/riscv64-lp64d-abi.c --- a/clang/test/CodeGen/RISCV/riscv64-lp64d-abi.c +++ b/clang/test/CodeGen/RISCV/riscv64-lp64d-abi.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -triple riscv64 -target-feature +d -target-abi lp64d -emit-llvm %s -o - \ +// RUN: %clang_cc1 -triple riscv64 -target-feature +d -target-feature +f -target-abi lp64d -emit-llvm %s -o - \ // RUN: | FileCheck %s #include diff --git a/clang/test/CodeGen/RISCV/riscv64-lp64f-lp64d-abi.c b/clang/test/CodeGen/RISCV/riscv64-lp64f-lp64d-abi.c --- a/clang/test/CodeGen/RISCV/riscv64-lp64f-lp64d-abi.c +++ b/clang/test/CodeGen/RISCV/riscv64-lp64f-lp64d-abi.c @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -triple riscv64 -target-feature +f -target-abi lp64f -emit-llvm %s -o - \ // RUN: | FileCheck %s -// RUN: %clang_cc1 -triple riscv64 -target-feature +d -target-abi lp64d -emit-llvm %s -o - \ +// RUN: %clang_cc1 -triple riscv64 -target-feature +d -target-feature +f -target-abi lp64d -emit-llvm %s -o - \ // RUN: | FileCheck %s #include diff --git a/clang/test/CodeGen/riscv32-ilp32d-abi.cpp b/clang/test/CodeGen/riscv32-ilp32d-abi.cpp --- a/clang/test/CodeGen/riscv32-ilp32d-abi.cpp +++ b/clang/test/CodeGen/riscv32-ilp32d-abi.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -triple riscv32 -target-feature +d -target-abi ilp32d \ +// RUN: %clang_cc1 -triple riscv32 -target-feature +d -target-feature +f -target-abi ilp32d \ // RUN: -Wno-missing-declarations -emit-llvm %s -o - | FileCheck %s struct empty_float2 { struct {}; float f; float g; }; diff --git a/clang/test/Driver/riscv-arch.c b/clang/test/Driver/riscv-arch.c --- a/clang/test/Driver/riscv-arch.c +++ b/clang/test/Driver/riscv-arch.c @@ -392,7 +392,7 @@ // RUN: %clang -target riscv32-unknown-elf -march=rv32izbb1p0zbp0p93 -menable-experimental-extensions -### %s \ // RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32-EXPERIMENTAL-ZBB-ZBP-UNDERSCORE %s -// RV32-EXPERIMENTAL-ZBB-ZBP-UNDERSCORE: error: invalid arch name 'rv32izbb1p0zbp0p93', multi-character extensions must be separated by underscores +// RV32-EXPERIMENTAL-ZBB-ZBP-UNDERSCORE: error: invalid arch name 'rv32izbb1p0zbp0p93', unsupported version number 0.93 for extension 'zbb1p0zbp' // RUN: %clang -target riscv32-unknown-elf -march=rv32izba1p0 -menable-experimental-extensions -### %s \ // RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32-EXPERIMENTAL-ZBA %s @@ -463,3 +463,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" diff --git a/clang/test/Preprocessor/riscv-target-features.c b/clang/test/Preprocessor/riscv-target-features.c --- a/clang/test/Preprocessor/riscv-target-features.c +++ b/clang/test/Preprocessor/riscv-target-features.c @@ -223,3 +223,8 @@ // RUN: -march=rv64izfh0p1 -x c -E -dM %s \ // RUN: -o - | FileCheck --check-prefix=CHECK-ZFH-EXT %s // CHECK-ZFH-EXT: __riscv_zfh 1000 + +// 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 diff --git a/llvm/include/llvm/Support/RISCVISAInfo.h b/llvm/include/llvm/Support/RISCVISAInfo.h --- a/llvm/include/llvm/Support/RISCVISAInfo.h +++ b/llvm/include/llvm/Support/RISCVISAInfo.h @@ -61,6 +61,7 @@ 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,17 +72,22 @@ 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; void addExtension(StringRef ExtName, unsigned MajorVersion, unsigned MinorVersion); + Error checkDependency(); + + void updateImplication(); void updateFLen(); + void updateMinVLen(); }; } // namespace llvm diff --git a/llvm/lib/Support/RISCVISAInfo.cpp b/llvm/lib/Support/RISCVISAInfo.cpp --- a/llvm/lib/Support/RISCVISAInfo.cpp +++ b/llvm/lib/Support/RISCVISAInfo.cpp @@ -10,6 +10,7 @@ #include "llvm/ADT/None.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/SetVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Errc.h" #include "llvm/Support/Error.h" @@ -18,6 +19,7 @@ #include #include #include +#include using namespace llvm; @@ -63,6 +65,18 @@ {"zvamo", RISCVExtensionVersion{0, 10}}, {"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}}, {"zfh", RISCVExtensionVersion{0, 1}}, }; @@ -411,7 +425,6 @@ assert(XLen == 32 || XLen == 64); std::unique_ptr ISAInfo(new RISCVISAInfo(XLen)); - bool HasE = false; for (auto &Feature : Features) { StringRef ExtName = Feature; bool Experimental = false; @@ -430,28 +443,19 @@ if (ExtensionInfoIterator == ExtensionInfos.end()) continue; - if (Add) { - if (ExtName == "e") { - if (XLen != 32) - return createStringError( - errc::invalid_argument, - "standard user-level extension 'e' requires 'rv32'"); - HasE = true; - } - + if (Add) ISAInfo->addExtension(ExtName, ExtensionInfoIterator->Version.Major, ExtensionInfoIterator->Version.Minor); - } else - ISAInfo->Exts.erase(ExtName.str()); - } - if (!HasE) { - if (auto Version = findDefaultVersion("i")) - ISAInfo->addExtension("i", Version->Major, Version->Minor); else - llvm_unreachable("Default extension version for 'i' not found?"); + ISAInfo->Exts.erase(ExtName.str()); } ISAInfo->updateFLen(); + ISAInfo->updateImplication(); + ISAInfo->updateMinVLen(); + + if (Error Result = ISAInfo->checkDependency()) + return std::move(Result); return std::move(ISAInfo); } @@ -478,7 +482,6 @@ // The canonical order specified in ISA manual. // Ref: Table 22.1 in RISC-V User-Level ISA V2.2 StringRef StdExts = AllStdExts; - bool HasF = false, HasD = false; char Baseline = Arch[4]; // First letter should be 'e', 'i' or 'g'. @@ -499,8 +502,6 @@ case 'g': // g = imafd StdExts = StdExts.drop_front(4); - HasF = true; - HasD = true; break; } @@ -518,6 +519,8 @@ Exts = Exts.substr(0, Pos); } + dbgs() << OtherExts << "\n"; + unsigned Major, Minor, ConsumeLength; if (auto E = getExtensionVersion(std::string(1, Baseline), Exts, Major, Minor, ConsumeLength, EnableExperimentalExtension, @@ -581,34 +584,14 @@ // The order is OK, then push it into features. // TODO: Use version number when setting target features - switch (C) { - default: - // Currently LLVM supports only "mafdcbv". + // Currently LLVM supports only "mafdcbv". + StringRef SupportedStandardExtension = "mafdcbv"; + if (SupportedStandardExtension.find(C) == StringRef::npos) return createStringError(errc::invalid_argument, "unsupported standard user-level extension '%c'", C); - case 'm': - ISAInfo->addExtension("m", Major, Minor); - break; - case 'a': - ISAInfo->addExtension("a", Major, Minor); - break; - case 'f': - ISAInfo->addExtension("f", Major, Minor); - HasF = true; - break; - case 'd': - ISAInfo->addExtension("d", Major, Minor); - HasD = true; - break; - case 'c': - ISAInfo->addExtension("c", Major, Minor); - break; - case 'v': - ISAInfo->addExtension("v", Major, Minor); - ISAInfo->addExtension("zvlsseg", Major, Minor); - break; - } + ISAInfo->addExtension(std::string(1, C), Major, Minor); + // Consume full extension name and version, including any optional '_' // between this extension and the next ++I; @@ -616,21 +599,6 @@ if (*I == '_') ++I; } - // Dependency check. - // It's illegal to specify the 'd' (double-precision floating point) - // extension without also specifying the 'f' (single precision - // floating-point) extension. - // TODO: This has been removed in later specs, which specify that D implies F - if (HasD && !HasF) - return createStringError(errc::invalid_argument, - "d requires f extension to also be specified"); - - // Additional dependency checks. - // TODO: The 'q' extension requires rv64. - // TODO: It is illegal to specify 'e' extensions with 'f' and 'd'. - - if (OtherExts.empty()) - return std::move(ISAInfo); // Handle other types of extensions other than the standard // general purpose and standard user-level extensions. @@ -651,52 +619,53 @@ std::array Prefix{"z", "x", "s", "sx"}; auto I = Prefix.begin(); auto E = Prefix.end(); + if (Split.size() > 1 || Split[0] != "") { + for (StringRef Ext : Split) { + if (Ext.empty()) + return createStringError(errc::invalid_argument, + "extension name missing after separator '_'"); + + StringRef Type = getExtensionType(Ext); + StringRef Desc = getExtensionTypeDesc(Ext); + auto Pos = findFirstNonVersionCharacter(Ext) + 1; + StringRef Name(Ext.substr(0, Pos)); + StringRef Vers(Ext.substr(Pos)); + + if (Type.empty()) + return createStringError(errc::invalid_argument, + "invalid extension prefix '" + Ext + "'"); + + // Check ISA extensions are specified in the canonical order. + while (I != E && *I != Type) + ++I; + + if (I == E) + return createStringError(errc::invalid_argument, + "%s not given in canonical order '%s'", + Desc.str().c_str(), Ext.str().c_str()); + + if (Name.size() == Type.size()) { + return createStringError(errc::invalid_argument, + "%s name missing after '%s'", Desc.str().c_str(), + Type.str().c_str()); + } - for (StringRef Ext : Split) { - if (Ext.empty()) - return createStringError(errc::invalid_argument, - "extension name missing after separator '_'"); - - StringRef Type = getExtensionType(Ext); - StringRef Desc = getExtensionTypeDesc(Ext); - size_t Pos = findFirstNonVersionCharacter(Ext) + 1; - StringRef Name(Ext.substr(0, Pos)); - StringRef Vers(Ext.substr(Pos)); - - if (Type.empty()) - return createStringError(errc::invalid_argument, - "invalid extension prefix '" + Ext + "'"); - - // Check ISA extensions are specified in the canonical order. - while (I != E && *I != Type) - ++I; - - if (I == E) - return createStringError(errc::invalid_argument, - "%s not given in canonical order '%s'", - Desc.str().c_str(), Ext.str().c_str()); - - if (Name.size() == Type.size()) { - return createStringError(errc::invalid_argument, - "%s name missing after '%s'", Desc.str().c_str(), - Type.str().c_str()); + unsigned Major, Minor, ConsumeLength; + if (auto E = getExtensionVersion(Name, Vers, Major, Minor, ConsumeLength, + EnableExperimentalExtension, + ExperimentalExtensionVersionCheck)) + return std::move(E); + + // Check if duplicated extension. + if (llvm::is_contained(AllExts, Name)) + return createStringError(errc::invalid_argument, "duplicated %s '%s'", + Desc.str().c_str(), Name.str().c_str()); + + ISAInfo->addExtension(Name, Major, Minor); + // Extension format is correct, keep parsing the extensions. + // TODO: Save Type, Name, Major, Minor to avoid parsing them later. + AllExts.push_back(Name); } - - unsigned Major, Minor, ConsumeLength; - if (auto E = getExtensionVersion(Name, Vers, Major, Minor, ConsumeLength, - EnableExperimentalExtension, - ExperimentalExtensionVersionCheck)) - return std::move(E); - - // Check if duplicated extension. - if (llvm::is_contained(AllExts, Name)) - return createStringError(errc::invalid_argument, "duplicated %s '%s'", - Desc.str().c_str(), Name.str().c_str()); - - ISAInfo->addExtension(Name, Major, Minor); - // Extension format is correct, keep parsing the extensions. - // TODO: Save Type, Name, Major, Minor to avoid parsing them later. - AllExts.push_back(Name); } for (auto Ext : AllExts) { @@ -707,11 +676,92 @@ } } + ISAInfo->updateImplication(); ISAInfo->updateFLen(); + ISAInfo->updateMinVLen(); + + if (Error Result = ISAInfo->checkDependency()) + return std::move(Result); return std::move(ISAInfo); } +Error RISCVISAInfo::checkDependency() { + bool IsRv32 = XLen == 32; + bool HasE = Exts.count("e") == 1; + bool HasD = Exts.count("d") == 1; + bool HasF = Exts.count("f") == 1; + + if (HasE && !IsRv32) + return createStringError( + errc::invalid_argument, + "standard user-level extension 'e' requires 'rv32'"); + + // It's illegal to specify the 'd' (double-precision floating point) + // extension without also specifying the 'f' (single precision + // floating-point) extension. + // TODO: This has been removed in later specs, which specify that D implies F + if (HasD && !HasF) + return createStringError( + errc::invalid_argument, + "d requires f extension to also be specified"); + + // Additional dependency checks. + // TODO: The 'q' extension requires rv64. + // TODO: It is illegal to specify 'e' extensions with 'f' and 'd'. + + return Error::success(); +} + +void RISCVISAInfo::updateImplication() { + const StringMap> Implications = { + {"v", {"zvlsseg", "zvl128b"}}, + + {"zvl64b", {"zvl32b"}}, + {"zvl128b", {"zvl64b"}}, + {"zvl256b", {"zvl128b"}}, + {"zvl512b", {"zvl256b"}}, + {"zvl1024b", {"zvl512b"}}, + {"zvl2048b", {"zvl1024b"}}, + {"zvl4096b", {"zvl2048b"}}, + {"zvl8192b", {"zvl4096b"}}, + {"zvl16384b", {"zvl8192b"}}, + {"zvl32768b", {"zvl16384b"}}, + {"zvl65536b", {"zvl32768b"}}, + }; + bool HasE = Exts.count("e") == 1; + bool HasI = Exts.count("i") == 1; + + // If not in e extension and i extension does not exist, i extension is + // implied + if (!HasE && !HasI) { + auto Version = findDefaultVersion("i"); + addExtension("i", Version->Major, Version->Minor); + } + + // This loop may execute over 1 iteration since implication can be layered + // Exits loop if no more implication is applied + SmallSetVector WorkList; + for (auto &Ext : Exts) + WorkList.insert(Ext.first); + + while (!WorkList.empty()) { + auto ExtName = WorkList.pop_back_val(); + auto Implication = Implications.find(ExtName); + if (Implication != Implications.end()) { + for (auto ImpliedExtName : Implication->second) { + if (WorkList.count(ImpliedExtName)) + continue; + if (Exts.count(ImpliedExtName.str())) + continue; + auto Version = findDefaultVersion(ImpliedExtName); + addExtension(ImpliedExtName, Version->Major, Version->Minor); + WorkList.insert(ImpliedExtName); + } + } + } +} + void RISCVISAInfo::updateFLen() { FLen = 0; // TODO: Handle q extension. @@ -721,6 +771,19 @@ FLen = 32; } +void RISCVISAInfo::updateMinVLen() { + for (auto &Ext : Exts) { + StringRef ExtName = Ext.first; + bool IsZvlExt = ExtName.consume_front("zvl"); + if (IsZvlExt) { + ExtName.consume_back("b"); + unsigned ZvlLen; + ExtName.getAsInteger(10, ZvlLen); + MinVLen = std::max(MinVLen, ZvlLen); + } + } +} + std::string RISCVISAInfo::toString() const { std::string Buffer; raw_string_ostream Arch(Buffer); diff --git a/llvm/lib/Target/RISCV/RISCV.td b/llvm/lib/Target/RISCV/RISCV.td --- a/llvm/lib/Target/RISCV/RISCV.td +++ b/llvm/lib/Target/RISCV/RISCV.td @@ -142,9 +142,47 @@ AssemblerPredicate<(all_of(not FeatureNoRVCHints)), "RVC Hint Instructions">; +def FeatureStdExtZvl32b : SubtargetFeature<"experimental-zvl32b", "ZvlLen", "ExtZvl::Zvl32b", + "'Zvl' (Minimum Vector Length) 32">; +def FeatureStdExtZvl64b : SubtargetFeature<"experimental-zvl64b", "ZvlLen", "ExtZvl::Zvl64b", + "'Zvl' (Minimum Vector Length) 64", + [FeatureStdExtZvl32b]>; +def FeatureStdExtZvl128b : SubtargetFeature<"experimental-zvl128b", "ZvlLen", "ExtZvl::Zvl128b", + "'Zvl' (Minimum Vector Length) 128", + [FeatureStdExtZvl64b]>; +def FeatureStdExtZvl256b : SubtargetFeature<"experimental-zvl256b", "ZvlLen", "ExtZvl::Zvl256b", + "'Zvl' (Minimum Vector Length) 256", + [FeatureStdExtZvl128b]>; +def FeatureStdExtZvl512b : SubtargetFeature<"experimental-zvl512b", "ZvlLen", "ExtZvl::Zvl512b", + "'Zvl' (Minimum Vector Length) 512", + [FeatureStdExtZvl256b]>; +def FeatureStdExtZvl1024b : SubtargetFeature<"experimental-zvl1024b", "ZvlLen", "ExtZvl::Zvl1024b", + "'Zvl' (Minimum Vector Length) 1024", + [FeatureStdExtZvl512b]>; +def FeatureStdExtZvl2048b : SubtargetFeature<"experimental-zvl2048b", "ZvlLen", "ExtZvl::Zvl2048b", + "'Zvl' (Minimum Vector Length) 2048", + [FeatureStdExtZvl1024b]>; +def FeatureStdExtZvl4096b : SubtargetFeature<"experimental-zvl4096b", "ZvlLen", "ExtZvl::Zvl4096b", + "'Zvl' (Minimum Vector Length) 4096", + [FeatureStdExtZvl2048b]>; +def FeatureStdExtZvl8192b : SubtargetFeature<"experimental-zvl8192b", "ZvlLen", "ExtZvl::Zvl8192b", + "'Zvl' (Minimum Vector Length) 8192", + [FeatureStdExtZvl4096b]>; +def FeatureStdExtZvl16384b : SubtargetFeature<"experimental-zvl16384b", "ZvlLen", "ExtZvl::Zvl16384b", + "'Zvl' (Minimum Vector Length) 16384", + [FeatureStdExtZvl8192b]>; +def FeatureStdExtZvl32768b : SubtargetFeature<"experimental-zvl32768b", "ZvlLen", "ExtZvl::Zvl32768b", + "'Zvl' (Minimum Vector Length) 32768", + [FeatureStdExtZvl16384b]>; +def FeatureStdExtZvl65536b : SubtargetFeature<"experimental-zvl65536b", "ZvlLen", "ExtZvl::Zvl65536b", + "'Zvl' (Minimum Vector Length) 65536", + [FeatureStdExtZvl32768b]>; +def HasStdExtZvl : Predicate<"Subtarget->hasStdExtZvl()">; + 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)">; diff --git a/llvm/lib/Target/RISCV/RISCVSubtarget.h b/llvm/lib/Target/RISCV/RISCVSubtarget.h --- a/llvm/lib/Target/RISCV/RISCVSubtarget.h +++ b/llvm/lib/Target/RISCV/RISCVSubtarget.h @@ -33,6 +33,22 @@ class StringRef; class RISCVSubtarget : public RISCVGenSubtargetInfo { + 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 + }; + virtual void anchor(); bool HasStdExtM = false; bool HasStdExtA = false; @@ -59,6 +75,7 @@ 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; @@ -117,6 +134,7 @@ bool hasStdExtZbt() const { return HasStdExtZbt; } bool hasStdExtV() const { return HasStdExtV; } bool hasStdExtZvlsseg() const { return HasStdExtZvlsseg; } + bool hasStdExtZvl() const { return ZvlLen != ExtZvl::NotSet; } bool hasStdExtZvamo() const { return HasStdExtZvamo; } bool hasStdExtZfh() const { return HasStdExtZfh; } bool is64Bit() const { return HasRV64; } diff --git a/llvm/lib/Target/RISCV/RISCVSubtarget.cpp b/llvm/lib/Target/RISCV/RISCVSubtarget.cpp --- a/llvm/lib/Target/RISCV/RISCVSubtarget.cpp +++ b/llvm/lib/Target/RISCV/RISCVSubtarget.cpp @@ -136,6 +136,9 @@ assert((RVVVectorBitsMax >= RVVVectorBitsMin || RVVVectorBitsMax == 0) && "Minimum V extension vector length should not be larger than its " "maximum!"); + if (RVVVectorBitsMin != 0 && RVVVectorBitsMin < ZvlLen) + report_fatal_error(Twine("riscv-v-vector-bits-min specified is lower than " + "the Zvl*b limitation")); unsigned Min = RVVVectorBitsMin; if (RVVVectorBitsMax != 0) Min = std::min(RVVVectorBitsMin, RVVVectorBitsMax); diff --git a/llvm/test/CodeGen/RISCV/attributes.ll b/llvm/test/CodeGen/RISCV/attributes.ll --- a/llvm/test/CodeGen/RISCV/attributes.ll +++ b/llvm/test/CodeGen/RISCV/attributes.ll @@ -42,7 +42,7 @@ ; RV32F: .attribute 5, "rv32i2p0_f2p0" ; RV32D: .attribute 5, "rv32i2p0_f2p0_d2p0" ; RV32C: .attribute 5, "rv32i2p0_c2p0" -; RV32V: .attribute 5, "rv32i2p0_v0p10_zvamo0p10_zvlsseg0p10" +; RV32V: .attribute 5, "rv32i2p0_v0p10_zvamo0p10_zvl128b0p10_zvl32b0p10_zvl64b0p10_zvlsseg0p10" ; RV32ZFH: .attribute 5, "rv32i2p0_f2p0_zfh0p1" ; RV32ZBA: .attribute 5, "rv32i2p0_zba1p0" ; RV32ZBB: .attribute 5, "rv32i2p0_zbb1p0" @@ -54,7 +54,7 @@ ; RV32ZBR: .attribute 5, "rv32i2p0_zbr0p93" ; RV32ZBS: .attribute 5, "rv32i2p0_zbs1p0" ; RV32ZBT: .attribute 5, "rv32i2p0_zbt0p93" -; RV32COMBINED: .attribute 5, "rv32i2p0_f2p0_v0p10_zfh0p1_zbb1p0_zvamo0p10_zvlsseg0p10" +; RV32COMBINED: .attribute 5, "rv32i2p0_f2p0_v0p10_zfh0p1_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_zvamo0p10_zvlsseg0p10" -; RV64COMBINED: .attribute 5, "rv64i2p0_f2p0_v0p10_zfh0p1_zbb1p0_zvamo0p10_zvlsseg0p10" +; RV64V: .attribute 5, "rv64i2p0_v0p10_zvamo0p10_zvl128b0p10_zvl32b0p10_zvl64b0p10_zvlsseg0p10" +; RV64COMBINED: .attribute 5, "rv64i2p0_f2p0_v0p10_zfh0p1_zbb1p0_zvamo0p10_zvl128b0p10_zvl32b0p10_zvl64b0p10_zvlsseg0p10" define i32 @addi(i32 %a) { diff --git a/llvm/test/MC/RISCV/attribute-arch.s b/llvm/test/MC/RISCV/attribute-arch.s --- a/llvm/test/MC/RISCV/attribute-arch.s +++ b/llvm/test/MC/RISCV/attribute-arch.s @@ -34,7 +34,7 @@ # CHECK: attribute 5, "rv32i2p0_m2p0_a2p0_f2p0_d2p0_c2p0" .attribute arch, "rv32iv" -# CHECK: attribute 5, "rv32i2p0_v0p10_zvlsseg0p10" +# CHECK: attribute 5, "rv32i2p0_v0p10_zvl128b0p10_zvl32b0p10_zvl64b0p10_zvlsseg0p10" .attribute arch, "rv32izba" # CHECK: attribute 5, "rv32i2p0_zba1p0" @@ -70,7 +70,43 @@ # CHECK: attribute 5, "rv32i2p0_f2p0_zfh0p1" .attribute arch, "rv32ivzvamo_zvlsseg" -# CHECK: attribute 5, "rv32i2p0_v0p10_zvamo0p10_zvlsseg0p10" +# CHECK: attribute 5, "rv32i2p0_v0p10_zvamo0p10_zvl128b0p10_zvl32b0p10_zvl64b0p10_zvlsseg0p10" .attribute arch, "rv32iv_zvamo0p10_zvlsseg" -# CHECK: attribute 5, "rv32i2p0_v0p10_zvamo0p10_zvlsseg0p10" +# CHECK: attribute 5, "rv32i2p0_v0p10_zvamo0p10_zvl128b0p10_zvl32b0p10_zvl64b0p10_zvlsseg0p10" + +.attribute arch, "rv32ifdv_zvl32b" +# CHECK: attribute 5, "rv32i2p0_f2p0_d2p0_v0p10_zvl128b0p10_zvl32b0p10_zvl64b0p10_zvlsseg0p10" + +.attribute arch, "rv32ifdv_zvl64b" +# CHECK: attribute 5, "rv32i2p0_f2p0_d2p0_v0p10_zvl128b0p10_zvl32b0p10_zvl64b0p10_zvlsseg0p10" + +.attribute arch, "rv32ifdv_zvl128b" +# CHECK: attribute 5, "rv32i2p0_f2p0_d2p0_v0p10_zvl128b0p10_zvl32b0p10_zvl64b0p10_zvlsseg0p10" + +.attribute arch, "rv32ifdv_zvl256b" +# CHECK: attribute 5, "rv32i2p0_f2p0_d2p0_v0p10_zvl128b0p10_zvl256b0p10_zvl32b0p10_zvl64b0p10_zvlsseg0p10" + +.attribute arch, "rv32ifdv_zvl512b" +# CHECK: attribute 5, "rv32i2p0_f2p0_d2p0_v0p10_zvl128b0p10_zvl256b0p10_zvl32b0p10_zvl512b0p10_zvl64b0p10_zvlsseg0p10" + +.attribute arch, "rv32ifdv_zvl1024b" +# CHECK: attribute 5, "rv32i2p0_f2p0_d2p0_v0p10_zvl1024b0p10_zvl128b0p10_zvl256b0p10_zvl32b0p10_zvl512b0p10_zvl64b0p10_zvlsseg0p10" + +.attribute arch, "rv32ifdv_zvl2048b" +# CHECK: attribute 5, "rv32i2p0_f2p0_d2p0_v0p10_zvl1024b0p10_zvl128b0p10_zvl2048b0p10_zvl256b0p10_zvl32b0p10_zvl512b0p10_zvl64b0p10_zvlsseg0p10" + +.attribute arch, "rv32ifdv_zvl4096b" +# CHECK: attribute 5, "rv32i2p0_f2p0_d2p0_v0p10_zvl1024b0p10_zvl128b0p10_zvl2048b0p10_zvl256b0p10_zvl32b0p10_zvl4096b0p10_zvl512b0p10_zvl64b0p10_zvlsseg0p10" + +.attribute arch, "rv32ifdv_zvl8192b" +# CHECK: attribute 5, "rv32i2p0_f2p0_d2p0_v0p10_zvl1024b0p10_zvl128b0p10_zvl2048b0p10_zvl256b0p10_zvl32b0p10_zvl4096b0p10_zvl512b0p10_zvl64b0p10_zvl8192b0p10_zvlsseg0p10" + +.attribute arch, "rv32ifdv_zvl16384b" +# CHECK: attribute 5, "rv32i2p0_f2p0_d2p0_v0p10_zvl1024b0p10_zvl128b0p10_zvl16384b0p10_zvl2048b0p10_zvl256b0p10_zvl32b0p10_zvl4096b0p10_zvl512b0p10_zvl64b0p10_zvl8192b0p10_zvlsseg0p10" + +.attribute arch, "rv32ifdv_zvl32768b" +# CHECK: attribute 5, "rv32i2p0_f2p0_d2p0_v0p10_zvl1024b0p10_zvl128b0p10_zvl16384b0p10_zvl2048b0p10_zvl256b0p10_zvl32768b0p10_zvl32b0p10_zvl4096b0p10_zvl512b0p10_zvl64b0p10_zvl8192b0p10_zvlsseg0p10" + +.attribute arch, "rv32ifdv_zvl65536b" +# CHECK: attribute 5, "rv32i2p0_f2p0_d2p0_v0p10_zvl1024b0p10_zvl128b0p10_zvl16384b0p10_zvl2048b0p10_zvl256b0p10_zvl32768b0p10_zvl32b0p10_zvl4096b0p10_zvl512b0p10_zvl64b0p10_zvl65536b0p10_zvl8192b0p10_zvlsseg0p10"