From 6a7b083f322f4ac47e58cbf9d4d5fd4d1f6fecd0 Mon Sep 17 00:00:00 2001 From: Richard-Qin-X Date: Tue, 11 Aug 2026 17:37:42 +0800 Subject: [MIR] Accept fixed-baseline LLVM syntax --- backend/unittests/CodeGen/CompilationUnitTest.cpp | 26 +++++++++------- backend/unittests/CodeGen/MachineDebugInfoTest.cpp | 35 ++++++++++++++++++++-- .../CodeGen/MachineFunctionRecordsTest.cpp | 6 ++-- .../unittests/CodeGen/MachineValueTypesTest.cpp | 35 ++++++++++++++++++++++ 4 files changed, 86 insertions(+), 16 deletions(-) (limited to 'backend/unittests/CodeGen') diff --git a/backend/unittests/CodeGen/CompilationUnitTest.cpp b/backend/unittests/CodeGen/CompilationUnitTest.cpp index a31c9a8..141d6db 100644 --- a/backend/unittests/CodeGen/CompilationUnitTest.cpp +++ b/backend/unittests/CodeGen/CompilationUnitTest.cpp @@ -19,29 +19,34 @@ int fail(const char *Message) { 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 FirstAnonymous = Unit.createMachineFunction(""); + auto SecondAnonymous = Unit.createMachineFunction(""); + if (!FirstAnonymous || !SecondAnonymous || Unit.functionCount() != 2 || + (*FirstAnonymous)->stableID().value() != 1 || (*SecondAnonymous)->stableID().value() != 2 || + Unit.function("") != nullptr) + return fail("CompilationUnit must retain anonymous functions by order and StableID"); auto First = Unit.createMachineFunction("first"); - if (!First || (*First)->stableID().value() != 1) + if (!First || (*First)->stableID().value() != 3) return fail("CompilationUnit must allocate the first stable function identity"); auto Duplicate = Unit.createMachineFunction("first"); - if (Duplicate || Unit.functionCount() != 1) + if (Duplicate || Unit.functionCount() != 3) return fail("CompilationUnit must reject duplicate function names atomically"); auto Second = Unit.createMachineFunction("second"); - if (!Second || (*Second)->stableID().value() != 2) + if (!Second || (*Second)->stableID().value() != 4) return fail("Rejected function creation must not consume a StableID"); - if (Unit.functionCount() != 2 || Unit.functionAt(0) != *First || Unit.functionAt(1) != *Second) + if (Unit.functionCount() != 4 || Unit.functionAt(0) != *FirstAnonymous || + Unit.functionAt(1) != *SecondAnonymous || Unit.functionAt(2) != *First || + Unit.functionAt(3) != *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) + if (Unit.functionAt(4) != nullptr) return fail("CompilationUnit must reject an out-of-range ordered lookup"); auto Zero = rcc::GlobalInitializer::zeroFill(4); @@ -58,7 +63,7 @@ int main() { return fail("CompilationUnit must own and index global objects"); auto ConflictingFunction = Unit.createMachineFunction("global"); - if (ConflictingFunction || Unit.functionCount() != 2) + if (ConflictingFunction || Unit.functionCount() != 4) return fail("CompilationUnit must reject function/global symbol conflicts atomically"); rcc::GlobalObjectDesc ConflictingGlobal; @@ -88,7 +93,8 @@ int main() { return fail("A valid CompilationUnit must pass verification"); rcc::CompilationUnit Moved = std::move(Unit); - if (Moved.functionCount() != 2 || Moved.function("first") != *First || + if (Moved.functionCount() != 4 || Moved.functionAt(0) != *FirstAnonymous || + Moved.functionAt(1) != *SecondAnonymous || Moved.function("first") != *First || Moved.function("second") != *Second || Moved.globalObject("global") != *Global) return fail("Moving a CompilationUnit must preserve owned object addresses and indices"); Verification = Moved.verify(); diff --git a/backend/unittests/CodeGen/MachineDebugInfoTest.cpp b/backend/unittests/CodeGen/MachineDebugInfoTest.cpp index 80a83e0..ae4d539 100644 --- a/backend/unittests/CodeGen/MachineDebugInfoTest.cpp +++ b/backend/unittests/CodeGen/MachineDebugInfoTest.cpp @@ -3,6 +3,7 @@ #include "rcc/CodeGen/MachineDebugInfo.h" #include "Target/TestTarget.h" +#include "rcc/CodeGen/GenericOpcodes.h" #include "rcc/CodeGen/InstructionDescriptor.h" #include "rcc/CodeGen/MachineBasicBlock.h" #include "rcc/CodeGen/MachineFrameInfo.h" @@ -26,8 +27,8 @@ namespace { -constexpr std::uint32_t ValueOpcode = 1; -constexpr std::uint32_t MetaOpcode = 2; +constexpr std::uint32_t ValueOpcode = 1024; +constexpr std::uint32_t MetaOpcode = 1025; class TestContext final { public: @@ -64,7 +65,11 @@ private: std::vector Descriptors; Descriptors.push_back(std::move(Value)); Descriptors.push_back(std::move(Meta)); - auto Instructions = rcc::InstructionSet::create(std::move(Descriptors)); + std::vector Predicates; + auto Generic = rcc::appendGenericInstructionInfo(Descriptors, Predicates); + if (!Generic) + return std::unexpected(Generic.error()); + auto Instructions = rcc::InstructionSet::create(std::move(Descriptors), std::move(Predicates)); if (!Instructions) return std::unexpected(Instructions.error()); return rcc::test::createTestTargetDescription(std::move(*Instructions)); @@ -418,6 +423,30 @@ void testVerifierFailures(TestContext &Context) { if (!Target) return; + { + auto Function = createFunction(Context, 9, "missing-debug-location"); + if (Function == nullptr) + return; + rcc::MachineBasicBlock *Block = appendBlock(Context, *Function); + if (Block == nullptr) + return; + auto Instruction = Function->createInstruction(rcc::opcode(rcc::GenericOpcode::DBG_VALUE)); + if (!Instruction) + return; + for (const std::int64_t Value : {1, 2, 3, 4}) { + if (!(*Instruction)->addOperand(rcc::MachineOperand::immediate(Value))) + return; + } + Context.expect(Block->appendInstruction(**Instruction).has_value(), + "four-operand DBG_VALUE must be linkable for verifier coverage"); + auto Verification = rcc::MachineVerifier::verify(*Function, *Target); + Context.expect(!Verification && + Verification.error().message().find( + "Bad machine code: Missing DebugLoc for debug instruction\n" + "- instruction: DBG_VALUE 1, 2, 3, 4") != std::string_view::npos, + "complete DBG_VALUE must require a DebugLoc with LLVM-compatible diagnostics"); + } + { auto Function = createFunction(Context, 10, "debug-meta"); if (Function == nullptr) diff --git a/backend/unittests/CodeGen/MachineFunctionRecordsTest.cpp b/backend/unittests/CodeGen/MachineFunctionRecordsTest.cpp index 8ca6bf3..621bd21 100644 --- a/backend/unittests/CodeGen/MachineFunctionRecordsTest.cpp +++ b/backend/unittests/CodeGen/MachineFunctionRecordsTest.cpp @@ -301,7 +301,7 @@ void testCrossReferenceFailures(TestContext &Context) { } { - auto Function = createFunction(Context, 13, "unknown-bbid"); + auto Function = createFunction(Context, 13, "dangling-prefetch-target"); if (Function == nullptr) return; rcc::MachineBasicBlock *Block = appendBlock(Context, *Function); @@ -313,8 +313,8 @@ void testCrossReferenceFailures(TestContext &Context) { .CallsiteIndex = 0, }) .has_value() && - !rcc::MachineVerifier::verify(*Function, *Target), - "prefetch targets must reference a live block bb_id"); + rcc::MachineVerifier::verify(*Function, *Target).has_value(), + "prefetch targets may reference a bb_id without a machine block"); } { diff --git a/backend/unittests/CodeGen/MachineValueTypesTest.cpp b/backend/unittests/CodeGen/MachineValueTypesTest.cpp index 40f121b..50482ba 100644 --- a/backend/unittests/CodeGen/MachineValueTypesTest.cpp +++ b/backend/unittests/CodeGen/MachineValueTypesTest.cpp @@ -119,6 +119,21 @@ void testMemoryValueTypes(TestContext &Context) { Context.expect(Symbol.kind() == rcc::MemoryBase::Kind::GlobalSymbol, "global memory base must preserve its kind"); Context.expect(Symbol.symbolName() == "global", "global memory base must preserve its symbol"); + + rcc::GenericConstantData PoisonPointer; + PoisonPointer.Type = rcc::GenericConstantType::pointer(); + PoisonPointer.Kind = rcc::GenericConstantKind::Poison; + auto ConstantBase = rcc::MemoryBase::irConstant(PoisonPointer); + Context.expect(ConstantBase && ConstantBase->kind() == rcc::MemoryBase::Kind::IRConstant && + ConstantBase->constantValue() != nullptr && + *ConstantBase->constantValue() == PoisonPointer, + "IR-constant memory base must preserve a structured pointer constant"); + + rcc::GenericConstantData InvalidIntegerBase; + InvalidIntegerBase.Type = *rcc::GenericConstantType::integer(8); + InvalidIntegerBase.Kind = rcc::GenericConstantKind::Poison; + Context.expect(!rcc::MemoryBase::irConstant(std::move(InvalidIntegerBase)), + "IR-constant memory base must reject a non-pointer constant"); } void testMachineMemOperand(TestContext &Context) { @@ -172,6 +187,26 @@ void testMachineMemOperand(TestContext &Context) { EmptySymbol.Base = rcc::MemoryBase::externalSymbol(""); Context.expect(!rcc::MachineMemOperand::create(EmptySymbol), "empty MMO symbol base must be rejected"); + + auto OffsetAlignment = makeBasicLoadDescription(); + OffsetAlignment.Offset = 12; + OffsetAlignment.Align = *rcc::Alignment::create(4); + OffsetAlignment.BaseAlign = *rcc::Alignment::create(8); + auto OffsetAligned = rcc::MachineMemOperand::create(OffsetAlignment); + Context.expect(OffsetAligned && OffsetAligned->description().BaseAlign && + OffsetAligned->description().BaseAlign->bytes() == 8, + "MMO base alignment must derive effective alignment through its offset"); + + OffsetAlignment.Align = *rcc::Alignment::create(8); + Context.expect(!rcc::MachineMemOperand::create(OffsetAlignment), + "MMO alignment inconsistent with its base and offset must be rejected"); + + OffsetAlignment.Offset = 16; + OffsetAlignment.Align = *rcc::Alignment::create(8); + OffsetAlignment.BaseAlign = *rcc::Alignment::create(8); + auto RedundantBase = rcc::MachineMemOperand::create(OffsetAlignment); + Context.expect(RedundantBase && !RedundantBase->description().BaseAlign, + "MMO base alignment equal to effective alignment must canonicalize away"); } } // namespace -- cgit v1.2.3