aboutsummaryrefslogtreecommitdiff
path: root/backend/tools/MIRTool/MIRToolMain.cpp
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/tools/MIRTool/MIRToolMain.cpp
parent1775d50ba02dab033c639f5c8fedd46cb6613bef (diff)
downloadrcc-project-09e8ef3e0dae29be7aa21a6e22a118a3f545945f.tar.gz
rcc-project-09e8ef3e0dae29be7aa21a6e22a118a3f545945f.tar.xz
[Tooling] Complete the LLVM MIR command-line contract
Diffstat (limited to 'backend/tools/MIRTool/MIRToolMain.cpp')
-rw-r--r--backend/tools/MIRTool/MIRToolMain.cpp221
1 files changed, 128 insertions, 93 deletions
diff --git a/backend/tools/MIRTool/MIRToolMain.cpp b/backend/tools/MIRTool/MIRToolMain.cpp
index ea180d6..2c0fe8d 100644
--- a/backend/tools/MIRTool/MIRToolMain.cpp
+++ b/backend/tools/MIRTool/MIRToolMain.cpp
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-3.0-or-later
+#include "rcc/CodeGen/CommandFlags.h"
#include "rcc/CodeGen/MachineFunction.h"
#include "rcc/Support/Error.h"
#include "rcc/Target/RISCV/RISCVPipeline.h"
@@ -68,6 +69,7 @@ struct CommandLine final {
rcc::tooling::PipelineControls Controls;
rcc::tooling::MIRFuzzOptions FuzzOptions;
bool OutputWasSpecified = false;
+ bool DiscardOutput = false;
bool PrintActions = false;
bool ShowHelp = false;
};
@@ -83,14 +85,16 @@ void printUsage(std::ostream &Output) {
"pipeline/output:\n"
" -run-pass <name> Run one named pass\n"
" -passes <name,...> Run an explicit pass sequence\n"
- " -stop-before <pass[#N]> Stop before a pass occurrence\n"
- " -stop-after <pass[#N]> Stop after a pass occurrence\n"
- " -print-before <pass[#N],...> Print snapshots before passes\n"
- " -print-after <pass[#N],...> Print snapshots after passes\n"
+ " -start-before <pass[,N]> Start before a pass instance\n"
+ " -start-after <pass[,N]> Start after a pass instance\n"
+ " -stop-before <pass[,N]> Stop before a pass instance\n"
+ " -stop-after <pass[,N]> Stop after a pass instance\n"
+ " -print-before <selector,...> Print snapshots before passes\n"
+ " -print-after <selector,...> Print snapshots after passes\n"
" -simplify-mir Omit default-valued MIR fields\n"
" -verify-machineinstrs Verify each machine pass result\n"
" --stage-snapshots Print every stage boundary\n"
- " --emit <stage|assembly|object> Select the output artifact\n"
+ " -filetype <asm|obj|null> Select the output artifact\n"
" -o <file|-> Select the output path\n"
"reproduction/cache/fuzz:\n"
" --crash-reproducer <path> Save input and manifest before execution\n"
@@ -118,7 +122,9 @@ void printUsage(std::ostream &Output) {
std::string_view Name,
int &Index, int ArgumentCount,
char *Arguments[]) {
- if (Argument == Name) {
+ const std::string LongName =
+ Name.starts_with('-') && !Name.starts_with("--") ? "-" + std::string(Name) : std::string();
+ if (Argument == Name || (!LongName.empty() && Argument == LongName)) {
if (Index + 1 >= ArgumentCount) {
return rcc::makeUnexpected(ErrorCode::InvalidInvocation,
"missing value for command-line option '" + std::string(Name) +
@@ -130,6 +136,12 @@ void printUsage(std::ostream &Output) {
Prefix.push_back('=');
if (Argument.starts_with(Prefix))
return Argument.substr(Prefix.size());
+ if (!LongName.empty()) {
+ std::string LongPrefix(LongName);
+ LongPrefix.push_back('=');
+ if (Argument.starts_with(LongPrefix))
+ return Argument.substr(LongPrefix.size());
+ }
return std::nullopt;
}
@@ -237,6 +249,13 @@ void applyFeatureOverrides(std::vector<std::string> Overrides, std::vector<std::
[[nodiscard]] Expected<CommandLine> parseCommandLine(int ArgumentCount, char *Arguments[]) {
CommandLine Command;
bool ExplicitPipeline = false;
+ bool UsedRunPass = false;
+ bool UsedPasses = false;
+ rcc::CodeGenCommandFlags CodeGenFlags;
+ std::vector<std::string_view> ArgumentViews;
+ ArgumentViews.reserve(static_cast<std::size_t>(ArgumentCount));
+ for (int Index = 0; Index < ArgumentCount; ++Index)
+ ArgumentViews.emplace_back(Arguments[Index]);
for (int Index = 1; Index < ArgumentCount; ++Index) {
const std::string_view Argument(Arguments[Index]);
if (Argument == "--help" || Argument == "-h") {
@@ -259,11 +278,11 @@ void applyFeatureOverrides(std::vector<std::string> Overrides, std::vector<std::
Command.Controls.CaptureStageSnapshots = true;
continue;
}
- if (Argument == "-simplify-mir") {
+ if (Argument == "-simplify-mir" || Argument == "--simplify-mir") {
Command.Controls.SimplifyMIR = true;
continue;
}
- if (Argument == "-verify-machineinstrs") {
+ if (Argument == "-verify-machineinstrs" || Argument == "--verify-machineinstrs") {
Command.Controls.VerifyEach = true;
continue;
}
@@ -279,24 +298,15 @@ void applyFeatureOverrides(std::vector<std::string> Overrides, std::vector<std::
Command.PrintActions = true;
continue;
}
- if (Argument == "-O0" || Argument == "-O1" || Argument == "-O2" || Argument == "-O3" ||
- Argument == "-Os" || Argument == "-Oz") {
- auto Level = rcc::tooling::parseOptimizationLevel(Argument.substr(1));
- if (!Level)
- return std::unexpected(Level.error());
- Command.Invocation.Optimization = *Level;
+ std::size_t CodeGenIndex = static_cast<std::size_t>(Index);
+ auto CodeGenFlag = rcc::parseCodeGenCommandFlag(ArgumentViews, CodeGenIndex, CodeGenFlags);
+ if (!CodeGenFlag)
+ return std::unexpected(CodeGenFlag.error());
+ if (*CodeGenFlag) {
+ Index = static_cast<int>(CodeGenIndex);
continue;
}
- auto Input = takeOption(Argument, "--input", Index, ArgumentCount, Arguments);
- if (!Input)
- return std::unexpected(Input.error());
- if (*Input) {
- if (!Command.InputPath.empty())
- return rcc::makeUnexpected(ErrorCode::InvalidInvocation, "input path is specified twice");
- Command.InputPath = std::string(**Input);
- continue;
- }
auto Output = takeOption(Argument, "-o", Index, ArgumentCount, Arguments);
if (!Output)
return std::unexpected(Output.error());
@@ -305,25 +315,22 @@ void applyFeatureOverrides(std::vector<std::string> Overrides, std::vector<std::
Command.OutputWasSpecified = true;
continue;
}
- auto Emit = takeOption(Argument, "--emit", Index, ArgumentCount, Arguments);
- if (!Emit)
- return std::unexpected(Emit.error());
- if (*Emit) {
- auto Kind = rcc::tooling::parseBackendOutputKind(**Emit);
- if (!Kind)
- return std::unexpected(Kind.error());
- Command.Output = *Kind;
- Command.OutputWasSpecified = true;
- continue;
- }
auto RunPass = takeOption(Argument, "-run-pass", Index, ArgumentCount, Arguments);
if (!RunPass)
return std::unexpected(RunPass.error());
if (*RunPass) {
- if (ExplicitPipeline)
+ if (UsedPasses)
return rcc::makeUnexpected(ErrorCode::InvalidInvocation,
"-run-pass and -passes cannot be combined");
- Command.Invocation.PassPipeline = {std::string(**RunPass)};
+ auto Names = splitList(**RunPass, "pass pipeline");
+ if (!Names)
+ return std::unexpected(Names.error());
+ if (!UsedRunPass)
+ Command.Invocation.PassPipeline.clear();
+ Command.Invocation.PassPipeline.insert(Command.Invocation.PassPipeline.end(),
+ std::make_move_iterator(Names->begin()),
+ std::make_move_iterator(Names->end()));
+ UsedRunPass = true;
ExplicitPipeline = true;
continue;
}
@@ -331,13 +338,14 @@ void applyFeatureOverrides(std::vector<std::string> Overrides, std::vector<std::
if (!Passes)
return std::unexpected(Passes.error());
if (*Passes) {
- if (ExplicitPipeline)
+ if (UsedRunPass || UsedPasses)
return rcc::makeUnexpected(ErrorCode::InvalidInvocation,
"-run-pass and -passes cannot be combined");
auto Names = splitList(**Passes, "pass pipeline");
if (!Names)
return std::unexpected(Names.error());
Command.Invocation.PassPipeline = std::move(*Names);
+ UsedPasses = true;
ExplicitPipeline = true;
continue;
}
@@ -362,6 +370,26 @@ void applyFeatureOverrides(std::vector<std::string> Overrides, std::vector<std::
return std::unexpected(StopAfter.error());
if (*StopAfter)
continue;
+ auto StartBefore = ParseSelector("-start-before", Command.Controls.StartBefore);
+ if (!StartBefore)
+ return std::unexpected(StartBefore.error());
+ if (*StartBefore)
+ continue;
+ auto StartAfter = ParseSelector("-start-after", Command.Controls.StartAfter);
+ if (!StartAfter)
+ return std::unexpected(StartAfter.error());
+ if (*StartAfter)
+ continue;
+
+ auto InputLanguage = takeOption(Argument, "-x", Index, ArgumentCount, Arguments);
+ if (!InputLanguage)
+ return std::unexpected(InputLanguage.error());
+ if (*InputLanguage) {
+ if (**InputLanguage != "mir") {
+ return rcc::makeUnexpected(ErrorCode::InvalidInvocation, "input language must be 'mir'");
+ }
+ continue;
+ }
const auto ParseSelectorList = [&](std::string_view Name,
std::vector<std::string> &Destination) -> Expected<bool> {
@@ -515,28 +543,6 @@ void applyFeatureOverrides(std::vector<std::string> Overrides, std::vector<std::
Destination = std::string(**Value);
return true;
};
- auto Triple = takeOption(Argument, "-mtriple", Index, ArgumentCount, Arguments);
- if (!Triple)
- return std::unexpected(Triple.error());
- if (*Triple) {
- Command.Invocation.Triple = normalizeRV64Triple(**Triple);
- continue;
- }
- auto CPU = ParseString("-mcpu", Command.Invocation.CPU);
- if (!CPU)
- return std::unexpected(CPU.error());
- if (*CPU)
- continue;
- auto TuneCPU = ParseString("-mtune", Command.Invocation.TuneCPU);
- if (!TuneCPU)
- return std::unexpected(TuneCPU.error());
- if (*TuneCPU)
- continue;
- auto ABI = ParseString("-target-abi", Command.Invocation.ABI);
- if (!ABI)
- return std::unexpected(ABI.error());
- if (*ABI)
- continue;
auto DataLayout = ParseString("--data-layout", Command.Invocation.DataLayout);
if (!DataLayout)
return std::unexpected(DataLayout.error());
@@ -552,36 +558,6 @@ void applyFeatureOverrides(std::vector<std::string> Overrides, std::vector<std::
return std::unexpected(AssemblerVersion.error());
if (*AssemblerVersion)
continue;
- auto Features = takeOption(Argument, "-mattr", Index, ArgumentCount, Arguments);
- if (!Features)
- return std::unexpected(Features.error());
- if (*Features) {
- auto Values = splitList(**Features, "target feature list");
- if (!Values)
- return std::unexpected(Values.error());
- applyFeatureOverrides(std::move(*Values), Command.Invocation.Features);
- continue;
- }
- auto Relocation = takeOption(Argument, "-relocation-model", Index, ArgumentCount, Arguments);
- if (!Relocation)
- return std::unexpected(Relocation.error());
- if (*Relocation) {
- auto Value = rcc::tooling::parseRelocationModel(**Relocation);
- if (!Value)
- return std::unexpected(Value.error());
- Command.Invocation.Relocation = *Value;
- continue;
- }
- auto Code = takeOption(Argument, "-code-model", Index, ArgumentCount, Arguments);
- if (!Code)
- return std::unexpected(Code.error());
- if (*Code) {
- auto Value = rcc::tooling::parseCodeModel(**Code);
- if (!Value)
- return std::unexpected(Value.error());
- Command.Invocation.Code = *Value;
- continue;
- }
auto Layout = takeOption(Argument, "--layout", Index, ArgumentCount, Arguments);
if (!Layout)
return std::unexpected(Layout.error());
@@ -636,6 +612,46 @@ void applyFeatureOverrides(std::vector<std::string> Overrides, std::vector<std::
if (Command.ShowHelp)
return Command;
+ if (CodeGenFlags.Triple)
+ Command.Invocation.Triple = normalizeRV64Triple(*CodeGenFlags.Triple);
+ if (CodeGenFlags.CPU)
+ Command.Invocation.CPU = *CodeGenFlags.CPU;
+ if (CodeGenFlags.TuneCPU)
+ Command.Invocation.TuneCPU = *CodeGenFlags.TuneCPU;
+ if (CodeGenFlags.ABI)
+ Command.Invocation.ABI = *CodeGenFlags.ABI;
+ applyFeatureOverrides(std::move(CodeGenFlags.FeatureOverrides), Command.Invocation.Features);
+ if (CodeGenFlags.Relocation)
+ Command.Invocation.Relocation = *CodeGenFlags.Relocation;
+ if (CodeGenFlags.Code)
+ Command.Invocation.Code = *CodeGenFlags.Code;
+ if (CodeGenFlags.Optimization)
+ Command.Invocation.Optimization = *CodeGenFlags.Optimization;
+ const bool HasLimitedCodeGenPipeline = Command.Controls.StartBefore ||
+ Command.Controls.StartAfter ||
+ Command.Controls.StopBefore || Command.Controls.StopAfter;
+ if (UsedRunPass && HasLimitedCodeGenPipeline) {
+ return rcc::makeUnexpected(ErrorCode::InvalidInvocation,
+ "-run-pass cannot be used with a limited code-generation pipeline");
+ }
+ if (ExplicitPipeline || HasLimitedCodeGenPipeline) {
+ Command.Output = BackendOutputKind::FinalMIR;
+ } else {
+ switch (CodeGenFlags.FileType) {
+ case rcc::CodeGenFileType::AssemblyFile:
+ Command.Output = BackendOutputKind::Assembly;
+ break;
+ case rcc::CodeGenFileType::ObjectFile:
+ Command.Output = BackendOutputKind::RelocatableObject;
+ break;
+ case rcc::CodeGenFileType::Null:
+ Command.Output = BackendOutputKind::Assembly;
+ Command.DiscardOutput = true;
+ break;
+ }
+ }
+ Command.DiscardOutput =
+ CodeGenFlags.FileTypeWasSpecified && CodeGenFlags.FileType == rcc::CodeGenFileType::Null;
if (Command.Action == Operation::Reproduce) {
if (!Command.InputPath.empty())
return rcc::makeUnexpected(ErrorCode::InvalidInvocation,
@@ -700,10 +716,27 @@ void applyFeatureOverrides(std::vector<std::string> Overrides, std::vector<std::
}
[[nodiscard]] Expected<BackendOutputKind> outputFromArtifact(ArtifactKind Artifact) {
- const auto Value = static_cast<BackendOutputKind>(static_cast<std::uint8_t>(Artifact));
- if (rcc::tooling::spelling(Value) == "invalid")
- return rcc::makeUnexpected(ErrorCode::ReproducerError, "invalid reproducer artifact kind");
- return Value;
+ switch (Artifact) {
+ case ArtifactKind::PreLegalizerMIR:
+ return BackendOutputKind::PreLegalizerMIR;
+ case ArtifactKind::LegalizedMIR:
+ return BackendOutputKind::LegalizedMIR;
+ case ArtifactKind::RegisterBankMIR:
+ return BackendOutputKind::RegisterBankMIR;
+ case ArtifactKind::SelectedMIR:
+ return BackendOutputKind::SelectedMIR;
+ case ArtifactKind::PostSSAMIR:
+ return BackendOutputKind::PostSSAMIR;
+ case ArtifactKind::PostRegisterAllocationMIR:
+ return BackendOutputKind::PostRegisterAllocationMIR;
+ case ArtifactKind::FinalMIR:
+ return BackendOutputKind::FinalMIR;
+ case ArtifactKind::Assembly:
+ return BackendOutputKind::Assembly;
+ case ArtifactKind::RelocatableObject:
+ return BackendOutputKind::RelocatableObject;
+ }
+ return rcc::makeUnexpected(ErrorCode::ReproducerError, "invalid reproducer artifact kind");
}
void printSnapshots(const BackendRunResult &Result) {
@@ -996,6 +1029,8 @@ runWithCache(const CommandLine &Command, CanonicalMIR Input, const rcc::TargetDe
printSnapshots(*Run);
if (Command.PrintActions)
printActions(*Run);
+ if (Command.DiscardOutput)
+ return {};
return writeOutput(Command.OutputPath, Run->Output);
}