aboutsummaryrefslogtreecommitdiff
path: root/backend/unittests
diff options
context:
space:
mode:
authorRichard-Qin-X <richard.qin.001@gmail.com>2026-08-01 17:10:33 +0800
committerRichard-Qin-X <richard.qin.001@gmail.com>2026-08-01 17:10:33 +0800
commit77d76b73a614820bf45024b053db376f35b06d10 (patch)
tree122fa035693683366ad51c0d57b7c9c91f5563b5 /backend/unittests
parent85eed8fb2d6563fea750f7b55730c9feaecc5898 (diff)
downloadrcc-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.txt1
-rw-r--r--backend/unittests/CodeGen/CMakeLists.txt12
-rw-r--r--backend/unittests/CodeGen/CompilationUnitTest.cpp58
-rw-r--r--backend/unittests/MIR/CMakeLists.txt10
-rw-r--r--backend/unittests/MIR/EmbeddedIRTest.cpp133
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();
+}