Skip to content

Commit 7ad5726

Browse files
committed
[RISCV] Relax march string order constraint
1 parent d5c9d40 commit 7ad5726

File tree

3 files changed

+226
-176
lines changed

3 files changed

+226
-176
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: 149 additions & 148 deletions
Original file line numberDiff line numberDiff line change
@@ -703,6 +703,106 @@ RISCVISAInfo::parseNormalizedArchString(StringRef Arch) {
703703
return std::move(ISAInfo);
704704
}
705705

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

724824
unsigned XLen = HasRV64 ? 64 : 32;
725825
std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen));
826+
SmallVector<std::string, 8> SeenExts;
827+
SmallVector<RISCVISAInfo::ExtensionVersion, 8> ExtsVersion;
726828

727829
// The canonical order specified in ISA manual.
728830
// Ref: Table 22.1 in RISC-V User-Level ISA V2.2
@@ -753,17 +855,6 @@ RISCVISAInfo::parseArchString(StringRef Arch, bool EnableExperimentalExtension,
753855
// Skip rvxxx
754856
StringRef Exts = Arch.substr(5);
755857

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-
767858
unsigned Major, Minor, ConsumeLength;
768859
if (Baseline == 'g') {
769860
// Versions for g are disallowed, and this was checked for previously.
@@ -773,9 +864,11 @@ RISCVISAInfo::parseArchString(StringRef Arch, bool EnableExperimentalExtension,
773864
// version since the we don't have clear version scheme for that on
774865
// ISA spec.
775866
for (const auto *Ext : RISCVGImplications) {
776-
if (auto Version = findDefaultVersion(Ext))
777-
ISAInfo->addExtension(Ext, *Version);
778-
else
867+
if (auto Version = findDefaultVersion(Ext)) {
868+
// Postpone AddExtension until end of this function
869+
SeenExts.push_back(Ext);
870+
ExtsVersion.push_back({Version->Major, Version->Minor});
871+
} else
779872
llvm_unreachable("Default extension version not found?");
780873
}
781874
} else {
@@ -793,153 +886,61 @@ RISCVISAInfo::parseArchString(StringRef Arch, bool EnableExperimentalExtension,
793886
Minor = Version->Minor;
794887
}
795888

796-
ISAInfo->addExtension(StringRef(&Baseline, 1), {Major, Minor});
889+
// Postpone AddExtension until end of this function
890+
SeenExts.push_back(StringRef(&Baseline, 1).str());
891+
ExtsVersion.push_back({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 '%c'",
826-
C);
827-
}
828-
829-
return createStringError(errc::invalid_argument,
830-
"invalid standard user-level extension '%c'", C);
831-
}
832-
833-
// Move to next char to prevent repeated letter.
834-
++StdExtsItr;
835-
836-
StringRef Next;
837-
unsigned Major, Minor, ConsumeLength;
838-
if (std::next(I) != E)
839-
Next = StringRef(std::next(I), E - std::next(I));
840-
if (auto E = getExtensionVersion(StringRef(&C, 1), Next, Major, Minor,
841-
ConsumeLength, EnableExperimentalExtension,
842-
ExperimentalExtensionVersionCheck)) {
843-
if (IgnoreUnknown) {
844-
consumeError(std::move(E));
845-
GoToNextExt(I, ConsumeLength, Exts.end());
846-
continue;
847-
}
848-
return std::move(E);
849-
}
850-
851-
// The order is OK, then push it into features.
852-
// Currently LLVM supports only "mafdcvh".
853-
if (!isSupportedExtension(StringRef(&C, 1))) {
854-
if (IgnoreUnknown) {
855-
GoToNextExt(I, ConsumeLength, Exts.end());
856-
continue;
857-
}
858-
return createStringError(errc::invalid_argument,
859-
"unsupported standard user-level extension '%c'",
860-
C);
861-
}
862-
ISAInfo->addExtension(StringRef(&C, 1), {Major, Minor});
863-
864-
// Consume full extension name and version, including any optional '_'
865-
// between this extension and the next
866-
GoToNextExt(I, ConsumeLength, Exts.end());
867-
}
868-
869-
// Handle other types of extensions other than the standard
870-
// general purpose and standard user-level extensions.
871-
// Parse the ISA string containing non-standard user-level
872-
// extensions, standard supervisor-level extensions and
873-
// non-standard supervisor-level extensions.
874-
// These extensions start with 'z', 's', 'x' prefixes, might have a version
875-
// number (major, minor) and are separated by a single underscore '_'. We do
876-
// not enforce a canonical order for them.
877-
// Set the hardware features for the extensions that are supported.
878-
879-
// Multi-letter extensions are seperated by a single underscore
880-
// as described in RISC-V User-Level ISA V2.2.
881-
SmallVector<StringRef, 8> Split;
882-
OtherExts.split(Split, '_');
883-
884-
SmallVector<StringRef, 8> AllExts;
885-
if (Split.size() > 1 || Split[0] != "") {
886-
for (StringRef Ext : Split) {
887-
if (Ext.empty())
888-
return createStringError(errc::invalid_argument,
889-
"extension name missing after separator '_'");
890-
891-
StringRef Type = getExtensionType(Ext);
892-
StringRef Desc = getExtensionTypeDesc(Ext);
893-
auto Pos = findLastNonVersionCharacter(Ext) + 1;
894-
StringRef Name(Ext.substr(0, Pos));
895-
StringRef Vers(Ext.substr(Pos));
896-
897-
if (Type.empty()) {
898-
if (IgnoreUnknown)
899-
continue;
900-
return createStringError(errc::invalid_argument,
901-
"invalid extension prefix '" + Ext + "'");
902-
}
903-
904-
if (!IgnoreUnknown && Name.size() == Type.size()) {
899+
std::vector<std::string> SplitedExts;
900+
if (auto E = splitExtsByUnderscore(Exts, SplitedExts))
901+
return std::move(E);
902+
903+
for (auto Ext : SplitedExts) {
904+
StringRef CurrExt = Ext;
905+
while (!CurrExt.empty()) {
906+
if (AllStdExts.contains(CurrExt.front())) {
907+
if (auto E = processSingleLetterExtension(
908+
CurrExt, SeenExts, ExtsVersion, IgnoreUnknown,
909+
EnableExperimentalExtension, ExperimentalExtensionVersionCheck))
910+
return E;
911+
} else if (CurrExt.front() == 'z' || CurrExt.front() == 's' ||
912+
CurrExt.front() == 'x') {
913+
if (auto E = processMultiLetterExtension(
914+
CurrExt, SeenExts, ExtsVersion, IgnoreUnknown,
915+
EnableExperimentalExtension, ExperimentalExtensionVersionCheck))
916+
return E;
917+
// Multi-letter extension must be seperate following extension with
918+
// underscore
919+
break;
920+
} else {
921+
// FIXME: Could it be ignored by IgnoreUnknown?
905922
return createStringError(errc::invalid_argument,
906-
"%s name missing after '%s'",
907-
Desc.str().c_str(), Type.str().c_str());
908-
}
909-
910-
unsigned Major, Minor, ConsumeLength;
911-
if (auto E = getExtensionVersion(Name, Vers, Major, Minor, ConsumeLength,
912-
EnableExperimentalExtension,
913-
ExperimentalExtensionVersionCheck)) {
914-
if (IgnoreUnknown) {
915-
consumeError(std::move(E));
916-
continue;
917-
}
918-
return std::move(E);
919-
}
920-
921-
// Check if duplicated extension.
922-
if (!IgnoreUnknown && llvm::is_contained(AllExts, Name)) {
923-
return createStringError(errc::invalid_argument, "duplicated %s '%s'",
924-
Desc.str().c_str(), Name.str().c_str());
923+
"invalid standard user-level extension '%c'",
924+
CurrExt.front());
925925
}
926-
927-
if (IgnoreUnknown && !isSupportedExtension(Name))
928-
continue;
929-
930-
ISAInfo->addExtension(Name, {Major, Minor});
931-
// Extension format is correct, keep parsing the extensions.
932-
// TODO: Save Type, Name, Major, Minor to avoid parsing them later.
933-
AllExts.push_back(Name);
934926
}
935927
}
936928

937-
for (auto Ext : AllExts) {
938-
if (!isSupportedExtension(Ext)) {
939-
StringRef Desc = getExtensionTypeDesc(getExtensionType(Ext));
940-
return createStringError(errc::invalid_argument, "unsupported %s '%s'",
941-
Desc.str().c_str(), Ext.str().c_str());
929+
// Check all Extensions are supported.
930+
for (size_t Idx = 0; Idx < SeenExts.size(); Idx++) {
931+
if (!RISCVISAInfo::isSupportedExtension(SeenExts[Idx])) {
932+
if (SeenExts[Idx].size() == 1) {
933+
return createStringError(
934+
errc::invalid_argument,
935+
"unsupported standard user-level extension '%s'",
936+
SeenExts[Idx].c_str());
937+
}
938+
return createStringError(
939+
errc::invalid_argument, "unsupported %s '%s'",
940+
getExtensionTypeDesc(SeenExts[Idx]).str().c_str(),
941+
SeenExts[Idx].c_str());
942942
}
943+
ISAInfo->addExtension(SeenExts[Idx], ExtsVersion[Idx]);
943944
}
944945

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

0 commit comments

Comments
 (0)