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/MIR/EmbeddedIRTest.cpp | |
| 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/MIR/EmbeddedIRTest.cpp')
| -rw-r--r-- | backend/unittests/MIR/EmbeddedIRTest.cpp | 133 |
1 files changed, 133 insertions, 0 deletions
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(); +} |
