diff options
Diffstat (limited to 'backend')
21 files changed, 620 insertions, 335 deletions
diff --git a/backend/include/rcc/CodeGen/CommandFlags.h b/backend/include/rcc/CodeGen/CommandFlags.h new file mode 100644 index 0000000..0ee2f0d --- /dev/null +++ b/backend/include/rcc/CodeGen/CommandFlags.h @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_CODEGEN_COMMANDFLAGS_H +#define RCC_CODEGEN_COMMANDFLAGS_H + +#include "rcc/Support/Error.h" + +#include <cstddef> +#include <cstdint> +#include <optional> +#include <span> +#include <string> +#include <string_view> +#include <vector> + +namespace rcc { + +enum class RelocationModel : std::uint8_t { + Static, + PositionIndependent, +}; + +enum class CodeModel : std::uint8_t { + Small, + Medium, + Large, +}; + +enum class OptimizationLevel : std::uint8_t { + O0, + O1, + O2, + O3, + Os, + Oz, +}; + +enum class CodeGenFileType : std::uint8_t { + AssemblyFile, + ObjectFile, + Null, +}; + +struct CodeGenCommandFlags final { + std::optional<std::string> Triple; + std::optional<std::string> CPU; + std::optional<std::string> TuneCPU; + std::optional<std::string> ABI; + std::vector<std::string> FeatureOverrides; + std::optional<RelocationModel> Relocation; + std::optional<CodeModel> Code; + std::optional<OptimizationLevel> Optimization; + CodeGenFileType FileType = CodeGenFileType::AssemblyFile; + bool FileTypeWasSpecified = false; +}; + +[[nodiscard]] std::string_view spelling(RelocationModel Value) noexcept; +[[nodiscard]] std::string_view spelling(CodeModel Value) noexcept; +[[nodiscard]] std::string_view spelling(OptimizationLevel Value) noexcept; +[[nodiscard]] std::string_view spelling(CodeGenFileType Value) noexcept; + +[[nodiscard]] Expected<RelocationModel> parseRelocationModel(std::string_view Value); +[[nodiscard]] Expected<CodeModel> parseCodeModel(std::string_view Value); +[[nodiscard]] Expected<OptimizationLevel> parseOptimizationLevel(std::string_view Value); +[[nodiscard]] Expected<CodeGenFileType> parseCodeGenFileType(std::string_view Value); +[[nodiscard]] Expected<bool> parseCodeGenCommandFlag(std::span<const std::string_view> Arguments, + std::size_t &Index, + CodeGenCommandFlags &Flags); + +} // namespace rcc + +#endif // RCC_CODEGEN_COMMANDFLAGS_H diff --git a/backend/include/rcc/Tooling/BackendDriver.h b/backend/include/rcc/Tooling/BackendDriver.h index f762c1e..7b62b6d 100644 --- a/backend/include/rcc/Tooling/BackendDriver.h +++ b/backend/include/rcc/Tooling/BackendDriver.h @@ -46,7 +46,6 @@ runBackend(CanonicalMIR Input, const TargetDescription &Target, const BackendInv MachinePassInstrumentation *Instrumentation = nullptr); [[nodiscard]] std::string_view spelling(BackendOutputKind Output) noexcept; -[[nodiscard]] Expected<BackendOutputKind> parseBackendOutputKind(std::string_view Value); [[nodiscard]] ArtifactKind manifestArtifactKind(BackendOutputKind Output) noexcept; [[nodiscard]] Expected<ArtifactKind> cacheArtifactKind(BackendOutputKind Output); diff --git a/backend/include/rcc/Tooling/BackendInvocation.h b/backend/include/rcc/Tooling/BackendInvocation.h index db1c5d2..d61f038 100644 --- a/backend/include/rcc/Tooling/BackendInvocation.h +++ b/backend/include/rcc/Tooling/BackendInvocation.h @@ -3,6 +3,7 @@ #ifndef RCC_TOOLING_BACKENDINVOCATION_H #define RCC_TOOLING_BACKENDINVOCATION_H +#include "rcc/CodeGen/CommandFlags.h" #include "rcc/Support/Error.h" #include <cstdint> @@ -25,26 +26,6 @@ inline constexpr std::string_view GenericOpcodeReferenceVersion = "rcc-generic-o inline constexpr std::string_view RV64GCTargetABILoweringVersion = "rcc-rv64gc-lp64d-v1"; inline constexpr std::string_view CompilerBuildFingerprint = "rcc-backend-0.1.0-stage17"; -enum class RelocationModel : std::uint8_t { - Static, - PositionIndependent, -}; - -enum class CodeModel : std::uint8_t { - Small, - Medium, - Large, -}; - -enum class OptimizationLevel : std::uint8_t { - O0, - O1, - O2, - O3, - Os, - Oz, -}; - enum class LayoutOwnership : std::uint8_t { NativeObject, CompilerFinalLayout, @@ -74,14 +55,14 @@ struct BackendInvocation final { std::vector<std::string> Features; std::string ABI; std::string DataLayout; - RelocationModel Relocation = RelocationModel::PositionIndependent; - CodeModel Code = CodeModel::Small; + rcc::RelocationModel Relocation = rcc::RelocationModel::PositionIndependent; + rcc::CodeModel Code = rcc::CodeModel::Small; std::vector<BackendOption> TargetOptions; LayoutOwnership Layout = LayoutOwnership::NativeObject; std::string AssemblerFlavor; std::string AssemblerVersion; std::vector<BackendOption> AssemblerOptions; - OptimizationLevel Optimization = OptimizationLevel::O2; + rcc::OptimizationLevel Optimization = rcc::OptimizationLevel::O2; std::vector<std::string> PassPipeline{"default"}; DeterminismOptions Determinism; std::optional<std::uint64_t> ActionFuel; @@ -104,13 +85,7 @@ computeTargetDescriptionFingerprint(const TargetDescription &Target); const BackendInvocation &Invocation, std::string_view TargetFingerprint); -[[nodiscard]] std::string_view spelling(RelocationModel Value) noexcept; -[[nodiscard]] std::string_view spelling(CodeModel Value) noexcept; -[[nodiscard]] std::string_view spelling(OptimizationLevel Value) noexcept; [[nodiscard]] std::string_view spelling(LayoutOwnership Value) noexcept; -[[nodiscard]] Expected<RelocationModel> parseRelocationModel(std::string_view Value); -[[nodiscard]] Expected<CodeModel> parseCodeModel(std::string_view Value); -[[nodiscard]] Expected<OptimizationLevel> parseOptimizationLevel(std::string_view Value); [[nodiscard]] Expected<LayoutOwnership> parseLayoutOwnership(std::string_view Value); } // namespace tooling diff --git a/backend/include/rcc/Tooling/PipelineDriver.h b/backend/include/rcc/Tooling/PipelineDriver.h index d6c9f58..5d2dc45 100644 --- a/backend/include/rcc/Tooling/PipelineDriver.h +++ b/backend/include/rcc/Tooling/PipelineDriver.h @@ -36,6 +36,8 @@ enum class SnapshotPhase : std::uint8_t { }; struct PipelineControls final { + std::optional<std::string> StartBefore; + std::optional<std::string> StartAfter; std::optional<std::string> StopBefore; std::optional<std::string> StopAfter; std::vector<std::string> PrintBefore; diff --git a/backend/lib/CodeGen/CMakeLists.txt b/backend/lib/CodeGen/CMakeLists.txt index d25d164..e584131 100644 --- a/backend/lib/CodeGen/CMakeLists.txt +++ b/backend/lib/CodeGen/CMakeLists.txt @@ -3,6 +3,7 @@ set( RCCBackendCodeGenSources CompilationUnit.cpp + CommandFlags.cpp GlobalObject.cpp GenericOpcodes.cpp GenericConstant.cpp @@ -83,6 +84,7 @@ set( set( RCCBackendCodeGenHeaders "${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/CompilationUnit.h" + "${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/CommandFlags.h" "${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/GlobalObject.h" "${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/GenericOpcodes.h" "${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/GenericConstant.h" @@ -204,6 +206,7 @@ install( rcc_backend_register_format_files( "${CMAKE_CURRENT_SOURCE_DIR}/CompilationUnit.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/CommandFlags.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/GlobalObject.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/GenericOpcodes.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/GenericConstant.cpp" @@ -285,6 +288,7 @@ rcc_backend_register_format_files( ) rcc_backend_register_tidy_files( "${CMAKE_CURRENT_SOURCE_DIR}/CompilationUnit.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/CommandFlags.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/GlobalObject.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/GenericOpcodes.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/GenericConstant.cpp" diff --git a/backend/lib/CodeGen/CommandFlags.cpp b/backend/lib/CodeGen/CommandFlags.cpp new file mode 100644 index 0000000..dfbaadc --- /dev/null +++ b/backend/lib/CodeGen/CommandFlags.cpp @@ -0,0 +1,233 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "rcc/CodeGen/CommandFlags.h" + +#include <optional> +#include <string> +#include <utility> + +namespace rcc { +namespace { + +[[nodiscard]] Expected<std::optional<std::string_view>> +takeValue(std::span<const std::string_view> Arguments, std::size_t &Index, std::string_view Name) { + const std::string_view Argument = Arguments[Index]; + const std::string LongName = + Name.starts_with('-') && !Name.starts_with("--") ? "-" + std::string(Name) : std::string(); + if (Argument == Name || (!LongName.empty() && Argument == LongName)) { + if (Index + 1U >= Arguments.size()) { + return makeUnexpected(ErrorCode::InvalidInvocation, + "missing value for command-line option '" + std::string(Name) + "'"); + } + return Arguments[++Index]; + } + std::string Prefix(Name); + 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; +} + +template <typename ValueT, typename ParserT> +[[nodiscard]] Expected<bool> parseValueFlag(std::span<const std::string_view> Arguments, + std::size_t &Index, std::string_view Name, + std::optional<ValueT> &Destination, ParserT Parser) { + auto Value = takeValue(Arguments, Index, Name); + if (!Value) + return std::unexpected(Value.error()); + if (!*Value) + return false; + auto Parsed = Parser(**Value); + if (!Parsed) + return std::unexpected(Parsed.error()); + Destination = std::move(*Parsed); + return true; +} + +} // 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(CodeGenFileType Value) noexcept { + switch (Value) { + case CodeGenFileType::AssemblyFile: + return "asm"; + case CodeGenFileType::ObjectFile: + return "obj"; + case CodeGenFileType::Null: + return "null"; + } + return "invalid"; +} + +Expected<RelocationModel> parseRelocationModel(std::string_view Value) { + if (Value == "static") + return RelocationModel::Static; + if (Value == "pic") + return RelocationModel::PositionIndependent; + return makeUnexpected(ErrorCode::InvalidInvocation, "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::InvalidInvocation, "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::InvalidInvocation, "unknown optimization level"); +} + +Expected<CodeGenFileType> parseCodeGenFileType(std::string_view Value) { + if (Value == "asm") + return CodeGenFileType::AssemblyFile; + if (Value == "obj") + return CodeGenFileType::ObjectFile; + if (Value == "null") + return CodeGenFileType::Null; + return makeUnexpected(ErrorCode::InvalidInvocation, "unknown file type"); +} + +Expected<bool> parseCodeGenCommandFlag(std::span<const std::string_view> Arguments, + std::size_t &Index, CodeGenCommandFlags &Flags) { + const std::string_view Argument = Arguments[Index]; + const std::string_view Optimization = Argument.starts_with("--") ? Argument.substr(2) + : Argument.starts_with('-') ? Argument.substr(1) + : std::string_view{}; + if ((Argument.starts_with('-') && !Argument.starts_with("---")) && + (Optimization == "O0" || Optimization == "O1" || Optimization == "O2" || + Optimization == "O3" || Optimization == "Os" || Optimization == "Oz")) { + auto Level = parseOptimizationLevel(Optimization); + if (!Level) + return std::unexpected(Level.error()); + Flags.Optimization = *Level; + return true; + } + + const auto ParseString = [&](std::string_view Name, + std::optional<std::string> &Destination) -> Expected<bool> { + auto Value = takeValue(Arguments, Index, Name); + if (!Value) + return std::unexpected(Value.error()); + if (!*Value) + return false; + Destination = std::string(**Value); + return true; + }; + for (const auto &[Name, Destination] : + {std::pair{"-mtriple", &Flags.Triple}, std::pair{"-mcpu", &Flags.CPU}, + std::pair{"-mtune", &Flags.TuneCPU}, std::pair{"-target-abi", &Flags.ABI}}) { + auto Parsed = ParseString(Name, *Destination); + if (!Parsed) + return std::unexpected(Parsed.error()); + if (*Parsed) + return true; + } + + auto Features = takeValue(Arguments, Index, "-mattr"); + if (!Features) + return std::unexpected(Features.error()); + if (*Features) { + std::size_t Begin = 0; + while (Begin <= (**Features).size()) { + const std::size_t Comma = (**Features).find(',', Begin); + const std::size_t End = Comma == std::string_view::npos ? (**Features).size() : Comma; + if (End == Begin) { + return makeUnexpected(ErrorCode::InvalidInvocation, + "target feature list contains an empty element"); + } + Flags.FeatureOverrides.emplace_back((**Features).substr(Begin, End - Begin)); + if (Comma == std::string_view::npos) + break; + Begin = Comma + 1U; + } + return true; + } + + auto Relocation = + parseValueFlag(Arguments, Index, "-relocation-model", Flags.Relocation, parseRelocationModel); + if (!Relocation) + return std::unexpected(Relocation.error()); + if (*Relocation) + return true; + auto Code = parseValueFlag(Arguments, Index, "-code-model", Flags.Code, parseCodeModel); + if (!Code) + return std::unexpected(Code.error()); + if (*Code) + return true; + + auto FileType = takeValue(Arguments, Index, "-filetype"); + if (!FileType) + return std::unexpected(FileType.error()); + if (*FileType) { + auto Parsed = parseCodeGenFileType(**FileType); + if (!Parsed) + return std::unexpected(Parsed.error()); + Flags.FileType = *Parsed; + Flags.FileTypeWasSpecified = true; + return true; + } + return false; +} + +} // namespace rcc diff --git a/backend/lib/CodeGen/MachinePseudoExpansion.cpp b/backend/lib/CodeGen/MachinePseudoExpansion.cpp index 924c515..022c63e 100644 --- a/backend/lib/CodeGen/MachinePseudoExpansion.cpp +++ b/backend/lib/CodeGen/MachinePseudoExpansion.cpp @@ -154,7 +154,7 @@ using BlockSizeSnapshot = std::vector<std::pair<MachineBlockStableID, std::uint6 }(); static const MachinePassContract PostRA = [] { MachinePassContract Value{ - .Name = "expand-post-ra-pseudos", + .Name = "postrapseudos", .Requires = {MachineFunctionProperty::Selected, MachineFunctionProperty::NoPHIs, MachineFunctionProperty::NoVRegs, MachineFunctionProperty::TracksLiveness, MachineFunctionProperty::FrameFinalized, diff --git a/backend/lib/CodeGen/MachineSSAExit.cpp b/backend/lib/CodeGen/MachineSSAExit.cpp index f2b0102..76963ea 100644 --- a/backend/lib/CodeGen/MachineSSAExit.cpp +++ b/backend/lib/CodeGen/MachineSSAExit.cpp @@ -776,7 +776,7 @@ placePhiCopiesOnEdge(MachineFunction &Function, const TargetDescription &Target, const MachinePassContract &PHIEliminationPass::contract() const noexcept { static const MachinePassContract Contract{ - .Name = "PHIElimination", + .Name = "phi-node-elimination", .Requires = {MachineFunctionProperty::IsSSA, MachineFunctionProperty::Selected, MachineFunctionProperty::RegBankSelected}, .Sets = {MachineFunctionProperty::NoPHIs}, @@ -912,7 +912,7 @@ Expected<MachinePassResult> PHIEliminationPass::runImplementation(MachineFunctio const MachinePassContract &TwoAddressRewritePass::contract() const noexcept { static const MachinePassContract Contract{ - .Name = "TwoAddressRewrite", + .Name = "twoaddressinstruction", .Requires = {MachineFunctionProperty::Selected, MachineFunctionProperty::NoPHIs}, .Sets = {MachineFunctionProperty::TiedOpsRewritten}, .Clears = {MachineFunctionProperty::IsSSA}, diff --git a/backend/lib/CodeGen/PostRAScheduler.cpp b/backend/lib/CodeGen/PostRAScheduler.cpp index 6a91239..38fd582 100644 --- a/backend/lib/CodeGen/PostRAScheduler.cpp +++ b/backend/lib/CodeGen/PostRAScheduler.cpp @@ -31,7 +31,7 @@ namespace { [[nodiscard]] const MachinePassContract &postRASchedulerContract() { static const MachinePassContract Contract = [] { MachinePassContract Value{ - .Name = "post-ra-machine-scheduler", + .Name = "postmisched", .Requires = {MachineFunctionProperty::Selected, MachineFunctionProperty::NoPHIs, MachineFunctionProperty::TiedOpsRewritten, MachineFunctionProperty::NoVRegs, MachineFunctionProperty::TracksLiveness}, diff --git a/backend/lib/CodeGen/PrologueEpilogueInsertion.cpp b/backend/lib/CodeGen/PrologueEpilogueInsertion.cpp index acbcbcf..36315f7 100644 --- a/backend/lib/CodeGen/PrologueEpilogueInsertion.cpp +++ b/backend/lib/CodeGen/PrologueEpilogueInsertion.cpp @@ -31,7 +31,7 @@ namespace { const MachinePassContract &PrologueEpilogueInsertionPass::contract() const noexcept { static const MachinePassContract Contract = [] { MachinePassContract Value{ - .Name = "PrologueEpilogueInsertion", + .Name = "prologepilog", .Requires = {MachineFunctionProperty::Selected, MachineFunctionProperty::NoPHIs, MachineFunctionProperty::TiedOpsRewritten, MachineFunctionProperty::NoVRegs}, .Sets = {MachineFunctionProperty::FrameFinalized, MachineFunctionProperty::NoFrameIndices}, 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; } diff --git a/backend/tools/MIRTool/CMakeLists.txt b/backend/tools/MIRTool/CMakeLists.txt index 3388481..37738c1 100644 --- a/backend/tools/MIRTool/CMakeLists.txt +++ b/backend/tools/MIRTool/CMakeLists.txt @@ -53,7 +53,7 @@ foreach( "-DTOOL=$<TARGET_FILE:RCCBackendMIRTool>" "-DINPUT=${RCCBackendMIRToolInputDirectory}/${InputName}.mir" "-DOUTPUT=${RCCBackendMIRToolTestDirectory}/${InputName}.s" - -DOUTPUT_KIND=assembly + -DOUTPUT_KIND=asm "-DLLVM_MC=${RCCBackendMIRToolLLVMMC}" -P "${CMAKE_CURRENT_SOURCE_DIR}/MIRToolOutputTest.cmake" ) @@ -64,7 +64,7 @@ foreach( "-DTOOL=$<TARGET_FILE:RCCBackendMIRTool>" "-DINPUT=${RCCBackendMIRToolInputDirectory}/${InputName}.mir" "-DOUTPUT=${RCCBackendMIRToolTestDirectory}/${InputName}.o" - -DOUTPUT_KIND=object + -DOUTPUT_KIND=obj "-DLLVM_READELF=${RCCBackendMIRToolLLVMReadELF}" "-DLLVM_OBJDUMP=${RCCBackendMIRToolLLVMObjdump}" -P "${CMAKE_CURRENT_SOURCE_DIR}/MIRToolOutputTest.cmake" 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); } diff --git a/backend/tools/MIRTool/MIRToolOperationsTest.cmake b/backend/tools/MIRTool/MIRToolOperationsTest.cmake index 8dee32f..ff03619 100644 --- a/backend/tools/MIRTool/MIRToolOperationsTest.cmake +++ b/backend/tools/MIRTool/MIRToolOperationsTest.cmake @@ -27,7 +27,7 @@ set(CachedAssembly "${WORK_DIRECTORY}/cached.s") set(ReloadedAssembly "${WORK_DIRECTORY}/reloaded.s") execute_process( COMMAND - "${TOOL}" --input "${INPUT}" --emit assembly --cache-dir "${CacheDirectory}" + "${TOOL}" "${INPUT}" -filetype=asm --cache-dir "${CacheDirectory}" --cache-policy write -o "${CachedAssembly}" RESULT_VARIABLE CacheWriteResult ERROR_VARIABLE CacheWriteDiagnostics @@ -37,7 +37,7 @@ if(NOT CacheWriteResult EQUAL 0) endif() execute_process( COMMAND - "${TOOL}" --input "${INPUT}" --emit assembly --cache-dir "${CacheDirectory}" + "${TOOL}" "${INPUT}" -filetype=asm --cache-dir "${CacheDirectory}" --cache-policy read -o "${ReloadedAssembly}" RESULT_VARIABLE CacheReadResult ERROR_VARIABLE CacheReadDiagnostics @@ -55,7 +55,7 @@ endif() execute_process( COMMAND - "${TOOL}" --input "${INPUT}" --emit assembly --cache-dir + "${TOOL}" "${INPUT}" -filetype=asm --cache-dir "${WORK_DIRECTORY}/empty-cache" --cache-policy read -o "${WORK_DIRECTORY}/miss.s" RESULT_VARIABLE CacheMissResult ERROR_VARIABLE CacheMissDiagnostics @@ -73,7 +73,7 @@ list(GET CachedArtifacts 0 CachedArtifact) file(WRITE "${CachedArtifact}" "corrupt") execute_process( COMMAND - "${TOOL}" --input "${INPUT}" --emit assembly --cache-dir "${CacheDirectory}" + "${TOOL}" "${INPUT}" -filetype=asm --cache-dir "${CacheDirectory}" --cache-policy read -o "${WORK_DIRECTORY}/corrupt.s" RESULT_VARIABLE CorruptCacheResult ERROR_VARIABLE CorruptCacheDiagnostics @@ -87,7 +87,7 @@ set(SuccessAssembly "${WORK_DIRECTORY}/success.s") set(ReplayedAssembly "${WORK_DIRECTORY}/success-replayed.s") execute_process( COMMAND - "${TOOL}" --input "${INPUT}" --emit assembly --crash-reproducer "${SuccessReproducer}" + "${TOOL}" "${INPUT}" -filetype=asm --crash-reproducer "${SuccessReproducer}" -o "${SuccessAssembly}" RESULT_VARIABLE ReproducerWriteResult ERROR_VARIABLE ReproducerWriteDiagnostics @@ -113,7 +113,7 @@ endif() set(RegBankInput "${WORK_DIRECTORY}/regbank.mir") execute_process( - COMMAND "${TOOL}" --input "${INPUT}" --emit regbank-mir -o "${RegBankInput}" + COMMAND "${TOOL}" "${INPUT}" -stop-after=regbankselect -o "${RegBankInput}" RESULT_VARIABLE RegBankResult ERROR_VARIABLE RegBankDiagnostics ) @@ -124,7 +124,7 @@ endif() set(FailureReproducer "${WORK_DIRECTORY}/failure-reproducer") execute_process( COMMAND - "${TOOL}" --input "${RegBankInput}" -run-pass instruction-select --emit selected-mir + "${TOOL}" "${RegBankInput}" -run-pass instruction-select --fuel 0 --crash-reproducer "${FailureReproducer}" -o "${WORK_DIRECTORY}/failure.mir" RESULT_VARIABLE FailureResult ERROR_VARIABLE FailureDiagnostics @@ -151,7 +151,7 @@ endif() set(ActionOutput "${WORK_DIRECTORY}/selected.mir") execute_process( COMMAND - "${TOOL}" --input "${RegBankInput}" -run-pass instruction-select --emit selected-mir + "${TOOL}" "${RegBankInput}" -run-pass instruction-select --print-actions -o "${ActionOutput}" RESULT_VARIABLE ActionResult ERROR_VARIABLE ActionDiagnostics @@ -172,7 +172,7 @@ set(CanonicalReducerSeed "${WORK_DIRECTORY}/reducer-seed.canonical.mir") set(ReducedMIR "${WORK_DIRECTORY}/reduced.mir") file(WRITE "${ReducerSeed}" "${ReducerSeedText}") execute_process( - COMMAND "${TOOL}" --verify --input "${ReducerSeed}" -o "${CanonicalReducerSeed}" + COMMAND "${TOOL}" --verify "${ReducerSeed}" -o "${CanonicalReducerSeed}" RESULT_VARIABLE ReducerSeedResult ERROR_VARIABLE ReducerSeedDiagnostics ) @@ -180,7 +180,7 @@ if(NOT ReducerSeedResult EQUAL 0) message(FATAL_ERROR "reducer seed failed canonicalization: ${ReducerSeedDiagnostics}") endif() execute_process( - COMMAND "${TOOL}" --reduce validity --input "${ReducerSeed}" -o "${ReducedMIR}" + COMMAND "${TOOL}" --reduce validity "${ReducerSeed}" -o "${ReducedMIR}" RESULT_VARIABLE ValidityReducerResult ERROR_VARIABLE ValidityReducerDiagnostics ) @@ -193,7 +193,7 @@ if(NOT ReducedMIRSize LESS CanonicalReducerSeedSize) message(FATAL_ERROR "validity reducer did not make the canonical seed smaller") endif() execute_process( - COMMAND "${TOOL}" --verify --input "${ReducedMIR}" + COMMAND "${TOOL}" --verify "${ReducedMIR}" RESULT_VARIABLE ReducedVerifyResult ERROR_VARIABLE ReducedVerifyDiagnostics ) @@ -204,8 +204,8 @@ endif() set(FailureReducedMIR "${WORK_DIRECTORY}/failure-reduced.mir") execute_process( COMMAND - "${TOOL}" --reduce failure --input "${RegBankInput}" -run-pass instruction-select - --emit selected-mir --fuel 0 -o "${FailureReducedMIR}" + "${TOOL}" --reduce failure "${RegBankInput}" -run-pass instruction-select --fuel 0 -o + "${FailureReducedMIR}" RESULT_VARIABLE FailureReducerResult ERROR_VARIABLE FailureReducerDiagnostics ) @@ -214,7 +214,7 @@ if(NOT FailureReducerResult EQUAL 0) endif() execute_process( COMMAND - "${TOOL}" --input "${FailureReducedMIR}" -run-pass instruction-select --emit selected-mir + "${TOOL}" "${FailureReducedMIR}" -run-pass instruction-select --fuel 0 -o "${WORK_DIRECTORY}/failure-reduced-output.mir" RESULT_VARIABLE ReducedFailureResult ERROR_VARIABLE ReducedFailureDiagnostics @@ -228,7 +228,7 @@ set(FirstFuzz "${WORK_DIRECTORY}/fuzz-1.txt") set(SecondFuzz "${WORK_DIRECTORY}/fuzz-2.txt") execute_process( COMMAND - "${TOOL}" --fuzz all --fuzz-iterations 2 --seed 123 --input "${INPUT}" -o + "${TOOL}" --fuzz all --fuzz-iterations 2 --seed 123 "${INPUT}" -o "${FirstFuzz}" RESULT_VARIABLE FirstFuzzResult ERROR_VARIABLE FirstFuzzDiagnostics @@ -238,7 +238,7 @@ if(NOT FirstFuzzResult EQUAL 0) endif() execute_process( COMMAND - "${TOOL}" --fuzz all --fuzz-iterations 2 --seed 123 --input "${INPUT}" -o + "${TOOL}" --fuzz all --fuzz-iterations 2 --seed 123 "${INPUT}" -o "${SecondFuzz}" RESULT_VARIABLE SecondFuzzResult ERROR_VARIABLE SecondFuzzDiagnostics @@ -264,7 +264,7 @@ if(NOT FuzzText MATCHES "seed=123 executed=11" OR message(FATAL_ERROR "layered fuzz output does not account for all six layers") endif() execute_process( - COMMAND "${TOOL}" --fuzz parser,parser --input "${INPUT}" + COMMAND "${TOOL}" --fuzz parser,parser "${INPUT}" RESULT_VARIABLE DuplicateFuzzResult ERROR_VARIABLE DuplicateFuzzDiagnostics ) diff --git a/backend/tools/MIRTool/MIRToolOutputTest.cmake b/backend/tools/MIRTool/MIRToolOutputTest.cmake index 13159b8..00840bc 100644 --- a/backend/tools/MIRTool/MIRToolOutputTest.cmake +++ b/backend/tools/MIRTool/MIRToolOutputTest.cmake @@ -10,7 +10,7 @@ file(MAKE_DIRECTORY "${OutputDirectory}") set(RepeatedOutput "${OUTPUT}.repeat") execute_process( - COMMAND "${TOOL}" --input "${INPUT}" --emit "${OUTPUT_KIND}" -o "${OUTPUT}" + COMMAND "${TOOL}" "${INPUT}" -filetype "${OUTPUT_KIND}" -o "${OUTPUT}" RESULT_VARIABLE FirstResult ERROR_VARIABLE FirstDiagnostics ) @@ -18,7 +18,7 @@ if(NOT FirstResult EQUAL 0) message(FATAL_ERROR "${OUTPUT_KIND} production failed: ${FirstDiagnostics}") endif() execute_process( - COMMAND "${TOOL}" --input "${INPUT}" --emit "${OUTPUT_KIND}" -o "${RepeatedOutput}" + COMMAND "${TOOL}" "${INPUT}" -filetype "${OUTPUT_KIND}" -o "${RepeatedOutput}" RESULT_VARIABLE SecondResult ERROR_VARIABLE SecondDiagnostics ) @@ -33,7 +33,7 @@ if(NOT ComparisonResult EQUAL 0) message(FATAL_ERROR "${OUTPUT_KIND} output is not deterministic") endif() -if(OUTPUT_KIND STREQUAL "assembly") +if(OUTPUT_KIND STREQUAL "asm") file(READ "${OUTPUT}" Assembly) if(NOT Assembly MATCHES "\\.attribute arch, \"rv64gc\"" OR NOT Assembly MATCHES "jalr x0, x1, 0") @@ -60,7 +60,7 @@ if(OUTPUT_KIND STREQUAL "assembly") message(FATAL_ERROR "LLVM MC rejected MIR tool assembly: ${AssemblerDiagnostics}") endif() endif() -elseif(OUTPUT_KIND STREQUAL "object") +elseif(OUTPUT_KIND STREQUAL "obj") file(READ "${OUTPUT}" ObjectMagic OFFSET 0 LIMIT 4 HEX) if(NOT ObjectMagic STREQUAL "7f454c46") message(FATAL_ERROR "object output is not an ELF file") diff --git a/backend/tools/MIRTool/MIRToolStageTest.cmake b/backend/tools/MIRTool/MIRToolStageTest.cmake index 25c55c3..0d3ef2e 100644 --- a/backend/tools/MIRTool/MIRToolStageTest.cmake +++ b/backend/tools/MIRTool/MIRToolStageTest.cmake @@ -17,12 +17,24 @@ set( post-ra-mir final-mir ) +set( + StageOptions + --verify + -stop-after=legalizer + -stop-after=regbankselect + -stop-after=instruction-select + -stop-after=twoaddressinstruction + -stop-after=PBQPAllocator + -stop-after=final-encodability-verifier +) +set(StageIndex 0) foreach(Stage IN LISTS Stages) + list(GET StageOptions ${StageIndex} StageOption) set(StageOutput "${WORK_DIRECTORY}/${Stage}.mir") set(RepeatedOutput "${WORK_DIRECTORY}/${Stage}.repeat.mir") set(CanonicalOutput "${WORK_DIRECTORY}/${Stage}.canonical.mir") execute_process( - COMMAND "${TOOL}" --input "${INPUT}" --emit "${Stage}" -o "${StageOutput}" + COMMAND "${TOOL}" "${INPUT}" "${StageOption}" -o "${StageOutput}" RESULT_VARIABLE StageResult ERROR_VARIABLE StageDiagnostics ) @@ -30,7 +42,7 @@ foreach(Stage IN LISTS Stages) message(FATAL_ERROR "${Stage} production failed: ${StageDiagnostics}") endif() execute_process( - COMMAND "${TOOL}" --input "${INPUT}" --emit "${Stage}" -o "${RepeatedOutput}" + COMMAND "${TOOL}" "${INPUT}" "${StageOption}" -o "${RepeatedOutput}" RESULT_VARIABLE RepeatedResult ERROR_VARIABLE RepeatedDiagnostics ) @@ -45,7 +57,7 @@ foreach(Stage IN LISTS Stages) message(FATAL_ERROR "${Stage} output is not deterministic") endif() execute_process( - COMMAND "${TOOL}" --verify --input "${StageOutput}" -o "${CanonicalOutput}" + COMMAND "${TOOL}" --verify "${StageOutput}" -o "${CanonicalOutput}" RESULT_VARIABLE VerifyResult ERROR_VARIABLE VerifyDiagnostics ) @@ -59,31 +71,13 @@ foreach(Stage IN LISTS Stages) if(NOT CanonicalResult EQUAL 0) message(FATAL_ERROR "${Stage} output is not canonical after strict reload") endif() + math(EXPR StageIndex "${StageIndex} + 1") endforeach() -set(NoPassOutput "${WORK_DIRECTORY}/none.mir") -execute_process( - COMMAND - "${TOOL}" --input "${INPUT}" -run-pass=none --emit final-mir -o "${NoPassOutput}" - RESULT_VARIABLE NoPassResult - ERROR_VARIABLE NoPassDiagnostics -) -if(NOT NoPassResult EQUAL 0) - message(FATAL_ERROR "LLVM-compatible none pass failed: ${NoPassDiagnostics}") -endif() -execute_process( - COMMAND "${CMAKE_COMMAND}" -E compare_files "${NoPassOutput}" - "${WORK_DIRECTORY}/prelegalizer-mir.mir" - RESULT_VARIABLE NoPassComparisonResult -) -if(NOT NoPassComparisonResult EQUAL 0) - message(FATAL_ERROR "LLVM-compatible none pass changed canonical MIR") -endif() - set(LLVMContractOutput "${WORK_DIRECTORY}/llvm-contract.mir") execute_process( COMMAND - "${TOOL}" "${INPUT}" -run-pass=none -mtriple=riscv64 + "${TOOL}" --verify "${INPUT}" -mtriple=riscv64 -mattr=+m,+a,+f,+d,+c -relocation-model=pic -code-model=small -simplify-mir -verify-machineinstrs -o "${LLVMContractOutput}" RESULT_VARIABLE LLVMContractResult @@ -100,13 +94,7 @@ endif() foreach( RemovedOption IN ITEMS - --run-pass=none - --passes=none - --stop-after=legalizer - --print-before=legalizer --features=+m - --relocation-model=pic - --code-model=small --output=- ) execute_process( @@ -122,7 +110,7 @@ endforeach() set(PassList "${WORK_DIRECTORY}/passes.txt") execute_process( - COMMAND "${TOOL}" --list-passes --input "${INPUT}" -o "${PassList}" + COMMAND "${TOOL}" --list-passes "${INPUT}" -o "${PassList}" RESULT_VARIABLE ListResult ERROR_VARIABLE ListDiagnostics ) @@ -130,7 +118,7 @@ if(NOT ListResult EQUAL 0) message(FATAL_ERROR "pass listing failed: ${ListDiagnostics}") endif() file(READ "${PassList}" PassListText) -foreach(RequiredPass IN ITEMS legalizer regbankselect instruction-select PrologueEpilogueInsertion) +foreach(RequiredPass IN ITEMS legalizer regbankselect instruction-select prologepilog) if(NOT PassListText MATCHES "(^|\n)${RequiredPass}(\n|$)") message(FATAL_ERROR "canonical pass list is missing ${RequiredPass}") endif() @@ -139,7 +127,7 @@ endforeach() set(LegalizedOutput "${WORK_DIRECTORY}/run-pass.mir") execute_process( COMMAND - "${TOOL}" --input "${INPUT}" -run-pass legalizer --emit legalized-mir -o + "${TOOL}" "${INPUT}" -run-pass legalizer -o "${LegalizedOutput}" RESULT_VARIABLE RunPassResult ERROR_VARIABLE RunPassDiagnostics @@ -151,7 +139,7 @@ endif() set(RegBankOutput "${WORK_DIRECTORY}/passes.mir") execute_process( COMMAND - "${TOOL}" --input "${INPUT}" -passes legalizer,regbankselect --emit regbank-mir -o + "${TOOL}" "${INPUT}" -passes legalizer,regbankselect -o "${RegBankOutput}" RESULT_VARIABLE PassesResult ERROR_VARIABLE PassesDiagnostics @@ -163,7 +151,7 @@ endif() set(StoppedOutput "${WORK_DIRECTORY}/stopped.mir") execute_process( COMMAND - "${TOOL}" --input "${INPUT}" -stop-after legalizer --emit final-mir -o + "${TOOL}" "${INPUT}" -stop-after legalizer -o "${StoppedOutput}" RESULT_VARIABLE StopResult ERROR_VARIABLE StopDiagnostics @@ -172,7 +160,7 @@ if(NOT StopResult EQUAL 0) message(FATAL_ERROR "stop-after control failed: ${StopDiagnostics}") endif() execute_process( - COMMAND "${TOOL}" --verify --input "${StoppedOutput}" + COMMAND "${TOOL}" --verify "${StoppedOutput}" RESULT_VARIABLE StopVerifyResult ERROR_VARIABLE StopVerifyDiagnostics ) @@ -182,8 +170,7 @@ endif() execute_process( COMMAND - "${TOOL}" --input "${INPUT}" --emit legalized-mir -print-before legalizer -print-after - legalizer -o "${WORK_DIRECTORY}/printed.mir" + "${TOOL}" "${INPUT}" -filetype=null -print-before legalizer -print-after legalizer RESULT_VARIABLE PrintResult ERROR_VARIABLE PrintDiagnostics ) @@ -197,8 +184,7 @@ endif() execute_process( COMMAND - "${TOOL}" --input "${INPUT}" --emit final-mir --stage-snapshots -o - "${WORK_DIRECTORY}/snapshot-final.mir" + "${TOOL}" "${INPUT}" -filetype=null --stage-snapshots RESULT_VARIABLE SnapshotResult ERROR_VARIABLE SnapshotDiagnostics ) diff --git a/backend/unittests/Tooling/BackendManifestTest.cpp b/backend/unittests/Tooling/BackendManifestTest.cpp index 36a023c..2e2a04c 100644 --- a/backend/unittests/Tooling/BackendManifestTest.cpp +++ b/backend/unittests/Tooling/BackendManifestTest.cpp @@ -97,11 +97,11 @@ int main() { if (!keyDiffers(Base, Changed, Input, *Fingerprint)) return tooling_test::fail("cache key must include the data layout"); Changed = Base; - Changed.Relocation = rcc::tooling::RelocationModel::Static; + Changed.Relocation = rcc::RelocationModel::Static; if (!keyDiffers(Base, Changed, Input, *Fingerprint)) return tooling_test::fail("cache key must include the relocation model"); Changed = Base; - Changed.Code = rcc::tooling::CodeModel::Medium; + Changed.Code = rcc::CodeModel::Medium; if (!keyDiffers(Base, Changed, Input, *Fingerprint)) return tooling_test::fail("cache key must include the code model"); Changed = Base; @@ -121,7 +121,7 @@ int main() { if (!keyDiffers(Base, Changed, Input, *Fingerprint)) return tooling_test::fail("cache key must include assembler options"); Changed = Base; - Changed.Optimization = rcc::tooling::OptimizationLevel::O3; + Changed.Optimization = rcc::OptimizationLevel::O3; if (!keyDiffers(Base, Changed, Input, *Fingerprint)) return tooling_test::fail("cache key must include the optimization level"); Changed = Base; diff --git a/backend/unittests/Tooling/PipelineDriverTest.cpp b/backend/unittests/Tooling/PipelineDriverTest.cpp index 273de52..473b444 100644 --- a/backend/unittests/Tooling/PipelineDriverTest.cpp +++ b/backend/unittests/Tooling/PipelineDriverTest.cpp @@ -195,7 +195,7 @@ int main() { return tooling_test::fail(PrintInput.error().message()); rcc::tooling::PipelineControls PrintControls; PrintControls.PrintBefore = {"legalizer"}; - PrintControls.PrintAfter = {"legalizer#1"}; + PrintControls.PrintAfter = {"legalizer"}; auto PrintPoints = rcc::tooling::runRV64GCPipeline(PrintInput->Document, *Target, Invocation, PrintControls); if (!PrintPoints || PrintPoints->Snapshots.size() != 2 || @@ -209,7 +209,7 @@ int main() { if (!StopInput) return tooling_test::fail(StopInput.error().message()); rcc::tooling::PipelineControls StopControls; - StopControls.StopAfter = "legalizer#1"; + StopControls.StopAfter = "legalizer,0"; auto Stopped = rcc::tooling::runRV64GCPipeline(StopInput->Document, *Target, Invocation, StopControls); const rcc::MachineFunction *StoppedFunction = StopInput->Document.unit().functionAt(0); @@ -221,9 +221,9 @@ int main() { Stopped->ExecutedPasses[1].Pass != "legalizer") { return tooling_test::fail("stop-after must stop at the selected pass occurrence"); } - StopControls.StopAfter = "legalizer#0"; + StopControls.StopAfter = "legalizer,-1"; if (rcc::tooling::runRV64GCPipeline(StopInput->Document, *Target, Invocation, StopControls)) - return tooling_test::fail("pipeline controls must reject occurrence zero"); + return tooling_test::fail("pipeline controls must reject a negative pass instance"); rcc::tooling::BackendInvocation MixedPipeline = Invocation; MixedPipeline.PassPipeline = {"default", "legalizer"}; @@ -234,20 +234,6 @@ int main() { if (rcc::tooling::runRV64GCPipeline(MixedInput->Document, *Target, MixedPipeline)) return tooling_test::fail("named passes must not be mixed with the default pipeline marker"); - rcc::tooling::BackendInvocation NoPassInvocation = Invocation; - NoPassInvocation.PassPipeline = {"none"}; - auto NoPassInput = - rcc::tooling::parseAndCanonicalizeMIR("no-pass.mir", *Source, *Target, NoPassInvocation); - if (!NoPassInput) - return tooling_test::fail(NoPassInput.error().message()); - const std::string NoPassExpected = NoPassInput->Text; - auto NoPassRun = rcc::tooling::runBackend(std::move(*NoPassInput), *Target, NoPassInvocation, - rcc::tooling::BackendOutputKind::FinalMIR); - if (!NoPassRun || !NoPassRun->Pipeline.ExecutedPasses.empty() || - NoPassRun->text() != NoPassExpected) { - return tooling_test::fail("the LLVM-compatible none pass must preserve canonical MIR"); - } - if (!SelectedMIR) return tooling_test::fail("selected MIR stage was not captured"); auto LaterInput = |
