aboutsummaryrefslogtreecommitdiff
path: root/backend/lib/Tooling/BackendDriver.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'backend/lib/Tooling/BackendDriver.cpp')
-rw-r--r--backend/lib/Tooling/BackendDriver.cpp134
1 files changed, 134 insertions, 0 deletions
diff --git a/backend/lib/Tooling/BackendDriver.cpp b/backend/lib/Tooling/BackendDriver.cpp
new file mode 100644
index 0000000..5932335
--- /dev/null
+++ b/backend/lib/Tooling/BackendDriver.cpp
@@ -0,0 +1,134 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "rcc/Tooling/BackendDriver.h"
+
+#include "rcc/CodeGen/MIRPrinter.h"
+#include "rcc/CodeGen/MachineFunction.h"
+#include "rcc/Target/TargetMachine.h"
+
+#include <cstddef>
+#include <cstdint>
+#include <string>
+#include <string_view>
+#include <utility>
+#include <vector>
+
+namespace rcc::tooling {
+namespace {
+
+[[nodiscard]] BackendStage outputStage(ArtifactKind Output) noexcept {
+ switch (Output) {
+ case ArtifactKind::PreLegalizerMIR:
+ return BackendStage::PreLegalizerMIR;
+ case ArtifactKind::LegalizedMIR:
+ return BackendStage::LegalizedMIR;
+ case ArtifactKind::RegisterBankMIR:
+ return BackendStage::RegisterBankMIR;
+ case ArtifactKind::SelectedMIR:
+ return BackendStage::SelectedMIR;
+ case ArtifactKind::PostSSAMIR:
+ return BackendStage::PostSSAMIR;
+ case ArtifactKind::PostRegisterAllocationMIR:
+ return BackendStage::PostRegisterAllocationMIR;
+ case ArtifactKind::FinalMIR:
+ case ArtifactKind::Assembly:
+ case ArtifactKind::RelocatableObject:
+ return BackendStage::FinalMIR;
+ }
+ return BackendStage::FinalMIR;
+}
+
+[[nodiscard]] Expected<std::vector<std::uint8_t>> printMIR(const mir::MIRDocument &Document,
+ const TargetDescription &Target,
+ const BackendInvocation &Invocation,
+ bool Simplify) {
+ mir::MIRDocumentPrinterOptions Options;
+ Options.Mode = Simplify ? mir::MIPrintMode::Readable : mir::MIPrintMode::Complete;
+ Options.EmitEmbeddedIR = true;
+ Options.DataLayout = Invocation.DataLayout;
+ auto Printed = mir::printMIRDocument(Document, Target, std::move(Options));
+ if (!Printed)
+ return std::unexpected(Printed.error());
+ return std::vector<std::uint8_t>(Printed->begin(), Printed->end());
+}
+
+} // namespace
+
+std::string_view BackendRunResult::text() const noexcept {
+ if (Kind == ArtifactKind::RelocatableObject || Output.empty())
+ return {};
+ return {reinterpret_cast<const char *>(Output.data()), Output.size()};
+}
+
+Expected<BackendRunResult> runBackend(CanonicalMIR Input, const BackendInvocation &Invocation,
+ ArtifactKind Output, PipelineControls Controls,
+ MachinePassInstrumentation *Instrumentation) {
+ auto TargetMachine = createTargetMachine(Invocation);
+ if (!TargetMachine)
+ return std::unexpected(TargetMachine.error());
+ const TargetDescription &Target = (*TargetMachine)->targetDescription();
+ if (Input.Document.unit().functionCount() == 0) {
+ return makeUnexpected(ErrorCode::InvalidArgument,
+ "backend input must contain at least one machine function");
+ }
+
+ BackendStage InitialStage = BackendStage::FinalMIR;
+ for (std::size_t Index = 0; Index < Input.Document.unit().functionCount(); ++Index) {
+ const MachineFunction *Function = Input.Document.unit().functionAt(Index);
+ if (Function == nullptr)
+ return makeUnexpected(ErrorCode::InternalError, "backend input contains a null function");
+ const BackendStage Stage = stageForFunction(*Function);
+ if (Index == 0 || isEarlierStage(Stage, InitialStage))
+ InitialStage = Stage;
+ }
+ const BackendStage RequiredStage = outputStage(Output);
+ if (isMIRArtifact(Output) && isEarlierStage(RequiredStage, InitialStage)) {
+ return makeUnexpected(ErrorCode::InvalidInvocation,
+ "backend cannot reconstruct an earlier MIR stage from a later snapshot");
+ }
+
+ if (isMIRArtifact(Output)) {
+ if (Controls.StopAtStage && *Controls.StopAtStage != RequiredStage) {
+ return makeUnexpected(ErrorCode::InvalidInvocation,
+ "output stage conflicts with the explicit pipeline stop stage");
+ }
+ Controls.StopAtStage = RequiredStage;
+ }
+
+ const bool SimplifyMIR = Controls.SimplifyMIR;
+
+ MachinePassInstrumentation LocalInstrumentation;
+ MachinePassInstrumentation *ActiveInstrumentation =
+ Instrumentation == nullptr ? &LocalInstrumentation : Instrumentation;
+ auto Pipeline = runTargetPipeline(Input.Document, **TargetMachine, Invocation,
+ std::move(Controls), ActiveInstrumentation);
+ if (!Pipeline)
+ return std::unexpected(Pipeline.error());
+
+ std::vector<std::uint8_t> Bytes;
+ if (isMIRArtifact(Output)) {
+ auto Printed = printMIR(Input.Document, Target, Invocation, SimplifyMIR);
+ if (!Printed)
+ return std::unexpected(Printed.error());
+ Bytes = std::move(*Printed);
+ } else if (Output == ArtifactKind::Assembly) {
+ auto Assembly = (*TargetMachine)->emitAssembly(Input.Document.unit());
+ if (!Assembly)
+ return std::unexpected(Assembly.error());
+ Bytes.assign(Assembly->begin(), Assembly->end());
+ } else {
+ auto Object = (*TargetMachine)->emitObject(Input.Document.unit());
+ if (!Object)
+ return std::unexpected(Object.error());
+ Bytes = std::move(*Object);
+ }
+
+ return BackendRunResult{
+ .Kind = Output,
+ .Output = std::move(Bytes),
+ .Pipeline = std::move(*Pipeline),
+ .Actions = ActiveInstrumentation->actionEvents(),
+ };
+}
+
+} // namespace rcc::tooling