From afce8c3e93059df6f9aab1bc57f72c83674d6d92 Mon Sep 17 00:00:00 2001 From: Richard-Qin-X Date: Thu, 13 Aug 2026 19:09:51 +0800 Subject: [RISCV] Model non-ISA subtarget features --- backend/include/rcc/Target/RISCV/RISCVSubtarget.h | 35 ++++++++++- backend/lib/Target/RISCV/RISCVSubtarget.cpp | 77 ++++++++++++++++++++--- 2 files changed, 104 insertions(+), 8 deletions(-) diff --git a/backend/include/rcc/Target/RISCV/RISCVSubtarget.h b/backend/include/rcc/Target/RISCV/RISCVSubtarget.h index 28718f0..9594a34 100644 --- a/backend/include/rcc/Target/RISCV/RISCVSubtarget.h +++ b/backend/include/rcc/Target/RISCV/RISCVSubtarget.h @@ -34,6 +34,35 @@ enum class RISCVExtension : std::uint8_t { Count, }; +enum class RISCVSubtargetOption : std::uint8_t { + DisablePostMISchedLoadClustering, + DisablePostMISchedStoreClustering, + FusionAddLoad, + FusionAddMemory, + FusionAddImmediateLoad, + FusionAUIPCAddImmediate, + FusionAUIPCLoad, + FusionLoadDoubleAdd, + FusionLogicImmediateRegister, + FusionLogicRegisterImmediate, + FusionLogicRegisterRegister, + FusionLUIAddImmediate, + FusionLUILoad, + FusionMultiplyAdd, + FusionShiftBitExtract, + FusionShiftedZeroExtendWord, + FusionZeroExtendHalf, + FusionZeroExtendWord, + PreferWordInstructions, + ReserveX6, + ReserveX7, + SaveRestore, + TaggedGlobals, + UnalignedScalarMemory, + UsePostRAScheduler, + Count, +}; + class RISCVSubtargetFeatures final { public: [[nodiscard]] static Expected @@ -41,14 +70,18 @@ public: [[nodiscard]] static RISCVSubtargetFeatures rv64gc() noexcept; [[nodiscard]] bool has(RISCVExtension Extension) const noexcept; + [[nodiscard]] bool has(RISCVSubtargetOption Option) const noexcept; friend bool operator==(const RISCVSubtargetFeatures &Left, const RISCVSubtargetFeatures &Right) = default; private: - explicit constexpr RISCVSubtargetFeatures(std::uint16_t Enabled) noexcept : Enabled(Enabled) {} + explicit constexpr RISCVSubtargetFeatures(std::uint16_t Enabled, + std::uint32_t Options = 0) noexcept + : Enabled(Enabled), Options(Options) {} std::uint16_t Enabled = 0; + std::uint32_t Options = 0; }; class RISCVSubtarget final { diff --git a/backend/lib/Target/RISCV/RISCVSubtarget.cpp b/backend/lib/Target/RISCV/RISCVSubtarget.cpp index 89f6c61..a4986e4 100644 --- a/backend/lib/Target/RISCV/RISCVSubtarget.cpp +++ b/backend/lib/Target/RISCV/RISCVSubtarget.cpp @@ -20,6 +20,11 @@ struct ExtensionName final { RISCVExtension Extension; }; +struct OptionName final { + std::string_view Name; + RISCVSubtargetOption Option; +}; + constexpr std::array ExtensionNames{ ExtensionName{"i", RISCVExtension::I}, ExtensionName{"m", RISCVExtension::M}, @@ -33,10 +38,45 @@ constexpr std::array ExtensionNames{ ExtensionName{"zabha", RISCVExtension::Zabha}, }; +constexpr std::array OptionNames{ + OptionName{"disable-postmisched-load-clustering", + RISCVSubtargetOption::DisablePostMISchedLoadClustering}, + OptionName{"disable-postmisched-store-clustering", + RISCVSubtargetOption::DisablePostMISchedStoreClustering}, + OptionName{"fusion-add-load", RISCVSubtargetOption::FusionAddLoad}, + OptionName{"fusion-add-mem", RISCVSubtargetOption::FusionAddMemory}, + OptionName{"fusion-addi-load", RISCVSubtargetOption::FusionAddImmediateLoad}, + OptionName{"fusion-auipc-addi", RISCVSubtargetOption::FusionAUIPCAddImmediate}, + OptionName{"fusion-auipc-load", RISCVSubtargetOption::FusionAUIPCLoad}, + OptionName{"fusion-ld-add", RISCVSubtargetOption::FusionLoadDoubleAdd}, + OptionName{"fusion-logic-imm-reg", RISCVSubtargetOption::FusionLogicImmediateRegister}, + OptionName{"fusion-logic-reg-imm", RISCVSubtargetOption::FusionLogicRegisterImmediate}, + OptionName{"fusion-logic-reg-reg", RISCVSubtargetOption::FusionLogicRegisterRegister}, + OptionName{"fusion-lui-addi", RISCVSubtargetOption::FusionLUIAddImmediate}, + OptionName{"fusion-lui-load", RISCVSubtargetOption::FusionLUILoad}, + OptionName{"fusion-mul-add", RISCVSubtargetOption::FusionMultiplyAdd}, + OptionName{"fusion-shift-bit-extract", RISCVSubtargetOption::FusionShiftBitExtract}, + OptionName{"fusion-shifted-zextw", RISCVSubtargetOption::FusionShiftedZeroExtendWord}, + OptionName{"fusion-zexth", RISCVSubtargetOption::FusionZeroExtendHalf}, + OptionName{"fusion-zextw", RISCVSubtargetOption::FusionZeroExtendWord}, + OptionName{"prefer-w-inst", RISCVSubtargetOption::PreferWordInstructions}, + OptionName{"reserve-x6", RISCVSubtargetOption::ReserveX6}, + OptionName{"reserve-x7", RISCVSubtargetOption::ReserveX7}, + OptionName{"save-restore", RISCVSubtargetOption::SaveRestore}, + OptionName{"tagged-globals", RISCVSubtargetOption::TaggedGlobals}, + OptionName{"unaligned-scalar-mem", RISCVSubtargetOption::UnalignedScalarMemory}, + OptionName{"use-postra-scheduler", RISCVSubtargetOption::UsePostRAScheduler}, +}; + [[nodiscard]] constexpr std::uint16_t extensionBit(RISCVExtension Extension) noexcept { return static_cast(std::uint16_t{1} << static_cast(Extension)); } +[[nodiscard]] constexpr std::uint32_t optionBit(RISCVSubtargetOption Option) noexcept { + static_assert(static_cast(RISCVSubtargetOption::Count) <= 32); + return std::uint32_t{1} << static_cast(Option); +} + [[nodiscard]] const ExtensionName *findExtension(std::string_view Name) noexcept { for (const ExtensionName &Entry : ExtensionNames) { if (Entry.Name == Name) @@ -45,28 +85,45 @@ constexpr std::array ExtensionNames{ return nullptr; } +[[nodiscard]] const OptionName *findOption(std::string_view Name) noexcept { + for (const OptionName &Entry : OptionNames) { + if (Entry.Name == Name) + return &Entry; + } + return nullptr; +} + } // namespace Expected RISCVSubtargetFeatures::fromFeatureList(std::span Features) { std::uint16_t Enabled = extensionBit(RISCVExtension::I); + std::uint32_t Options = 0; 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) { + const std::string_view Name = std::string_view(Feature).substr(1); + const ExtensionName *Extension = findExtension(Name); + const OptionName *Option = findOption(Name); + if (Extension == nullptr && Option == 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(~extensionBit(Extension->Extension)); + if (Extension != nullptr) { + if (Feature.front() == '+') + Enabled |= extensionBit(Extension->Extension); + else + Enabled &= static_cast(~extensionBit(Extension->Extension)); + } else if (Feature.front() == '+') { + Options |= optionBit(Option->Option); + } else { + Options &= ~optionBit(Option->Option); + } } - RISCVSubtargetFeatures Result(Enabled); + RISCVSubtargetFeatures Result(Enabled, Options); if (!Result.has(RISCVExtension::I)) { return makeUnexpected(ErrorCode::InvalidInvocation, "RV64 target feature configuration cannot disable the base I extension"); @@ -97,6 +154,12 @@ bool RISCVSubtargetFeatures::has(RISCVExtension Extension) const noexcept { return (Enabled & extensionBit(Extension)) != 0; } +bool RISCVSubtargetFeatures::has(RISCVSubtargetOption Option) const noexcept { + if (Option >= RISCVSubtargetOption::Count) + return false; + return (Options & optionBit(Option)) != 0; +} + RISCVSubtarget::RISCVSubtarget(RISCVSubtargetFeatures Features) : Features(Features) {} RISCVSubtarget::~RISCVSubtarget() = default; -- cgit v1.2.3