aboutsummaryrefslogtreecommitdiff
path: root/backend/lib/Tooling
diff options
context:
space:
mode:
authorRichard-Qin-X <richard.qin.001@gmail.com>2026-08-12 19:45:09 +0800
committerRichard-Qin-X <richard.qin.001@gmail.com>2026-08-12 19:45:09 +0800
commit09e8ef3e0dae29be7aa21a6e22a118a3f545945f (patch)
treecfc5a7148aca9e768df16743c2c637e8c00a9d44 /backend/lib/Tooling
parent1775d50ba02dab033c639f5c8fedd46cb6613bef (diff)
downloadrcc-project-09e8ef3e0dae29be7aa21a6e22a118a3f545945f.tar.gz
rcc-project-09e8ef3e0dae29be7aa21a6e22a118a3f545945f.tar.xz
[Tooling] Complete the LLVM MIR command-line contract
Diffstat (limited to 'backend/lib/Tooling')
-rw-r--r--backend/lib/Tooling/BackendDriver.cpp44
-rw-r--r--backend/lib/Tooling/BackendInvocation.cpp74
-rw-r--r--backend/lib/Tooling/MIRFuzzer.cpp18
-rw-r--r--backend/lib/Tooling/PipelineDriver.cpp105
4 files changed, 117 insertions, 124 deletions
diff --git a/backend/lib/Tooling/BackendDriver.cpp b/backend/lib/Tooling/BackendDriver.cpp
index fff58c5..c726fd3 100644
--- a/backend/lib/Tooling/BackendDriver.cpp
+++ b/backend/lib/Tooling/BackendDriver.cpp
@@ -164,30 +164,28 @@ std::string_view spelling(BackendOutputKind Output) noexcept {
return "invalid";
}
-Expected<BackendOutputKind> parseBackendOutputKind(std::string_view Value) {
- if (Value == "prelegalizer-mir")
- return BackendOutputKind::PreLegalizerMIR;
- if (Value == "legalized-mir")
- return BackendOutputKind::LegalizedMIR;
- if (Value == "regbank-mir")
- return BackendOutputKind::RegisterBankMIR;
- if (Value == "selected-mir")
- return BackendOutputKind::SelectedMIR;
- if (Value == "post-ssa-mir")
- return BackendOutputKind::PostSSAMIR;
- if (Value == "post-ra-mir")
- return BackendOutputKind::PostRegisterAllocationMIR;
- if (Value == "final-mir")
- return BackendOutputKind::FinalMIR;
- if (Value == "assembly" || Value == "asm")
- return BackendOutputKind::Assembly;
- if (Value == "object" || Value == "obj")
- return BackendOutputKind::RelocatableObject;
- return makeUnexpected(ErrorCode::InvalidInvocation, "unknown backend output kind");
-}
-
ArtifactKind manifestArtifactKind(BackendOutputKind Output) noexcept {
- return static_cast<ArtifactKind>(static_cast<std::uint8_t>(Output));
+ switch (Output) {
+ case BackendOutputKind::PreLegalizerMIR:
+ return ArtifactKind::PreLegalizerMIR;
+ case BackendOutputKind::LegalizedMIR:
+ return ArtifactKind::LegalizedMIR;
+ case BackendOutputKind::RegisterBankMIR:
+ return ArtifactKind::RegisterBankMIR;
+ case BackendOutputKind::SelectedMIR:
+ return ArtifactKind::SelectedMIR;
+ case BackendOutputKind::PostSSAMIR:
+ return ArtifactKind::PostSSAMIR;
+ case BackendOutputKind::PostRegisterAllocationMIR:
+ return ArtifactKind::PostRegisterAllocationMIR;
+ case BackendOutputKind::FinalMIR:
+ return ArtifactKind::FinalMIR;
+ case BackendOutputKind::Assembly:
+ return ArtifactKind::Assembly;
+ case BackendOutputKind::RelocatableObject:
+ return ArtifactKind::RelocatableObject;
+ }
+ return ArtifactKind::FinalMIR;
}
Expected<ArtifactKind> cacheArtifactKind(BackendOutputKind Output) {
diff --git a/backend/lib/Tooling/BackendInvocation.cpp b/backend/lib/Tooling/BackendInvocation.cpp
index 677cd2d..232d34f 100644
--- a/backend/lib/Tooling/BackendInvocation.cpp
+++ b/backend/lib/Tooling/BackendInvocation.cpp
@@ -265,46 +265,6 @@ void appendMIRTextInfo(std::string &Output, const TargetMIRTextInfo &MIRText) {
} // namespace
-std::string_view spelling(RelocationModel Value) noexcept {
- switch (Value) {
- case RelocationModel::Static:
- return "static";
- case RelocationModel::PositionIndependent:
- return "pic";
- }
- return "invalid";
-}
-
-std::string_view spelling(CodeModel Value) noexcept {
- switch (Value) {
- case CodeModel::Small:
- return "small";
- case CodeModel::Medium:
- return "medium";
- case CodeModel::Large:
- return "large";
- }
- return "invalid";
-}
-
-std::string_view spelling(OptimizationLevel Value) noexcept {
- switch (Value) {
- case OptimizationLevel::O0:
- return "O0";
- case OptimizationLevel::O1:
- return "O1";
- case OptimizationLevel::O2:
- return "O2";
- case OptimizationLevel::O3:
- return "O3";
- case OptimizationLevel::Os:
- return "Os";
- case OptimizationLevel::Oz:
- return "Oz";
- }
- return "invalid";
-}
-
std::string_view spelling(LayoutOwnership Value) noexcept {
switch (Value) {
case LayoutOwnership::NativeObject:
@@ -317,40 +277,6 @@ std::string_view spelling(LayoutOwnership Value) noexcept {
return "invalid";
}
-Expected<RelocationModel> parseRelocationModel(std::string_view Value) {
- if (Value == "static")
- return RelocationModel::Static;
- if (Value == "pic")
- return RelocationModel::PositionIndependent;
- return makeUnexpected(ErrorCode::ManifestError, "unknown relocation model");
-}
-
-Expected<CodeModel> parseCodeModel(std::string_view Value) {
- if (Value == "small")
- return CodeModel::Small;
- if (Value == "medium")
- return CodeModel::Medium;
- if (Value == "large")
- return CodeModel::Large;
- return makeUnexpected(ErrorCode::ManifestError, "unknown code model");
-}
-
-Expected<OptimizationLevel> parseOptimizationLevel(std::string_view Value) {
- if (Value == "O0")
- return OptimizationLevel::O0;
- if (Value == "O1")
- return OptimizationLevel::O1;
- if (Value == "O2")
- return OptimizationLevel::O2;
- if (Value == "O3")
- return OptimizationLevel::O3;
- if (Value == "Os")
- return OptimizationLevel::Os;
- if (Value == "Oz")
- return OptimizationLevel::Oz;
- return makeUnexpected(ErrorCode::ManifestError, "unknown optimization level");
-}
-
Expected<LayoutOwnership> parseLayoutOwnership(std::string_view Value) {
if (Value == "native-object")
return LayoutOwnership::NativeObject;
diff --git a/backend/lib/Tooling/MIRFuzzer.cpp b/backend/lib/Tooling/MIRFuzzer.cpp
index ed5b2fa..653b9fd 100644
--- a/backend/lib/Tooling/MIRFuzzer.cpp
+++ b/backend/lib/Tooling/MIRFuzzer.cpp
@@ -225,7 +225,23 @@ private:
}
[[nodiscard]] BackendOutputKind outputForStage(BackendStage Stage) noexcept {
- return static_cast<BackendOutputKind>(static_cast<std::uint8_t>(Stage));
+ switch (Stage) {
+ case BackendStage::PreLegalizerMIR:
+ return BackendOutputKind::PreLegalizerMIR;
+ case BackendStage::LegalizedMIR:
+ return BackendOutputKind::LegalizedMIR;
+ case BackendStage::RegisterBankMIR:
+ return BackendOutputKind::RegisterBankMIR;
+ case BackendStage::SelectedMIR:
+ return BackendOutputKind::SelectedMIR;
+ case BackendStage::PostSSAMIR:
+ return BackendOutputKind::PostSSAMIR;
+ case BackendStage::PostRegisterAllocationMIR:
+ return BackendOutputKind::PostRegisterAllocationMIR;
+ case BackendStage::FinalMIR:
+ return BackendOutputKind::FinalMIR;
+ }
+ return BackendOutputKind::FinalMIR;
}
[[nodiscard]] Expected<bool> propertyCase(std::string_view Canonical, DeterministicRandom &Random,
diff --git a/backend/lib/Tooling/PipelineDriver.cpp b/backend/lib/Tooling/PipelineDriver.cpp
index 620367f..3d137d8 100644
--- a/backend/lib/Tooling/PipelineDriver.cpp
+++ b/backend/lib/Tooling/PipelineDriver.cpp
@@ -11,6 +11,7 @@
#include <algorithm>
#include <atomic>
+#include <charconv>
#include <cstddef>
#include <cstdint>
#include <memory>
@@ -38,19 +39,27 @@ struct FunctionRunResult final {
}
[[nodiscard]] bool selectorMatches(std::string_view Selector, std::string_view Pass,
- std::uint32_t Occurrence) {
- if (Selector == "all" || Selector == Pass)
+ std::uint32_t Occurrence, bool MatchAllOccurrences) {
+ if (Selector == "all")
return true;
- std::string Qualified(Pass);
- Qualified.push_back('#');
- Qualified.append(std::to_string(Occurrence));
- return Selector == Qualified;
+ const std::size_t Comma = Selector.find(',');
+ const std::string_view Name =
+ Comma == std::string_view::npos ? Selector : Selector.substr(0, Comma);
+ if (Name != Pass)
+ return false;
+ if (Comma == std::string_view::npos)
+ return MatchAllOccurrences || Occurrence == 1U;
+ std::uint32_t Instance = 0;
+ const std::string_view Text = Selector.substr(Comma + 1U);
+ const auto Parsed = std::from_chars(Text.data(), Text.data() + Text.size(), Instance);
+ return Parsed.ec == std::errc{} && Parsed.ptr == Text.data() + Text.size() &&
+ Occurrence == Instance + 1U;
}
[[nodiscard]] bool anySelectorMatches(std::span<const std::string> Selectors, std::string_view Pass,
std::uint32_t Occurrence) {
return std::ranges::any_of(Selectors, [Pass, Occurrence](const std::string &Selector) {
- return selectorMatches(Selector, Pass, Occurrence);
+ return selectorMatches(Selector, Pass, Occurrence, true);
});
}
@@ -61,7 +70,7 @@ struct FunctionRunResult final {
return BackendStage::RegisterBankMIR;
if (Pass == "instruction-select")
return BackendStage::SelectedMIR;
- if (Pass == "TwoAddressRewrite")
+ if (Pass == "twoaddressinstruction")
return BackendStage::PostSSAMIR;
if (Pass == "PBQPAllocator")
return BackendStage::PostRegisterAllocationMIR;
@@ -84,8 +93,6 @@ createPasses(const MachineFunction &Function, const BackendInvocation &Invocatio
"the default pipeline marker cannot be mixed with named passes");
}
for (const std::string &Name : Invocation.PassPipeline) {
- if (Name == "none")
- continue;
auto Pass = riscv::createCanonicalPipelinePass(Name, Features);
if (!Pass)
return std::unexpected(Pass.error());
@@ -97,47 +104,67 @@ createPasses(const MachineFunction &Function, const BackendInvocation &Invocatio
return std::move(Pipeline).takePasses();
}
-[[nodiscard]] Expected<void> validateSelector(std::string_view Selector) {
- if (Selector == "all")
+[[nodiscard]] Expected<void> validateSelector(std::string_view Selector, bool AllowAll) {
+ if (Selector == "all" && AllowAll)
return {};
- const std::size_t Hash = Selector.rfind('#');
+ const std::size_t Comma = Selector.find(',');
const std::string_view Name =
- Hash == std::string_view::npos ? Selector : Selector.substr(0, Hash);
+ Comma == std::string_view::npos ? Selector : Selector.substr(0, Comma);
if (Name.empty())
return makeUnexpected(ErrorCode::InvalidInvocation, "empty pipeline pass selector");
auto Pass = riscv::createCanonicalPipelinePass(Name);
if (!Pass)
return std::unexpected(Pass.error());
- if (Hash != std::string_view::npos) {
- const std::string_view Occurrence = Selector.substr(Hash + 1U);
- if (Occurrence.empty() || Occurrence == "0" ||
- !std::ranges::all_of(Occurrence,
- [](char Character) { return Character >= '0' && Character <= '9'; })) {
+ if (Comma != std::string_view::npos) {
+ const std::string_view InstanceText = Selector.substr(Comma + 1U);
+ std::uint32_t Instance = 0;
+ const auto Parsed =
+ std::from_chars(InstanceText.data(), InstanceText.data() + InstanceText.size(), Instance);
+ if (InstanceText.empty() || Parsed.ec != std::errc{} ||
+ Parsed.ptr != InstanceText.data() + InstanceText.size()) {
return makeUnexpected(ErrorCode::InvalidInvocation,
- "pipeline pass occurrence must be a positive integer");
+ "pipeline pass instance must be a nonnegative integer");
}
}
return {};
}
[[nodiscard]] Expected<void> validateControls(const PipelineControls &Controls) {
+ if (Controls.StartBefore && Controls.StartAfter) {
+ return makeUnexpected(ErrorCode::InvalidInvocation,
+ "-start-before and -start-after cannot be combined");
+ }
+ if (Controls.StopBefore && Controls.StopAfter) {
+ return makeUnexpected(ErrorCode::InvalidInvocation,
+ "-stop-before and -stop-after cannot be combined");
+ }
+ if (Controls.StartBefore) {
+ auto Result = validateSelector(*Controls.StartBefore, false);
+ if (!Result)
+ return Result;
+ }
+ if (Controls.StartAfter) {
+ auto Result = validateSelector(*Controls.StartAfter, false);
+ if (!Result)
+ return Result;
+ }
if (Controls.StopBefore) {
- auto Result = validateSelector(*Controls.StopBefore);
+ auto Result = validateSelector(*Controls.StopBefore, false);
if (!Result)
return Result;
}
if (Controls.StopAfter) {
- auto Result = validateSelector(*Controls.StopAfter);
+ auto Result = validateSelector(*Controls.StopAfter, false);
if (!Result)
return Result;
}
for (const std::string &Selector : Controls.PrintBefore) {
- auto Result = validateSelector(Selector);
+ auto Result = validateSelector(Selector, true);
if (!Result)
return Result;
}
for (const std::string &Selector : Controls.PrintAfter) {
- auto Result = validateSelector(Selector);
+ auto Result = validateSelector(Selector, true);
if (!Result)
return Result;
}
@@ -198,13 +225,26 @@ runFunction(MachineFunction &Function, mir::MIRDocument &Document, const TargetD
}
std::unordered_map<std::string, std::uint32_t> Occurrences;
+ bool Started = !Controls.StartBefore && !Controls.StartAfter;
+ bool StopMatched = !Controls.StopBefore && !Controls.StopAfter;
for (std::unique_ptr<MachineFunctionPass> &Pass : *Passes) {
if (Pass == nullptr)
return makeUnexpected(ErrorCode::InternalError, "pipeline contains a null pass");
const std::string Name = Pass->contract().Name;
const std::uint32_t Occurrence = ++Occurrences[Name];
- if (Controls.StopBefore && selectorMatches(*Controls.StopBefore, Name, Occurrence))
+ if (!Started) {
+ if (Controls.StartBefore && selectorMatches(*Controls.StartBefore, Name, Occurrence, false)) {
+ Started = true;
+ } else {
+ if (Controls.StartAfter && selectorMatches(*Controls.StartAfter, Name, Occurrence, false))
+ Started = true;
+ continue;
+ }
+ }
+ if (Controls.StopBefore && selectorMatches(*Controls.StopBefore, Name, Occurrence, false)) {
+ StopMatched = true;
break;
+ }
if (AllowSnapshots && anySelectorMatches(Controls.PrintBefore, Name, Occurrence)) {
auto Captured =
captureSnapshot(Result, Document, Target, Invocation, SnapshotPhase::BeforePass,
@@ -241,12 +281,25 @@ runFunction(MachineFunction &Function, mir::MIRDocument &Document, const TargetD
if (!Captured)
return std::unexpected(Captured.error());
}
- if (Controls.StopAfter && selectorMatches(*Controls.StopAfter, Name, Occurrence))
+ if (Controls.StopAfter && selectorMatches(*Controls.StopAfter, Name, Occurrence, false)) {
+ StopMatched = true;
break;
+ }
if (Controls.StopAtStage && stageOrdinal(CurrentStage) >= stageOrdinal(*Controls.StopAtStage)) {
break;
}
}
+ if (!Started) {
+ const std::string &Selector =
+ Controls.StartBefore ? *Controls.StartBefore : *Controls.StartAfter;
+ return makeUnexpected(ErrorCode::InvalidInvocation,
+ "pipeline start selector did not match: '" + Selector + "'");
+ }
+ if (!StopMatched) {
+ const std::string &Selector = Controls.StopBefore ? *Controls.StopBefore : *Controls.StopAfter;
+ return makeUnexpected(ErrorCode::InvalidInvocation,
+ "pipeline stop selector did not match: '" + Selector + "'");
+ }
return Result;
}