aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--backend/include/rcc/Config/Targets.def7
-rw-r--r--backend/include/rcc/MC/TargetRegistry.h89
-rw-r--r--backend/include/rcc/Support/TargetSelect.h18
-rw-r--r--backend/include/rcc/Target/RISCV/RISCVPipeline.h14
-rw-r--r--backend/include/rcc/Target/RISCV/RISCVSubtarget.h8
-rw-r--r--backend/include/rcc/Target/TargetMachine.h69
-rw-r--r--backend/include/rcc/Target/TargetOptions.h49
-rw-r--r--backend/include/rcc/Tooling/BackendDriver.h14
-rw-r--r--backend/include/rcc/Tooling/BackendInvocation.h18
-rw-r--r--backend/include/rcc/Tooling/PipelineDriver.h6
-rw-r--r--backend/lib/MC/CMakeLists.txt4
-rw-r--r--backend/lib/MC/TargetRegistry.cpp73
-rw-r--r--backend/lib/Target/CMakeLists.txt36
-rw-r--r--backend/lib/Target/RISCV/CMakeLists.txt3
-rw-r--r--backend/lib/Target/RISCV/RISCVPipeline.cpp13
-rw-r--r--backend/lib/Target/RISCV/RISCVSubtarget.cpp13
-rw-r--r--backend/lib/Target/RISCV/RISCVTargetMachine.cpp161
-rw-r--r--backend/lib/Target/TargetMachine.cpp18
-rw-r--r--backend/lib/Tooling/BackendDriver.cpp23
-rw-r--r--backend/lib/Tooling/BackendInvocation.cpp72
-rw-r--r--backend/lib/Tooling/CMakeLists.txt3
-rw-r--r--backend/lib/Tooling/MIRFuzzer.cpp20
-rw-r--r--backend/lib/Tooling/PipelineDriver.cpp137
-rw-r--r--backend/tools/MIRTool/MIRToolMain.cpp100
24 files changed, 735 insertions, 233 deletions
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 <memory>
+#include <span>
+#include <string>
+#include <string_view>
+
+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<const std::string> Features);
+ using TargetMachineCtorFn = Expected<std::unique_ptr<TargetMachine>> (*)(
+ 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<const std::string_view> 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<const std::string> Features) const {
+ return DefaultABI(Features);
+ }
+
+ [[nodiscard]] std::span<const std::string_view> baselineFeatures() const noexcept {
+ return BaselineFeatures;
+ }
+
+ [[nodiscard]] Expected<std::unique_ptr<TargetMachine>>
+ 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<const std::string_view> BaselineFeatures;
+ TargetMachineCtorFn TargetMachineCtor = nullptr;
+};
+
+class TargetRegistry final {
+public:
+ static void registerTarget(const Target &RegisteredTarget);
+ [[nodiscard]] static Expected<const Target *> lookupTarget(std::string_view Triple);
+ [[nodiscard]] static Expected<const Target *> 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 <memory>
#include <string>
@@ -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<void> addCanonicalPipeline(MachineFunctionPassManager &Pipeline,
const MachineFunction &Function,
const RISCVSubtarget &Subtarget,
- RISCVPipelineOptions Options = {});
+ TargetPipelineOptions Options = {});
[[nodiscard]] Expected<std::unique_ptr<MachineFunctionPass>>
createCanonicalPipelinePass(std::string_view Name, const RISCVSubtarget &Subtarget,
- RISCVPipelineOptions Options = {});
+ TargetPipelineOptions Options = {});
[[nodiscard]] Expected<std::vector<std::string>>
canonicalPipelinePassNames(const MachineFunction &Function, const RISCVSubtarget &Subtarget);
[[nodiscard]] Expected<std::unique_ptr<TargetMachineOutlinerInfo>>
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<TargetFrameLowering> FrameLoweringInfo;
- mutable std::unique_ptr<TargetCallLowering> CallLoweringInfo;
- mutable std::unique_ptr<InstructionSelector> InstSelector;
- mutable std::unique_ptr<LegalizerInfo> Legalizer;
- mutable std::unique_ptr<RISCVRegisterBankInfo> RegBankInfo;
+ std::unique_ptr<TargetCallLowering> CallLoweringInfo;
+ std::unique_ptr<InstructionSelector> InstSelector;
+ std::unique_ptr<LegalizerInfo> Legalizer;
+ std::unique_ptr<RISCVRegisterBankInfo> RegBankInfo;
std::unique_ptr<TargetSchedulingHooks> SchedulingHooks;
std::unique_ptr<TargetSchedulingModel> 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 <cstdint>
+#include <memory>
+#include <string>
+#include <string_view>
+#include <vector>
+
+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<void>
+ addCodeGenPasses(MachineFunctionPassManager &Pipeline, const MachineFunction &Function,
+ TargetPipelineOptions PipelineOptions) const = 0;
+ [[nodiscard]] virtual Expected<std::unique_ptr<MachineFunctionPass>>
+ createMachinePass(std::string_view Name, TargetPipelineOptions PipelineOptions) const = 0;
+ [[nodiscard]] virtual Expected<std::vector<std::string>>
+ codeGenPassNames(const MachineFunction &Function) const = 0;
+ [[nodiscard]] virtual Expected<std::unique_ptr<TargetMachineOutlinerInfo>>
+ createOutlinerInfo() const = 0;
+ [[nodiscard]] virtual Expected<std::string> emitAssembly(const CompilationUnit &Unit) const = 0;
+ [[nodiscard]] virtual Expected<std::vector<std::uint8_t>>
+ 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 <string>
+#include <vector>
+
+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<std::string> Features;
+ std::string ABI;
+ std::string DataLayout;
+ RelocationModel Relocation = RelocationModel::Static;
+ CodeModel Code = CodeModel::Small;
+ OptimizationLevel Optimization = OptimizationLevel::O2;
+ std::vector<TargetOption> Options;
+ std::string ABILoweringVersion;
+ std::string AssemblerFlavor;
+ std::string AssemblerVersion;
+ std::vector<TargetOption> 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 <string_view>
#include <vector>
-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<BackendRunResult>
-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 <cstdint>
+#include <memory>
#include <optional>
#include <span>
#include <string>
@@ -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<std::string> EnabledActions;
std::string MIRReferenceRevision{LLVMReferenceRevision};
std::string GenericOpcodeVersion{GenericOpcodeReferenceVersion};
- std::string TargetABILoweringVersion{RV64GCTargetABILoweringVersion};
+ std::string TargetABILoweringVersion;
std::string BuildFingerprint{CompilerBuildFingerprint};
[[nodiscard]] Expected<void> canonicalizeAndVerify();
@@ -78,7 +76,9 @@ struct BackendInvocation final {
friend bool operator==(const BackendInvocation &, const BackendInvocation &) = default;
};
-[[nodiscard]] BackendInvocation defaultRV64GCInvocation();
+[[nodiscard]] Expected<BackendInvocation> defaultBackendInvocation(const Target &Target);
+[[nodiscard]] Expected<std::unique_ptr<TargetMachine>>
+createTargetMachine(const BackendInvocation &Invocation);
[[nodiscard]] Expected<std::string>
computeTargetDescriptionFingerprint(const TargetDescription &Target);
[[nodiscard]] Expected<std::string> 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 <cstdint>
@@ -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<PipelineSnapshot> Snapshots;
};
-[[nodiscard]] Expected<void> verifyRV64GCInvocation(const BackendInvocation &Invocation);
[[nodiscard]] Expected<PipelineRunResult>
-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(
"$<BUILD_INTERFACE:${RCC_BACKEND_SOURCE_DIR}/include>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
)
-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 <algorithm>
+#include <string>
+#include <utility>
+#include <vector>
+
+namespace rcc {
+namespace {
+
+[[nodiscard]] std::vector<const Target *> &registeredTargets() {
+ static std::vector<const Target *> Targets;
+ return Targets;
+}
+
+} // namespace
+
+TargetMachineOptions Target::defaultMachineOptions() const {
+ return DefaultOptions();
+}
+
+Expected<std::unique_ptr<TargetMachine>>
+Target::createTargetMachine(TargetMachineOptions Options) const {
+ return TargetMachineCtor(*this, std::move(Options));
+}
+
+void TargetRegistry::registerTarget(const Target &RegisteredTarget) {
+ std::vector<const Target *> &Targets = registeredTargets();
+ if (std::ranges::find(Targets, &RegisteredTarget) == Targets.end())
+ Targets.push_back(&RegisteredTarget);
+}
+
+Expected<const Target *> 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<const Target *> 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
+ "$<BUILD_INTERFACE:${RCC_BACKEND_SOURCE_DIR}/include>"
+ "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
+)
+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 <typename PassT, typename... ArgumentT>
[[nodiscard]] Expected<void> addInitialPipeline(MachineFunctionPassManager &Pipeline,
const RISCVSubtarget &Subtarget,
- RISCVPipelineOptions Options) {
+ TargetPipelineOptions Options) {
auto Added = addPass<GlobalISelCombinerPass>(
Pipeline, giselCombinerTable(), giselCombinerExecutor(), "riscv-prelegalizer-combiner");
if (!Added)
@@ -67,7 +67,7 @@ template <typename PassT, typename... ArgumentT>
[[nodiscard]] Expected<void> 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 <typename PassT, typename... ArgumentT>
[[nodiscard]] Expected<void> addRegisterAllocationPipeline(MachineFunctionPassManager &Pipeline,
const RISCVSubtarget &Subtarget,
- RISCVPipelineOptions Options) {
+ TargetPipelineOptions Options) {
auto Added = addPass<PreRATargetPseudoExpansionPass>(Pipeline, pseudoExpansionInfo());
if (!Added)
return std::unexpected(Added.error());
@@ -104,7 +104,7 @@ template <typename PassT, typename... ArgumentT>
[[nodiscard]] Expected<void> 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 <typename PassT, typename... ArgumentT>
Expected<void> 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<GlobalISelCombinerPass>(
Pipeline, giselCombinerTable(), giselCombinerExecutor(), "riscv-prelegalizer-combiner");
@@ -211,7 +212,7 @@ Expected<void> addCanonicalPipeline(MachineFunctionPassManager &Pipeline,
Expected<std::unique_ptr<MachineFunctionPass>>
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 <array>
#include <cstddef>
#include <cstdlib>
+#include <memory>
#include <string_view>
#include <utility>
@@ -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<RISCVCallLowering>();
+ RegBankInfo = std::make_unique<RISCVRegisterBankInfo>();
+ InstSelector.reset(createRISCVInstructionSelector(*this, *RegBankInfo));
+ Legalizer = std::make_unique<RISCVLegalizerInfo>(*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<RISCVCallLowering>();
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<RISCVLegalizerInfo>(*this);
return Legalizer.get();
}
const RISCVRegisterBankInfo *RISCVSubtarget::getRegBankInfo() const {
- if (!RegBankInfo)
- RegBankInfo = std::make_unique<RISCVRegisterBankInfo>();
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 <algorithm>
+#include <array>
+#include <memory>
+#include <ranges>
+#include <span>
+#include <string>
+#include <string_view>
+#include <utility>
+#include <vector>
+
+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<std::string_view, 1> 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<const std::string> 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<const TargetOption> 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<void>
+ addCodeGenPasses(MachineFunctionPassManager &Pipeline, const MachineFunction &Function,
+ TargetPipelineOptions PipelineOptions) const override {
+ return riscv::addCanonicalPipeline(Pipeline, Function, Subtarget, PipelineOptions);
+ }
+
+ [[nodiscard]] Expected<std::unique_ptr<MachineFunctionPass>>
+ createMachinePass(std::string_view Name, TargetPipelineOptions PipelineOptions) const override {
+ return riscv::createCanonicalPipelinePass(Name, Subtarget, PipelineOptions);
+ }
+
+ [[nodiscard]] Expected<std::vector<std::string>>
+ codeGenPassNames(const MachineFunction &Function) const override {
+ return riscv::canonicalPipelinePassNames(Function, Subtarget);
+ }
+
+ [[nodiscard]] Expected<std::unique_ptr<TargetMachineOutlinerInfo>>
+ createOutlinerInfo() const override {
+ return riscv::createMachineOutlinerInfo(
+ booleanOption(options().Options, "function-sections"),
+ booleanOption(options().Options, "riscv-outliner-regsave"));
+ }
+
+ [[nodiscard]] Expected<std::string> emitAssembly(const CompilationUnit &Unit) const override {
+ return riscv::emitAssembly(Unit, targetDescription());
+ }
+
+ [[nodiscard]] Expected<std::vector<std::uint8_t>>
+ emitObject(const CompilationUnit &Unit) const override {
+ return riscv::emitObject(Unit, targetDescription());
+ }
+
+private:
+ riscv::RISCVSubtarget Subtarget;
+};
+
+[[nodiscard]] Expected<std::unique_ptr<TargetMachine>>
+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<RISCVTargetMachine>(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 <utility>
+
+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 <cstddef>
#include <cstdint>
@@ -61,13 +60,13 @@ std::string_view BackendRunResult::text() const noexcept {
return {reinterpret_cast<const char *>(Output.data()), Output.size()};
}
-Expected<BackendRunResult> runBackend(CanonicalMIR Input, const TargetDescription &Target,
- const BackendInvocation &Invocation, ArtifactKind Output,
- PipelineControls Controls,
+Expected<BackendRunResult> 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<BackendRunResult> 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<BackendRunResult> 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 <algorithm>
#include <cctype>
@@ -374,27 +376,65 @@ std::string BackendInvocation::canonicalText() const {
return Output;
}
-BackendInvocation defaultRV64GCInvocation() {
+Expected<BackendInvocation> 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<std::unique_ptr<TargetMachine>> 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<std::string> 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<std::uint32_t, 3>{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<std::uint64_t, std::uint64_t>;
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 <algorithm>
#include <atomic>
@@ -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<BackendStage> stageAfterPass(std::string_view Pass) noexcept {
if (Pass == "legalizer")
return BackendStage::LegalizedMIR;
@@ -123,16 +117,16 @@ struct FunctionRunResult final {
}
[[nodiscard]] Expected<std::unique_ptr<MachineFunctionPass>>
-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<mir::ReachingDefPrinterPass>();
- return riscv::createCanonicalPipelinePass(Name, Subtarget, Options);
+ return TargetMachine.createMachinePass(Name, Options);
}
[[nodiscard]] Expected<MachineFunctionPassManager::PassList>
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<void> 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<void> 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<FunctionRunResult>
-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<PipelineRunResult>
-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<BackendStage> parseBackendStage(std::string_view Value) {
return makeUnexpected(ErrorCode::InvalidInvocation, "unknown backend stage");
}
-Expected<void> 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<PipelineRunResult> runRV64GCPipeline(mir::MIRDocument &Document,
- const TargetDescription &Target,
+Expected<PipelineRunResult> 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<PipelineRunResult> 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<PipelineRunResult> 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<PipelineRunResult> 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<std::string> Overrides, std::vector<std::
}
}
-[[nodiscard]] std::string normalizeRV64Triple(std::string_view Triple) {
- if (Triple == "riscv64" || Triple == "riscv64-linux-gnu")
- return "riscv64-unknown-linux-gnu";
- return std::string(Triple);
-}
-
[[nodiscard]] Expected<rcc::tooling::BackendOption> parseBackendOption(std::string_view Text,
std::string_view Category) {
const std::size_t Equal = Text.find('=');
@@ -282,8 +277,10 @@ void setBackendOption(std::vector<rcc::tooling::BackendOption> &Options, std::st
return {};
}
-[[nodiscard]] Expected<CommandLine> parseCommandLine(int ArgumentCount, char *Arguments[]) {
+[[nodiscard]] Expected<CommandLine> 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<rcc::tooling::BackendOption> &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<rcc::tooling::BackendOption> &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<void> 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 == "-" ? "<stdin>" : 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<std::string> 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<bool> {
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);