aboutsummaryrefslogtreecommitdiff
path: root/backend/utils/TableGen/Common
diff options
context:
space:
mode:
Diffstat (limited to 'backend/utils/TableGen/Common')
-rw-r--r--backend/utils/TableGen/Common/CodeGenInstruction.cpp9
-rw-r--r--backend/utils/TableGen/Common/CodeGenMCPseudoLowering.cpp121
-rw-r--r--backend/utils/TableGen/Common/CodeGenTarget.cpp3
-rw-r--r--backend/utils/TableGen/Common/CodeGenTarget.h20
4 files changed, 146 insertions, 7 deletions
diff --git a/backend/utils/TableGen/Common/CodeGenInstruction.cpp b/backend/utils/TableGen/Common/CodeGenInstruction.cpp
index 61c72a2..45b597c 100644
--- a/backend/utils/TableGen/Common/CodeGenInstruction.cpp
+++ b/backend/utils/TableGen/Common/CodeGenInstruction.cpp
@@ -388,13 +388,10 @@ CodeGenTarget::normalizeImplicitRegisters(const std::vector<SourceImplicitRegist
HasEncodingCategory || HasAssemblyFormat;
const bool IsPseudoSource =
std::ranges::find(Instruction.Flags, "pseudo") != Instruction.Flags.end();
- const bool IsTerminalEmissionSource =
- std::ranges::find(Instruction.Flags, "terminal_emission") != Instruction.Flags.end();
- if (HasAnyMachineFact != HasAllMachineFacts ||
- ((!IsPseudoSource || IsTerminalEmissionSource) && !HasAllMachineFacts)) {
+ if ((!IsPseudoSource && !HasAllMachineFacts) || HasAnyMachineFact != HasAllMachineFacts) {
fail(Instruction.Range,
- "encoded instructions and terminal-emission pseudos require complete scheduling, "
- "encoding, mnemonic, and assembly-format facts");
+ "encoded instructions require complete scheduling, encoding, mnemonic, and "
+ "assembly-format facts");
return false;
}
const auto SchedulingClass = SchedulingClassBySymbol.find(Instruction.SchedulingClassSymbol);
diff --git a/backend/utils/TableGen/Common/CodeGenMCPseudoLowering.cpp b/backend/utils/TableGen/Common/CodeGenMCPseudoLowering.cpp
new file mode 100644
index 0000000..49ec2a6
--- /dev/null
+++ b/backend/utils/TableGen/Common/CodeGenMCPseudoLowering.cpp
@@ -0,0 +1,121 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "CodeGenTarget.h"
+
+#include <algorithm>
+#include <cstdint>
+#include <ranges>
+#include <string_view>
+#include <unordered_set>
+
+namespace rcc::targetgen {
+namespace {
+
+[[nodiscard]] const NormalizedInstruction *findInstruction(const NormalizedTargetModel &Model,
+ std::string_view Symbol) noexcept {
+ const auto Position =
+ std::ranges::find(Model.Instructions, Symbol, &NormalizedInstruction::Symbol);
+ return Position == Model.Instructions.end() ? nullptr : &*Position;
+}
+
+[[nodiscard]] bool hasFlag(const NormalizedInstruction &Instruction,
+ std::string_view Flag) noexcept {
+ return std::ranges::contains(Instruction.Flags, Flag);
+}
+
+[[nodiscard]] bool hasCompatibleKind(const NormalizedOperand &Source,
+ const NormalizedOperand &Result) noexcept {
+ return std::ranges::any_of(Source.Kinds, [&Result](const std::string &Kind) {
+ return std::ranges::contains(Result.Kinds, Kind);
+ });
+}
+
+} // namespace
+
+bool CodeGenTarget::normalizeMCPseudoExpansions(NormalizedTargetModel &Result) {
+ std::unordered_set<std::uint32_t> PseudoOpcodes;
+ for (const SourceMCPseudoExpansion &Expansion : Input.MCPseudoExpansions) {
+ const NormalizedInstruction *Pseudo = findInstruction(Result, Expansion.PseudoOpcodeSymbol);
+ const NormalizedInstruction *ResultInstruction =
+ findInstruction(Result, Expansion.ResultOpcodeSymbol);
+ if (Pseudo == nullptr || ResultInstruction == nullptr ||
+ !PseudoOpcodes.insert(Pseudo == nullptr ? 0 : Pseudo->ID).second) {
+ fail(Expansion.Range,
+ "MC pseudo expansions require a unique declared pseudo and result instruction");
+ return false;
+ }
+ if (!hasFlag(*Pseudo, "Pseudo") || !hasFlag(*Pseudo, "TerminalEmission") ||
+ Pseudo->Owner != "AsmPrinter" || Pseudo->Deadline != "Emission" ||
+ hasFlag(*ResultInstruction, "Pseudo") || ResultInstruction->AssemblyMnemonic.empty()) {
+ fail(Expansion.Range,
+ "MC pseudo expansions require an AsmPrinter-owned terminal pseudo and encoded result");
+ return false;
+ }
+ if (Expansion.Operands.size() != ResultInstruction->Operands.size()) {
+ fail(Expansion.Range, "MC pseudo expansion operand count must match the result instruction");
+ return false;
+ }
+
+ NormalizedMCPseudoExpansion Normalized{
+ .PseudoOpcode = Pseudo->ID,
+ .ResultOpcode = ResultInstruction->ID,
+ .Operands = {},
+ };
+ Normalized.Operands.reserve(Expansion.Operands.size());
+ for (std::size_t Index = 0; Index < Expansion.Operands.size(); ++Index) {
+ const SourceMCPseudoOperand &Operand = Expansion.Operands[Index];
+ const unsigned SourceCount = static_cast<unsigned>(Operand.SourceOperandIndex.has_value()) +
+ static_cast<unsigned>(!Operand.RegisterSymbol.empty()) +
+ static_cast<unsigned>(Operand.Immediate.has_value());
+ if (SourceCount != 1) {
+ fail(Operand.Range,
+ "MC pseudo expansion operands require exactly one operand, register, or immediate");
+ return false;
+ }
+ const NormalizedOperand &ResultOperand = ResultInstruction->Operands[Index];
+ if (Operand.SourceOperandIndex) {
+ if (*Operand.SourceOperandIndex >= Pseudo->Operands.size() ||
+ !hasCompatibleKind(Pseudo->Operands[*Operand.SourceOperandIndex], ResultOperand)) {
+ fail(Operand.Range,
+ "MC pseudo source operand must exist and match the result operand kind");
+ return false;
+ }
+ Normalized.Operands.push_back({
+ .Kind = NormalizedMCPseudoOperandKind::SourceOperand,
+ .Value = *Operand.SourceOperandIndex,
+ .Immediate = 0,
+ });
+ continue;
+ }
+ if (!Operand.RegisterSymbol.empty()) {
+ const auto Register = RegisterBySymbol.find(Operand.RegisterSymbol);
+ if (Register == RegisterBySymbol.end() ||
+ !std::ranges::contains(ResultOperand.Kinds, "Register")) {
+ fail(Operand.Range,
+ "MC pseudo fixed register must be declared and target a register operand");
+ return false;
+ }
+ Normalized.Operands.push_back({
+ .Kind = NormalizedMCPseudoOperandKind::Register,
+ .Value = Register->second,
+ .Immediate = 0,
+ });
+ continue;
+ }
+ if (!std::ranges::contains(ResultOperand.Kinds, "Immediate")) {
+ fail(Operand.Range, "MC pseudo fixed immediate must target an immediate operand");
+ return false;
+ }
+ Normalized.Operands.push_back({
+ .Kind = NormalizedMCPseudoOperandKind::Immediate,
+ .Value = 0,
+ .Immediate = *Operand.Immediate,
+ });
+ }
+ Result.MCPseudoExpansions.push_back(std::move(Normalized));
+ }
+ std::ranges::sort(Result.MCPseudoExpansions, {}, &NormalizedMCPseudoExpansion::PseudoOpcode);
+ return true;
+}
+
+} // namespace rcc::targetgen
diff --git a/backend/utils/TableGen/Common/CodeGenTarget.cpp b/backend/utils/TableGen/Common/CodeGenTarget.cpp
index 9b96d2e..d4c9795 100644
--- a/backend/utils/TableGen/Common/CodeGenTarget.cpp
+++ b/backend/utils/TableGen/Common/CodeGenTarget.cpp
@@ -37,7 +37,7 @@ CodeGenTarget::CodeGenTarget(const DescriptionAST &Input, std::string SourceName
!normalizeSchedulingClasses(Result) || !normalizeEncodingCategories(Result) ||
!normalizeAssemblyFormats(Result) || !normalizeInstructions(Result) ||
!normalizeSelectionRules(Result) || !normalizeCombinerRules(Result) ||
- !normalizeMacroFusionRules(Result)) {
+ !normalizeMacroFusionRules(Result) || !normalizeMCPseudoExpansions(Result)) {
return std::nullopt;
}
std::ranges::sort(Result.RegisterUnits, {}, &SourceRegisterUnit::ID);
@@ -219,6 +219,7 @@ DescriptionGenerationResult generateDescription(const std::string &SourceName,
.GlobalISel = emitGlobalISel(*Model, DisplayName),
.GlobalISelCombiner = emitGlobalISelCombiner(*Model, DisplayName),
.MacroFusion = emitMacroFusion(*Model, DisplayName),
+ .MCPseudoLowering = emitMCPseudoLowering(*Model, DisplayName),
},
.Diagnostics = {},
};
diff --git a/backend/utils/TableGen/Common/CodeGenTarget.h b/backend/utils/TableGen/Common/CodeGenTarget.h
index 6d3e185..43c7383 100644
--- a/backend/utils/TableGen/Common/CodeGenTarget.h
+++ b/backend/utils/TableGen/Common/CodeGenTarget.h
@@ -151,6 +151,24 @@ struct NormalizedMacroFusionRule final {
bool RequireSecondDestinationTie = false;
};
+enum class NormalizedMCPseudoOperandKind : std::uint8_t {
+ SourceOperand,
+ Register,
+ Immediate,
+};
+
+struct NormalizedMCPseudoOperand final {
+ NormalizedMCPseudoOperandKind Kind = NormalizedMCPseudoOperandKind::SourceOperand;
+ std::uint32_t Value = 0;
+ std::int64_t Immediate = 0;
+};
+
+struct NormalizedMCPseudoExpansion final {
+ std::uint32_t PseudoOpcode = 0;
+ std::uint32_t ResultOpcode = 0;
+ std::vector<NormalizedMCPseudoOperand> Operands;
+};
+
struct NormalizedEncodingCategory final {
std::uint32_t ID = 0;
std::string Symbol;
@@ -393,6 +411,7 @@ struct NormalizedTargetModel final {
std::vector<NormalizedSelectionRule> SelectionRules;
std::vector<NormalizedCombinerRule> CombinerRules;
std::vector<NormalizedMacroFusionRule> MacroFusionRules;
+ std::vector<NormalizedMCPseudoExpansion> MCPseudoExpansions;
};
[[nodiscard]] std::optional<std::string_view>
@@ -437,6 +456,7 @@ private:
[[nodiscard]] bool normalizeSelectionRules(NormalizedTargetModel &Result);
[[nodiscard]] bool normalizeCombinerRules(NormalizedTargetModel &Result);
[[nodiscard]] bool normalizeMacroFusionRules(NormalizedTargetModel &Result);
+ [[nodiscard]] bool normalizeMCPseudoExpansions(NormalizedTargetModel &Result);
const DescriptionAST &Input;
std::string SourceName;