diff options
| author | Richard-Qin-X <richard.qin.001@gmail.com> | 2026-08-16 16:13:12 +0800 |
|---|---|---|
| committer | Richard-Qin-X <richard.qin.001@gmail.com> | 2026-08-16 16:13:12 +0800 |
| commit | ca25d25d4c5131491a50b1a94e63e9b2d3c34ed4 (patch) | |
| tree | 995b2f5e2a1312bced1d899be4fd87f95e49c73b /backend/utils/TableGen/Common/CodeGenSelection.cpp | |
| parent | 4f7b41c3c711d6c6fa4e422f3eec8961c91eea7a (diff) | |
| download | rcc-project-ca25d25d4c5131491a50b1a94e63e9b2d3c34ed4.tar.gz rcc-project-ca25d25d4c5131491a50b1a94e63e9b2d3c34ed4.tar.xz | |
[RISCV][GlobalISel] Select comparisons against zero
Diffstat (limited to 'backend/utils/TableGen/Common/CodeGenSelection.cpp')
| -rw-r--r-- | backend/utils/TableGen/Common/CodeGenSelection.cpp | 186 |
1 files changed, 185 insertions, 1 deletions
diff --git a/backend/utils/TableGen/Common/CodeGenSelection.cpp b/backend/utils/TableGen/Common/CodeGenSelection.cpp index 0216136..cc80e41 100644 --- a/backend/utils/TableGen/Common/CodeGenSelection.cpp +++ b/backend/utils/TableGen/Common/CodeGenSelection.cpp @@ -3,11 +3,14 @@ #include "CodeGenTarget.h" #include "rcc/CodeGen/GenericOpcodes.h" #include "rcc/CodeGen/LowLevelType.h" +#include "rcc/CodeGen/MachineOperand.h" #include <algorithm> +#include <array> #include <cstdint> #include <optional> #include <ranges> +#include <span> #include <string_view> #include <unordered_set> #include <utility> @@ -46,6 +49,86 @@ findInstructionBySymbol(const NormalizedTargetModel &Model, std::string_view Sym std::ranges::contains(Instruction.Operands[Index].Kinds, "Register"); } +[[nodiscard]] std::optional<std::uint32_t> integerPredicateValue(std::string_view Symbol) noexcept { + static constexpr std::array<std::pair<std::string_view, IntegerPredicate>, 2> Predicates = {{ + {"eq", IntegerPredicate::Equal}, + {"ne", IntegerPredicate::NotEqual}, + }}; + if (Symbol == "sgt") + return static_cast<std::uint32_t>(IntegerPredicate::SignedGreaterThan); + if (Symbol == "sge") + return static_cast<std::uint32_t>(IntegerPredicate::SignedGreaterEqual); + if (Symbol == "sle") + return static_cast<std::uint32_t>(IntegerPredicate::SignedLessEqual); + if (Symbol == "slt") + return static_cast<std::uint32_t>(IntegerPredicate::SignedLessThan); + if (Symbol == "ugt") + return static_cast<std::uint32_t>(IntegerPredicate::UnsignedGreaterThan); + if (Symbol == "uge") + return static_cast<std::uint32_t>(IntegerPredicate::UnsignedGreaterEqual); + if (Symbol == "ult") + return static_cast<std::uint32_t>(IntegerPredicate::UnsignedLessThan); + if (Symbol == "ule") + return static_cast<std::uint32_t>(IntegerPredicate::UnsignedLessEqual); + const auto *const Position = + std::ranges::find(Predicates, Symbol, &decltype(Predicates)::value_type::first); + if (Position == Predicates.end()) + return std::nullopt; + return static_cast<std::uint32_t>(Position->second); +} + +[[nodiscard]] const NormalizedRegister *findRegisterBySymbol(const NormalizedTargetModel &Model, + std::string_view Symbol) { + const auto Position = std::ranges::find(Model.Registers, Symbol, &NormalizedRegister::Symbol); + return Position == Model.Registers.end() ? nullptr : &*Position; +} + +[[nodiscard]] std::optional<RegisterOperandFlags> +registerOperandFlags(std::span<const std::string> Names) noexcept { + RegisterOperandFlags Flags; + for (const std::string &Name : Names) { + const auto Set = [&Flags](RegisterOperandFlag Flag) { + Flags.set(Flag); + return true; + }; + if (Name == "define") + Set(RegisterOperandFlag::Define); + else if (Name == "use") + Set(RegisterOperandFlag::Use); + else if (Name == "implicit") + Set(RegisterOperandFlag::Implicit); + else if (Name == "kill") + Set(RegisterOperandFlag::Kill); + else if (Name == "dead") + Set(RegisterOperandFlag::Dead); + else if (Name == "undef") + Set(RegisterOperandFlag::Undef); + else if (Name == "early_clobber") + Set(RegisterOperandFlag::EarlyClobber); + else if (Name == "internal_read") + Set(RegisterOperandFlag::InternalRead); + else if (Name == "renamable") + Set(RegisterOperandFlag::Renamable); + else if (Name == "debug") + Set(RegisterOperandFlag::Debug); + else + return std::nullopt; + } + return Flags; +} + +[[nodiscard]] bool validRegisterOperandFlags(RegisterOperandFlags Flags) noexcept { + const bool IsDef = Flags.has(RegisterOperandFlag::Define); + const bool IsUse = Flags.has(RegisterOperandFlag::Use); + return (IsDef || IsUse) && (!Flags.has(RegisterOperandFlag::Kill) || IsUse) && + (!Flags.has(RegisterOperandFlag::Dead) || IsDef) && + (!Flags.has(RegisterOperandFlag::Undef) || IsUse) && + (!Flags.has(RegisterOperandFlag::EarlyClobber) || IsDef) && + (!Flags.has(RegisterOperandFlag::InternalRead) || (IsDef && IsUse)) && + (!(IsDef && IsUse) || Flags.has(RegisterOperandFlag::InternalRead)) && + (!Flags.has(RegisterOperandFlag::Debug) || (IsUse && !IsDef)); +} + } // namespace bool CodeGenTarget::normalizeSelectionRules(NormalizedTargetModel &Result) { @@ -73,7 +156,7 @@ bool CodeGenTarget::normalizeSelectionRules(NormalizedTargetModel &Result) { fail(Rule.Range, "selection rule result opcode must not be generic"); return false; } - if (MatchInstruction != nullptr && ResultInstruction != nullptr && + if (!Rule.OperandRenderers && MatchInstruction != nullptr && ResultInstruction != nullptr && ResultInstruction->Operands.size() != MatchInstruction->Operands.size() + Rule.AppendedImmediates.size()) { fail(Rule.Range, "selection rule result opcode has an incompatible operand count"); @@ -106,6 +189,7 @@ bool CodeGenTarget::normalizeSelectionRules(NormalizedTargetModel &Result) { Normalized.MatchOpcode = *MatchOpcode; Normalized.ResultOpcode = *ResultOpcode; Normalized.AppendedImmediates = Rule.AppendedImmediates; + Normalized.EraseOperandDefinitions = Rule.EraseOperandDefinitions; if (Rule.ResultType) { auto Type = NormalizeType(*Rule.ResultType); if (!Type) @@ -119,6 +203,29 @@ bool CodeGenTarget::normalizeSelectionRules(NormalizedTargetModel &Result) { ++Normalized.Specificity; } + if (Rule.IntegerPredicate) { + const auto Predicate = integerPredicateValue(Rule.IntegerPredicate->Predicate); + if (!Predicate) { + fail(Rule.IntegerPredicate->Range, + "selection integer predicate is not a recognized integer predicate"); + return false; + } + if (MatchInstruction != nullptr && + (Rule.IntegerPredicate->OperandIndex >= MatchInstruction->Operands.size() || + !std::ranges::contains( + MatchInstruction->Operands[Rule.IntegerPredicate->OperandIndex].Kinds, + "Predicate"))) { + fail(Rule.IntegerPredicate->Range, + "selection integer predicate requires a predicate operand"); + return false; + } + Normalized.IntegerPredicate = { + .OperandIndex = Rule.IntegerPredicate->OperandIndex, + .Predicate = *Predicate, + }; + ++Normalized.Specificity; + } + std::unordered_set<std::uint32_t> TypeOperands; for (const SourceSelectionOperandTypePredicate &Predicate : Rule.OperandTypes) { auto Type = NormalizeType(Predicate.Type); @@ -166,6 +273,83 @@ bool CodeGenTarget::normalizeSelectionRules(NormalizedTargetModel &Result) { {.OperandIndex = Predicate.OperandIndex, .RegClass = RegClass->second}); ++Normalized.Specificity; } + + std::unordered_set<std::uint32_t> ConstantOperands; + for (const SourceSelectionOperandDefConstantPredicate &Predicate : Rule.OperandDefConstants) { + if (!ConstantOperands.insert(Predicate.OperandIndex).second || + (MatchInstruction != nullptr && + !isRegisterOperand(*MatchInstruction, Predicate.OperandIndex))) { + fail(Predicate.Range, + "selection operand definition constant predicates require distinct register " + "operands"); + return false; + } + Normalized.OperandDefConstants.push_back( + {.OperandIndex = Predicate.OperandIndex, .Value = Predicate.Value}); + ++Normalized.Specificity; + } + + if (Rule.OperandRenderers) { + if (!Rule.AppendedImmediates.empty()) { + fail(Rule.Range, "selection rule cannot combine operand renderers and appended immediates"); + return false; + } + std::vector<NormalizedSelectionOperandRenderer> Renderers; + Renderers.reserve(Rule.OperandRenderers->size()); + for (const SourceSelectionOperandRenderer &Renderer : *Rule.OperandRenderers) { + if (Renderer.OperandIndex) { + if (MatchInstruction != nullptr && + *Renderer.OperandIndex >= MatchInstruction->Operands.size()) { + fail(Renderer.Range, "selection operand renderer references an unknown operand"); + return false; + } + Renderers.push_back({ + .SourceKind = NormalizedSelectionOperandRenderer::Kind::Operand, + .Value = *Renderer.OperandIndex, + .Flags = 0, + }); + continue; + } + + const NormalizedRegister *Physical = + findRegisterBySymbol(Result, Renderer.PhysicalRegisterSymbol); + const auto Flags = registerOperandFlags(Renderer.Flags); + if (Physical == nullptr || Physical->ID == 0 || !Flags) { + fail(Renderer.Range, + "selection physical register renderer requires a declared register and valid " + "register flags"); + return false; + } + if (!validRegisterOperandFlags(*Flags)) { + fail(Renderer.Range, "selection physical register renderer is invalid"); + return false; + } + Renderers.push_back({ + .SourceKind = NormalizedSelectionOperandRenderer::Kind::PhysicalRegister, + .Value = Physical->ID, + .Flags = Flags->rawValue(), + }); + } + if (ResultInstruction != nullptr && ResultInstruction->Operands.size() != Renderers.size()) { + fail(Rule.Range, "selection operand renderer has an incompatible operand count"); + return false; + } + Normalized.OperandRenderers = std::move(Renderers); + } else if (ResultInstruction != nullptr && MatchInstruction != nullptr && + ResultInstruction->Operands.size() != + MatchInstruction->Operands.size() + Rule.AppendedImmediates.size()) { + fail(Rule.Range, "selection rule result opcode has an incompatible operand count"); + return false; + } + + std::unordered_set<std::uint32_t> ErasedOperands; + for (const std::uint32_t OperandIndex : Rule.EraseOperandDefinitions) { + if (!ErasedOperands.insert(OperandIndex).second || + (MatchInstruction != nullptr && !isRegisterOperand(*MatchInstruction, OperandIndex))) { + fail(Rule.Range, "selection erased definitions require distinct register operands"); + return false; + } + } Result.SelectionRules.push_back(std::move(Normalized)); } |
