From f89d528efc0228c049c2867dcba886a56bac8619 Mon Sep 17 00:00:00 2001 From: Richard-Qin-X Date: Fri, 28 Aug 2026 18:51:10 +0800 Subject: [CodeGen] Add target machine registry --- backend/include/rcc/Config/Targets.def | 7 + backend/include/rcc/MC/TargetRegistry.h | 89 ++++++++++++ backend/include/rcc/Support/TargetSelect.h | 18 +++ backend/include/rcc/Target/RISCV/RISCVPipeline.h | 14 +- backend/include/rcc/Target/RISCV/RISCVSubtarget.h | 8 +- backend/include/rcc/Target/TargetMachine.h | 69 ++++++++++ backend/include/rcc/Target/TargetOptions.h | 49 +++++++ backend/include/rcc/Tooling/BackendDriver.h | 14 +- backend/include/rcc/Tooling/BackendInvocation.h | 18 +-- backend/include/rcc/Tooling/PipelineDriver.h | 6 +- backend/lib/MC/CMakeLists.txt | 4 +- backend/lib/MC/TargetRegistry.cpp | 73 ++++++++++ backend/lib/Target/CMakeLists.txt | 36 +++++ backend/lib/Target/RISCV/CMakeLists.txt | 3 + backend/lib/Target/RISCV/RISCVPipeline.cpp | 13 +- backend/lib/Target/RISCV/RISCVSubtarget.cpp | 13 +- backend/lib/Target/RISCV/RISCVTargetMachine.cpp | 161 ++++++++++++++++++++++ backend/lib/Target/TargetMachine.cpp | 18 +++ backend/lib/Tooling/BackendDriver.cpp | 23 ++-- backend/lib/Tooling/BackendInvocation.cpp | 72 +++++++--- backend/lib/Tooling/CMakeLists.txt | 3 +- backend/lib/Tooling/MIRFuzzer.cpp | 20 ++- backend/lib/Tooling/PipelineDriver.cpp | 137 ++++++------------ backend/tools/MIRTool/MIRToolMain.cpp | 100 ++++++++------ 24 files changed, 735 insertions(+), 233 deletions(-) create mode 100644 backend/include/rcc/Config/Targets.def create mode 100644 backend/include/rcc/MC/TargetRegistry.h create mode 100644 backend/include/rcc/Support/TargetSelect.h create mode 100644 backend/include/rcc/Target/TargetMachine.h create mode 100644 backend/include/rcc/Target/TargetOptions.h create mode 100644 backend/lib/MC/TargetRegistry.cpp create mode 100644 backend/lib/Target/RISCV/RISCVTargetMachine.cpp create mode 100644 backend/lib/Target/TargetMachine.cpp (limited to 'backend') diff --git a/backend/include/rcc/Config/Targets.def b/backend/include/rcc/Config/Targets.def new file mode 100644 index 0000000..e6cdd96 --- /dev/null +++ b/backend/include/rcc/Config/Targets.def @@ -0,0 +1,7 @@ +#ifndef RCC_TARGET +#define RCC_TARGET(TargetName) +#endif + +RCC_TARGET(RISCV) + +#undef RCC_TARGET diff --git a/backend/include/rcc/MC/TargetRegistry.h b/backend/include/rcc/MC/TargetRegistry.h new file mode 100644 index 0000000..3e1de7c --- /dev/null +++ b/backend/include/rcc/MC/TargetRegistry.h @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_MC_TARGETREGISTRY_H +#define RCC_MC_TARGETREGISTRY_H + +#include "rcc/Support/Error.h" + +#include +#include +#include +#include + +namespace rcc { + +class TargetMachine; +struct TargetMachineOptions; + +class Target final { +public: + using MatchQualityFn = unsigned (*)(std::string_view Triple); + using NormalizeTripleFn = std::string (*)(std::string_view Triple); + using DefaultOptionsFn = TargetMachineOptions (*)(); + using DefaultABIFn = std::string (*)(std::span Features); + using TargetMachineCtorFn = Expected> (*)( + const Target &RegisteredTarget, TargetMachineOptions Options); + + constexpr Target(std::string_view Name, std::string_view Description, bool IsDefault, + MatchQualityFn MatchQuality, NormalizeTripleFn NormalizeTriple, + DefaultOptionsFn DefaultOptions, DefaultABIFn DefaultABI, + std::span BaselineFeatures, + TargetMachineCtorFn TargetMachineCtor) noexcept + : Name(Name), Description(Description), IsDefault(IsDefault), MatchQuality(MatchQuality), + NormalizeTriple(NormalizeTriple), DefaultOptions(DefaultOptions), DefaultABI(DefaultABI), + BaselineFeatures(BaselineFeatures), TargetMachineCtor(TargetMachineCtor) {} + + [[nodiscard]] std::string_view name() const noexcept { + return Name; + } + + [[nodiscard]] std::string_view description() const noexcept { + return Description; + } + + [[nodiscard]] bool isDefault() const noexcept { + return IsDefault; + } + + [[nodiscard]] unsigned matchQuality(std::string_view Triple) const noexcept { + return MatchQuality(Triple); + } + + [[nodiscard]] std::string normalizeTriple(std::string_view Triple) const { + return NormalizeTriple(Triple); + } + + [[nodiscard]] TargetMachineOptions defaultMachineOptions() const; + [[nodiscard]] std::string defaultABI(std::span Features) const { + return DefaultABI(Features); + } + + [[nodiscard]] std::span baselineFeatures() const noexcept { + return BaselineFeatures; + } + + [[nodiscard]] Expected> + createTargetMachine(TargetMachineOptions Options) const; + +private: + std::string_view Name; + std::string_view Description; + bool IsDefault = false; + MatchQualityFn MatchQuality = nullptr; + NormalizeTripleFn NormalizeTriple = nullptr; + DefaultOptionsFn DefaultOptions = nullptr; + DefaultABIFn DefaultABI = nullptr; + std::span BaselineFeatures; + TargetMachineCtorFn TargetMachineCtor = nullptr; +}; + +class TargetRegistry final { +public: + static void registerTarget(const Target &RegisteredTarget); + [[nodiscard]] static Expected lookupTarget(std::string_view Triple); + [[nodiscard]] static Expected defaultTarget(); +}; + +} // namespace rcc + +#endif // RCC_MC_TARGETREGISTRY_H diff --git a/backend/include/rcc/Support/TargetSelect.h b/backend/include/rcc/Support/TargetSelect.h new file mode 100644 index 0000000..f56090b --- /dev/null +++ b/backend/include/rcc/Support/TargetSelect.h @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_SUPPORT_TARGETSELECT_H +#define RCC_SUPPORT_TARGETSELECT_H + +namespace rcc { + +#define RCC_TARGET(TargetName) void initialize##TargetName##Target(); +#include "rcc/Config/Targets.def" + +inline void initializeAllTargets() { +#define RCC_TARGET(TargetName) initialize##TargetName##Target(); +#include "rcc/Config/Targets.def" +} + +} // namespace rcc + +#endif // RCC_SUPPORT_TARGETSELECT_H diff --git a/backend/include/rcc/Target/RISCV/RISCVPipeline.h b/backend/include/rcc/Target/RISCV/RISCVPipeline.h index 3e8ea3d..f556ded 100644 --- a/backend/include/rcc/Target/RISCV/RISCVPipeline.h +++ b/backend/include/rcc/Target/RISCV/RISCVPipeline.h @@ -3,10 +3,10 @@ #ifndef RCC_TARGET_RISCV_RISCVPIPELINE_H #define RCC_TARGET_RISCV_RISCVPIPELINE_H -#include "rcc/CodeGen/CommandFlags.h" #include "rcc/CodeGen/MachinePassManager.h" #include "rcc/Support/Error.h" #include "rcc/Target/RISCV/RISCVSubtarget.h" +#include "rcc/Target/TargetMachine.h" #include #include @@ -21,21 +21,13 @@ class TargetMachineOutlinerInfo; namespace riscv { -struct RISCVPipelineOptions final { - OptimizationLevel Optimization = OptimizationLevel::O2; - bool UseTargetCopyInstructions = false; - GlobalISelAbortMode GlobalISelAbort = GlobalISelAbortMode::Enable; - bool DebugMachineScheduler = false; - bool DebugPrologueEpilogue = false; -}; - [[nodiscard]] Expected addCanonicalPipeline(MachineFunctionPassManager &Pipeline, const MachineFunction &Function, const RISCVSubtarget &Subtarget, - RISCVPipelineOptions Options = {}); + TargetPipelineOptions Options = {}); [[nodiscard]] Expected> createCanonicalPipelinePass(std::string_view Name, const RISCVSubtarget &Subtarget, - RISCVPipelineOptions Options = {}); + TargetPipelineOptions Options = {}); [[nodiscard]] Expected> canonicalPipelinePassNames(const MachineFunction &Function, const RISCVSubtarget &Subtarget); [[nodiscard]] Expected> diff --git a/backend/include/rcc/Target/RISCV/RISCVSubtarget.h b/backend/include/rcc/Target/RISCV/RISCVSubtarget.h index 52e4b03..a5ba01a 100644 --- a/backend/include/rcc/Target/RISCV/RISCVSubtarget.h +++ b/backend/include/rcc/Target/RISCV/RISCVSubtarget.h @@ -142,10 +142,10 @@ private: CodeModel Code; RISCVABI ABI; std::unique_ptr FrameLoweringInfo; - mutable std::unique_ptr CallLoweringInfo; - mutable std::unique_ptr InstSelector; - mutable std::unique_ptr Legalizer; - mutable std::unique_ptr RegBankInfo; + std::unique_ptr CallLoweringInfo; + std::unique_ptr InstSelector; + std::unique_ptr Legalizer; + std::unique_ptr RegBankInfo; std::unique_ptr SchedulingHooks; std::unique_ptr SchedulingModel; }; diff --git a/backend/include/rcc/Target/TargetMachine.h b/backend/include/rcc/Target/TargetMachine.h new file mode 100644 index 0000000..e45b8ca --- /dev/null +++ b/backend/include/rcc/Target/TargetMachine.h @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_TARGET_TARGETMACHINE_H +#define RCC_TARGET_TARGETMACHINE_H + +#include "rcc/CodeGen/MachineOutliner.h" +#include "rcc/CodeGen/MachinePassManager.h" +#include "rcc/CodeGen/TargetDescription.h" +#include "rcc/Support/Error.h" +#include "rcc/Target/TargetOptions.h" + +#include +#include +#include +#include +#include + +namespace rcc { + +class CompilationUnit; +class MachineFunction; +class Target; + +class TargetMachine { +public: + TargetMachine(const TargetMachine &) = delete; + TargetMachine &operator=(const TargetMachine &) = delete; + TargetMachine(TargetMachine &&) = delete; + TargetMachine &operator=(TargetMachine &&) = delete; + virtual ~TargetMachine(); + + [[nodiscard]] const Target &target() const noexcept { + return RegisteredTarget; + } + + [[nodiscard]] const TargetDescription &targetDescription() const noexcept { + return Description; + } + + [[nodiscard]] const TargetMachineOptions &options() const noexcept { + return Options; + } + + [[nodiscard]] virtual Expected + addCodeGenPasses(MachineFunctionPassManager &Pipeline, const MachineFunction &Function, + TargetPipelineOptions PipelineOptions) const = 0; + [[nodiscard]] virtual Expected> + createMachinePass(std::string_view Name, TargetPipelineOptions PipelineOptions) const = 0; + [[nodiscard]] virtual Expected> + codeGenPassNames(const MachineFunction &Function) const = 0; + [[nodiscard]] virtual Expected> + createOutlinerInfo() const = 0; + [[nodiscard]] virtual Expected emitAssembly(const CompilationUnit &Unit) const = 0; + [[nodiscard]] virtual Expected> + emitObject(const CompilationUnit &Unit) const = 0; + +protected: + TargetMachine(const Target &RegisteredTarget, TargetMachineOptions Options, + TargetDescription Description); + +private: + const Target &RegisteredTarget; + TargetMachineOptions Options; + TargetDescription Description; +}; + +} // namespace rcc + +#endif // RCC_TARGET_TARGETMACHINE_H diff --git a/backend/include/rcc/Target/TargetOptions.h b/backend/include/rcc/Target/TargetOptions.h new file mode 100644 index 0000000..1db183c --- /dev/null +++ b/backend/include/rcc/Target/TargetOptions.h @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_TARGET_TARGETOPTIONS_H +#define RCC_TARGET_TARGETOPTIONS_H + +#include "rcc/CodeGen/CommandFlags.h" + +#include +#include + +namespace rcc { + +struct TargetOption final { + std::string Name; + std::string Value; + + friend bool operator==(const TargetOption &, const TargetOption &) = default; +}; + +struct TargetMachineOptions final { + std::string Triple; + std::string CPU; + std::string TuneCPU; + std::vector Features; + std::string ABI; + std::string DataLayout; + RelocationModel Relocation = RelocationModel::Static; + CodeModel Code = CodeModel::Small; + OptimizationLevel Optimization = OptimizationLevel::O2; + std::vector Options; + std::string ABILoweringVersion; + std::string AssemblerFlavor; + std::string AssemblerVersion; + std::vector AssemblerOptions; + + friend bool operator==(const TargetMachineOptions &, const TargetMachineOptions &) = default; +}; + +struct TargetPipelineOptions final { + OptimizationLevel Optimization = OptimizationLevel::O2; + bool UseTargetCopyInstructions = false; + GlobalISelAbortMode GlobalISelAbort = GlobalISelAbortMode::Enable; + bool DebugMachineScheduler = false; + bool DebugPrologueEpilogue = false; +}; + +} // namespace rcc + +#endif // RCC_TARGET_TARGETOPTIONS_H diff --git a/backend/include/rcc/Tooling/BackendDriver.h b/backend/include/rcc/Tooling/BackendDriver.h index 8117a0c..2003983 100644 --- a/backend/include/rcc/Tooling/BackendDriver.h +++ b/backend/include/rcc/Tooling/BackendDriver.h @@ -13,11 +13,7 @@ #include #include -namespace rcc { - -class TargetDescription; - -namespace tooling { +namespace rcc::tooling { struct BackendRunResult final { ArtifactKind Kind = ArtifactKind::FinalMIR; @@ -29,11 +25,9 @@ struct BackendRunResult final { }; [[nodiscard]] Expected -runBackend(CanonicalMIR Input, const TargetDescription &Target, const BackendInvocation &Invocation, - ArtifactKind Output, PipelineControls Controls = {}, - MachinePassInstrumentation *Instrumentation = nullptr); +runBackend(CanonicalMIR Input, const BackendInvocation &Invocation, ArtifactKind Output, + PipelineControls Controls = {}, MachinePassInstrumentation *Instrumentation = nullptr); -} // namespace tooling -} // namespace rcc +} // namespace rcc::tooling #endif // RCC_TOOLING_BACKENDDRIVER_H diff --git a/backend/include/rcc/Tooling/BackendInvocation.h b/backend/include/rcc/Tooling/BackendInvocation.h index 504dc3a..c50148a 100644 --- a/backend/include/rcc/Tooling/BackendInvocation.h +++ b/backend/include/rcc/Tooling/BackendInvocation.h @@ -5,8 +5,10 @@ #include "rcc/CodeGen/CommandFlags.h" #include "rcc/Support/Error.h" +#include "rcc/Target/TargetOptions.h" #include +#include #include #include #include @@ -16,6 +18,8 @@ namespace rcc { class TargetDescription; +class Target; +class TargetMachine; namespace tooling { @@ -23,7 +27,6 @@ inline constexpr std::uint32_t BackendInvocationSchemaVersion = 1; inline constexpr std::string_view LLVMReferenceRevision = "2b40c303e79f64c5c7642032554eda026594d604"; inline constexpr std::string_view GenericOpcodeReferenceVersion = "rcc-generic-opcode-v1"; -inline constexpr std::string_view RV64GCTargetABILoweringVersion = "rcc-rv64gc-lp64d-v1"; inline constexpr std::string_view CompilerBuildFingerprint = "rcc-backend-0.1.0-stage17"; enum class LayoutOwnership : std::uint8_t { @@ -32,12 +35,7 @@ enum class LayoutOwnership : std::uint8_t { ExternalRelaxation, }; -struct BackendOption final { - std::string Name; - std::string Value; - - friend bool operator==(const BackendOption &, const BackendOption &) = default; -}; +using BackendOption = TargetOption; struct DeterminismOptions final { std::uint64_t RandomSeed = 0; @@ -69,7 +67,7 @@ struct BackendInvocation final { std::vector EnabledActions; std::string MIRReferenceRevision{LLVMReferenceRevision}; std::string GenericOpcodeVersion{GenericOpcodeReferenceVersion}; - std::string TargetABILoweringVersion{RV64GCTargetABILoweringVersion}; + std::string TargetABILoweringVersion; std::string BuildFingerprint{CompilerBuildFingerprint}; [[nodiscard]] Expected canonicalizeAndVerify(); @@ -78,7 +76,9 @@ struct BackendInvocation final { friend bool operator==(const BackendInvocation &, const BackendInvocation &) = default; }; -[[nodiscard]] BackendInvocation defaultRV64GCInvocation(); +[[nodiscard]] Expected defaultBackendInvocation(const Target &Target); +[[nodiscard]] Expected> +createTargetMachine(const BackendInvocation &Invocation); [[nodiscard]] Expected computeTargetDescriptionFingerprint(const TargetDescription &Target); [[nodiscard]] Expected computeCacheKey(std::string_view CanonicalMIR, diff --git a/backend/include/rcc/Tooling/PipelineDriver.h b/backend/include/rcc/Tooling/PipelineDriver.h index c01650c..ce88e64 100644 --- a/backend/include/rcc/Tooling/PipelineDriver.h +++ b/backend/include/rcc/Tooling/PipelineDriver.h @@ -5,6 +5,7 @@ #include "rcc/CodeGen/MIRParser/MIRParser.h" #include "rcc/CodeGen/MachinePassManager.h" +#include "rcc/Target/TargetMachine.h" #include "rcc/Tooling/BackendInvocation.h" #include @@ -15,8 +16,6 @@ namespace rcc { -class TargetDescription; - namespace tooling { enum class BackendStage : std::uint8_t { @@ -72,9 +71,8 @@ struct PipelineRunResult final { std::vector Snapshots; }; -[[nodiscard]] Expected verifyRV64GCInvocation(const BackendInvocation &Invocation); [[nodiscard]] Expected -runRV64GCPipeline(mir::MIRDocument &Document, const TargetDescription &Target, +runTargetPipeline(mir::MIRDocument &Document, const TargetMachine &TargetMachine, const BackendInvocation &Invocation, PipelineControls Controls = {}, MachinePassInstrumentation *Instrumentation = nullptr); [[nodiscard]] BackendStage stageForFunction(const MachineFunction &Function) noexcept; diff --git a/backend/lib/MC/CMakeLists.txt b/backend/lib/MC/CMakeLists.txt index 330ede3..b314c58 100644 --- a/backend/lib/MC/CMakeLists.txt +++ b/backend/lib/MC/CMakeLists.txt @@ -14,6 +14,7 @@ set( MCObjectStreamer.cpp MCSection.cpp MCStreamer.cpp + TargetRegistry.cpp ) set( RCCBackendMCHeaders @@ -33,6 +34,7 @@ set( "${RCC_BACKEND_SOURCE_DIR}/include/rcc/MC/MCSection.h" "${RCC_BACKEND_SOURCE_DIR}/include/rcc/MC/MCStreamer.h" "${RCC_BACKEND_SOURCE_DIR}/include/rcc/MC/MCSymbol.h" + "${RCC_BACKEND_SOURCE_DIR}/include/rcc/MC/TargetRegistry.h" ) add_library(RCCBackendMC ${RCCBackendMCSources}) @@ -46,7 +48,7 @@ target_include_directories( "$" "$" ) -target_link_libraries(RCCBackendMC PUBLIC RCCBackend::Support) +target_link_libraries(RCCBackendMC PUBLIC RCCBackend::Support RCCBackend::Target) set_target_properties( RCCBackendMC diff --git a/backend/lib/MC/TargetRegistry.cpp b/backend/lib/MC/TargetRegistry.cpp new file mode 100644 index 0000000..217f59b --- /dev/null +++ b/backend/lib/MC/TargetRegistry.cpp @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "rcc/MC/TargetRegistry.h" + +#include "rcc/Target/TargetMachine.h" + +#include +#include +#include +#include + +namespace rcc { +namespace { + +[[nodiscard]] std::vector ®isteredTargets() { + static std::vector Targets; + return Targets; +} + +} // namespace + +TargetMachineOptions Target::defaultMachineOptions() const { + return DefaultOptions(); +} + +Expected> +Target::createTargetMachine(TargetMachineOptions Options) const { + return TargetMachineCtor(*this, std::move(Options)); +} + +void TargetRegistry::registerTarget(const Target &RegisteredTarget) { + std::vector &Targets = registeredTargets(); + if (std::ranges::find(Targets, &RegisteredTarget) == Targets.end()) + Targets.push_back(&RegisteredTarget); +} + +Expected TargetRegistry::lookupTarget(std::string_view Triple) { + const Target *Best = nullptr; + unsigned BestQuality = 0; + for (const Target *Candidate : registeredTargets()) { + const unsigned Quality = Candidate->matchQuality(Triple); + if (Quality > BestQuality) { + Best = Candidate; + BestQuality = Quality; + } else if (Quality != 0 && Quality == BestQuality) { + return makeUnexpected(ErrorCode::InvalidInvocation, + "target triple matches multiple registered targets"); + } + } + if (Best == nullptr) { + return makeUnexpected(ErrorCode::Unsupported, + "no registered target supports triple '" + std::string(Triple) + "'"); + } + return Best; +} + +Expected TargetRegistry::defaultTarget() { + const Target *Default = nullptr; + for (const Target *Candidate : registeredTargets()) { + if (!Candidate->isDefault()) + continue; + if (Default != nullptr) { + return makeUnexpected(ErrorCode::InternalError, + "multiple targets are registered as the default target"); + } + Default = Candidate; + } + if (Default == nullptr) + return makeUnexpected(ErrorCode::InternalError, "no default target is registered"); + return Default; +} + +} // namespace rcc diff --git a/backend/lib/Target/CMakeLists.txt b/backend/lib/Target/CMakeLists.txt index 341d98d..0c61f57 100644 --- a/backend/lib/Target/CMakeLists.txt +++ b/backend/lib/Target/CMakeLists.txt @@ -1,3 +1,39 @@ # SPDX-License-Identifier: GPL-3.0-or-later +add_library(RCCBackendTarget TargetMachine.cpp) +add_library(RCCBackend::Target ALIAS RCCBackendTarget) + +rcc_backend_configure_target(RCCBackendTarget) + +target_include_directories( + RCCBackendTarget + PUBLIC + "$" + "$" +) +target_link_libraries(RCCBackendTarget PUBLIC RCCBackend::CodeGen) + +set_target_properties( + RCCBackendTarget + PROPERTIES + EXPORT_NAME Target + OUTPUT_NAME RCCBackendTarget +) + +install( + TARGETS RCCBackendTarget + EXPORT RCCBackendTargets + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" +) + +rcc_backend_register_format_files( + "${CMAKE_CURRENT_SOURCE_DIR}/TargetMachine.cpp" + "${RCC_BACKEND_SOURCE_DIR}/include/rcc/Target/TargetMachine.h" + "${RCC_BACKEND_SOURCE_DIR}/include/rcc/Target/TargetOptions.h" + "${RCC_BACKEND_SOURCE_DIR}/include/rcc/Support/TargetSelect.h" +) +rcc_backend_register_tidy_files("${CMAKE_CURRENT_SOURCE_DIR}/TargetMachine.cpp") + add_subdirectory(RISCV) diff --git a/backend/lib/Target/RISCV/CMakeLists.txt b/backend/lib/Target/RISCV/CMakeLists.txt index aca8ad4..2b9c023 100644 --- a/backend/lib/Target/RISCV/CMakeLists.txt +++ b/backend/lib/Target/RISCV/CMakeLists.txt @@ -139,6 +139,7 @@ add_library( RISCVScheduling.cpp RISCVSubtarget.cpp RISCVTarget.cpp + RISCVTargetMachine.cpp RISCVTargetConstant.cpp RISCVTargetObjectFile.cpp "${RCCBackendRISCVGeneratedRegisterHeader}" @@ -170,6 +171,7 @@ target_link_libraries( RCCBackend::AsmPrinter RCCBackend::CodeGen RCCBackend::MC + RCCBackend::Target ) set_target_properties( @@ -232,6 +234,7 @@ rcc_backend_register_format_files( "${CMAKE_CURRENT_SOURCE_DIR}/RISCVScheduling.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/RISCVSubtarget.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/RISCVTarget.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/RISCVTargetMachine.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/RISCVTargetConstant.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/RISCVTargetObjectFile.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/RISCVTargetObjectFile.h" diff --git a/backend/lib/Target/RISCV/RISCVPipeline.cpp b/backend/lib/Target/RISCV/RISCVPipeline.cpp index 61b3888..c34a590 100644 --- a/backend/lib/Target/RISCV/RISCVPipeline.cpp +++ b/backend/lib/Target/RISCV/RISCVPipeline.cpp @@ -47,7 +47,7 @@ template [[nodiscard]] Expected addInitialPipeline(MachineFunctionPassManager &Pipeline, const RISCVSubtarget &Subtarget, - RISCVPipelineOptions Options) { + TargetPipelineOptions Options) { auto Added = addPass( Pipeline, giselCombinerTable(), giselCombinerExecutor(), "riscv-prelegalizer-combiner"); if (!Added) @@ -67,7 +67,7 @@ template [[nodiscard]] Expected addSSAExitPipeline(MachineFunctionPassManager &Pipeline, const RISCVSubtarget &Subtarget, - RISCVPipelineOptions Options) { + TargetPipelineOptions Options) { auto Added = addSelectedSSAOptimizationPipeline( Pipeline, optimizationPipelineInfo(Subtarget, Options.DebugMachineScheduler, Options.DebugPrologueEpilogue)); @@ -84,7 +84,7 @@ template [[nodiscard]] Expected addRegisterAllocationPipeline(MachineFunctionPassManager &Pipeline, const RISCVSubtarget &Subtarget, - RISCVPipelineOptions Options) { + TargetPipelineOptions Options) { auto Added = addPass(Pipeline, pseudoExpansionInfo()); if (!Added) return std::unexpected(Added.error()); @@ -104,7 +104,7 @@ template [[nodiscard]] Expected addCompleteRegistry(MachineFunctionPassManager &Pipeline, const RISCVSubtarget &Subtarget, - RISCVPipelineOptions Options) { + TargetPipelineOptions Options) { auto Added = addInitialPipeline(Pipeline, Subtarget, Options); if (!Added) return std::unexpected(Added.error()); @@ -139,7 +139,8 @@ template Expected addCanonicalPipeline(MachineFunctionPassManager &Pipeline, const MachineFunction &Function, - const RISCVSubtarget &Subtarget, RISCVPipelineOptions Options) { + const RISCVSubtarget &Subtarget, + TargetPipelineOptions Options) { if (!Function.properties().has(MachineFunctionProperty::Legalized)) { auto Added = addPass( Pipeline, giselCombinerTable(), giselCombinerExecutor(), "riscv-prelegalizer-combiner"); @@ -211,7 +212,7 @@ Expected addCanonicalPipeline(MachineFunctionPassManager &Pipeline, Expected> createCanonicalPipelinePass(std::string_view Name, const RISCVSubtarget &Subtarget, - RISCVPipelineOptions Options) { + TargetPipelineOptions Options) { if (Name.empty()) return makeUnexpected(ErrorCode::InvalidArgument, "pipeline pass name cannot be empty"); MachineFunctionPassManager Registry; diff --git a/backend/lib/Target/RISCV/RISCVSubtarget.cpp b/backend/lib/Target/RISCV/RISCVSubtarget.cpp index c97d3cd..5e9efb6 100644 --- a/backend/lib/Target/RISCV/RISCVSubtarget.cpp +++ b/backend/lib/Target/RISCV/RISCVSubtarget.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -199,6 +200,10 @@ RISCVSubtarget::RISCVSubtarget(RISCVSubtargetFeatures Features, RelocationModel : Features(Features), Relocation(Relocation), Code(Code), ABI(ABI), SchedulingHooks(createSchedulingHooks(Features)) { FrameLoweringInfo = createFrameLowering(*this); + CallLoweringInfo = std::make_unique(); + RegBankInfo = std::make_unique(); + InstSelector.reset(createRISCVInstructionSelector(*this, *RegBankInfo)); + Legalizer = std::make_unique(*this); auto Model = createSchedulingModel(*SchedulingHooks); if (!Model) std::abort(); @@ -208,26 +213,18 @@ RISCVSubtarget::RISCVSubtarget(RISCVSubtargetFeatures Features, RelocationModel RISCVSubtarget::~RISCVSubtarget() = default; const TargetCallLowering *RISCVSubtarget::getCallLowering() const { - if (!CallLoweringInfo) - CallLoweringInfo = std::make_unique(); return CallLoweringInfo.get(); } InstructionSelector *RISCVSubtarget::getInstructionSelector() const { - if (!InstSelector) - InstSelector.reset(createRISCVInstructionSelector(*this, *getRegBankInfo())); return InstSelector.get(); } const LegalizerInfo *RISCVSubtarget::getLegalizerInfo() const { - if (!Legalizer) - Legalizer = std::make_unique(*this); return Legalizer.get(); } const RISCVRegisterBankInfo *RISCVSubtarget::getRegBankInfo() const { - if (!RegBankInfo) - RegBankInfo = std::make_unique(); return RegBankInfo.get(); } diff --git a/backend/lib/Target/RISCV/RISCVTargetMachine.cpp b/backend/lib/Target/RISCV/RISCVTargetMachine.cpp new file mode 100644 index 0000000..6f82ce8 --- /dev/null +++ b/backend/lib/Target/RISCV/RISCVTargetMachine.cpp @@ -0,0 +1,161 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "rcc/MC/TargetRegistry.h" +#include "rcc/Target/RISCV/RISCVAssemblyPrinter.h" +#include "rcc/Target/RISCV/RISCVObjectFile.h" +#include "rcc/Target/RISCV/RISCVPipeline.h" +#include "rcc/Target/RISCV/RISCVTarget.h" +#include "rcc/Target/TargetMachine.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace rcc { +namespace { + +constexpr std::string_view RISCV64Triple = "riscv64-unknown-linux-gnu"; +constexpr std::string_view RISCV64CPU = "generic-rv64gc"; +constexpr std::string_view RISCV64DataLayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"; +constexpr std::string_view RISCV64ABILoweringVersion = "rcc-rv64gc-lp64d-v1"; +constexpr std::array RISCV64BaselineFeatures{"+i"}; + +[[nodiscard]] unsigned matchRISCV64Triple(std::string_view Triple) noexcept { + if (Triple == "riscv64" || Triple == "riscv64-linux-gnu" || Triple == RISCV64Triple) + return 20; + return Triple.starts_with("riscv64-") ? 10U : 0U; +} + +[[nodiscard]] std::string normalizeRISCV64Triple(std::string_view Triple) { + if (Triple == "riscv64" || Triple == "riscv64-linux-gnu") + return std::string(RISCV64Triple); + return std::string(Triple); +} + +[[nodiscard]] std::string defaultRISCV64ABI(std::span Features) { + return std::ranges::find(Features, "+d") == Features.end() ? "lp64" : "lp64d"; +} + +[[nodiscard]] TargetMachineOptions defaultRISCV64Options() { + return TargetMachineOptions{ + .Triple = std::string(RISCV64Triple), + .CPU = std::string(RISCV64CPU), + .TuneCPU = std::string(RISCV64CPU), + .Features = {"+i", "+m", "+a", "+f", "+d", "+c", "+zicsr", "+zifencei"}, + .ABI = "lp64d", + .DataLayout = std::string(RISCV64DataLayout), + .Relocation = RelocationModel::Static, + .Code = CodeModel::Small, + .Optimization = OptimizationLevel::O2, + .Options = {{"function-sections", "false"}, + {"omit-frame-pointer", "true"}, + {"stack-realignment", "false"}}, + .ABILoweringVersion = std::string(RISCV64ABILoweringVersion), + .AssemblerFlavor = "rcc-integrated-gnu", + .AssemblerVersion = "rcc-mc-v1", + .AssemblerOptions = {{"relax", "true"}}, + }; +} + +[[nodiscard]] bool booleanOption(std::span Options, + std::string_view Name) noexcept { + const auto Position = std::ranges::find(Options, Name, &TargetOption::Name); + return Position != Options.end() && Position->Value == "true"; +} + +class RISCVTargetMachine final : public TargetMachine { +public: + RISCVTargetMachine(const Target &RegisteredTarget, TargetMachineOptions Options, + TargetDescription Description, riscv::RISCVSubtargetFeatures Features, + RelocationModel Relocation, CodeModel Code, riscv::RISCVABI ABI) + : TargetMachine(RegisteredTarget, std::move(Options), std::move(Description)), + Subtarget(Features, Relocation, Code, ABI) {} + + [[nodiscard]] Expected + addCodeGenPasses(MachineFunctionPassManager &Pipeline, const MachineFunction &Function, + TargetPipelineOptions PipelineOptions) const override { + return riscv::addCanonicalPipeline(Pipeline, Function, Subtarget, PipelineOptions); + } + + [[nodiscard]] Expected> + createMachinePass(std::string_view Name, TargetPipelineOptions PipelineOptions) const override { + return riscv::createCanonicalPipelinePass(Name, Subtarget, PipelineOptions); + } + + [[nodiscard]] Expected> + codeGenPassNames(const MachineFunction &Function) const override { + return riscv::canonicalPipelinePassNames(Function, Subtarget); + } + + [[nodiscard]] Expected> + createOutlinerInfo() const override { + return riscv::createMachineOutlinerInfo( + booleanOption(options().Options, "function-sections"), + booleanOption(options().Options, "riscv-outliner-regsave")); + } + + [[nodiscard]] Expected emitAssembly(const CompilationUnit &Unit) const override { + return riscv::emitAssembly(Unit, targetDescription()); + } + + [[nodiscard]] Expected> + emitObject(const CompilationUnit &Unit) const override { + return riscv::emitObject(Unit, targetDescription()); + } + +private: + riscv::RISCVSubtarget Subtarget; +}; + +[[nodiscard]] Expected> +createRISCVTargetMachine(const Target &RegisteredTarget, TargetMachineOptions Options) { + Options.Triple = RegisteredTarget.normalizeTriple(Options.Triple); + const TargetMachineOptions Defaults = defaultRISCV64Options(); + if (Options.Triple != Defaults.Triple || Options.CPU != Defaults.CPU || + Options.TuneCPU != Defaults.TuneCPU || Options.DataLayout != Defaults.DataLayout) { + return makeUnexpected(ErrorCode::InvalidInvocation, + "backend invocation does not select a supported RV64 target"); + } + if (Options.ABILoweringVersion != RISCV64ABILoweringVersion) { + return makeUnexpected(ErrorCode::InvalidInvocation, + "RISC-V ABI lowering version does not match this build"); + } + auto Features = riscv::RISCVSubtargetFeatures::fromFeatureList(Options.Features); + if (!Features) + return std::unexpected(Features.error()); + auto ABI = riscv::parseRISCVABI(Options.ABI); + if (!ABI) + return std::unexpected(ABI.error()); + if (*ABI == riscv::RISCVABI::LP64D && !Features->has(riscv::RISCVExtension::D)) { + return makeUnexpected(ErrorCode::InvalidInvocation, "RISC-V LP64D requires the D extension"); + } + auto Description = riscv::createTargetDescription(); + if (!Description) + return std::unexpected(Description.error()); + const RelocationModel Relocation = Options.Relocation; + const CodeModel Code = Options.Code; + return std::make_unique(RegisteredTarget, std::move(Options), + std::move(*Description), *Features, Relocation, Code, + *ABI); +} + +const Target &getRISCV64Target() { + static const Target RegisteredTarget( + "riscv64", "64-bit RISC-V", true, matchRISCV64Triple, normalizeRISCV64Triple, + defaultRISCV64Options, defaultRISCV64ABI, RISCV64BaselineFeatures, createRISCVTargetMachine); + return RegisteredTarget; +} + +} // namespace + +void initializeRISCVTarget() { + TargetRegistry::registerTarget(getRISCV64Target()); +} + +} // namespace rcc diff --git a/backend/lib/Target/TargetMachine.cpp b/backend/lib/Target/TargetMachine.cpp new file mode 100644 index 0000000..bc6b704 --- /dev/null +++ b/backend/lib/Target/TargetMachine.cpp @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "rcc/Target/TargetMachine.h" + +#include "rcc/MC/TargetRegistry.h" + +#include + +namespace rcc { + +TargetMachine::TargetMachine(const Target &RegisteredTarget, TargetMachineOptions Options, + TargetDescription Description) + : RegisteredTarget(RegisteredTarget), Options(std::move(Options)), + Description(std::move(Description)) {} + +TargetMachine::~TargetMachine() = default; + +} // namespace rcc diff --git a/backend/lib/Tooling/BackendDriver.cpp b/backend/lib/Tooling/BackendDriver.cpp index fa82c0c..5932335 100644 --- a/backend/lib/Tooling/BackendDriver.cpp +++ b/backend/lib/Tooling/BackendDriver.cpp @@ -4,8 +4,7 @@ #include "rcc/CodeGen/MIRPrinter.h" #include "rcc/CodeGen/MachineFunction.h" -#include "rcc/Target/RISCV/RISCVAssemblyPrinter.h" -#include "rcc/Target/RISCV/RISCVObjectFile.h" +#include "rcc/Target/TargetMachine.h" #include #include @@ -61,13 +60,13 @@ std::string_view BackendRunResult::text() const noexcept { return {reinterpret_cast(Output.data()), Output.size()}; } -Expected runBackend(CanonicalMIR Input, const TargetDescription &Target, - const BackendInvocation &Invocation, ArtifactKind Output, - PipelineControls Controls, +Expected runBackend(CanonicalMIR Input, const BackendInvocation &Invocation, + ArtifactKind Output, PipelineControls Controls, MachinePassInstrumentation *Instrumentation) { - auto InvocationVerification = verifyRV64GCInvocation(Invocation); - if (!InvocationVerification) - return std::unexpected(InvocationVerification.error()); + auto TargetMachine = createTargetMachine(Invocation); + if (!TargetMachine) + return std::unexpected(TargetMachine.error()); + const TargetDescription &Target = (*TargetMachine)->targetDescription(); if (Input.Document.unit().functionCount() == 0) { return makeUnexpected(ErrorCode::InvalidArgument, "backend input must contain at least one machine function"); @@ -101,8 +100,8 @@ Expected runBackend(CanonicalMIR Input, const TargetDescriptio MachinePassInstrumentation LocalInstrumentation; MachinePassInstrumentation *ActiveInstrumentation = Instrumentation == nullptr ? &LocalInstrumentation : Instrumentation; - auto Pipeline = runRV64GCPipeline(Input.Document, Target, Invocation, std::move(Controls), - ActiveInstrumentation); + auto Pipeline = runTargetPipeline(Input.Document, **TargetMachine, Invocation, + std::move(Controls), ActiveInstrumentation); if (!Pipeline) return std::unexpected(Pipeline.error()); @@ -113,12 +112,12 @@ Expected runBackend(CanonicalMIR Input, const TargetDescriptio return std::unexpected(Printed.error()); Bytes = std::move(*Printed); } else if (Output == ArtifactKind::Assembly) { - auto Assembly = riscv::emitAssembly(Input.Document.unit(), Target); + auto Assembly = (*TargetMachine)->emitAssembly(Input.Document.unit()); if (!Assembly) return std::unexpected(Assembly.error()); Bytes.assign(Assembly->begin(), Assembly->end()); } else { - auto Object = riscv::emitObject(Input.Document.unit(), Target); + auto Object = (*TargetMachine)->emitObject(Input.Document.unit()); if (!Object) return std::unexpected(Object.error()); Bytes = std::move(*Object); diff --git a/backend/lib/Tooling/BackendInvocation.cpp b/backend/lib/Tooling/BackendInvocation.cpp index 232d34f..8fbc4d6 100644 --- a/backend/lib/Tooling/BackendInvocation.cpp +++ b/backend/lib/Tooling/BackendInvocation.cpp @@ -7,7 +7,9 @@ #include "rcc/CodeGen/TargetDescription.h" #include "rcc/CodeGen/TargetMIRTextInfo.h" #include "rcc/CodeGen/TargetRegisterInfo.h" +#include "rcc/MC/TargetRegistry.h" #include "rcc/Support/SHA256.h" +#include "rcc/Target/TargetMachine.h" #include #include @@ -374,27 +376,65 @@ std::string BackendInvocation::canonicalText() const { return Output; } -BackendInvocation defaultRV64GCInvocation() { +Expected defaultBackendInvocation(const Target &Target) { + TargetMachineOptions Defaults = Target.defaultMachineOptions(); BackendInvocation Result; - Result.Triple = "riscv64-unknown-linux-gnu"; - Result.CPU = "generic-rv64gc"; - Result.TuneCPU = "generic-rv64gc"; - Result.Features = {"+i", "+m", "+a", "+f", "+d", "+c", "+zicsr", "+zifencei"}; - Result.ABI = "lp64d"; - Result.DataLayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"; - Result.TargetOptions = { - {"function-sections", "false"}, - {"omit-frame-pointer", "true"}, - {"stack-realignment", "false"}, - }; - Result.AssemblerFlavor = "rcc-integrated-gnu"; - Result.AssemblerVersion = "rcc-mc-v1"; - Result.AssemblerOptions = {{"relax", "true"}}; + Result.Triple = std::move(Defaults.Triple); + Result.CPU = std::move(Defaults.CPU); + Result.TuneCPU = std::move(Defaults.TuneCPU); + Result.Features = std::move(Defaults.Features); + Result.ABI = std::move(Defaults.ABI); + Result.DataLayout = std::move(Defaults.DataLayout); + Result.Relocation = Defaults.Relocation; + Result.Code = Defaults.Code; + Result.Optimization = Defaults.Optimization; + Result.TargetOptions = std::move(Defaults.Options); + Result.TargetABILoweringVersion = std::move(Defaults.ABILoweringVersion); + Result.AssemblerFlavor = std::move(Defaults.AssemblerFlavor); + Result.AssemblerVersion = std::move(Defaults.AssemblerVersion); + Result.AssemblerOptions = std::move(Defaults.AssemblerOptions); auto Verified = Result.canonicalizeAndVerify(); - (void)Verified; + if (!Verified) + return std::unexpected(Verified.error()); return Result; } +Expected> createTargetMachine(const BackendInvocation &Invocation) { + BackendInvocation Canonical = Invocation; + auto Verified = Canonical.canonicalizeAndVerify(); + if (!Verified) + return std::unexpected(Verified.error()); + if (Canonical != Invocation) { + return makeUnexpected(ErrorCode::InvalidInvocation, + "backend invocation must be canonicalized before execution"); + } + if (Invocation.MIRReferenceRevision != LLVMReferenceRevision || + Invocation.GenericOpcodeVersion != GenericOpcodeReferenceVersion) { + return makeUnexpected(ErrorCode::InvalidInvocation, + "backend invocation reference versions do not match this build"); + } + auto RegisteredTarget = TargetRegistry::lookupTarget(Invocation.Triple); + if (!RegisteredTarget) + return std::unexpected(RegisteredTarget.error()); + TargetMachineOptions Options{ + .Triple = Invocation.Triple, + .CPU = Invocation.CPU, + .TuneCPU = Invocation.TuneCPU, + .Features = Invocation.Features, + .ABI = Invocation.ABI, + .DataLayout = Invocation.DataLayout, + .Relocation = Invocation.Relocation, + .Code = Invocation.Code, + .Optimization = Invocation.Optimization, + .Options = Invocation.TargetOptions, + .ABILoweringVersion = Invocation.TargetABILoweringVersion, + .AssemblerFlavor = Invocation.AssemblerFlavor, + .AssemblerVersion = Invocation.AssemblerVersion, + .AssemblerOptions = Invocation.AssemblerOptions, + }; + return (*RegisteredTarget)->createTargetMachine(std::move(Options)); +} + Expected computeTargetDescriptionFingerprint(const TargetDescription &Target) { std::string Canonical; appendField(Canonical, "fingerprint-schema", "rcc-target-fingerprint-v1"); diff --git a/backend/lib/Tooling/CMakeLists.txt b/backend/lib/Tooling/CMakeLists.txt index bf20e37..361a776 100644 --- a/backend/lib/Tooling/CMakeLists.txt +++ b/backend/lib/Tooling/CMakeLists.txt @@ -36,8 +36,9 @@ target_link_libraries( RCCBackendTooling PUBLIC RCCBackend::MIR - RCCBackend::RISCV + RCCBackend::MC RCCBackend::Support + RCCBackend::Target ) set_target_properties( diff --git a/backend/lib/Tooling/MIRFuzzer.cpp b/backend/lib/Tooling/MIRFuzzer.cpp index 79e1b50..2ab3b6f 100644 --- a/backend/lib/Tooling/MIRFuzzer.cpp +++ b/backend/lib/Tooling/MIRFuzzer.cpp @@ -14,7 +14,7 @@ #include "rcc/CodeGen/MachineRegisterInfo.h" #include "rcc/CodeGen/MachineVerifier.h" #include "rcc/CodeGen/TargetDescription.h" -#include "rcc/Target/RISCV/RISCVPipeline.h" +#include "rcc/Target/TargetMachine.h" #include "rcc/Tooling/ArtifactStore.h" #include "rcc/Tooling/BackendDriver.h" @@ -262,7 +262,7 @@ private: if (Function == nullptr || isEarlierStage(Stage, stageForFunction(*Function))) { return false; } - auto Run = runBackend(std::move(*Parsed), Target, Invocation, outputForStage(Stage)); + auto Run = runBackend(std::move(*Parsed), Invocation, outputForStage(Stage)); if (!Run) return std::unexpected(Run.error()); auto RoundTrip = verifyCanonicalRoundTrip(std::string(Run->text()), Target, Invocation); @@ -295,14 +295,10 @@ private: const MachineFunction *Function = Parsed->Document.unit().functionAt(0); if (Function == nullptr) return std::unexpected(Error(ErrorCode::InternalError, "pipeline fuzz input has no function")); - auto Features = riscv::RISCVSubtargetFeatures::fromFeatureList(Invocation.Features); - if (!Features) - return std::unexpected(Features.error()); - auto ABI = riscv::parseRISCVABI(Invocation.ABI); - if (!ABI) - return std::unexpected(ABI.error()); - const riscv::RISCVSubtarget Subtarget(*Features, Invocation.Relocation, Invocation.Code, *ABI); - auto Names = riscv::canonicalPipelinePassNames(*Function, Subtarget); + auto TargetMachine = createTargetMachine(Invocation); + if (!TargetMachine) + return std::unexpected(TargetMachine.error()); + auto Names = (*TargetMachine)->codeGenPassNames(*Function); if (!Names) return std::unexpected(Names.error()); PipelineControls Controls; @@ -312,7 +308,7 @@ private: Controls.DetectUnreportedChanges = true; Invocation.Determinism.ThreadCount = std::array{1, 2, 4}[Random.index(3U)]; const std::string Stop = Controls.StopAfter ? *Controls.StopAfter : "end"; - auto Run = runBackend(std::move(*Parsed), Target, Invocation, ArtifactKind::FinalMIR, Controls); + auto Run = runBackend(std::move(*Parsed), Invocation, ArtifactKind::FinalMIR, Controls); if (!Run) return std::unexpected(Run.error()); auto RoundTrip = verifyCanonicalRoundTrip(std::string(Run->text()), Target, Invocation); @@ -486,7 +482,7 @@ using RegisterValues = std::unordered_map; parseAndCanonicalizeMIR("semantic-pipeline.mir", std::string(Canonical), Target, Invocation); if (!CompiledInput) return std::unexpected(CompiledInput.error()); - auto Compiled = runBackend(std::move(*CompiledInput), Target, Invocation, ArtifactKind::FinalMIR); + auto Compiled = runBackend(std::move(*CompiledInput), Invocation, ArtifactKind::FinalMIR); if (!Compiled) return std::unexpected(Compiled.error()); auto Final = parseAndCanonicalizeMIR("semantic-final.mir", std::string(Compiled->text()), Target, diff --git a/backend/lib/Tooling/PipelineDriver.cpp b/backend/lib/Tooling/PipelineDriver.cpp index 72c7dd2..6020979 100644 --- a/backend/lib/Tooling/PipelineDriver.cpp +++ b/backend/lib/Tooling/PipelineDriver.cpp @@ -10,7 +10,7 @@ #include "rcc/CodeGen/MachineStripDebug.h" #include "rcc/CodeGen/MachineVerifier.h" #include "rcc/MIR/ReachingDefPrinter.h" -#include "rcc/Target/RISCV/RISCVPipeline.h" +#include "rcc/Target/TargetMachine.h" #include #include @@ -100,12 +100,6 @@ struct FunctionRunResult final { return false; } -[[nodiscard]] bool booleanTargetOption(const BackendInvocation &Invocation, - std::string_view Name) noexcept { - const auto Option = std::ranges::find(Invocation.TargetOptions, Name, &BackendOption::Name); - return Option != Invocation.TargetOptions.end() && Option->Value == "true"; -} - [[nodiscard]] std::optional stageAfterPass(std::string_view Pass) noexcept { if (Pass == "legalizer") return BackendStage::LegalizedMIR; @@ -123,16 +117,16 @@ struct FunctionRunResult final { } [[nodiscard]] Expected> -createNamedMachinePass(std::string_view Name, const riscv::RISCVSubtarget &Subtarget, - riscv::RISCVPipelineOptions Options = {}) { +createNamedMachinePass(std::string_view Name, const TargetMachine &TargetMachine, + TargetPipelineOptions Options = {}) { if (Name == mir::ReachingDefPrinterPass::name()) return std::make_unique(); - return riscv::createCanonicalPipelinePass(Name, Subtarget, Options); + return TargetMachine.createMachinePass(Name, Options); } [[nodiscard]] Expected createPasses(const MachineFunction &Function, const BackendInvocation &Invocation, - const riscv::RISCVSubtarget &Subtarget, MachinePassManagerOptions Options) { + const TargetMachine &TargetMachine, MachinePassManagerOptions Options) { const auto GlobalISelAbortOption = std::ranges::find( Invocation.TargetOptions, std::string_view{"global-isel-abort"}, &BackendOption::Name); GlobalISelAbortMode GlobalISelAbort = GlobalISelAbortMode::Enable; @@ -146,13 +140,13 @@ createPasses(const MachineFunction &Function, const BackendInvocation &Invocatio const bool DebugMachineScheduler = hasDebugType(Invocation, "machine-scheduler"); const bool DebugPrologueEpilogue = hasDebugType(Invocation, "prologepilog"); if (Invocation.PassPipeline.size() == 1 && Invocation.PassPipeline.front() == "default") { - auto Added = riscv::addCanonicalPipeline( - Pipeline, Function, Subtarget, - riscv::RISCVPipelineOptions{.Optimization = Invocation.Optimization, - .UseTargetCopyInstructions = true, - .GlobalISelAbort = GlobalISelAbort, - .DebugMachineScheduler = DebugMachineScheduler, - .DebugPrologueEpilogue = DebugPrologueEpilogue}); + auto Added = TargetMachine.addCodeGenPasses( + Pipeline, Function, + TargetPipelineOptions{.Optimization = Invocation.Optimization, + .UseTargetCopyInstructions = true, + .GlobalISelAbort = GlobalISelAbort, + .DebugMachineScheduler = DebugMachineScheduler, + .DebugPrologueEpilogue = DebugPrologueEpilogue}); if (!Added) return std::unexpected(Added.error()); } else { @@ -166,12 +160,12 @@ createPasses(const MachineFunction &Function, const BackendInvocation &Invocatio TargetCopyOption != Invocation.TargetOptions.end() && TargetCopyOption->Value == "true"; for (const std::string &Name : Invocation.PassPipeline) { auto Pass = createNamedMachinePass( - Name, Subtarget, - riscv::RISCVPipelineOptions{.Optimization = Invocation.Optimization, - .UseTargetCopyInstructions = UseTargetCopyInstructions, - .GlobalISelAbort = GlobalISelAbort, - .DebugMachineScheduler = DebugMachineScheduler, - .DebugPrologueEpilogue = DebugPrologueEpilogue}); + Name, TargetMachine, + TargetPipelineOptions{.Optimization = Invocation.Optimization, + .UseTargetCopyInstructions = UseTargetCopyInstructions, + .GlobalISelAbort = GlobalISelAbort, + .DebugMachineScheduler = DebugMachineScheduler, + .DebugPrologueEpilogue = DebugPrologueEpilogue}); if (!Pass) return std::unexpected(Pass.error()); auto Added = Pipeline.addPass(std::move(*Pass)); @@ -183,7 +177,7 @@ createPasses(const MachineFunction &Function, const BackendInvocation &Invocatio } [[nodiscard]] Expected validateSelector(std::string_view Selector, bool AllowAll, - const riscv::RISCVSubtarget &Subtarget) { + const TargetMachine &TargetMachine) { if (Selector == "all" && AllowAll) return {}; const std::size_t Comma = Selector.find(','); @@ -192,7 +186,7 @@ createPasses(const MachineFunction &Function, const BackendInvocation &Invocatio if (Name.empty()) return makeUnexpected(ErrorCode::InvalidInvocation, "empty pipeline pass selector"); if (Name != "machine-outliner") { - auto Pass = createNamedMachinePass(Name, Subtarget); + auto Pass = createNamedMachinePass(Name, TargetMachine); if (!Pass) return std::unexpected(Pass.error()); } @@ -211,8 +205,7 @@ createPasses(const MachineFunction &Function, const BackendInvocation &Invocatio } [[nodiscard]] Expected validateControls(const PipelineControls &Controls, - riscv::RISCVSubtargetFeatures Features) { - const riscv::RISCVSubtarget Subtarget(Features); + const TargetMachine &TargetMachine) { if (Controls.StartBefore && Controls.StartAfter) { return makeUnexpected(ErrorCode::InvalidInvocation, "-start-before and -start-after cannot be combined"); @@ -222,32 +215,32 @@ createPasses(const MachineFunction &Function, const BackendInvocation &Invocatio "-stop-before and -stop-after cannot be combined"); } if (Controls.StartBefore) { - auto Result = validateSelector(*Controls.StartBefore, false, Subtarget); + auto Result = validateSelector(*Controls.StartBefore, false, TargetMachine); if (!Result) return Result; } if (Controls.StartAfter) { - auto Result = validateSelector(*Controls.StartAfter, false, Subtarget); + auto Result = validateSelector(*Controls.StartAfter, false, TargetMachine); if (!Result) return Result; } if (Controls.StopBefore) { - auto Result = validateSelector(*Controls.StopBefore, false, Subtarget); + auto Result = validateSelector(*Controls.StopBefore, false, TargetMachine); if (!Result) return Result; } if (Controls.StopAfter) { - auto Result = validateSelector(*Controls.StopAfter, false, Subtarget); + auto Result = validateSelector(*Controls.StopAfter, false, TargetMachine); if (!Result) return Result; } for (const std::string &Selector : Controls.PrintBefore) { - auto Result = validateSelector(Selector, true, Subtarget); + auto Result = validateSelector(Selector, true, TargetMachine); if (!Result) return Result; } for (const std::string &Selector : Controls.PrintAfter) { - auto Result = validateSelector(Selector, true, Subtarget); + auto Result = validateSelector(Selector, true, TargetMachine); if (!Result) return Result; } @@ -278,21 +271,18 @@ captureSnapshot(FunctionRunResult &Result, const mir::MIRDocument &Document, } [[nodiscard]] Expected -runFunction(MachineFunction &Function, mir::MIRDocument &Document, const TargetDescription &Target, - const BackendInvocation &Invocation, const PipelineControls &Controls, - riscv::RISCVSubtargetFeatures Features, bool AllowSnapshots, +runFunction(MachineFunction &Function, mir::MIRDocument &Document, + const TargetMachine &TargetMachine, const BackendInvocation &Invocation, + const PipelineControls &Controls, bool AllowSnapshots, MachinePassInstrumentation *Instrumentation) { FunctionRunResult Result; - auto ABI = riscv::parseRISCVABI(Invocation.ABI); - if (!ABI) - return std::unexpected(ABI.error()); - const riscv::RISCVSubtarget Subtarget(Features, Invocation.Relocation, Invocation.Code, *ABI); + const TargetDescription &Target = TargetMachine.targetDescription(); MachinePassManagerOptions ManagerOptions{ .VerifyBefore = true, .VerifyEach = Controls.VerifyEach, .DetectUnreportedChanges = Controls.DetectUnreportedChanges, }; - auto Passes = createPasses(Function, Invocation, Subtarget, ManagerOptions); + auto Passes = createPasses(Function, Invocation, TargetMachine, ManagerOptions); if (!Passes) return std::unexpected(Passes.error()); MachineFunctionAnalysisManager Analyses; @@ -402,12 +392,9 @@ runFunction(MachineFunction &Function, mir::MIRDocument &Document, const TargetD } [[nodiscard]] Expected -runMachineOutliner(mir::MIRDocument &Document, const TargetDescription &Target, - const BackendInvocation &Invocation, const PipelineControls &Controls, - MachinePassInstrumentation *Instrumentation) { - auto TargetInfo = - riscv::createMachineOutlinerInfo(booleanTargetOption(Invocation, "function-sections"), - booleanTargetOption(Invocation, "riscv-outliner-regsave")); +runMachineOutliner(mir::MIRDocument &Document, const TargetMachine &TargetMachine, + const PipelineControls &Controls, MachinePassInstrumentation *Instrumentation) { + auto TargetInfo = TargetMachine.createOutlinerInfo(); if (!TargetInfo) return std::unexpected(TargetInfo.error()); @@ -434,7 +421,8 @@ runMachineOutliner(mir::MIRDocument &Document, const TargetDescription &Target, auto Registered = registerMachineOptimizationAnalyses(FunctionAnalyses); if (!Registered) return std::unexpected(Registered.error()); - auto Run = Pipeline.run(Document.unit(), Target, UnitAnalyses, FunctionAnalyses, Instrumentation); + auto Run = Pipeline.run(Document.unit(), TargetMachine.targetDescription(), UnitAnalyses, + FunctionAnalyses, Instrumentation); if (!Run) return std::unexpected(Run.error()); PipelineRunResult Result; @@ -507,51 +495,12 @@ Expected parseBackendStage(std::string_view Value) { return makeUnexpected(ErrorCode::InvalidInvocation, "unknown backend stage"); } -Expected verifyRV64GCInvocation(const BackendInvocation &Invocation) { - BackendInvocation Canonical = Invocation; - auto Verified = Canonical.canonicalizeAndVerify(); - if (!Verified) - return std::unexpected(Verified.error()); - if (Canonical != Invocation) { - return makeUnexpected(ErrorCode::InvalidInvocation, - "RV64GC backend invocation must be canonicalized before execution"); - } - const BackendInvocation Expected = defaultRV64GCInvocation(); - auto Features = riscv::RISCVSubtargetFeatures::fromFeatureList(Invocation.Features); - if (!Features) - return std::unexpected(Features.error()); - auto ABI = riscv::parseRISCVABI(Invocation.ABI); - if (!ABI) - return std::unexpected(ABI.error()); - if (*ABI == riscv::RISCVABI::LP64D && !Features->has(riscv::RISCVExtension::D)) { - return makeUnexpected(ErrorCode::InvalidInvocation, "RISC-V LP64D requires the D extension"); - } - if (Invocation.Triple != Expected.Triple || Invocation.CPU != Expected.CPU || - Invocation.TuneCPU != Expected.TuneCPU || Invocation.DataLayout != Expected.DataLayout) { - return makeUnexpected(ErrorCode::InvalidInvocation, - "backend invocation does not select a supported RV64 target"); - } - if (Invocation.MIRReferenceRevision != LLVMReferenceRevision || - Invocation.GenericOpcodeVersion != GenericOpcodeReferenceVersion || - Invocation.TargetABILoweringVersion != RV64GCTargetABILoweringVersion) { - return makeUnexpected(ErrorCode::InvalidInvocation, - "backend invocation reference versions do not match this build"); - } - return {}; -} - -Expected runRV64GCPipeline(mir::MIRDocument &Document, - const TargetDescription &Target, +Expected runTargetPipeline(mir::MIRDocument &Document, + const TargetMachine &TargetMachine, const BackendInvocation &Invocation, PipelineControls Controls, MachinePassInstrumentation *Instrumentation) { - auto InvocationVerification = verifyRV64GCInvocation(Invocation); - if (!InvocationVerification) - return std::unexpected(InvocationVerification.error()); - auto Features = riscv::RISCVSubtargetFeatures::fromFeatureList(Invocation.Features); - if (!Features) - return std::unexpected(Features.error()); - auto ControlVerification = validateControls(Controls, *Features); + auto ControlVerification = validateControls(Controls, TargetMachine); if (!ControlVerification) return std::unexpected(ControlVerification.error()); auto UnitVerification = Document.unit().verify(); @@ -583,7 +532,7 @@ Expected runRV64GCPipeline(mir::MIRDocument &Document, return makeUnexpected(ErrorCode::InvalidInvocation, "machine-outliner cannot be mixed with per-function passes"); } - return runMachineOutliner(Document, Target, Invocation, Controls, ActiveInstrumentation); + return runMachineOutliner(Document, TargetMachine, Controls, ActiveInstrumentation); } const std::size_t FunctionCount = Document.unit().functionCount(); @@ -596,7 +545,7 @@ Expected runRV64GCPipeline(mir::MIRDocument &Document, if (Function == nullptr) return makeUnexpected(ErrorCode::InternalError, "compilation unit contains a null function"); - auto Run = runFunction(*Function, Document, Target, Invocation, Controls, *Features, true, + auto Run = runFunction(*Function, Document, TargetMachine, Invocation, Controls, true, ActiveInstrumentation); if (!Run) return std::unexpected(Run.error()); @@ -617,7 +566,7 @@ Expected runRV64GCPipeline(mir::MIRDocument &Document, Error(ErrorCode::InternalError, "compilation unit contains a null function"); continue; } - auto Run = runFunction(*Function, Document, Target, Invocation, Controls, *Features, false, + auto Run = runFunction(*Function, Document, TargetMachine, Invocation, Controls, false, ActiveInstrumentation); if (!Run) { FunctionResults[Index].Failure = Run.error(); diff --git a/backend/tools/MIRTool/MIRToolMain.cpp b/backend/tools/MIRTool/MIRToolMain.cpp index cfee95d..ae341f8 100644 --- a/backend/tools/MIRTool/MIRToolMain.cpp +++ b/backend/tools/MIRTool/MIRToolMain.cpp @@ -2,9 +2,10 @@ #include "rcc/CodeGen/CommandFlags.h" #include "rcc/CodeGen/MachineFunction.h" +#include "rcc/MC/TargetRegistry.h" #include "rcc/Support/Error.h" -#include "rcc/Target/RISCV/RISCVPipeline.h" -#include "rcc/Target/RISCV/RISCVTarget.h" +#include "rcc/Support/TargetSelect.h" +#include "rcc/Target/TargetMachine.h" #include "rcc/Tooling/ArtifactStore.h" #include "rcc/Tooling/BackendDriver.h" #include "rcc/Tooling/BackendInvocation.h" @@ -64,7 +65,7 @@ struct CommandLine final { std::filesystem::path ReproducerPath; std::filesystem::path CachePath; ArtifactKind Output = ArtifactKind::FinalMIR; - BackendInvocation Invocation = rcc::tooling::defaultRV64GCInvocation(); + BackendInvocation Invocation; rcc::tooling::PipelineControls Controls; rcc::tooling::MIRFuzzOptions FuzzOptions; bool OutputWasSpecified = false; @@ -214,12 +215,6 @@ void applyFeatureOverrides(std::vector Overrides, std::vector parseBackendOption(std::string_view Text, std::string_view Category) { const std::size_t Equal = Text.find('='); @@ -282,8 +277,10 @@ void setBackendOption(std::vector &Options, std::st return {}; } -[[nodiscard]] Expected parseCommandLine(int ArgumentCount, char *Arguments[]) { +[[nodiscard]] Expected parseCommandLine(int ArgumentCount, char *Arguments[], + BackendInvocation DefaultInvocation) { CommandLine Command; + Command.Invocation = std::move(DefaultInvocation); bool ExplicitPipeline = false; bool UsedRunPass = false; bool UsedPasses = false; @@ -699,8 +696,13 @@ void setBackendOption(std::vector &Options, std::st if (Command.ShowHelp) return Command; if (CodeGenFlags.Triple) { - Command.Invocation.Triple = normalizeRV64Triple(*CodeGenFlags.Triple); - Command.Invocation.Features = {"+i"}; + auto SelectedTarget = rcc::TargetRegistry::lookupTarget(*CodeGenFlags.Triple); + if (!SelectedTarget) + return std::unexpected(SelectedTarget.error()); + Command.Invocation.Triple = (*SelectedTarget)->normalizeTriple(*CodeGenFlags.Triple); + Command.Invocation.Features.clear(); + for (std::string_view Feature : (*SelectedTarget)->baselineFeatures()) + Command.Invocation.Features.emplace_back(Feature); } if (CodeGenFlags.CPU) Command.Invocation.CPU = *CodeGenFlags.CPU; @@ -710,9 +712,10 @@ void setBackendOption(std::vector &Options, std::st if (CodeGenFlags.ABI) { Command.Invocation.ABI = *CodeGenFlags.ABI; } else { - const bool HasDoubleFloat = - std::ranges::find(Command.Invocation.Features, "+d") != Command.Invocation.Features.end(); - Command.Invocation.ABI = HasDoubleFloat ? "lp64d" : "lp64"; + auto SelectedTarget = rcc::TargetRegistry::lookupTarget(Command.Invocation.Triple); + if (!SelectedTarget) + return std::unexpected(SelectedTarget.error()); + Command.Invocation.ABI = (*SelectedTarget)->defaultABI(Command.Invocation.Features); } if (CodeGenFlags.Relocation) Command.Invocation.Relocation = *CodeGenFlags.Relocation; @@ -845,7 +848,7 @@ void printActions(const BackendRunResult &Result) { runWithCache(const CommandLine &Command, CanonicalMIR Input, const rcc::TargetDescription &Target, rcc::MachinePassInstrumentation *Instrumentation = nullptr) { if (Command.Cache == CachePolicy::Off) { - return rcc::tooling::runBackend(std::move(Input), Target, Command.Invocation, Command.Output, + return rcc::tooling::runBackend(std::move(Input), Command.Invocation, Command.Output, Command.Controls, Instrumentation); } if (!rcc::tooling::isCacheableArtifact(Command.Output)) { @@ -869,7 +872,7 @@ runWithCache(const CommandLine &Command, CanonicalMIR Input, const rcc::TargetDe } const std::string CanonicalInput = Input.Text; - auto Run = rcc::tooling::runBackend(std::move(Input), Target, Command.Invocation, Command.Output, + auto Run = rcc::tooling::runBackend(std::move(Input), Command.Invocation, Command.Output, Command.Controls, Instrumentation); if (!Run) return std::unexpected(Run.error()); @@ -888,19 +891,24 @@ runWithCache(const CommandLine &Command, CanonicalMIR Input, const rcc::TargetDe } [[nodiscard]] Expected runCommand(const CommandLine &OriginalCommand) { - auto Target = rcc::riscv::createTargetDescription(); - if (!Target) - return std::unexpected(Target.error()); CommandLine Command = OriginalCommand; + auto Machine = rcc::tooling::createTargetMachine(Command.Invocation); + if (!Machine) + return std::unexpected(Machine.error()); + const rcc::TargetDescription &Target = (*Machine)->targetDescription(); if (Command.Action == Operation::Reproduce) { - auto Package = rcc::tooling::loadReproducer(Command.ReproducerPath, *Target); + auto Package = rcc::tooling::loadReproducer(Command.ReproducerPath, Target); if (!Package) return std::unexpected(Package.error()); Command.Output = Package->Manifest.Artifact; Command.Invocation = Package->Manifest.Invocation; Command.ReproducerPath.clear(); - auto Run = runWithCache(Command, std::move(Package->Input), *Target); + auto ReplayMachine = rcc::tooling::createTargetMachine(Command.Invocation); + if (!ReplayMachine) + return std::unexpected(ReplayMachine.error()); + auto Run = + runWithCache(Command, std::move(Package->Input), (*ReplayMachine)->targetDescription()); if (!Run) return std::unexpected(Run.error()); printSnapshots(*Run); @@ -913,7 +921,7 @@ runWithCache(const CommandLine &Command, CanonicalMIR Input, const rcc::TargetDe if (!Source) return std::unexpected(Source.error()); const std::string SourceName = Command.InputPath == "-" ? "" : Command.InputPath; - auto Input = rcc::tooling::parseAndCanonicalizeMIR(SourceName, std::move(*Source), *Target, + auto Input = rcc::tooling::parseAndCanonicalizeMIR(SourceName, std::move(*Source), Target, Command.Invocation); if (!Input) return std::unexpected(Input.error()); @@ -924,21 +932,12 @@ runWithCache(const CommandLine &Command, CanonicalMIR Input, const rcc::TargetDe return {}; } if (Command.Action == Operation::ListPasses) { - auto Features = - rcc::riscv::RISCVSubtargetFeatures::fromFeatureList(Command.Invocation.Features); - if (!Features) - return std::unexpected(Features.error()); - auto ABI = rcc::riscv::parseRISCVABI(Command.Invocation.ABI); - if (!ABI) - return std::unexpected(ABI.error()); - const rcc::riscv::RISCVSubtarget Subtarget(*Features, Command.Invocation.Relocation, - Command.Invocation.Code, *ABI); std::vector Names; for (std::size_t Index = 0; Index < Input->Document.unit().functionCount(); ++Index) { const rcc::MachineFunction *Function = Input->Document.unit().functionAt(Index); if (Function == nullptr) return rcc::makeUnexpected(ErrorCode::InternalError, "MIR input contains a null function"); - auto FunctionNames = rcc::riscv::canonicalPipelinePassNames(*Function, Subtarget); + auto FunctionNames = (*Machine)->codeGenPassNames(*Function); if (!FunctionNames) return std::unexpected(FunctionNames.error()); for (std::string &Name : *FunctionNames) { @@ -954,7 +953,7 @@ runWithCache(const CommandLine &Command, CanonicalMIR Input, const rcc::TargetDe return writeText(Command.OutputPath, Output); } if (Command.Action == Operation::Fuzz) { - auto Result = rcc::tooling::fuzzMIR(Command.InputPath, Input->Text, Command.Invocation, *Target, + auto Result = rcc::tooling::fuzzMIR(Command.InputPath, Input->Text, Command.Invocation, Target, Command.FuzzOptions); if (!Result) return std::unexpected(Result.error()); @@ -978,18 +977,18 @@ runWithCache(const CommandLine &Command, CanonicalMIR Input, const rcc::TargetDe rcc::tooling::MIRReducerOptions Options; Options.Mode = rcc::tooling::ReductionMode::PreserveValidity; auto Reduced = rcc::tooling::reduceMIR(Command.InputPath, Input->Text, Command.Invocation, - *Target, {}, std::move(Options)); + Target, {}, std::move(Options)); if (!Reduced) return std::unexpected(Reduced.error()); return writeText(Command.OutputPath, Reduced->MIR); } if (Command.Action == Operation::ReduceFailure) { auto InitialForRun = rcc::tooling::parseAndCanonicalizeMIR("reducer-initial.mir", Input->Text, - *Target, Command.Invocation); + Target, Command.Invocation); if (!InitialForRun) return std::unexpected(InitialForRun.error()); - auto InitialRun = rcc::tooling::runBackend( - std::move(*InitialForRun), *Target, Command.Invocation, Command.Output, Command.Controls); + auto InitialRun = rcc::tooling::runBackend(std::move(*InitialForRun), Command.Invocation, + Command.Output, Command.Controls); if (InitialRun) { return rcc::makeUnexpected(ErrorCode::ReductionFailed, "failure-preserving reduction requires an initially failing run"); @@ -998,23 +997,23 @@ runWithCache(const CommandLine &Command, CanonicalMIR Input, const rcc::TargetDe const auto Interesting = [&](std::string_view MIR, const BackendInvocation &Invocation) -> Expected { auto Candidate = rcc::tooling::parseAndCanonicalizeMIR("reducer-interesting.mir", - std::string(MIR), *Target, Invocation); + std::string(MIR), Target, Invocation); if (!Candidate) return std::unexpected(Candidate.error()); - auto Run = rcc::tooling::runBackend(std::move(*Candidate), *Target, Invocation, - Command.Output, Command.Controls); + auto Run = rcc::tooling::runBackend(std::move(*Candidate), Invocation, Command.Output, + Command.Controls); return !Run && Run.error().code() == FailureCode; }; rcc::tooling::MIRReducerOptions Options; Options.Mode = rcc::tooling::ReductionMode::PreserveFailure; auto Reduced = rcc::tooling::reduceMIR(Command.InputPath, Input->Text, Command.Invocation, - *Target, Interesting, std::move(Options)); + Target, Interesting, std::move(Options)); if (!Reduced) return std::unexpected(Reduced.error()); return writeText(Command.OutputPath, Reduced->MIR); } - auto Reproducer = writePreExecutionReproducer(Command, *Input, *Target); + auto Reproducer = writePreExecutionReproducer(Command, *Input, Target); if (!Reproducer) return std::unexpected(Reproducer.error()); @@ -1066,7 +1065,7 @@ runWithCache(const CommandLine &Command, CanonicalMIR Input, const rcc::TargetDe FailureDiagnostics.push_back(std::move(Diagnostic)); }); - auto Run = runWithCache(Command, std::move(*Input), *Target, + auto Run = runWithCache(Command, std::move(*Input), Target, Command.ReproducerPath.empty() ? nullptr : &Instrumentation); if (!Run) { if (!Command.ReproducerPath.empty()) { @@ -1113,7 +1112,18 @@ runWithCache(const CommandLine &Command, CanonicalMIR Input, const rcc::TargetDe } // namespace int main(int ArgumentCount, char *Arguments[]) { - auto Command = parseCommandLine(ArgumentCount, Arguments); + rcc::initializeAllTargets(); + auto DefaultTarget = rcc::TargetRegistry::defaultTarget(); + if (!DefaultTarget) { + std::cerr << "rcc-backend-mir: " << DefaultTarget.error().message() << '\n'; + return 1; + } + auto DefaultInvocation = rcc::tooling::defaultBackendInvocation(**DefaultTarget); + if (!DefaultInvocation) { + std::cerr << "rcc-backend-mir: " << DefaultInvocation.error().message() << '\n'; + return 1; + } + auto Command = parseCommandLine(ArgumentCount, Arguments, std::move(*DefaultInvocation)); if (!Command) { std::cerr << "rcc-backend-mir: " << Command.error().message() << '\n'; printUsage(std::cerr); -- cgit v1.2.3