diff options
Diffstat (limited to 'backend/unittests/CodeGen/MachineVerifierTest.cpp')
| -rw-r--r-- | backend/unittests/CodeGen/MachineVerifierTest.cpp | 115 |
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"); } |
