aboutsummaryrefslogtreecommitdiff
path: root/backend/unittests/CodeGen/MachineVerifierTest.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'backend/unittests/CodeGen/MachineVerifierTest.cpp')
-rw-r--r--backend/unittests/CodeGen/MachineVerifierTest.cpp115
1 files changed, 59 insertions, 56 deletions
diff --git a/backend/unittests/CodeGen/MachineVerifierTest.cpp b/backend/unittests/CodeGen/MachineVerifierTest.cpp
index 3cc79d1..a803c08 100644
--- a/backend/unittests/CodeGen/MachineVerifierTest.cpp
+++ b/backend/unittests/CodeGen/MachineVerifierTest.cpp
@@ -2,6 +2,7 @@
#include "rcc/CodeGen/MachineVerifier.h"
+#include "Target/TestTarget.h"
#include "rcc/CodeGen/InstructionDescriptor.h"
#include "rcc/CodeGen/LowLevelType.h"
#include "rcc/CodeGen/MachineBasicBlock.h"
@@ -71,7 +72,7 @@ private:
return Descriptor;
}
-[[nodiscard]] rcc::Expected<rcc::InstructionSet> createInstructionSet() {
+[[nodiscard]] rcc::Expected<rcc::TargetDescription> createTarget() {
auto GenericDef = instructionDescriptor(GenericDefOpcode, "TEST_GENERIC_DEF");
GenericDef.Operands.push_back(registerDescriptor(rcc::RegisterOperandRole::Def));
GenericDef.NumExplicitDefs = 1;
@@ -140,7 +141,10 @@ private:
Descriptors.push_back(std::move(Nop));
Descriptors.push_back(std::move(ConstantPool));
Descriptors.push_back(std::move(JumpTable));
- return rcc::InstructionSet::create(std::move(Descriptors));
+ auto Instructions = rcc::InstructionSet::create(std::move(Descriptors));
+ if (!Instructions)
+ return std::unexpected(Instructions.error());
+ return rcc::test::createTestTargetDescription(std::move(*Instructions));
}
[[nodiscard]] std::unique_ptr<rcc::MachineFunction>
@@ -178,7 +182,7 @@ buildNoOperand(TestContext &Context, rcc::MachineIRBuilder &Builder, std::uint32
}
[[nodiscard]] bool populateValidPreLegalizer(TestContext &Context, rcc::MachineFunction &Function,
- const rcc::InstructionSet &InstructionSet) {
+ const rcc::TargetDescription &Target) {
rcc::MachineBasicBlock *Entry = createBlock(Context, Function);
rcc::MachineBasicBlock *Exit = createBlock(Context, Function);
if (Entry == nullptr || Exit == nullptr)
@@ -190,7 +194,7 @@ buildNoOperand(TestContext &Context, rcc::MachineIRBuilder &Builder, std::uint32
if (!Value)
return false;
- rcc::MachineIRBuilder Builder(Function, InstructionSet);
+ rcc::MachineIRBuilder Builder(Function, Target);
Context.expect(Builder.setInsertPoint(*Entry).has_value(), "entry insertion point must be valid");
auto Def = Builder.buildInstr(rcc::Opcode::fromValue(GenericDefOpcode));
Context.expect(Def && Def->addDef(*Value).has_value(), "generic definition must be assembled");
@@ -219,18 +223,17 @@ buildNoOperand(TestContext &Context, rcc::MachineIRBuilder &Builder, std::uint32
}
void testValidFunctionAndModes(TestContext &Context) {
- auto InstructionSet = createInstructionSet();
+ auto Target = createTarget();
auto Function = createFunction(Context, "valid", 1);
- if (!InstructionSet || !Function ||
- !populateValidPreLegalizer(Context, *Function, *InstructionSet)) {
+ if (!Target || !Function || !populateValidPreLegalizer(Context, *Function, *Target)) {
return;
}
- Context.expect(rcc::MachineVerifier::verify(*Function, *InstructionSet).has_value(),
+ Context.expect(rcc::MachineVerifier::verify(*Function, *Target).has_value(),
"well-formed function must pass generic verification");
Context.expect(
rcc::MachineVerifier::verify(
- *Function, *InstructionSet,
+ *Function, *Target,
rcc::MachineVerifierOptions{rcc::MachineVerifierMode::PreLegalizer, std::nullopt, true})
.has_value(),
"typed SSA input must pass pre-legalizer verification");
@@ -239,20 +242,20 @@ void testValidFunctionAndModes(TestContext &Context) {
auto DetachedInstruction = Function->createInstruction(rcc::Opcode::fromValue(NopOpcode));
Context.expect(DetachedBlock && DetachedInstruction,
"detached arena history must be allocatable");
- Context.expect(rcc::MachineVerifier::verify(*Function, *InstructionSet).has_value(),
+ Context.expect(rcc::MachineVerifier::verify(*Function, *Target).has_value(),
"empty detached arena objects must not invalidate live layout");
Function->properties().set(rcc::MachineFunctionProperty::Legalized);
Context.expect(
!rcc::MachineVerifier::verify(
- *Function, *InstructionSet,
+ *Function, *Target,
rcc::MachineVerifierOptions{rcc::MachineVerifierMode::PreLegalizer, std::nullopt, true}),
"pre-legalizer mode must reject later-stage properties");
}
void testReachableStructuralFailures(TestContext &Context) {
- auto InstructionSet = createInstructionSet();
- if (!InstructionSet)
+ auto Target = createTarget();
+ if (!Target)
return;
auto Unknown = createFunction(Context, "unknown_opcode", 2);
@@ -261,7 +264,7 @@ void testReachableStructuralFailures(TestContext &Context) {
auto Instruction = Unknown->createInstruction(rcc::Opcode::fromValue(999));
Context.expect(Instruction && UnknownBlock->appendInstruction(**Instruction).has_value(),
"unknown opcode negative test must be linked");
- Context.expect(!rcc::MachineVerifier::verify(*Unknown, *InstructionSet),
+ Context.expect(!rcc::MachineVerifier::verify(*Unknown, *Target),
"live unregistered opcode must fail verification");
}
@@ -272,7 +275,7 @@ void testReachableStructuralFailures(TestContext &Context) {
auto Instruction = WrongOperands->createInstruction(rcc::Opcode::fromValue(GenericDefOpcode));
Context.expect(Instruction && WrongBlock->appendInstruction(**Instruction).has_value(),
"wrong-operand negative test must be linked");
- Context.expect(!rcc::MachineVerifier::verify(*WrongOperands, *InstructionSet),
+ Context.expect(!rcc::MachineVerifier::verify(*WrongOperands, *Target),
"descriptor operand-count mismatch must fail verification");
}
@@ -282,7 +285,7 @@ void testReachableStructuralFailures(TestContext &Context) {
auto Instruction = DetachedChild->createInstruction(rcc::Opcode::fromValue(NopOpcode));
Context.expect(Block && Instruction && (*Block)->appendInstruction(**Instruction).has_value(),
"detached block negative test must contain an instruction");
- Context.expect(!rcc::MachineVerifier::verify(*DetachedChild, *InstructionSet),
+ Context.expect(!rcc::MachineVerifier::verify(*DetachedChild, *Target),
"detached block retaining instructions must fail verification");
}
@@ -294,14 +297,14 @@ void testReachableStructuralFailures(TestContext &Context) {
.addSuccessor(**Detached, *Linked, rcc::BranchProbability::one())
.has_value(),
"detached CFG negative test edge must be created");
- Context.expect(!rcc::MachineVerifier::verify(*DetachedCFG, *InstructionSet),
+ Context.expect(!rcc::MachineVerifier::verify(*DetachedCFG, *Target),
"detached block retaining CFG state must fail verification");
}
}
void testPropertyFailures(TestContext &Context) {
- auto InstructionSet = createInstructionSet();
- if (!InstructionSet)
+ auto Target = createTarget();
+ if (!Target)
return;
auto Type = rcc::LLT::makeInteger(64);
@@ -309,7 +312,7 @@ void testPropertyFailures(TestContext &Context) {
rcc::MachineBasicBlock *SSABlock = SSA ? createBlock(Context, *SSA) : nullptr;
if (SSA && SSABlock != nullptr) {
auto Value = SSA->registerInfo().createVirtualRegister(*Type);
- rcc::MachineIRBuilder Builder(*SSA, *InstructionSet);
+ rcc::MachineIRBuilder Builder(*SSA, *Target);
Context.expect(Value && Builder.setInsertPoint(*SSABlock).has_value(),
"SSA negative test setup must succeed");
for (int Index = 0; Index != 2 && Value; ++Index) {
@@ -318,7 +321,7 @@ void testPropertyFailures(TestContext &Context) {
"SSA negative test definition must build");
}
SSA->properties().set(rcc::MachineFunctionProperty::IsSSA);
- Context.expect(!rcc::MachineVerifier::verify(*SSA, *InstructionSet),
+ Context.expect(!rcc::MachineVerifier::verify(*SSA, *Target),
"IsSSA must reject a multiply-defined virtual register");
}
@@ -326,14 +329,14 @@ void testPropertyFailures(TestContext &Context) {
rcc::MachineBasicBlock *PHIBlock = PHI ? createBlock(Context, *PHI) : nullptr;
if (PHI && PHIBlock != nullptr) {
auto Value = PHI->registerInfo().createVirtualRegister(*Type);
- rcc::MachineIRBuilder Builder(*PHI, *InstructionSet);
+ rcc::MachineIRBuilder Builder(*PHI, *Target);
Context.expect(Value && Builder.setInsertPoint(*PHIBlock).has_value(),
"PHI negative test setup must succeed");
auto Pending = Builder.buildInstr(rcc::Opcode::fromValue(PhiOpcode));
Context.expect(Pending && Pending->addDef(*Value).has_value() && Pending->build(),
"PHI negative test instruction must build");
PHI->properties().set(rcc::MachineFunctionProperty::NoPHIs);
- Context.expect(!rcc::MachineVerifier::verify(*PHI, *InstructionSet),
+ Context.expect(!rcc::MachineVerifier::verify(*PHI, *Target),
"NoPHIs must reject a PHI instruction");
}
@@ -341,7 +344,7 @@ void testPropertyFailures(TestContext &Context) {
if (NoVRegs) {
rcc::MachineBasicBlock *Block = createBlock(Context, *NoVRegs);
auto Value = NoVRegs->registerInfo().createVirtualRegister(*Type);
- rcc::MachineIRBuilder Builder(*NoVRegs, *InstructionSet);
+ rcc::MachineIRBuilder Builder(*NoVRegs, *Target);
Context.expect(Block != nullptr && Builder.setInsertPoint(*Block).has_value(),
"NoVRegs negative test setup must succeed");
auto Pending = Builder.buildInstr(rcc::Opcode::fromValue(GenericDefOpcode));
@@ -351,12 +354,12 @@ void testPropertyFailures(TestContext &Context) {
return;
auto Built = Pending->build();
NoVRegs->properties().set(rcc::MachineFunctionProperty::NoVRegs);
- Context.expect(Value && Built && !rcc::MachineVerifier::verify(*NoVRegs, *InstructionSet),
+ Context.expect(Value && Built && !rcc::MachineVerifier::verify(*NoVRegs, *Target),
"NoVRegs must reject a live virtual register");
Context.expect(Value && Built && Block != nullptr &&
Block->removeInstruction(**Built).has_value() &&
NoVRegs->registerInfo().eraseVirtualRegister(*Value).has_value() &&
- rcc::MachineVerifier::verify(*NoVRegs, *InstructionSet).has_value(),
+ rcc::MachineVerifier::verify(*NoVRegs, *Target).has_value(),
"NoVRegs must accept tombstoned def-use history");
}
@@ -367,7 +370,7 @@ void testPropertyFailures(TestContext &Context) {
StackSlot.Size = 8;
StackSlot.Align = *rcc::Alignment::create(8);
auto FrameIndex = Frame->frameInfo().createObject(StackSlot);
- rcc::MachineIRBuilder Builder(*Frame, *InstructionSet);
+ rcc::MachineIRBuilder Builder(*Frame, *Target);
Context.expect(FrameIndex && Builder.setInsertPoint(*FrameBlock).has_value(),
"frame-index negative test setup must succeed");
if (!FrameIndex)
@@ -376,27 +379,27 @@ void testPropertyFailures(TestContext &Context) {
Context.expect(Pending && Pending->addFrameIndex(*FrameIndex).has_value() && Pending->build(),
"frame-index negative test instruction must build");
Frame->properties().set(rcc::MachineFunctionProperty::NoFrameIndices);
- Context.expect(!rcc::MachineVerifier::verify(*Frame, *InstructionSet),
+ Context.expect(!rcc::MachineVerifier::verify(*Frame, *Target),
"NoFrameIndices must reject a frame-index operand");
}
auto Pseudo = createFunction(Context, "pseudo", 10);
rcc::MachineBasicBlock *PseudoBlock = Pseudo ? createBlock(Context, *Pseudo) : nullptr;
if (Pseudo && PseudoBlock != nullptr) {
- rcc::MachineIRBuilder Builder(*Pseudo, *InstructionSet);
+ rcc::MachineIRBuilder Builder(*Pseudo, *Target);
Context.expect(Builder.setInsertPoint(*PseudoBlock).has_value() &&
buildNoOperand(Context, Builder, PseudoOpcode) != nullptr,
"pseudo negative test instruction must build");
Pseudo->properties().set(rcc::MachineFunctionProperty::NoExecutablePseudos);
- Context.expect(!rcc::MachineVerifier::verify(*Pseudo, *InstructionSet),
+ Context.expect(!rcc::MachineVerifier::verify(*Pseudo, *Target),
"NoExecutablePseudos must reject an executable pseudo");
}
}
void testSelectedStateAndPseudoDeadline(TestContext &Context) {
- auto InstructionSet = createInstructionSet();
+ auto Target = createTarget();
auto Type = rcc::LLT::makeInteger(64);
- if (!InstructionSet)
+ if (!Target)
return;
auto Tied = createFunction(Context, "tied", 11);
@@ -416,7 +419,7 @@ void testSelectedStateAndPseudoDeadline(TestContext &Context) {
"selected-state register constraints must be recorded");
}
- rcc::MachineIRBuilder Builder(*Tied, *InstructionSet);
+ rcc::MachineIRBuilder Builder(*Tied, *Target);
Context.expect(Builder.setInsertPoint(*TiedBlock).has_value(),
"tied-state insertion point must be valid");
auto Pending = Builder.buildInstr(rcc::Opcode::fromValue(CopyOpcode));
@@ -428,30 +431,30 @@ void testSelectedStateAndPseudoDeadline(TestContext &Context) {
rcc::MachineFunctionProperty::Selected, rcc::MachineFunctionProperty::TiedOpsRewritten}) {
Tied->properties().set(Property);
}
- Context.expect(!rcc::MachineVerifier::verify(*Tied, *InstructionSet),
+ Context.expect(!rcc::MachineVerifier::verify(*Tied, *Target),
"TiedOpsRewritten must reject unequal tied registers");
rcc::MachineInstr *Instruction = TiedBlock->firstInstruction();
Context.expect(Instruction != nullptr &&
Instruction->operandAt(1)->setRegister(*Def).has_value() &&
- rcc::MachineVerifier::verify(*Tied, *InstructionSet).has_value(),
+ rcc::MachineVerifier::verify(*Tied, *Target).has_value(),
"equal tied registers must satisfy TiedOpsRewritten");
}
auto Pseudo = createFunction(Context, "pseudo_deadline", 12);
rcc::MachineBasicBlock *Block = Pseudo ? createBlock(Context, *Pseudo) : nullptr;
if (Pseudo && Block != nullptr) {
- rcc::MachineIRBuilder Builder(*Pseudo, *InstructionSet);
+ rcc::MachineIRBuilder Builder(*Pseudo, *Target);
Context.expect(Builder.setInsertPoint(*Block).has_value() &&
buildNoOperand(Context, Builder, PseudoOpcode) != nullptr,
"deadline pseudo must build");
Context.expect(
- rcc::MachineVerifier::verify(*Pseudo, *InstructionSet,
+ rcc::MachineVerifier::verify(*Pseudo, *Target,
rcc::MachineVerifierOptions{rcc::MachineVerifierMode::Generic,
rcc::PipelineStage::Selected})
.has_value(),
"pseudo may remain at its declared deadline");
Context.expect(!rcc::MachineVerifier::verify(
- *Pseudo, *InstructionSet,
+ *Pseudo, *Target,
rcc::MachineVerifierOptions{rcc::MachineVerifierMode::Generic,
rcc::PipelineStage::RegisterAllocated}),
"pseudo must not survive beyond its declared deadline");
@@ -460,23 +463,23 @@ void testSelectedStateAndPseudoDeadline(TestContext &Context) {
auto Dependency = createFunction(Context, "property_dependency", 13);
if (Dependency) {
Dependency->properties().set(rcc::MachineFunctionProperty::Selected);
- Context.expect(!rcc::MachineVerifier::verify(*Dependency, *InstructionSet),
+ Context.expect(!rcc::MachineVerifier::verify(*Dependency, *Target),
"Selected must require prior pipeline properties");
Dependency->properties().clear(rcc::MachineFunctionProperty::Selected);
Dependency->properties().set(rcc::MachineFunctionProperty::FrameFinalized);
- Context.expect(!rcc::MachineVerifier::verify(*Dependency, *InstructionSet),
+ Context.expect(!rcc::MachineVerifier::verify(*Dependency, *Target),
"FrameFinalized must require NoVRegs and NoFrameIndices");
}
}
void testFrameStateFailures(TestContext &Context) {
- auto InstructionSet = createInstructionSet();
+ auto Target = createTarget();
auto Function = createFunction(Context, "frame_references", 14);
rcc::MachineBasicBlock *Block = Function ? createBlock(Context, *Function) : nullptr;
- if (!InstructionSet || !Function || Block == nullptr)
+ if (!Target || !Function || Block == nullptr)
return;
- rcc::MachineIRBuilder Builder(*Function, *InstructionSet);
+ rcc::MachineIRBuilder Builder(*Function, *Target);
Context.expect(Builder.setInsertPoint(*Block).has_value(),
"frame reference insertion point must be valid");
auto Unknown = Builder.buildInstr(rcc::Opcode::fromValue(FrameOpcode));
@@ -494,7 +497,7 @@ void testFrameStateFailures(TestContext &Context) {
Context.expect(Live && Live->addFrameIndex(*FrameIndex).has_value() && Live->build(),
"known live frame index must build");
Context.expect(Function->frameInfo().markObjectDead(*FrameIndex).has_value() &&
- !rcc::MachineVerifier::verify(*Function, *InstructionSet),
+ !rcc::MachineVerifier::verify(*Function, *Target),
"verifier must reject an instruction that references a dead stack object");
auto Lifetime = createFunction(Context, "frame_lifetime", 15);
@@ -506,16 +509,16 @@ void testFrameStateFailures(TestContext &Context) {
LifetimeSlot.Lifetime.push_back(
{rcc::MachineInstrStableID::fromValue(1), rcc::MachineInstrStableID::fromValue(2)});
Context.expect(Lifetime->frameInfo().createObject(LifetimeSlot).has_value() &&
- !rcc::MachineVerifier::verify(*Lifetime, *InstructionSet),
+ !rcc::MachineVerifier::verify(*Lifetime, *Target),
"verifier must reject stack lifetimes that reference unknown instructions");
}
void testTableReferenceFailures(TestContext &Context) {
- auto InstructionSet = createInstructionSet();
+ auto Target = createTarget();
auto ConstantFunction = createFunction(Context, "constant_reference", 16);
rcc::MachineBasicBlock *ConstantBlock =
ConstantFunction ? createBlock(Context, *ConstantFunction) : nullptr;
- if (!InstructionSet || !ConstantFunction || ConstantBlock == nullptr)
+ if (!Target || !ConstantFunction || ConstantBlock == nullptr)
return;
rcc::MachineConstantPoolEntryDesc ConstantDescription;
@@ -524,7 +527,7 @@ void testTableReferenceFailures(TestContext &Context) {
ConstantDescription.Size = 4;
ConstantDescription.Align = *rcc::Alignment::create(4);
auto ConstantIndex = ConstantFunction->constantPool().addEntry(std::move(ConstantDescription));
- rcc::MachineIRBuilder ConstantBuilder(*ConstantFunction, *InstructionSet);
+ rcc::MachineIRBuilder ConstantBuilder(*ConstantFunction, *Target);
Context.expect(ConstantIndex && ConstantBuilder.setInsertPoint(*ConstantBlock).has_value(),
"constant-pool verifier setup must succeed");
if (!ConstantIndex)
@@ -534,7 +537,7 @@ void testTableReferenceFailures(TestContext &Context) {
ConstantInstruction->addConstantPool(*ConstantIndex).has_value() &&
ConstantInstruction->build() &&
ConstantFunction->constantPool().eraseEntry(*ConstantIndex).has_value() &&
- !rcc::MachineVerifier::verify(*ConstantFunction, *InstructionSet),
+ !rcc::MachineVerifier::verify(*ConstantFunction, *Target),
"verifier must reject a tombstoned constant-pool reference");
auto JumpFunction = createFunction(Context, "jump_reference", 17);
@@ -544,7 +547,7 @@ void testTableReferenceFailures(TestContext &Context) {
rcc::MachineJumpTableDesc JumpDescription;
JumpDescription.Targets = {JumpBlock};
auto JumpIndex = JumpFunction->jumpTableInfo().createTable(std::move(JumpDescription));
- rcc::MachineIRBuilder JumpBuilder(*JumpFunction, *InstructionSet);
+ rcc::MachineIRBuilder JumpBuilder(*JumpFunction, *Target);
Context.expect(JumpIndex && JumpBuilder.setInsertPoint(*JumpBlock).has_value(),
"jump-table verifier setup must succeed");
if (!JumpIndex)
@@ -553,14 +556,14 @@ void testTableReferenceFailures(TestContext &Context) {
Context.expect(JumpInstruction && JumpInstruction->addJumpTable(*JumpIndex).has_value() &&
JumpInstruction->build() &&
JumpFunction->jumpTableInfo().eraseTable(*JumpIndex).has_value() &&
- !rcc::MachineVerifier::verify(*JumpFunction, *InstructionSet),
+ !rcc::MachineVerifier::verify(*JumpFunction, *Target),
"verifier must reject a tombstoned jump-table reference");
}
void testCompilationStatusReferences(TestContext &Context) {
- auto InstructionSet = createInstructionSet();
+ auto Target = createTarget();
auto Unknown = createFunction(Context, "unknown_failure_instruction", 18);
- if (!InstructionSet || !Unknown)
+ if (!Target || !Unknown)
return;
rcc::MachineCompilationFailure UnknownFailure;
@@ -572,14 +575,14 @@ void testCompilationStatusReferences(TestContext &Context) {
Unknown->compilationStatus()
.fail(rcc::MachineCompilationState::SelectionFailed, std::move(UnknownFailure))
.has_value() &&
- !rcc::MachineVerifier::verify(*Unknown, *InstructionSet),
+ !rcc::MachineVerifier::verify(*Unknown, *Target),
"verifier must reject compilation status that references an unknown instruction");
auto Live = createFunction(Context, "live_failure_instruction", 19);
rcc::MachineBasicBlock *Block = Live ? createBlock(Context, *Live) : nullptr;
if (!Live || Block == nullptr)
return;
- rcc::MachineIRBuilder Builder(*Live, *InstructionSet);
+ rcc::MachineIRBuilder Builder(*Live, *Target);
Context.expect(Builder.setInsertPoint(*Block).has_value(),
"live failure instruction insertion point must be valid");
rcc::MachineInstr *Instruction = buildNoOperand(Context, Builder, NopOpcode);
@@ -595,7 +598,7 @@ void testCompilationStatusReferences(TestContext &Context) {
Live->compilationStatus()
.fail(rcc::MachineCompilationState::FinalizationFailed, std::move(LiveFailure))
.has_value() &&
- rcc::MachineVerifier::verify(*Live, *InstructionSet).has_value(),
+ rcc::MachineVerifier::verify(*Live, *Target).has_value(),
"verifier must accept a structurally valid failed function");
}