aboutsummaryrefslogtreecommitdiff
path: root/backend/lib/Target
diff options
context:
space:
mode:
authorRichard-Qin-X <richard.qin.001@gmail.com>2026-08-11 19:36:06 +0800
committerRichard-Qin-X <richard.qin.001@gmail.com>2026-08-11 19:36:06 +0800
commitb7716aba458fb3d49742f7a3c169deee7345396e (patch)
tree85a8f99a8bd06e9dfbe6e7973c3440f2db7110af /backend/lib/Target
parente7bf0d93d40ad86902d9a8636d24420b5abd2937 (diff)
downloadrcc-project-b7716aba458fb3d49742f7a3c169deee7345396e.tar.gz
rcc-project-b7716aba458fb3d49742f7a3c169deee7345396e.tar.xz
[RISCV] Honor invocation subtarget features
Diffstat (limited to 'backend/lib/Target')
-rw-r--r--backend/lib/Target/RISCV/CMakeLists.txt4
-rw-r--r--backend/lib/Target/RISCV/RISCVCodeGen.cpp15
-rw-r--r--backend/lib/Target/RISCV/RISCVPipeline.cpp24
-rw-r--r--backend/lib/Target/RISCV/RISCVSubtarget.cpp94
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 &registerBankInfo() 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