diff options
Diffstat (limited to 'backend/unittests/CodeGen')
| -rw-r--r-- | backend/unittests/CodeGen/MachineDebugInfoTest.cpp | 221 | ||||
| -rw-r--r-- | backend/unittests/CodeGen/MachineFrameInfoTest.cpp | 19 | ||||
| -rw-r--r-- | backend/unittests/CodeGen/MachineFunctionRecordsTest.cpp | 79 | ||||
| -rw-r--r-- | backend/unittests/CodeGen/MachineIRBuilderTest.cpp | 24 | ||||
| -rw-r--r-- | backend/unittests/CodeGen/MachineIRCoreTest.cpp | 16 |
5 files changed, 335 insertions, 24 deletions
diff --git a/backend/unittests/CodeGen/MachineDebugInfoTest.cpp b/backend/unittests/CodeGen/MachineDebugInfoTest.cpp index 6c5eea7..80a83e0 100644 --- a/backend/unittests/CodeGen/MachineDebugInfoTest.cpp +++ b/backend/unittests/CodeGen/MachineDebugInfoTest.cpp @@ -1,8 +1,11 @@ // SPDX-License-Identifier: GPL-3.0-or-later +#include "rcc/CodeGen/MachineDebugInfo.h" + #include "Target/TestTarget.h" #include "rcc/CodeGen/InstructionDescriptor.h" #include "rcc/CodeGen/MachineBasicBlock.h" +#include "rcc/CodeGen/MachineFrameInfo.h" #include "rcc/CodeGen/MachineFunction.h" #include "rcc/CodeGen/MachineFunctionAttributes.h" #include "rcc/CodeGen/MachineFunctionCloner.h" @@ -15,6 +18,7 @@ #include <iostream> #include <limits> #include <memory> +#include <optional> #include <string> #include <string_view> #include <utility> @@ -47,6 +51,10 @@ private: Value.InstructionOpcode = rcc::Opcode::fromValue(ValueOpcode); Value.Name = "TEST_VALUE"; Value.Flags = {rcc::InstructionFlag::ProducesCode}; + rcc::OperandDescriptor OptionalMetadata; + OptionalMetadata.Kinds = {rcc::MachineOperand::Kind::Metadata}; + OptionalMetadata.Optional = true; + Value.Operands.push_back(OptionalMetadata); rcc::InstructionDescriptor Meta; Meta.InstructionOpcode = rcc::Opcode::fromValue(MetaOpcode); @@ -90,6 +98,217 @@ createFunction(TestContext &Context, std::uint64_t StableID, std::string Name) { return Instruction ? *Instruction : nullptr; } +void testMetadataValuesAndLocations(TestContext &Context) { + rcc::MachineMetadataInfo Metadata; + Context.expect(Metadata.addNode({.Slot = 0, .IsDistinct = false, .Elements = {}}).has_value(), + "function-local debug metadata setup must succeed"); + + const rcc::MachineDIExpression Expression( + std::vector<std::uint64_t>{0x1005, 0, 0x22, 0x1000, 0, 64}); + Context.expect(Expression.elements().size() == 6 && Expression.elements()[0] == 0x1005, + "inline DIExpression elements must preserve their exact unsigned encoding"); + auto ExpressionValue = rcc::MachineMetadataValue::expression(Expression); + Context.expect(ExpressionValue.verify(Metadata).has_value() && + ExpressionValue.expression() != nullptr && + *ExpressionValue.expression() == Expression, + "inline DIExpression metadata values must remain structured"); + Context.expect(!rcc::MachineMetadataValue{}.verify(Metadata), + "an unrepresented metadata value must be rejected"); + + Context.expect(!rcc::MachineDILocation::create({}), + "an inline DILocation must contain a root frame"); + Context.expect(!rcc::MachineDILocation::create({{}}), + "an inline DILocation frame must contain a valid scope"); + Context.expect(!rcc::MachineDILocation::create({ + { + .Line = 1, + .Column = 0, + .Scope = rcc::MachineMetadataReference::embeddedIR(1), + .IsImplicitCode = false, + .AtomGroup = 0, + .AtomRank = 8, + }, + }), + "an inline DILocation atom rank must fit the fixed three-bit field"); + Context.expect(!rcc::MachineDILocation::create({ + { + .Line = 1, + .Column = 0, + .Scope = rcc::MachineMetadataReference::embeddedIR(1), + .IsImplicitCode = false, + .AtomGroup = rcc::MachineDILocation::MaxAtomGroup + 1, + .AtomRank = 0, + }, + }), + "an inline DILocation atom group must fit the fixed 61-bit field"); + + auto InlineLocation = rcc::MachineDILocation::create( + { + { + .Line = 7, + .Column = 65'535, + .Scope = rcc::MachineMetadataReference::embeddedIR(3), + .IsImplicitCode = true, + .AtomGroup = rcc::MachineDILocation::MaxAtomGroup, + .AtomRank = 7, + }, + { + .Line = 9, + .Column = 4, + .Scope = rcc::MachineMetadataReference::embeddedIR(0), + .IsImplicitCode = false, + .AtomGroup = 0, + .AtomRank = 0, + }, + }, + rcc::MachineMetadataReference::embeddedIR(4)); + Context.expect(InlineLocation.has_value() && InlineLocation->verify(Metadata).has_value() && + InlineLocation->inlineChain().size() == 2 && + InlineLocation->terminalInlinedAt() == + rcc::MachineMetadataReference::embeddedIR(4), + "inline DILocation chains must preserve nested and terminal references"); + if (!InlineLocation) + return; + + auto DebugLocation = rcc::MachineDebugLocation::inlineLocation(*InlineLocation); + Context.expect(DebugLocation.verify(Metadata).has_value() && + DebugLocation.inlineLocation() != nullptr, + "a structured inline DILocation must form a debug-location attachment"); + rcc::MachineVariableDebugInfo VariableInfo{ + .Variable = rcc::MachineMetadataReference::embeddedIR(5), + .Expression = ExpressionValue, + .Location = DebugLocation, + }; + Context.expect(VariableInfo.verify(Metadata).has_value() && + !rcc::MachineVariableDebugInfo{}.verify(Metadata), + "variable debug records must carry at least one verified metadata component"); + + auto Undefined = + rcc::MachineDebugLocation::reference(rcc::MachineMetadataReference::machineFunction(99)); + Context.expect(!Undefined, "typed debug locations must not accept function-local tuple metadata"); +} + +void testInstructionMetadataAndClone(TestContext &Context) { + auto Target = createTarget(); + auto Function = createFunction(Context, 20, "debug-metadata"); + if (!Target || Function == nullptr) + return; + Context.expect( + Function->metadata().addNode({.Slot = 0, .IsDistinct = false, .Elements = {}}).has_value(), + "instruction metadata graph setup must succeed"); + rcc::MachineBasicBlock *Block = appendBlock(Context, *Function); + if (Block == nullptr) + return; + rcc::MachineInstr *Instruction = appendInstruction(Context, *Function, *Block, ValueOpcode); + if (Instruction == nullptr) + return; + + auto MetadataValue = + rcc::MachineMetadataValue::reference(rcc::MachineMetadataReference::machineFunction(0)); + Context.expect(MetadataValue.has_value(), "instruction metadata reference must be valid"); + if (!MetadataValue) + return; + auto Operand = rcc::MachineOperand::metadata(std::move(*MetadataValue)); + auto InlineLocation = rcc::MachineDILocation::create({ + { + .Line = 12, + .Column = 8, + .Scope = rcc::MachineMetadataReference::embeddedIR(7), + .IsImplicitCode = false, + .AtomGroup = 0, + .AtomRank = 0, + }, + }); + Context.expect(Operand.has_value() && InlineLocation.has_value(), + "instruction metadata values must be constructible"); + if (!Operand || !InlineLocation) + return; + const rcc::MachineDebugLocation DebugLocation = + rcc::MachineDebugLocation::inlineLocation(*InlineLocation); + Context.expect(Instruction->addOperand(std::move(*Operand)).has_value() && + Instruction->setDebugLocation(DebugLocation).has_value(), + "instruction metadata operand and debug location must attach independently"); + Instruction->setSourceLocation({"debug-input.mir", 3, 5, 0}); + const rcc::MachineVariableDebugInfo StackDebugInfo{ + .Variable = rcc::MachineMetadataReference::embeddedIR(8), + .Expression = rcc::MachineMetadataValue::expression( + rcc::MachineDIExpression(std::vector<std::uint64_t>{0x1000, 0, 64})), + .Location = DebugLocation, + }; + rcc::StackObjectDesc StackDescription; + StackDescription.Size = 8; + StackDescription.Align = *rcc::Alignment::create(8); + StackDescription.DebugInfo = StackDebugInfo; + auto StackIndex = Function->frameInfo().createObject(std::move(StackDescription)); + Context.expect(StackIndex.has_value(), + "structured variable debug information must attach to a stack object"); + if (!StackIndex) + return; + Context.expect(rcc::MachineVerifier::verify(*Function, *Target).has_value(), + "well-formed instruction metadata must pass unified verification"); + + auto Clone = + rcc::cloneMachineFunction(*Function, *Target, + { + .NewStableID = rcc::MachineFunctionStableID::fromValue(21), + .NewName = std::string("debug-metadata.clone"), + }); + Context.expect(Clone.has_value(), "instruction debug metadata must support deep cloning"); + if (!Clone) + return; + const rcc::MachineInstr *ClonedInstruction = + Clone->ClonedFunction->firstBlock()->firstInstruction(); + const auto ClonedStackIndex = Clone->FrameIndices.find(*StackIndex); + const rcc::StackObject *ClonedStack = + ClonedStackIndex == Clone->FrameIndices.end() + ? nullptr + : Clone->ClonedFunction->frameInfo().object(ClonedStackIndex->second); + Context.expect( + ClonedInstruction->debugLocation() == DebugLocation && + ClonedInstruction->sourceLocation() == rcc::SourceLocation{"debug-input.mir", 3, 5, 0} && + ClonedInstruction->operandAt(0)->getIf<rcc::MetadataOperand>()->Value.reference() != + nullptr && + ClonedStack != nullptr && ClonedStack->description() != nullptr && + ClonedStack->description()->DebugInfo == StackDebugInfo, + "clone must preserve distinct parser source and semantic debug information"); + + auto InvalidFunction = createFunction(Context, 22, "invalid-debug-metadata"); + if (InvalidFunction == nullptr) + return; + rcc::MachineBasicBlock *InvalidBlock = appendBlock(Context, *InvalidFunction); + if (InvalidBlock == nullptr) + return; + rcc::MachineInstr *InvalidInstruction = + appendInstruction(Context, *InvalidFunction, *InvalidBlock, ValueOpcode); + if (InvalidInstruction == nullptr) + return; + auto InvalidValue = + rcc::MachineMetadataValue::reference(rcc::MachineMetadataReference::machineFunction(9)); + Context.expect(InvalidValue.has_value(), "undefined scoped references remain representable"); + if (!InvalidValue) + return; + auto InvalidOperand = rcc::MachineOperand::metadata(std::move(*InvalidValue)); + Context.expect(InvalidOperand.has_value() && + InvalidInstruction->addOperand(std::move(*InvalidOperand)).has_value() && + !rcc::MachineVerifier::verify(*InvalidFunction, *Target), + "undefined instruction metadata references must fail unified verification"); + + auto InvalidFrameFunction = createFunction(Context, 23, "invalid-frame-debug-metadata"); + if (InvalidFrameFunction == nullptr) + return; + rcc::StackObjectDesc InvalidStackDescription; + InvalidStackDescription.Size = 8; + InvalidStackDescription.Align = *rcc::Alignment::create(8); + InvalidStackDescription.DebugInfo = rcc::MachineVariableDebugInfo{ + .Variable = rcc::MachineMetadataReference::machineFunction(9), + .Expression = std::nullopt, + .Location = std::nullopt, + }; + Context.expect( + !InvalidFrameFunction->frameInfo().createObject(std::move(InvalidStackDescription)), + "typed stack debug information must reject function-local tuple metadata"); +} + void testInstructionNumbering(TestContext &Context) { auto Target = createTarget(); auto Function = createFunction(Context, 1, "debug-numbering"); @@ -261,6 +480,8 @@ void testVerifierFailures(TestContext &Context) { int main() { TestContext Context; + testMetadataValuesAndLocations(Context); + testInstructionMetadataAndClone(Context); testInstructionNumbering(Context); testSubstitutionsAndClone(Context); testVerifierFailures(Context); diff --git a/backend/unittests/CodeGen/MachineFrameInfoTest.cpp b/backend/unittests/CodeGen/MachineFrameInfoTest.cpp index 7368815..c9289c7 100644 --- a/backend/unittests/CodeGen/MachineFrameInfoTest.cpp +++ b/backend/unittests/CodeGen/MachineFrameInfoTest.cpp @@ -2,8 +2,11 @@ #include "rcc/CodeGen/MachineFrameInfo.h" +#include "rcc/CodeGen/MachineDebugInfo.h" + #include <cstdint> #include <iostream> +#include <optional> #include <string_view> namespace { @@ -130,6 +133,22 @@ void testInvalidDescriptions(TestContext &Context) { Context.expect(!Frame.createObject(InvalidLifetime), "stack object lifetime must reject equal boundaries"); + auto InvalidDebugInfo = fixedObject(8, 8); + InvalidDebugInfo.DebugInfo.emplace(); + Context.expect(!Frame.createObject(InvalidDebugInfo), + "stack object debug information must not be structurally empty"); + + auto DebugObject = fixedObject(8, 8); + DebugObject.DebugInfo = rcc::MachineVariableDebugInfo{ + .Variable = rcc::MachineMetadataReference::embeddedIR(1), + .Expression = rcc::MachineMetadataValue::expression(rcc::MachineDIExpression{}), + .Location = std::nullopt, + }; + auto DebugIndex = Frame.createObject(DebugObject); + Context.expect(DebugIndex.has_value() && + Frame.object(*DebugIndex)->description()->DebugInfo == DebugObject.DebugInfo, + "stack object debug information must remain structured"); + Context.expect(!rcc::StackID::targetStack(4), "target stack IDs must not overlap built-in IDs"); auto TargetStack = rcc::StackID::targetStack(256); auto Target = fixedObject(8, 8); diff --git a/backend/unittests/CodeGen/MachineFunctionRecordsTest.cpp b/backend/unittests/CodeGen/MachineFunctionRecordsTest.cpp index 4f41b39..8ca6bf3 100644 --- a/backend/unittests/CodeGen/MachineFunctionRecordsTest.cpp +++ b/backend/unittests/CodeGen/MachineFunctionRecordsTest.cpp @@ -5,6 +5,7 @@ #include "Target/TestTarget.h" #include "rcc/CodeGen/InstructionDescriptor.h" #include "rcc/CodeGen/MachineBasicBlock.h" +#include "rcc/CodeGen/MachineDebugInfo.h" #include "rcc/CodeGen/MachineFunction.h" #include "rcc/CodeGen/MachineFunctionCloner.h" #include "rcc/CodeGen/MachineInstr.h" @@ -14,6 +15,7 @@ #include <cstdint> #include <iostream> #include <memory> +#include <optional> #include <string> #include <string_view> #include <utility> @@ -120,6 +122,8 @@ void testValueValidation(TestContext &Context) { .Flags = 0, }), "a called-global record must require a nonempty callee"); + Context.expect(!Records.addEntryValue({}), + "an entry-value record must require a physical register and debug metadata"); const rcc::MachinePrefetchTarget Target{ .Block = {.BaseID = 7, .CloneID = 3}, @@ -135,6 +139,9 @@ void testVerifierAndClone(TestContext &Context) { auto Function = createFunction(Context, 1, "records"); if (!Target || Function == nullptr) return; + Context.expect( + Function->metadata().addNode({.Slot = 0, .IsDistinct = false, .Elements = {}}).has_value(), + "function record metadata setup must succeed"); rcc::MachineBasicBlock *Block = appendBlock(Context, *Function); if (Block == nullptr) @@ -175,6 +182,22 @@ void testVerifierAndClone(TestContext &Context) { }) .has_value(), "structured prefetch target information must be stored"); + auto EntryLocation = + rcc::MachineDebugLocation::reference(rcc::MachineMetadataReference::embeddedIR(12)); + Context.expect(EntryLocation.has_value(), "entry-value debug location must be representable"); + if (!EntryLocation) + return; + const rcc::MachineEntryValueInfo EntryValue{ + .Reg = G0, + .DebugInfo = + { + .Variable = rcc::MachineMetadataReference::embeddedIR(10), + .Expression = rcc::MachineMetadataValue::expression(rcc::MachineDIExpression{}), + .Location = *EntryLocation, + }, + }; + Context.expect(Function->records().addEntryValue(EntryValue).has_value(), + "structured entry-value debug information must be stored"); Context.expect(rcc::MachineVerifier::verify(*Function, *Target).has_value(), "well-formed function records must pass unified verification"); @@ -190,24 +213,25 @@ void testVerifierAndClone(TestContext &Context) { const auto InstructionID = Clone->InstructionStableIDs.find(Call->stableID()); const rcc::MachineFunctionRecords &ClonedRecords = Clone->ClonedFunction->records(); - Context.expect(InstructionID != Clone->InstructionStableIDs.end() && - ClonedRecords.hasCalleeSavedRegisters() && - ClonedRecords.calleeSavedRegisters().size() == 2 && - ClonedRecords.callSites().size() == 1 && - ClonedRecords.callSites()[0].CallInstruction == InstructionID->second && - ClonedRecords.callSites()[0].ForwardedArguments.size() == 2 && - ClonedRecords.callSites()[0].ForwardedArguments[1].ArgumentNumber == 0 && - ClonedRecords.callSites()[0].CalleeTypeIDs == - std::vector<std::uint64_t>({0x11, 0x22}) && - ClonedRecords.calledGlobals().size() == 1 && - ClonedRecords.calledGlobals()[0].CallInstruction == InstructionID->second && - ClonedRecords.calledGlobals()[0].Callee == "callee" && - ClonedRecords.calledGlobals()[0].Flags == 5 && - ClonedRecords.prefetchTargets().size() == 1 && - ClonedRecords.prefetchTargets()[0].Block == - rcc::MachineBasicBlockProfileID{.BaseID = 19, .CloneID = 2} && - ClonedRecords.prefetchTargets()[0].CallsiteIndex == 8, - "deep clone must preserve records and remap instruction StableIDs"); + Context.expect( + InstructionID != Clone->InstructionStableIDs.end() && + ClonedRecords.hasCalleeSavedRegisters() && + ClonedRecords.calleeSavedRegisters().size() == 2 && + ClonedRecords.callSites().size() == 1 && + ClonedRecords.callSites()[0].CallInstruction == InstructionID->second && + ClonedRecords.callSites()[0].ForwardedArguments.size() == 2 && + ClonedRecords.callSites()[0].ForwardedArguments[1].ArgumentNumber == 0 && + ClonedRecords.callSites()[0].CalleeTypeIDs == std::vector<std::uint64_t>({0x11, 0x22}) && + ClonedRecords.calledGlobals().size() == 1 && + ClonedRecords.calledGlobals()[0].CallInstruction == InstructionID->second && + ClonedRecords.calledGlobals()[0].Callee == "callee" && + ClonedRecords.calledGlobals()[0].Flags == 5 && + ClonedRecords.prefetchTargets().size() == 1 && + ClonedRecords.prefetchTargets()[0].Block == + rcc::MachineBasicBlockProfileID{.BaseID = 19, .CloneID = 2} && + ClonedRecords.prefetchTargets()[0].CallsiteIndex == 8 && + ClonedRecords.entryValues().size() == 1 && ClonedRecords.entryValues()[0] == EntryValue, + "deep clone must preserve records and remap instruction StableIDs"); } void testCrossReferenceFailures(TestContext &Context) { @@ -306,6 +330,25 @@ void testCrossReferenceFailures(TestContext &Context) { Context.expect(!rcc::MachineVerifier::verify(*Function, *Target), "linked block bb_id values must be unique"); } + + { + auto Function = createFunction(Context, 13, "entry-value-register"); + if (Function == nullptr) + return; + Context.expect(Function->records() + .addEntryValue({ + .Reg = phys(999), + .DebugInfo = + { + .Variable = rcc::MachineMetadataReference::embeddedIR(1), + .Expression = std::nullopt, + .Location = std::nullopt, + }, + }) + .has_value() && + !rcc::MachineVerifier::verify(*Function, *Target), + "entry-value records must reject target-unknown physical registers"); + } } } // namespace diff --git a/backend/unittests/CodeGen/MachineIRBuilderTest.cpp b/backend/unittests/CodeGen/MachineIRBuilderTest.cpp index 15f6cd2..9f5cf5e 100644 --- a/backend/unittests/CodeGen/MachineIRBuilderTest.cpp +++ b/backend/unittests/CodeGen/MachineIRBuilderTest.cpp @@ -7,6 +7,7 @@ #include "rcc/CodeGen/LowLevelType.h" #include "rcc/CodeGen/MachineBasicBlock.h" #include "rcc/CodeGen/MachineConstantPool.h" +#include "rcc/CodeGen/MachineDebugInfo.h" #include "rcc/CodeGen/MachineFunction.h" #include "rcc/CodeGen/MachineInstr.h" #include "rcc/CodeGen/MachineJumpTableInfo.h" @@ -208,6 +209,7 @@ void testTransactionalBuild(TestContext &Context) { if (!Incomplete) return; Context.expect(!Incomplete->tieOperands(0, 1) && !Incomplete->setSourceLocation({"", 0, 0, 0}) && + !Incomplete->setDebugLocation({}) && !Incomplete->setOrigin(rcc::OriginID::fromValue(0)), "invalid pending metadata and tie indices must be rejected"); Context.expect(!Incomplete->build(), "descriptor validation must reject a missing operand"); @@ -225,10 +227,27 @@ void testTransactionalBuild(TestContext &Context) { "an explicit tie matching the descriptor default must be idempotent"); Context.expect(Complete->setFlags({rcc::MachineInstrFlag::FrameSetup}).has_value(), "valid instruction flags must be accepted"); + auto InlineDebugLocation = rcc::MachineDILocation::create({ + { + .Line = 11, + .Column = 2, + .Scope = rcc::MachineMetadataReference::embeddedIR(3), + .IsImplicitCode = false, + .AtomGroup = 0, + .AtomRank = 0, + }, + }); + Context.expect(InlineDebugLocation.has_value(), + "builder debug location setup must be structurally valid"); + if (!InlineDebugLocation) + return; + const rcc::MachineDebugLocation DebugLocation = + rcc::MachineDebugLocation::inlineLocation(*InlineDebugLocation); Context.expect( Complete->setSourceLocation(rcc::SourceLocation{"builder.mir", 7, 3, 1}).has_value() && + Complete->setDebugLocation(DebugLocation).has_value() && Complete->setOrigin(rcc::OriginID::fromValue(19)).has_value(), - "valid source and origin metadata must be accepted"); + "valid parser source, debug location, and origin metadata must be accepted"); auto Built = Complete->build(); Context.expect(Built.has_value(), "valid pending instruction must build"); if (!Built) @@ -244,13 +263,14 @@ void testTransactionalBuild(TestContext &Context) { "descriptor-default tie must be materialized bidirectionally"); Context.expect(Instruction->flags().has(rcc::MachineInstrFlag::FrameSetup) && Instruction->sourceLocation() == rcc::SourceLocation{"builder.mir", 7, 3, 1} && + Instruction->debugLocation() == DebugLocation && Instruction->origin() == rcc::OriginID::fromValue(19), "builder metadata must be preserved on the published instruction"); Context.expect(Target->validateInstruction(*Instruction, Function->registerInfo()).has_value(), "builder output must satisfy the shared instruction descriptor"); Context.expect(!Complete->build(), "a successful pending builder must be single-use"); Context.expect(!Complete->setFlags({}) && !Complete->clearSourceLocation() && - !Complete->clearOrigin(), + !Complete->clearDebugLocation() && !Complete->clearOrigin(), "all pending-builder mutators must reject use after publication"); Context.expect(Function->registerInfo().verifyDefUseChains().has_value(), "published builder operands must enter exact def-use chains"); diff --git a/backend/unittests/CodeGen/MachineIRCoreTest.cpp b/backend/unittests/CodeGen/MachineIRCoreTest.cpp index 1083422..028afc5 100644 --- a/backend/unittests/CodeGen/MachineIRCoreTest.cpp +++ b/backend/unittests/CodeGen/MachineIRCoreTest.cpp @@ -169,10 +169,18 @@ void testOperandKinds(TestContext &Context) { Context.expect(!rcc::MachineOperand::registerMask(nullptr), "null register mask operand must be rejected"); - auto Metadata = rcc::MachineOperand::metadata("source-marker"); - Context.expect(Metadata && Metadata->kind() == rcc::MachineOperand::Kind::Metadata, - "metadata operand must preserve its kind"); - Context.expect(!rcc::MachineOperand::metadata(""), "empty metadata marker must be rejected"); + auto MetadataReference = + rcc::MachineMetadataValue::reference(rcc::MachineMetadataReference::embeddedIR(0)); + Context.expect(MetadataReference.has_value(), + "a valid scoped metadata reference must form an operand value"); + if (!MetadataReference) + return; + auto Metadata = rcc::MachineOperand::metadata(std::move(*MetadataReference)); + Context.expect(Metadata && Metadata->kind() == rcc::MachineOperand::Kind::Metadata && + Metadata->getIf<rcc::MetadataOperand>()->Value.reference() != nullptr, + "metadata operand must preserve its scoped semantic value"); + Context.expect(!rcc::MachineOperand::metadata({}), + "an unrepresented metadata operand value must be rejected"); auto Target = rcc::MachineOperand::targetIndex(rcc::TargetIndex::fromValue(8), 9); Context.expect(Target.getIf<rcc::TargetIndexOperand>()->Offset == 9, |
