diff options
| author | Richard-Qin-X <richard.qin.001@gmail.com> | 2026-08-28 18:51:10 +0800 |
|---|---|---|
| committer | Richard-Qin-X <richard.qin.001@gmail.com> | 2026-08-28 18:51:10 +0800 |
| commit | f89d528efc0228c049c2867dcba886a56bac8619 (patch) | |
| tree | 7a47f751e729845af1537beee20bc57007d3e21c /backend/lib/Target | |
| parent | 6889b82a5c9ecc6bd178760c66653d7af0121162 (diff) | |
| download | rcc-project-f89d528efc0228c049c2867dcba886a56bac8619.tar.gz rcc-project-f89d528efc0228c049c2867dcba886a56bac8619.tar.xz | |
[CodeGen] Add target machine registry
Diffstat (limited to 'backend/lib/Target')
| -rw-r--r-- | backend/lib/Target/CMakeLists.txt | 36 | ||||
| -rw-r--r-- | backend/lib/Target/RISCV/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | backend/lib/Target/RISCV/RISCVPipeline.cpp | 13 | ||||
| -rw-r--r-- | backend/lib/Target/RISCV/RISCVSubtarget.cpp | 13 | ||||
| -rw-r--r-- | backend/lib/Target/RISCV/RISCVTargetMachine.cpp | 161 | ||||
| -rw-r--r-- | backend/lib/Target/TargetMachine.cpp | 18 |
6 files changed, 230 insertions, 14 deletions
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 |
