Skip to content

Commit d09082f

Browse files
authored
[RISCV] Relax march string order constraint (#78120)
Follow riscv-non-isa/riscv-toolchain-conventions#14 by dropping the order requirement of `-march`. 1. single-letter extension can be arbitrary order - march=rv32iamdf 2. single-letter extension and multi-letter extension can be mixed - march=rv32i_zihintntl_m_a_f_d_svinval 3. multi-letter extension need seperate the following extension by underscore, otherwise it will be intreprete as one extension. - march=rv32i_zbam -> i,zbam - march=rv32i_zba_m -> i,zba,m
1 parent 5910e34 commit d09082f

File tree

3 files changed

+246
-173
lines changed

3 files changed

+246
-173
lines changed

clang/test/Driver/riscv-arch.c

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -156,9 +156,8 @@
156156
// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32L %s
157157
// RV32L: error: invalid arch name 'rv32l'
158158

159-
// RUN: not %clang --target=riscv32-unknown-elf -march=rv32imadf -### %s \
160-
// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32IMADF %s
161-
// RV32IMADF: error: invalid arch name 'rv32imadf'
159+
// RUN: %clang --target=riscv32-unknown-elf -march=rv32imadf -### %s \
160+
// RUN: -fsyntax-only 2>&1 | FileCheck %s
162161

163162
// RUN: not %clang --target=riscv32-unknown-elf -march=rv32imm -### %s \
164163
// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32IMM %s
@@ -184,9 +183,8 @@
184183
// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV64L %s
185184
// RV64L: error: invalid arch name 'rv64l'
186185

187-
// RUN: not %clang --target=riscv64-unknown-elf -march=rv64imadf -### %s \
188-
// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV64IMADF %s
189-
// RV64IMADF: error: invalid arch name 'rv64imadf'
186+
// RUN: %clang --target=riscv64-unknown-elf -march=rv64imadf -### %s \
187+
// RUN: -fsyntax-only 2>&1 | FileCheck %s
190188

191189
// RUN: not %clang --target=riscv64-unknown-elf -march=rv64imm -### %s \
192190
// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV64IMM %s
@@ -216,7 +214,7 @@
216214
// RUN: not %clang --target=riscv32-unknown-elf -march=rv32imcq -### %s \
217215
// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32-ORDER %s
218216
// RV32-ORDER: error: invalid arch name 'rv32imcq',
219-
// RV32-ORDER: standard user-level extension not given in canonical order 'q'
217+
// RV32-ORDER: unsupported standard user-level extension 'q'
220218

221219
// RUN: not %clang --target=riscv32-unknown-elf -march=rv32izvl64b -### %s \
222220
// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32-ZVL64B-ER %s
@@ -318,7 +316,7 @@
318316
// RUN: not %clang --target=riscv32-unknown-elf -march=rv32ixabc_a -### %s \
319317
// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32-PREFIX %s
320318
// RV32-PREFIX: error: invalid arch name 'rv32ixabc_a',
321-
// RV32-PREFIX: invalid extension prefix 'a'
319+
// RV32-PREFIX: unsupported non-standard user-level extension 'xabc'
322320

323321
// RUN: not %clang --target=riscv32-unknown-elf -march=rv32ixdef_sabc -### %s \
324322
// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32-X-ORDER %s

llvm/lib/Support/RISCVISAInfo.cpp

Lines changed: 157 additions & 145 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "llvm/Support/RISCVISAInfo.h"
10+
#include "llvm/ADT/MapVector.h"
1011
#include "llvm/ADT/STLExtras.h"
1112
#include "llvm/ADT/SetVector.h"
1213
#include "llvm/ADT/StringExtras.h"
@@ -703,6 +704,106 @@ RISCVISAInfo::parseNormalizedArchString(StringRef Arch) {
703704
return std::move(ISAInfo);
704705
}
705706

707+
static Error splitExtsByUnderscore(StringRef Exts,
708+
std::vector<std::string> &SplitExts) {
709+
SmallVector<StringRef, 8> Split;
710+
if (Exts.empty())
711+
return Error::success();
712+
713+
Exts.split(Split, "_");
714+
715+
for (auto Ext : Split) {
716+
if (Ext.empty())
717+
return createStringError(errc::invalid_argument,
718+
"extension name missing after separator '_'");
719+
720+
SplitExts.push_back(Ext.str());
721+
}
722+
return Error::success();
723+
}
724+
725+
static Error processMultiLetterExtension(
726+
StringRef RawExt,
727+
MapVector<std::string, RISCVISAInfo::ExtensionVersion,
728+
std::map<std::string, unsigned>> &SeenExtMap,
729+
bool IgnoreUnknown, bool EnableExperimentalExtension,
730+
bool ExperimentalExtensionVersionCheck) {
731+
StringRef Type = getExtensionType(RawExt);
732+
StringRef Desc = getExtensionTypeDesc(RawExt);
733+
auto Pos = findLastNonVersionCharacter(RawExt) + 1;
734+
StringRef Name(RawExt.substr(0, Pos));
735+
StringRef Vers(RawExt.substr(Pos));
736+
737+
if (Type.empty()) {
738+
if (IgnoreUnknown)
739+
return Error::success();
740+
return createStringError(errc::invalid_argument,
741+
"invalid extension prefix '" + RawExt + "'");
742+
}
743+
744+
if (!IgnoreUnknown && Name.size() == Type.size())
745+
return createStringError(errc::invalid_argument,
746+
"%s name missing after '%s'", Desc.str().c_str(),
747+
Type.str().c_str());
748+
749+
unsigned Major, Minor, ConsumeLength;
750+
if (auto E = getExtensionVersion(Name, Vers, Major, Minor, ConsumeLength,
751+
EnableExperimentalExtension,
752+
ExperimentalExtensionVersionCheck)) {
753+
if (IgnoreUnknown) {
754+
consumeError(std::move(E));
755+
return Error::success();
756+
}
757+
return E;
758+
}
759+
760+
// Check if duplicated extension.
761+
if (!IgnoreUnknown && SeenExtMap.contains(Name.str()))
762+
return createStringError(errc::invalid_argument, "duplicated %s '%s'",
763+
Desc.str().c_str(), Name.str().c_str());
764+
765+
if (IgnoreUnknown && !RISCVISAInfo::isSupportedExtension(Name))
766+
return Error::success();
767+
768+
SeenExtMap[Name.str()] = {Major, Minor};
769+
return Error::success();
770+
}
771+
772+
static Error processSingleLetterExtension(
773+
StringRef &RawExt,
774+
MapVector<std::string, RISCVISAInfo::ExtensionVersion,
775+
std::map<std::string, unsigned>> &SeenExtMap,
776+
bool IgnoreUnknown, bool EnableExperimentalExtension,
777+
bool ExperimentalExtensionVersionCheck) {
778+
unsigned Major, Minor, ConsumeLength;
779+
StringRef Name = RawExt.take_front(1);
780+
RawExt.consume_front(Name);
781+
if (auto E = getExtensionVersion(Name, RawExt, Major, Minor, ConsumeLength,
782+
EnableExperimentalExtension,
783+
ExperimentalExtensionVersionCheck)) {
784+
if (IgnoreUnknown) {
785+
consumeError(std::move(E));
786+
RawExt = RawExt.substr(ConsumeLength);
787+
return Error::success();
788+
}
789+
return E;
790+
}
791+
792+
RawExt = RawExt.substr(ConsumeLength);
793+
794+
// Check if duplicated extension.
795+
if (!IgnoreUnknown && SeenExtMap.contains(Name.str()))
796+
return createStringError(errc::invalid_argument,
797+
"duplicated standard user-level extension '%s'",
798+
Name.str().c_str());
799+
800+
if (IgnoreUnknown && !RISCVISAInfo::isSupportedExtension(Name))
801+
return Error::success();
802+
803+
SeenExtMap[Name.str()] = {Major, Minor};
804+
return Error::success();
805+
}
806+
706807
llvm::Expected<std::unique_ptr<RISCVISAInfo>>
707808
RISCVISAInfo::parseArchString(StringRef Arch, bool EnableExperimentalExtension,
708809
bool ExperimentalExtensionVersionCheck,
@@ -723,6 +824,9 @@ RISCVISAInfo::parseArchString(StringRef Arch, bool EnableExperimentalExtension,
723824

724825
unsigned XLen = HasRV64 ? 64 : 32;
725826
std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen));
827+
MapVector<std::string, RISCVISAInfo::ExtensionVersion,
828+
std::map<std::string, unsigned>>
829+
SeenExtMap;
726830

727831
// The canonical order specified in ISA manual.
728832
// Ref: Table 22.1 in RISC-V User-Level ISA V2.2
@@ -753,17 +857,6 @@ RISCVISAInfo::parseArchString(StringRef Arch, bool EnableExperimentalExtension,
753857
// Skip rvxxx
754858
StringRef Exts = Arch.substr(5);
755859

756-
// Remove multi-letter standard extensions, non-standard extensions and
757-
// supervisor-level extensions. They have 'z', 'x', 's' prefixes.
758-
// Parse them at the end.
759-
// Find the very first occurrence of 's', 'x' or 'z'.
760-
StringRef OtherExts;
761-
size_t Pos = Exts.find_first_of("zsx");
762-
if (Pos != StringRef::npos) {
763-
OtherExts = Exts.substr(Pos);
764-
Exts = Exts.substr(0, Pos);
765-
}
766-
767860
unsigned Major, Minor, ConsumeLength;
768861
if (Baseline == 'g') {
769862
// Versions for g are disallowed, and this was checked for previously.
@@ -773,9 +866,10 @@ RISCVISAInfo::parseArchString(StringRef Arch, bool EnableExperimentalExtension,
773866
// version since the we don't have clear version scheme for that on
774867
// ISA spec.
775868
for (const auto *Ext : RISCVGImplications) {
776-
if (auto Version = findDefaultVersion(Ext))
777-
ISAInfo->addExtension(Ext, *Version);
778-
else
869+
if (auto Version = findDefaultVersion(Ext)) {
870+
// Postpone AddExtension until end of this function
871+
SeenExtMap[Ext] = {Version->Major, Version->Minor};
872+
} else
779873
llvm_unreachable("Default extension version not found?");
780874
}
781875
} else {
@@ -793,151 +887,69 @@ RISCVISAInfo::parseArchString(StringRef Arch, bool EnableExperimentalExtension,
793887
Minor = Version->Minor;
794888
}
795889

796-
ISAInfo->addExtension(StringRef(&Baseline, 1), {Major, Minor});
890+
// Postpone AddExtension until end of this function
891+
SeenExtMap[StringRef(&Baseline, 1).str()] = {Major, Minor};
797892
}
798893

799894
// Consume the base ISA version number and any '_' between rvxxx and the
800895
// first extension
801896
Exts = Exts.drop_front(ConsumeLength);
802897
Exts.consume_front("_");
803898

804-
auto StdExtsItr = StdExts.begin();
805-
auto StdExtsEnd = StdExts.end();
806-
auto GoToNextExt = [](StringRef::iterator &I, unsigned ConsumeLength,
807-
StringRef::iterator E) {
808-
I += 1 + ConsumeLength;
809-
if (I != E && *I == '_')
810-
++I;
811-
};
812-
for (auto I = Exts.begin(), E = Exts.end(); I != E;) {
813-
char C = *I;
814-
815-
// Check ISA extensions are specified in the canonical order.
816-
while (StdExtsItr != StdExtsEnd && *StdExtsItr != C)
817-
++StdExtsItr;
818-
819-
if (StdExtsItr == StdExtsEnd) {
820-
// Either c contains a valid extension but it was not given in
821-
// canonical order or it is an invalid extension.
822-
if (StdExts.contains(C)) {
823-
return createStringError(
824-
errc::invalid_argument,
825-
"standard user-level extension not given in canonical order '" +
826-
Twine(C) + "'");
827-
}
828-
829-
return createStringError(errc::invalid_argument,
830-
"invalid standard user-level extension '" +
831-
Twine(C) + "'");
832-
}
833-
834-
// Move to next char to prevent repeated letter.
835-
++StdExtsItr;
836-
837-
StringRef Next;
838-
unsigned Major, Minor, ConsumeLength;
839-
if (std::next(I) != E)
840-
Next = StringRef(std::next(I), E - std::next(I));
841-
if (auto E = getExtensionVersion(StringRef(&C, 1), Next, Major, Minor,
842-
ConsumeLength, EnableExperimentalExtension,
843-
ExperimentalExtensionVersionCheck)) {
844-
if (IgnoreUnknown) {
845-
consumeError(std::move(E));
846-
GoToNextExt(I, ConsumeLength, Exts.end());
847-
continue;
848-
}
849-
return std::move(E);
850-
}
851-
852-
// The order is OK, then push it into features.
853-
// Currently LLVM supports only "mafdcvh".
854-
if (!isSupportedExtension(StringRef(&C, 1))) {
855-
if (IgnoreUnknown) {
856-
GoToNextExt(I, ConsumeLength, Exts.end());
857-
continue;
899+
std::vector<std::string> SplittedExts;
900+
if (auto E = splitExtsByUnderscore(Exts, SplittedExts))
901+
return std::move(E);
902+
903+
for (auto &Ext : SplittedExts) {
904+
StringRef CurrExt = Ext;
905+
while (!CurrExt.empty()) {
906+
if (AllStdExts.contains(CurrExt.front())) {
907+
if (auto E = processSingleLetterExtension(
908+
CurrExt, SeenExtMap, IgnoreUnknown, EnableExperimentalExtension,
909+
ExperimentalExtensionVersionCheck))
910+
return E;
911+
} else if (CurrExt.front() == 'z' || CurrExt.front() == 's' ||
912+
CurrExt.front() == 'x') {
913+
// Handle other types of extensions other than the standard
914+
// general purpose and standard user-level extensions.
915+
// Parse the ISA string containing non-standard user-level
916+
// extensions, standard supervisor-level extensions and
917+
// non-standard supervisor-level extensions.
918+
// These extensions start with 'z', 's', 'x' prefixes, might have a
919+
// version number (major, minor) and are separated by a single
920+
// underscore '_'. We do not enforce a canonical order for them.
921+
if (auto E = processMultiLetterExtension(
922+
CurrExt, SeenExtMap, IgnoreUnknown, EnableExperimentalExtension,
923+
ExperimentalExtensionVersionCheck))
924+
return E;
925+
// Multi-letter extension must be seperate following extension with
926+
// underscore
927+
break;
928+
} else {
929+
// FIXME: Could it be ignored by IgnoreUnknown?
930+
return createStringError(errc::invalid_argument,
931+
"invalid standard user-level extension '%c'",
932+
CurrExt.front());
858933
}
859-
return createStringError(errc::invalid_argument,
860-
"unsupported standard user-level extension '" +
861-
Twine(C) + "'");
862934
}
863-
ISAInfo->addExtension(StringRef(&C, 1), {Major, Minor});
864-
865-
// Consume full extension name and version, including any optional '_'
866-
// between this extension and the next
867-
GoToNextExt(I, ConsumeLength, Exts.end());
868935
}
869936

870-
// Handle other types of extensions other than the standard
871-
// general purpose and standard user-level extensions.
872-
// Parse the ISA string containing non-standard user-level
873-
// extensions, standard supervisor-level extensions and
874-
// non-standard supervisor-level extensions.
875-
// These extensions start with 'z', 's', 'x' prefixes, might have a version
876-
// number (major, minor) and are separated by a single underscore '_'. We do
877-
// not enforce a canonical order for them.
878-
// Set the hardware features for the extensions that are supported.
879-
880-
// Multi-letter extensions are seperated by a single underscore
881-
// as described in RISC-V User-Level ISA V2.2.
882-
SmallVector<StringRef, 8> Split;
883-
OtherExts.split(Split, '_');
884-
885-
SmallVector<StringRef, 8> AllExts;
886-
if (Split.size() > 1 || Split[0] != "") {
887-
for (StringRef Ext : Split) {
888-
if (Ext.empty())
889-
return createStringError(errc::invalid_argument,
890-
"extension name missing after separator '_'");
891-
892-
StringRef Type = getExtensionType(Ext);
893-
StringRef Desc = getExtensionTypeDesc(Ext);
894-
auto Pos = findLastNonVersionCharacter(Ext) + 1;
895-
StringRef Name(Ext.substr(0, Pos));
896-
StringRef Vers(Ext.substr(Pos));
897-
898-
if (Type.empty()) {
899-
if (IgnoreUnknown)
900-
continue;
901-
return createStringError(errc::invalid_argument,
902-
"invalid extension prefix '" + Ext + "'");
903-
}
937+
// Check all Extensions are supported.
938+
for (auto &SeenExtAndVers : SeenExtMap) {
939+
const std::string &ExtName = SeenExtAndVers.first;
940+
RISCVISAInfo::ExtensionVersion ExtVers = SeenExtAndVers.second;
904941

905-
if (!IgnoreUnknown && Name.size() == Type.size())
906-
return createStringError(errc::invalid_argument,
907-
Desc + " name missing after '" + Type + "'");
908-
909-
unsigned Major, Minor, ConsumeLength;
910-
if (auto E = getExtensionVersion(Name, Vers, Major, Minor, ConsumeLength,
911-
EnableExperimentalExtension,
912-
ExperimentalExtensionVersionCheck)) {
913-
if (IgnoreUnknown) {
914-
consumeError(std::move(E));
915-
continue;
916-
}
917-
return std::move(E);
942+
if (!RISCVISAInfo::isSupportedExtension(ExtName)) {
943+
if (ExtName.size() == 1) {
944+
return createStringError(
945+
errc::invalid_argument,
946+
"unsupported standard user-level extension '%s'", ExtName.c_str());
918947
}
919-
920-
// Check if duplicated extension.
921-
if (!IgnoreUnknown && llvm::is_contained(AllExts, Name))
922-
return createStringError(errc::invalid_argument,
923-
"duplicated " + Desc + " '" + Name + "'");
924-
925-
if (IgnoreUnknown && !isSupportedExtension(Name))
926-
continue;
927-
928-
ISAInfo->addExtension(Name, {Major, Minor});
929-
// Extension format is correct, keep parsing the extensions.
930-
// TODO: Save Type, Name, Major, Minor to avoid parsing them later.
931-
AllExts.push_back(Name);
932-
}
933-
}
934-
935-
for (auto Ext : AllExts) {
936-
if (!isSupportedExtension(Ext)) {
937-
StringRef Desc = getExtensionTypeDesc(getExtensionType(Ext));
938-
return createStringError(errc::invalid_argument,
939-
"unsupported " + Desc + " '" + Ext + "'");
948+
return createStringError(errc::invalid_argument, "unsupported %s '%s'",
949+
getExtensionTypeDesc(ExtName).str().c_str(),
950+
ExtName.c_str());
940951
}
952+
ISAInfo->addExtension(ExtName, ExtVers);
941953
}
942954

943955
return RISCVISAInfo::postProcessAndChecking(std::move(ISAInfo));

0 commit comments

Comments
 (0)