aboutsummaryrefslogtreecommitdiff
path: root/backend/unittests/Target/DescriptionGeneratorTest.cpp
diff options
context:
space:
mode:
authorRichard-Qin-X <richard.qin.001@gmail.com>2026-08-13 13:10:47 +0800
committerRichard-Qin-X <richard.qin.001@gmail.com>2026-08-13 13:10:47 +0800
commit444db30751380e8fe459bfeae4c5bb2a93c596eb (patch)
tree5c60a23678f836113e75fb2526d3ec7b28b42f55 /backend/unittests/Target/DescriptionGeneratorTest.cpp
parentfde3e045d4dcc5c404cb4216389e18b0e720b8e0 (diff)
downloadrcc-project-444db30751380e8fe459bfeae4c5bb2a93c596eb.tar.gz
rcc-project-444db30751380e8fe459bfeae4c5bb2a93c596eb.tar.xz
[TableGen] Split the target description generator
Diffstat (limited to 'backend/unittests/Target/DescriptionGeneratorTest.cpp')
-rw-r--r--backend/unittests/Target/DescriptionGeneratorTest.cpp202
1 files changed, 0 insertions, 202 deletions
diff --git a/backend/unittests/Target/DescriptionGeneratorTest.cpp b/backend/unittests/Target/DescriptionGeneratorTest.cpp
deleted file mode 100644
index e6679e8..0000000
--- a/backend/unittests/Target/DescriptionGeneratorTest.cpp
+++ /dev/null
@@ -1,202 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#include "TargetDescriptionGenerator.h"
-
-#include <cstddef>
-#include <iostream>
-#include <string>
-#include <string_view>
-
-namespace {
-
-class TestContext final {
-public:
- void expect(bool Condition, std::string_view Message) {
- if (Condition)
- return;
- std::cerr << Message << '\n';
- ++FailureCount;
- }
-
- [[nodiscard]] int result() const noexcept {
- return FailureCount == 0 ? 0 : 1;
- }
-
-private:
- int FailureCount = 0;
-};
-
-[[nodiscard]] std::string validDescription(std::string_view Aliases = "[acc]") {
- return std::string(R"(schema: rcc-target-description-v2
-target:
- namespace: tiny
- name: Tiny
- triple: tiny-unknown-none
- cpu: tiny-cpu
- abi: tiny-abi
- data_layout: e-p:64:64
- features: [base]
-register_units:
- - { id: 1, symbol: U_R1, name: r1.unit }
-registers:
- - { id: 1, symbol: R1, name: r1, encoding: 0, dwarf_register: 0, units: [{ unit: U_R1, lanes: 1 }], aliases: )") +
- std::string(Aliases) + R"( }
-register_banks:
- - { id: 1, symbol: GPR, name: GPR, maximum_size_bits: 64 }
-register_classes:
- - { id: 1, symbol: GPR64, name: GPR64, bank: GPR, size_bits: 64, spill_size_bits: 64, spill_alignment_bits: 64, lanes: 1, registers: [R1], allocation_order: [R1] }
-register_masks:
- - { name: CSR_TINY, preserved: [R1] }
-mir_operand_flags:
- direct_mask: 31
- direct: [{ name: tiny-call, value: 1 }]
- bitmask: [{ name: tiny-relax, value: 32 }]
-calling_conventions:
- - { id: 1, symbol: TINY, name: tiny, integer_register_class: GPR64, floating_register_class: GPR64, integer_argument_registers: [R1], floating_argument_registers: [R1], integer_return_registers: [R1], floating_return_registers: [R1], preserved_mask: CSR_TINY, stack_alignment_bytes: 8, stack_argument_alignment_bytes: 8, shadow_space_bytes: 0, supports_varargs: true, supports_tail_calls: true }
-named_operands:
- - { id: 1, symbol: RD, name: rd }
- - { id: 2, symbol: IMM, name: imm }
-immediate_predicates:
- - { id: 1, symbol: SIMM8, name: simm8, kind: signed, bits: 8 }
-scheduling_classes:
- - { id: 1, symbol: ALU, name: alu, micro_ops: 1, latency: 1 }
-encoding_categories:
- - { id: 1, symbol: I, name: i, size_bytes: 4 }
-assembly_formats:
- - { id: 1, symbol: RD_IMM, name: rd-imm }
-instructions:
- - { id: 1024, symbol: LOAD_IMM, name: LOAD_IMM, assembly_mnemonic: load.imm, encoding: 19, operands: [{ kinds: [register], role: def, register_class: GPR64, register_bank: GPR, name: RD }, { kinds: [immediate, global_symbol], immediate_predicate: SIMM8, name: IMM, allowed_target_flags: 33 }], num_explicit_defs: 1, flags: [produces_code], scheduling_class: ALU, encoding_category: I, assembly_format: RD_IMM }
-)";
-}
-
-void testGeneration(TestContext &Context) {
- const auto First = rcc::targetgen::generateDescription("tiny.rccdesc", validDescription());
- const auto Second = rcc::targetgen::generateDescription("tiny.rccdesc", validDescription());
- if (!First.succeeded()) {
- for (const rcc::TextDiagnostic &Diagnostic : First.Diagnostics)
- std::cerr << Diagnostic.Message << '\n';
- }
- Context.expect(First.succeeded() && Second.succeeded(),
- "a complete restricted target description must generate successfully");
- if (!First.succeeded() || !Second.succeeded() || !First.Output || !Second.Output)
- return;
- const auto &FirstOutput = First.Output.value();
- const auto &SecondOutput = Second.Output.value();
-
- Context.expect(FirstOutput.RegisterHeader == SecondOutput.RegisterHeader &&
- FirstOutput.InstructionHeader == SecondOutput.InstructionHeader &&
- FirstOutput.TargetTables == SecondOutput.TargetTables,
- "target description generation must be deterministic");
- Context.expect(
- FirstOutput.RegisterHeader.find("enum class PhysicalRegisterID") != std::string::npos &&
- FirstOutput.RegisterHeader.find("R1 = 1") != std::string::npos &&
- FirstOutput.InstructionHeader.find("enum class InstructionOpcode") != std::string::npos &&
- FirstOutput.InstructionHeader.find("LOAD_IMM = 1024") != std::string::npos &&
- FirstOutput.TargetTables.find("appendGeneratedRegisterInfo") != std::string::npos &&
- FirstOutput.TargetTables.find("appendGeneratedInstructionInfo") != std::string::npos &&
- FirstOutput.TargetTables.find("GeneratedAssemblyInstructions") != std::string::npos &&
- FirstOutput.TargetTables.find("Description.DirectOperandFlagMask = 31") !=
- std::string::npos &&
- FirstOutput.TargetTables.find("\"tiny-call\", 1") != std::string::npos &&
- FirstOutput.TargetTables.find("\"load.imm\"") != std::string::npos &&
- FirstOutput.TargetTables.find("makePreservedMask") != std::string::npos,
- "generated output must contain typed target IDs, assembly mnemonics, and static target "
- "tables");
-}
-
-void testSemanticRejection(TestContext &Context) {
- const auto CollidingAlias =
- rcc::targetgen::generateDescription("bad-alias.rccdesc", validDescription("[r1]"));
- if (CollidingAlias.succeeded())
- std::cerr << "colliding alias description unexpectedly generated\n";
- Context.expect(!CollidingAlias.succeeded() && !CollidingAlias.Diagnostics.empty() &&
- CollidingAlias.Diagnostics.front().Message.find("aliases") !=
- std::string::npos,
- "an ABI alias that collides with a canonical name must be rejected");
-
- std::string UnknownUnit = validDescription();
- constexpr std::string_view UnitReference = "unit: U_R1";
- const std::size_t UnitPosition = UnknownUnit.find(UnitReference);
- if (UnitPosition != std::string::npos)
- UnknownUnit.replace(UnitPosition, UnitReference.size(), "unit: U_MISSING");
- const auto BadUnit = rcc::targetgen::generateDescription("bad-unit.rccdesc", UnknownUnit);
- Context.expect(!BadUnit.succeeded() && !BadUnit.Diagnostics.empty() &&
- BadUnit.Diagnostics.front().Message.find("declared units") !=
- std::string::npos,
- "a register unit reference must resolve during semantic validation");
-
- std::string UnknownClass = validDescription();
- constexpr std::string_view ClassReference = "register_class: GPR64";
- const std::size_t ClassPosition = UnknownClass.find(ClassReference);
- if (ClassPosition != std::string::npos)
- UnknownClass.replace(ClassPosition, ClassReference.size(), "register_class: MISSING");
- const auto BadClass =
- rcc::targetgen::generateDescription("bad-instruction-class.rccdesc", UnknownClass);
- Context.expect(!BadClass.succeeded() && !BadClass.Diagnostics.empty() &&
- BadClass.Diagnostics.front().Message.find("register class") !=
- std::string::npos,
- "instruction register classes must resolve during semantic validation");
-
- std::string BadAllowedValue = validDescription();
- constexpr std::string_view Predicate = "kind: signed, bits: 8";
- const std::size_t PredicatePosition = BadAllowedValue.find(Predicate);
- if (PredicatePosition != std::string::npos) {
- BadAllowedValue.replace(PredicatePosition, Predicate.size(),
- "kind: signed, bits: 8, allowed_values: [128]");
- }
- const auto InvalidAllowedValue =
- rcc::targetgen::generateDescription("bad-allowed-value.rccdesc", BadAllowedValue);
- Context.expect(!InvalidAllowedValue.succeeded() && !InvalidAllowedValue.Diagnostics.empty() &&
- InvalidAllowedValue.Diagnostics.front().Message.find("allowed_values") !=
- std::string::npos,
- "immediate predicates must reject allowed values outside their signed range");
-
- std::string ContradictoryNonZero = validDescription();
- if (PredicatePosition != std::string::npos) {
- const std::size_t Position = ContradictoryNonZero.find(Predicate);
- ContradictoryNonZero.replace(Position, Predicate.size(),
- "kind: signed, bits: 8, nonzero: true, allowed_values: [0]");
- }
- const auto InvalidNonZero =
- rcc::targetgen::generateDescription("bad-nonzero.rccdesc", ContradictoryNonZero);
- Context.expect(!InvalidNonZero.succeeded() && !InvalidNonZero.Diagnostics.empty() &&
- InvalidNonZero.Diagnostics.front().Message.find("allowed_values") !=
- std::string::npos,
- "nonzero immediate predicates must reject an explicit zero value");
-
- std::string BadStackAlignment = validDescription();
- constexpr std::string_view StackAlignment =
- "stack_alignment_bytes: 8, stack_argument_alignment_bytes: 8";
- const std::size_t StackPosition = BadStackAlignment.find(StackAlignment);
- if (StackPosition != std::string::npos) {
- BadStackAlignment.replace(StackPosition, StackAlignment.size(),
- "stack_alignment_bytes: 8, stack_argument_alignment_bytes: 16");
- }
- const auto InvalidStackAlignment =
- rcc::targetgen::generateDescription("bad-stack-alignment.rccdesc", BadStackAlignment);
- Context.expect(!InvalidStackAlignment.succeeded() && !InvalidStackAlignment.Diagnostics.empty() &&
- InvalidStackAlignment.Diagnostics.front().Message.find("stack alignments") !=
- std::string::npos,
- "calling conventions must reject incompatible stack alignments");
-
- std::string BadMnemonic = validDescription();
- constexpr std::string_view Mnemonic = "assembly_mnemonic: load.imm";
- const std::size_t MnemonicPosition = BadMnemonic.find(Mnemonic);
- if (MnemonicPosition != std::string::npos)
- BadMnemonic.replace(MnemonicPosition, Mnemonic.size(), "assembly_mnemonic: .load");
- const auto InvalidMnemonic =
- rcc::targetgen::generateDescription("bad-mnemonic.rccdesc", BadMnemonic);
- Context.expect(!InvalidMnemonic.succeeded() && !InvalidMnemonic.Diagnostics.empty() &&
- InvalidMnemonic.Diagnostics.front().Message.find("assembly mnemonics") !=
- std::string::npos,
- "assembly mnemonics must use a canonical lowercase spelling");
-}
-
-} // namespace
-
-int main() {
- TestContext Context;
- testGeneration(Context);
- testSemanticRejection(Context);
- return Context.result();
-}