Skip to content

Commit aaee7cf

Browse files
committed
[RISCV] Relax march string order constraint
1 parent 1b37e80 commit aaee7cf

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
@@ -707,6 +707,106 @@ RISCVISAInfo::parseNormalizedArchString(StringRef Arch) {
707707
return std::move(ISAInfo);
708708
}
709709

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

728828
unsigned XLen = HasRV64 ? 64 : 32;
729829
std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen));
830+
SmallVector<std::string, 8> SeenExts;
831+
SmallVector<RISCVISAInfo::ExtensionVersion, 8> ExtsVersion;
730832

731833
// The canonical order specified in ISA manual.
732834
// Ref: Table 22.1 in RISC-V User-Level ISA V2.2
@@ -757,17 +859,6 @@ RISCVISAInfo::parseArchString(StringRef Arch, bool EnableExperimentalExtension,
757859
// Skip rvxxx
758860
StringRef Exts = Arch.substr(5);
759861

760-
// Remove multi-letter standard extensions, non-standard extensions and
761-
// supervisor-level extensions. They have 'z', 'x', 's' prefixes.
762-
// Parse them at the end.
763-
// Find the very first occurrence of 's', 'x' or 'z'.
764-
StringRef OtherExts;
765-
size_t Pos = Exts.find_first_of("zsx");
766-
if (Pos != StringRef::npos) {
767-
OtherExts = Exts.substr(Pos);
768-
Exts = Exts.substr(0, Pos);
769-
}
770-
771862
unsigned Major, Minor, ConsumeLength;
772863
if (Baseline == 'g') {
773864
// Versions for g are disallowed, and this was checked for previously.
@@ -777,9 +868,11 @@ RISCVISAInfo::parseArchString(StringRef Arch, bool EnableExperimentalExtension,
777868
// version since the we don't have clear version scheme for that on
778869
// ISA spec.
779870
for (const auto *Ext : RISCVGImplications) {
780-
if (auto Version = findDefaultVersion(Ext))
781-
ISAInfo->addExtension(Ext, *Version);
782-
else
871+
if (auto Version = findDefaultVersion(Ext)) {
872+
// Postpone AddExtension until end of this function
873+
SeenExts.push_back(Ext);
874+
ExtsVersion.push_back({Version->Major, Version->Minor});
875+
} else
783876
llvm_unreachable("Default extension version not found?");
784877
}
785878
} else {
@@ -797,153 +890,61 @@ RISCVISAInfo::parseArchString(StringRef Arch, bool EnableExperimentalExtension,
797890
Minor = Version->Minor;
798891
}
799892

800-
ISAInfo->addExtension(StringRef(&Baseline, 1), {Major, Minor});
893+
// Postpone AddExtension until end of this function
894+
SeenExts.push_back(StringRef(&Baseline, 1).str());
895+
ExtsVersion.push_back({Major, Minor});
801896
}
802897

803898
// Consume the base ISA version number and any '_' between rvxxx and the
804899
// first extension
805900
Exts = Exts.drop_front(ConsumeLength);
806901
Exts.consume_front("_");
807902

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

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

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

0 commit comments

Comments
 (0)