diff options
| author | Richard-Qin-X <richard.qin.001@gmail.com> | 2026-08-01 14:50:04 +0800 |
|---|---|---|
| committer | Richard-Qin-X <richard.qin.001@gmail.com> | 2026-08-01 14:50:04 +0800 |
| commit | cfdbcc469f9691bd9dce3b0b86982a63d86ca6b7 (patch) | |
| tree | 19f4ad856c3e4900a0501ab2cad41981b49569b5 /backend/lib/CodeGen/MachineCompilationStatus.cpp | |
| parent | a69d14b8ebc028dddc689658b08d42d3e83f5e38 (diff) | |
| download | rcc-project-cfdbcc469f9691bd9dce3b0b86982a63d86ca6b7.tar.gz rcc-project-cfdbcc469f9691bd9dce3b0b86982a63d86ca6b7.tar.xz | |
[CodeGen] Add target state and compilation status
Diffstat (limited to 'backend/lib/CodeGen/MachineCompilationStatus.cpp')
| -rw-r--r-- | backend/lib/CodeGen/MachineCompilationStatus.cpp | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/backend/lib/CodeGen/MachineCompilationStatus.cpp b/backend/lib/CodeGen/MachineCompilationStatus.cpp new file mode 100644 index 0000000..600deac --- /dev/null +++ b/backend/lib/CodeGen/MachineCompilationStatus.cpp @@ -0,0 +1,195 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "rcc/CodeGen/MachineCompilationStatus.h" + +#include "rcc/CodeGen/MachineFunctionCloner.h" + +#include <array> +#include <cstddef> +#include <optional> +#include <string> +#include <string_view> +#include <utility> + +namespace rcc { +namespace { + +constexpr std::array StateNames{ + std::string_view{"Success"}, + std::string_view{"Unsupported"}, + std::string_view{"MIRParseFailed"}, + std::string_view{"LegalizationFailed"}, + std::string_view{"SelectionFailed"}, + std::string_view{"RegisterAllocationFailed"}, + std::string_view{"CallLoweringFailed"}, + std::string_view{"FrameLayoutFailed"}, + std::string_view{"FinalizationFailed"}, + std::string_view{"AssemblyLoweringFailed"}, + std::string_view{"InternalError"}, +}; + +static_assert(StateNames.size() == static_cast<std::size_t>(MachineCompilationState::Count)); + +[[nodiscard]] bool +isKnownDiagnosticSeverity(MachineCompilationDiagnosticSeverity Severity) noexcept { + return static_cast<std::size_t>(Severity) < + static_cast<std::size_t>(MachineCompilationDiagnosticSeverity::Count); +} + +[[nodiscard]] bool isKnownErrorCode(ErrorCode Code) noexcept { + switch (Code) { + case ErrorCode::InvalidArgument: + case ErrorCode::ParseError: + case ErrorCode::VerificationError: + case ErrorCode::Unsupported: + case ErrorCode::IoError: + case ErrorCode::InternalError: + return true; + } + return false; +} + +[[nodiscard]] bool isKnownPipelineStage(PipelineStage Stage) noexcept { + switch (Stage) { + case PipelineStage::MachineIRInput: + case PipelineStage::Legalized: + case PipelineStage::RegBankSelected: + case PipelineStage::Selected: + case PipelineStage::SSAEliminated: + case PipelineStage::TiedOpsRewritten: + case PipelineStage::RegisterAllocated: + case PipelineStage::FrameFinalized: + case PipelineStage::PostRAFinalized: + case PipelineStage::Emission: + return true; + } + return false; +} + +[[nodiscard]] Expected<void> verifyOptionalText(const std::optional<std::string> &Text, + std::string_view FieldName) { + if (Text && Text->empty()) { + return makeUnexpected(ErrorCode::VerificationError, "machine compilation failure " + + std::string(FieldName) + + " cannot be empty"); + } + return {}; +} + +} // namespace + +bool isKnownMachineCompilationState(MachineCompilationState State) noexcept { + return static_cast<std::size_t>(State) < StateNames.size(); +} + +std::string_view getMachineCompilationStateName(MachineCompilationState State) noexcept { + const auto Index = static_cast<std::size_t>(State); + if (Index >= StateNames.size()) + return "Unknown"; + return StateNames[Index]; +} + +Expected<void> MachineCompilationStatus::fail(MachineCompilationState NewState, + MachineCompilationFailure NewFailure) { + if (!succeeded()) { + return makeUnexpected(ErrorCode::InvalidArgument, + "machine compilation status already contains a failure"); + } + if (!isKnownMachineCompilationState(NewState) || NewState == MachineCompilationState::Success) { + return makeUnexpected(ErrorCode::InvalidArgument, + "machine compilation failure requires a known failure state"); + } + + MachineCompilationStatus Candidate; + Candidate.State = NewState; + Candidate.Failure = std::move(NewFailure); + auto Verification = Candidate.verify(); + if (!Verification) + return std::unexpected(Verification.error()); + + *this = std::move(Candidate); + return {}; +} + +Expected<void> MachineCompilationStatus::verify() const { + if (!isKnownMachineCompilationState(State)) { + return makeUnexpected(ErrorCode::VerificationError, + "machine compilation status has an unknown state"); + } + if (State == MachineCompilationState::Success) { + if (Failure) { + return makeUnexpected(ErrorCode::VerificationError, + "successful machine compilation status contains failure details"); + } + return {}; + } + if (!Failure) { + return makeUnexpected(ErrorCode::VerificationError, + "failed machine compilation status lacks failure details"); + } + + if (!isKnownDiagnosticSeverity(Failure->Diagnostic.Severity)) { + return makeUnexpected(ErrorCode::VerificationError, + "machine compilation diagnostic has an unknown severity"); + } + if (!isKnownErrorCode(Failure->Diagnostic.Code)) { + return makeUnexpected(ErrorCode::VerificationError, + "machine compilation diagnostic has an unknown error code"); + } + if (Failure->Diagnostic.Message.empty()) { + return makeUnexpected(ErrorCode::VerificationError, + "machine compilation diagnostic message cannot be empty"); + } + if (Failure->Diagnostic.Location && !Failure->Diagnostic.Location->isValid()) { + return makeUnexpected(ErrorCode::VerificationError, + "machine compilation diagnostic has an invalid source location"); + } + if (Failure->FailureInstruction && !Failure->FailureInstruction->isValid()) { + return makeUnexpected(ErrorCode::VerificationError, + "machine compilation failure has an invalid instruction StableID"); + } + if (Failure->FailureStage && !isKnownPipelineStage(*Failure->FailureStage)) { + return makeUnexpected(ErrorCode::VerificationError, + "machine compilation failure has an unknown pipeline stage"); + } + + for (const auto &[Text, Name] : + {std::pair{&Failure->FailurePass, std::string_view{"pass"}}, + std::pair{&Failure->FailureRule, std::string_view{"rule or pattern"}}, + std::pair{&Failure->Target, std::string_view{"target"}}, + std::pair{&Failure->Subtarget, std::string_view{"subtarget"}}}) { + auto TextVerification = verifyOptionalText(*Text, Name); + if (!TextVerification) + return TextVerification; + } + return {}; +} + +Expected<MachineCompilationStatus> +MachineCompilationStatus::clone(const MachineFunctionCloneContext &CloneContext) const { + auto Verification = verify(); + if (!Verification) + return std::unexpected(Verification.error()); + if (succeeded()) + return MachineCompilationStatus{}; + if (!Failure) { + return makeUnexpected(ErrorCode::InternalError, + "verified failed compilation status has no failure details"); + } + + MachineCompilationFailure ClonedFailure = *Failure; + if (ClonedFailure.FailureInstruction) { + auto Mapped = CloneContext.mapInstructionStableID(*ClonedFailure.FailureInstruction); + if (!Mapped) + return std::unexpected(Mapped.error()); + ClonedFailure.FailureInstruction = *Mapped; + } + + MachineCompilationStatus Result; + auto FailureResult = Result.fail(State, std::move(ClonedFailure)); + if (!FailureResult) + return std::unexpected(FailureResult.error()); + return Result; +} + +} // namespace rcc |
