aboutsummaryrefslogtreecommitdiff
path: root/backend/lib/Target/RISCV
diff options
context:
space:
mode:
Diffstat (limited to 'backend/lib/Target/RISCV')
-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
4 files changed, 176 insertions, 14 deletions
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