diff options
| author | Richard-Qin-X <richard.qin.001@gmail.com> | 2026-08-01 17:10:33 +0800 |
|---|---|---|
| committer | Richard-Qin-X <richard.qin.001@gmail.com> | 2026-08-01 17:10:33 +0800 |
| commit | 77d76b73a614820bf45024b053db376f35b06d10 (patch) | |
| tree | 122fa035693683366ad51c0d57b7c9c91f5563b5 /backend/unittests | |
| parent | 85eed8fb2d6563fea750f7b55730c9feaecc5898 (diff) | |
| download | rcc-project-77d76b73a614820bf45024b053db376f35b06d10.tar.gz rcc-project-77d76b73a614820bf45024b053db376f35b06d10.tar.xz | |
[MIR] Add compilation unit reference context
Diffstat (limited to 'backend/unittests')
| -rw-r--r-- | backend/unittests/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | backend/unittests/CodeGen/CMakeLists.txt | 12 | ||||
| -rw-r--r-- | backend/unittests/CodeGen/CompilationUnitTest.cpp | 58 | ||||
| -rw-r--r-- | backend/unittests/MIR/CMakeLists.txt | 10 | ||||
| -rw-r--r-- | backend/unittests/MIR/EmbeddedIRTest.cpp | 133 |
5 files changed, 214 insertions, 0 deletions
diff --git a/backend/unittests/CMakeLists.txt b/backend/unittests/CMakeLists.txt index e612449..b93373d 100644 --- a/backend/unittests/CMakeLists.txt +++ b/backend/unittests/CMakeLists.txt @@ -3,3 +3,4 @@ add_subdirectory(Support) add_subdirectory(Target) add_subdirectory(CodeGen) +add_subdirectory(MIR) diff --git a/backend/unittests/CodeGen/CMakeLists.txt b/backend/unittests/CodeGen/CMakeLists.txt index b0bdd13..e128d0b 100644 --- a/backend/unittests/CodeGen/CMakeLists.txt +++ b/backend/unittests/CodeGen/CMakeLists.txt @@ -2,6 +2,7 @@ set( RCCBackendCodeGenTestSources + CompilationUnitTest.cpp CoreTypesTest.cpp InstructionDescriptorTest.cpp MachineCompilationStatusTest.cpp @@ -19,6 +20,15 @@ set( TargetRegisterInfoTest.cpp ) +add_executable(RCCBackendCodeGenCompilationUnitTests CompilationUnitTest.cpp) +rcc_backend_configure_target(RCCBackendCodeGenCompilationUnitTests) +target_link_libraries(RCCBackendCodeGenCompilationUnitTests PRIVATE RCCBackend::CodeGen) + +add_test( + NAME RCCBackend.CodeGen.CompilationUnit + COMMAND RCCBackendCodeGenCompilationUnitTests +) + add_executable(RCCBackendCodeGenCoreTypesTests CoreTypesTest.cpp) rcc_backend_configure_target(RCCBackendCodeGenCoreTypesTests) target_link_libraries(RCCBackendCodeGenCoreTypesTests PRIVATE RCCBackend::CodeGen) @@ -188,6 +198,7 @@ add_test( ) rcc_backend_register_format_files( + "${CMAKE_CURRENT_SOURCE_DIR}/CompilationUnitTest.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/CoreTypesTest.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/InstructionDescriptorTest.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineCompilationStatusTest.cpp" @@ -205,6 +216,7 @@ rcc_backend_register_format_files( "${CMAKE_CURRENT_SOURCE_DIR}/TargetRegisterInfoTest.cpp" ) rcc_backend_register_tidy_files( + "${CMAKE_CURRENT_SOURCE_DIR}/CompilationUnitTest.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/CoreTypesTest.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/InstructionDescriptorTest.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineCompilationStatusTest.cpp" diff --git a/backend/unittests/CodeGen/CompilationUnitTest.cpp b/backend/unittests/CodeGen/CompilationUnitTest.cpp new file mode 100644 index 0000000..39cd175 --- /dev/null +++ b/backend/unittests/CodeGen/CompilationUnitTest.cpp @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "rcc/CodeGen/CompilationUnit.h" + +#include "rcc/CodeGen/MachineFunction.h" + +#include <iostream> +#include <utility> + +namespace { + +int fail(const char *Message) { + std::cerr << Message << '\n'; + return 1; +} + +} // namespace + +int main() { + rcc::CompilationUnit Unit; + auto Empty = Unit.createMachineFunction(""); + if (Empty || Unit.functionCount() != 0) + return fail("CompilationUnit must reject an empty function name atomically"); + + auto First = Unit.createMachineFunction("first"); + if (!First || (*First)->stableID().value() != 1) + return fail("CompilationUnit must allocate the first stable function identity"); + + auto Duplicate = Unit.createMachineFunction("first"); + if (Duplicate || Unit.functionCount() != 1) + return fail("CompilationUnit must reject duplicate function names atomically"); + + auto Second = Unit.createMachineFunction("second"); + if (!Second || (*Second)->stableID().value() != 2) + return fail("Rejected function creation must not consume a StableID"); + if (Unit.functionCount() != 2 || Unit.functionAt(0) != *First || Unit.functionAt(1) != *Second) + return fail("CompilationUnit must preserve function document order"); + if (Unit.function("first") != *First || Unit.function("missing") != nullptr) + return fail("CompilationUnit must provide exact name lookup"); + if (Unit.function((*Second)->stableID()) != *Second || + Unit.function(rcc::MachineFunctionStableID::fromValue(99)) != nullptr) + return fail("CompilationUnit must provide exact StableID lookup"); + if (Unit.functionAt(2) != nullptr) + return fail("CompilationUnit must reject an out-of-range ordered lookup"); + + auto Verification = Unit.verify(); + if (!Verification) + return fail("A valid CompilationUnit must pass verification"); + + rcc::CompilationUnit Moved = std::move(Unit); + if (Moved.functionCount() != 2 || Moved.function("first") != *First || + Moved.function("second") != *Second) + return fail("Moving a CompilationUnit must preserve owned function addresses and indices"); + Verification = Moved.verify(); + if (!Verification) + return fail("A moved CompilationUnit must pass verification"); + return 0; +} diff --git a/backend/unittests/MIR/CMakeLists.txt b/backend/unittests/MIR/CMakeLists.txt new file mode 100644 index 0000000..7a60ba2 --- /dev/null +++ b/backend/unittests/MIR/CMakeLists.txt @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-3.0-or-later + +add_executable(RCCBackendEmbeddedIRTests EmbeddedIRTest.cpp) +rcc_backend_configure_target(RCCBackendEmbeddedIRTests) +target_link_libraries(RCCBackendEmbeddedIRTests PRIVATE RCCBackend::MIR) + +add_test(NAME RCCBackend.MIR.EmbeddedIR COMMAND RCCBackendEmbeddedIRTests) + +rcc_backend_register_format_files("${CMAKE_CURRENT_SOURCE_DIR}/EmbeddedIRTest.cpp") +rcc_backend_register_tidy_files("${CMAKE_CURRENT_SOURCE_DIR}/EmbeddedIRTest.cpp") diff --git a/backend/unittests/MIR/EmbeddedIRTest.cpp b/backend/unittests/MIR/EmbeddedIRTest.cpp new file mode 100644 index 0000000..58c6162 --- /dev/null +++ b/backend/unittests/MIR/EmbeddedIRTest.cpp @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "rcc/MIR/EmbeddedIR.h" + +#include <iostream> +#include <string> +#include <string_view> + +namespace { + +int fail(const char *Message) { + std::cerr << Message << '\n'; + return 1; +} + +int testReferenceIndex() { + const std::string Input = "; @commented = global i8 0\n" + "target datalayout = \"e-m:e-p:64:64\"\n" + "target triple = \"riscv64-unknown-linux-gnu\"\n" + "@ordinary = global i32 0\n" + "@\"space\\20global\" = external global i8\n" + "declare void @declared()\n" + "define void @\"function\\20name\"(\n" + " { i32, i32 } %argument\n" + ") {\n" + "entry:\n" + " %slot = alloca i32, align 4\n" + " %not_an_alloca = add i32 1, 2\n" + " br label %\"exit\\20block\"\n" + "\"exit\\20block\":\n" + " ret void\n" + "}\n" + "!0 = !{}\n" + "!llvm.module.flags = !{!0}\n"; + + rcc::mir::EmbeddedIRIndexResult Result = rcc::mir::indexEmbeddedIR("embedded.ll", Input); + const rcc::mir::EmbeddedIRReferenceIndex *Index = Result.index(); + if (!Result.succeeded() || Index == nullptr) + return fail("Embedded IR indexing must accept the MIR reference subset"); + if (Index->source().text() != Input) + return fail("Embedded IR indexing must preserve the original text"); + if (Index->targetTriple() != std::optional<std::string_view>("riscv64-unknown-linux-gnu") || + Index->dataLayout() != std::optional<std::string_view>("e-m:e-p:64:64")) + return fail("Embedded IR indexing must preserve target facts"); + if (Index->functions().size() != 2 || Index->function("declared") == nullptr || + Index->function("declared")->isDefinition()) + return fail("Embedded IR indexing must retain function declarations"); + + const rcc::mir::EmbeddedIRFunction *Function = Index->function("function name"); + if (Function == nullptr || !Function->isDefinition() || Function->blocks().size() != 2) + return fail("Embedded IR indexing must decode function and block identifiers"); + if (Function->block("entry") == nullptr || Function->block("exit block") == nullptr) + return fail("Embedded IR block lookup must use decoded names"); + if (Function->allocas().size() != 1 || Function->alloca("slot") == nullptr || + Function->alloca("not_an_alloca") != nullptr) + return fail("Embedded IR indexing must distinguish named allocas from other local values"); + + if (!Index->hasGlobalValue("ordinary") || !Index->hasGlobalValue("space global") || + !Index->hasGlobalValue("declared") || Index->hasGlobalValue("commented")) + return fail("Embedded IR global lookup must include objects and functions but ignore comments"); + if (Index->metadata("0") == nullptr || Index->metadata("llvm.module.flags") == nullptr || + Index->metadataDefinitions().size() != 2) + return fail("Embedded IR indexing must retain numeric and named metadata definitions"); + return 0; +} + +int testDeclarationDefinitionMerge() { + const std::string Input = "declare void @shared()\n" + "define void @shared() {\n" + "0:\n" + " ret void\n" + "}\n"; + rcc::mir::EmbeddedIRIndexResult Result = rcc::mir::indexEmbeddedIR("merge.ll", Input); + const rcc::mir::EmbeddedIRReferenceIndex *Index = Result.index(); + if (!Result.succeeded() || Index == nullptr || Index->functions().size() != 1) + return fail("Embedded IR indexing must merge a declaration with its definition"); + const rcc::mir::EmbeddedIRFunction *Function = Index->function("shared"); + if (Function == nullptr || !Function->isDefinition() || Function->block("0") == nullptr) + return fail("A later definition must complete its indexed declaration"); + return 0; +} + +bool hasSingleDiagnostic(const rcc::mir::EmbeddedIRIndexResult &Result, std::string_view Message) { + return !Result.succeeded() && Result.diagnostics().size() == 1 && + Result.diagnostics()[0].Message == Message; +} + +int testDiagnostics() { + auto DuplicateBlock = + rcc::mir::indexEmbeddedIR("blocks.ll", "define void @f() {\nentry:\nentry:\n ret void\n}\n"); + if (!hasSingleDiagnostic(DuplicateBlock, "duplicate embedded LLVM IR basic block label") || + DuplicateBlock.diagnostics()[0].Range.Begin.Line != 3) + return fail("Embedded IR indexing must reject a duplicate block at its second label"); + + auto BadEscape = rcc::mir::indexEmbeddedIR("escape.ll", "@\"bad\\q0\" = global i8 0\n"); + if (!hasSingleDiagnostic(BadEscape, + "LLVM IR identifier escape must contain two hexadecimal digits")) + return fail("Embedded IR indexing must reject malformed identifier escapes"); + + auto Unterminated = + rcc::mir::indexEmbeddedIR("function.ll", "define void @f() {\nentry:\n ret void\n"); + if (!hasSingleDiagnostic(Unterminated, + "embedded LLVM IR function definition has no closing brace")) + return fail("Embedded IR indexing must reject an unterminated function definition"); + + auto DuplicateTriple = + rcc::mir::indexEmbeddedIR("triple.ll", "target triple = \"riscv64-unknown-linux-gnu\"\n" + "target triple = \"riscv64-unknown-linux-gnu\"\n"); + if (!hasSingleDiagnostic(DuplicateTriple, "duplicate embedded LLVM IR target triple")) + return fail("Embedded IR indexing must reject duplicate target facts"); + + auto NameConflict = + rcc::mir::indexEmbeddedIR("names.ll", "@same = global i32 0\ndeclare void @same()\n"); + if (!hasSingleDiagnostic(NameConflict, + "embedded LLVM IR name is used by both a function and a global object")) + return fail("Embedded IR indexing must reject conflicting global value kinds"); + + const std::string NulInput("target triple = \"x\"\0", 20); + auto Nul = rcc::mir::indexEmbeddedIR("nul.ll", NulInput); + if (!hasSingleDiagnostic(Nul, "NUL bytes are not allowed in embedded LLVM IR")) + return fail("Embedded IR indexing must reject embedded NUL bytes"); + return 0; +} + +} // namespace + +int main() { + if (const int Result = testReferenceIndex(); Result != 0) + return Result; + if (const int Result = testDeclarationDefinitionMerge(); Result != 0) + return Result; + return testDiagnostics(); +} |
