aboutsummaryrefslogtreecommitdiff
path: root/backend/unittests/CodeGen
diff options
context:
space:
mode:
Diffstat (limited to 'backend/unittests/CodeGen')
-rw-r--r--backend/unittests/CodeGen/MachineDebugInfoTest.cpp221
-rw-r--r--backend/unittests/CodeGen/MachineFrameInfoTest.cpp19
-rw-r--r--backend/unittests/CodeGen/MachineFunctionRecordsTest.cpp79
-rw-r--r--backend/unittests/CodeGen/MachineIRBuilderTest.cpp24
-rw-r--r--backend/unittests/CodeGen/MachineIRCoreTest.cpp16
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,