diff options
| author | Richard-Qin-X <richard.qin.001@gmail.com> | 2026-08-11 19:36:06 +0800 |
|---|---|---|
| committer | Richard-Qin-X <richard.qin.001@gmail.com> | 2026-08-11 19:36:06 +0800 |
| commit | b7716aba458fb3d49742f7a3c169deee7345396e (patch) | |
| tree | 85a8f99a8bd06e9dfbe6e7973c3440f2db7110af /backend/lib/Target/RISCV | |
| parent | e7bf0d93d40ad86902d9a8636d24420b5abd2937 (diff) | |
| download | rcc-project-b7716aba458fb3d49742f7a3c169deee7345396e.tar.gz rcc-project-b7716aba458fb3d49742f7a3c169deee7345396e.tar.xz | |
[RISCV] Honor invocation subtarget features
Diffstat (limited to 'backend/lib/Target/RISCV')
| -rw-r--r-- | backend/lib/Target/RISCV/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | backend/lib/Target/RISCV/RISCVCodeGen.cpp | 15 | ||||
| -rw-r--r-- | backend/lib/Target/RISCV/RISCVPipeline.cpp | 24 | ||||
| -rw-r--r-- | backend/lib/Target/RISCV/RISCVSubtarget.cpp | 94 |
4 files changed, 130 insertions, 7 deletions
diff --git a/backend/lib/Target/RISCV/CMakeLists.txt b/backend/lib/Target/RISCV/CMakeLists.txt index eae426c..68bd444 100644 --- a/backend/lib/Target/RISCV/CMakeLists.txt +++ b/backend/lib/Target/RISCV/CMakeLists.txt @@ -66,6 +66,7 @@ add_library( RISCVPseudoExpansion.cpp RISCVRegisterAllocation.cpp RISCVScheduling.cpp + RISCVSubtarget.cpp RISCVTarget.cpp RISCVTargetConstant.cpp "${RCCBackendRISCVGeneratedRegisterHeader}" @@ -135,6 +136,7 @@ rcc_backend_register_format_files( "${CMAKE_CURRENT_SOURCE_DIR}/RISCVPseudoExpansion.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/RISCVRegisterAllocation.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/RISCVScheduling.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/RISCVSubtarget.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/RISCVTarget.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/RISCVTargetConstant.cpp" "${RCC_BACKEND_SOURCE_DIR}/include/rcc/Target/RISCV/RISCVCodeGen.h" @@ -147,6 +149,7 @@ rcc_backend_register_format_files( "${RCC_BACKEND_SOURCE_DIR}/include/rcc/Target/RISCV/RISCVMCCodeEmitter.h" "${RCC_BACKEND_SOURCE_DIR}/include/rcc/Target/RISCV/RISCVObjectFile.h" "${RCC_BACKEND_SOURCE_DIR}/include/rcc/Target/RISCV/RISCVPipeline.h" + "${RCC_BACKEND_SOURCE_DIR}/include/rcc/Target/RISCV/RISCVSubtarget.h" "${RCC_BACKEND_SOURCE_DIR}/include/rcc/Target/RISCV/RISCVMCTargetLowering.h" "${RCC_BACKEND_SOURCE_DIR}/include/rcc/Target/RISCV/RISCVTarget.h" "${RCC_BACKEND_SOURCE_DIR}/include/rcc/Target/RISCV/RISCVTargetConstant.h" @@ -172,6 +175,7 @@ rcc_backend_register_tidy_files( "${CMAKE_CURRENT_SOURCE_DIR}/RISCVPseudoExpansion.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/RISCVRegisterAllocation.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/RISCVScheduling.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/RISCVSubtarget.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/RISCVTarget.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/RISCVTargetConstant.cpp" ) diff --git a/backend/lib/Target/RISCV/RISCVCodeGen.cpp b/backend/lib/Target/RISCV/RISCVCodeGen.cpp index 8676a2b..0bd3298 100644 --- a/backend/lib/Target/RISCV/RISCVCodeGen.cpp +++ b/backend/lib/Target/RISCV/RISCVCodeGen.cpp @@ -2879,9 +2879,15 @@ buildIncomingConversion(MachineFunction &Function, const TargetDescription &Targ class RISCVLegalizerInfo final : public TargetLegalizerInfo { public: + explicit RISCVLegalizerInfo(RISCVSubtargetFeatures Features) : Features(Features) {} + [[nodiscard]] Expected<LegalizationAction> classify(const MachineInstr &Instruction, const MachineFunction &Function, const TargetDescription &) const override { + if (!Features.has(RISCVExtension::I)) { + return makeUnexpected(ErrorCode::InternalError, + "RISC-V legalizer requires the base I extension"); + } if (!isGenericOpcode(Instruction.opcode())) return LegalizationAction::Legal; @@ -3560,6 +3566,9 @@ public: return makeUnexpected(ErrorCode::Unsupported, "RISC-V legalizer has no lowering rule for this instruction"); } + +private: + RISCVSubtargetFeatures Features; }; class RISCVRegisterBankInfo final : public TargetRegisterBankInfo { @@ -6284,10 +6293,14 @@ private: } // namespace const TargetLegalizerInfo &legalizerInfo() noexcept { - static const RISCVLegalizerInfo Value; + static const RISCVLegalizerInfo Value(RISCVSubtargetFeatures::rv64gc()); return Value; } +std::unique_ptr<TargetLegalizerInfo> createLegalizerInfo(RISCVSubtargetFeatures Features) { + return std::make_unique<RISCVLegalizerInfo>(Features); +} + const TargetRegisterBankInfo ®isterBankInfo() noexcept { static const RISCVRegisterBankInfo Value; return Value; diff --git a/backend/lib/Target/RISCV/RISCVPipeline.cpp b/backend/lib/Target/RISCV/RISCVPipeline.cpp index 8d05bba..05d26b3 100644 --- a/backend/lib/Target/RISCV/RISCVPipeline.cpp +++ b/backend/lib/Target/RISCV/RISCVPipeline.cpp @@ -25,8 +25,9 @@ template <typename PassT, typename... ArgumentT> return Pipeline.addPass(std::make_unique<PassT>(std::forward<ArgumentT>(Arguments)...)); } -[[nodiscard]] Expected<void> addInitialPipeline(MachinePassManager &Pipeline) { - auto Added = addPass<LegalizerPass>(Pipeline, legalizerInfo()); +[[nodiscard]] Expected<void> addInitialPipeline(MachinePassManager &Pipeline, + RISCVSubtargetFeatures Features) { + auto Added = addPass<LegalizerPass>(Pipeline, createLegalizerInfo(Features)); if (!Added) return std::unexpected(Added.error()); Added = addPass<RegisterBankSelectPass>(Pipeline, registerBankInfo()); @@ -52,8 +53,9 @@ template <typename PassT, typename... ArgumentT> return addPass<PBQPAllocatorPass>(Pipeline, registerAllocationInfo()); } -[[nodiscard]] Expected<void> addCompleteRegistry(MachinePassManager &Pipeline) { - auto Added = addInitialPipeline(Pipeline); +[[nodiscard]] Expected<void> addCompleteRegistry(MachinePassManager &Pipeline, + RISCVSubtargetFeatures Features) { + auto Added = addInitialPipeline(Pipeline, Features); if (!Added) return std::unexpected(Added.error()); Added = addSSAExitPipeline(Pipeline); @@ -68,8 +70,13 @@ template <typename PassT, typename... ArgumentT> } // namespace Expected<void> addCanonicalPipeline(MachinePassManager &Pipeline, const MachineFunction &Function) { + return addCanonicalPipeline(Pipeline, Function, RISCVSubtargetFeatures::rv64gc()); +} + +Expected<void> addCanonicalPipeline(MachinePassManager &Pipeline, const MachineFunction &Function, + RISCVSubtargetFeatures Features) { if (!Function.properties().has(MachineFunctionProperty::Legalized)) { - auto Added = addPass<LegalizerPass>(Pipeline, legalizerInfo()); + auto Added = addPass<LegalizerPass>(Pipeline, createLegalizerInfo(Features)); if (!Added) return std::unexpected(Added.error()); } @@ -112,10 +119,15 @@ Expected<void> addCanonicalPipeline(MachinePassManager &Pipeline, const MachineF } Expected<std::unique_ptr<MachineFunctionPass>> createCanonicalPipelinePass(std::string_view Name) { + return createCanonicalPipelinePass(Name, RISCVSubtargetFeatures::rv64gc()); +} + +Expected<std::unique_ptr<MachineFunctionPass>> +createCanonicalPipelinePass(std::string_view Name, RISCVSubtargetFeatures Features) { if (Name.empty()) return makeUnexpected(ErrorCode::InvalidArgument, "pipeline pass name cannot be empty"); MachinePassManager Registry; - auto Added = addCompleteRegistry(Registry); + auto Added = addCompleteRegistry(Registry, Features); if (!Added) return std::unexpected(Added.error()); MachinePassManager::PassList Passes = std::move(Registry).takePasses(); diff --git a/backend/lib/Target/RISCV/RISCVSubtarget.cpp b/backend/lib/Target/RISCV/RISCVSubtarget.cpp new file mode 100644 index 0000000..3a3d9e2 --- /dev/null +++ b/backend/lib/Target/RISCV/RISCVSubtarget.cpp @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "rcc/Target/RISCV/RISCVSubtarget.h" + +#include <array> +#include <cstddef> +#include <string_view> + +namespace rcc::riscv { +namespace { + +struct ExtensionName final { + std::string_view Name; + RISCVExtension Extension; +}; + +constexpr std::array ExtensionNames{ + ExtensionName{"i", RISCVExtension::I}, + ExtensionName{"m", RISCVExtension::M}, + ExtensionName{"a", RISCVExtension::A}, + ExtensionName{"f", RISCVExtension::F}, + ExtensionName{"d", RISCVExtension::D}, + ExtensionName{"c", RISCVExtension::C}, + ExtensionName{"zicsr", RISCVExtension::Zicsr}, + ExtensionName{"zifencei", RISCVExtension::Zifencei}, + ExtensionName{"zacas", RISCVExtension::Zacas}, + ExtensionName{"zabha", RISCVExtension::Zabha}, +}; + +[[nodiscard]] constexpr std::uint16_t extensionBit(RISCVExtension Extension) noexcept { + return static_cast<std::uint16_t>(std::uint16_t{1} << static_cast<std::uint8_t>(Extension)); +} + +[[nodiscard]] const ExtensionName *findExtension(std::string_view Name) noexcept { + for (const ExtensionName &Entry : ExtensionNames) { + if (Entry.Name == Name) + return &Entry; + } + return nullptr; +} + +} // namespace + +Expected<RISCVSubtargetFeatures> +RISCVSubtargetFeatures::fromFeatureList(std::span<const std::string> Features) { + std::uint16_t Enabled = extensionBit(RISCVExtension::I); + for (const std::string &Feature : Features) { + if (Feature.size() < 2 || (Feature.front() != '+' && Feature.front() != '-')) { + return makeUnexpected(ErrorCode::InvalidInvocation, + "RISC-V target feature must use canonical +/- spelling"); + } + const ExtensionName *Extension = findExtension(std::string_view(Feature).substr(1)); + if (Extension == nullptr) { + return makeUnexpected(ErrorCode::InvalidInvocation, + "RISC-V backend does not support target feature '" + Feature + "'"); + } + if (Feature.front() == '+') + Enabled |= extensionBit(Extension->Extension); + else + Enabled &= static_cast<std::uint16_t>(~extensionBit(Extension->Extension)); + } + + RISCVSubtargetFeatures Result(Enabled); + if (!Result.has(RISCVExtension::I)) { + return makeUnexpected(ErrorCode::InvalidInvocation, + "RV64 target feature configuration cannot disable the base I extension"); + } + if (Result.has(RISCVExtension::D) && !Result.has(RISCVExtension::F)) { + return makeUnexpected(ErrorCode::InvalidInvocation, + "RISC-V D extension requires the F extension"); + } + if ((Result.has(RISCVExtension::Zacas) || Result.has(RISCVExtension::Zabha)) && + !Result.has(RISCVExtension::A)) { + return makeUnexpected(ErrorCode::InvalidInvocation, + "RISC-V Zacas and Zabha extensions require the A extension"); + } + return Result; +} + +RISCVSubtargetFeatures RISCVSubtargetFeatures::rv64gc() noexcept { + return RISCVSubtargetFeatures(extensionBit(RISCVExtension::I) | extensionBit(RISCVExtension::M) | + extensionBit(RISCVExtension::A) | extensionBit(RISCVExtension::F) | + extensionBit(RISCVExtension::D) | extensionBit(RISCVExtension::C) | + extensionBit(RISCVExtension::Zicsr) | + extensionBit(RISCVExtension::Zifencei)); +} + +bool RISCVSubtargetFeatures::has(RISCVExtension Extension) const noexcept { + if (Extension >= RISCVExtension::Count) + return false; + return (Enabled & extensionBit(Extension)) != 0; +} + +} // namespace rcc::riscv |
