diff --git a/mlir/lib/Compiler/TargetCompilation.cpp b/mlir/lib/Compiler/TargetCompilation.cpp index 9c142e8e51..617383db11 100644 --- a/mlir/lib/Compiler/TargetCompilation.cpp +++ b/mlir/lib/Compiler/TargetCompilation.cpp @@ -34,7 +34,6 @@ void populateTargetCompilationPipeline(OpPassManager& pm, populateQCOCleanupPipeline(pm); pm.addPass(qco::createTargetNativeSynthesis(target)); pm.addPass(createCSEPass()); - pm.addPass(createRemoveDeadValuesPass()); pm.addPass(qco::createVerifyTargetConformance(target)); } diff --git a/mlir/unittests/Compiler/test_compiler_pipeline.cpp b/mlir/unittests/Compiler/test_compiler_pipeline.cpp index 0b2e1bd93d..1f8325b39d 100644 --- a/mlir/unittests/Compiler/test_compiler_pipeline.cpp +++ b/mlir/unittests/Compiler/test_compiler_pipeline.cpp @@ -57,6 +57,7 @@ #include #include #include +#include #include #include @@ -1382,6 +1383,67 @@ TEST_F(CompilerPipelineTest, QCOProgramCompilesForTarget) { EXPECT_FALSE(unsupportedQCO->compileForTarget(makeSparseUCZTarget(false))); } +/// Test that target compilation leaves dead-value cleanup at a fixed point. +TEST_F(CompilerPipelineTest, + TargetCompilationLeavesDeadValueCleanupAtFixedPoint) { + constexpr llvm::StringLiteral source = R"mlir( + module { + func.func private @forward(%condition: i1) -> i1 { + return %condition : i1 + } + func.func @main(%condition: i1) + attributes {mqt.entry_point} { + %q0 = qco.alloc : !qco.qubit + %q1 = qco.alloc : !qco.qubit + %forwarded = func.call @forward(%condition) : (i1) -> i1 + %q2, %q3 = qco.if %forwarded + args(%control = %q0, %target = %q1) + -> (!qco.qubit, !qco.qubit) { + %controlOut, %targetOut = qco.ctrl(%control) + targets(%targetArg = %target) { + %x = qco.x %targetArg : !qco.qubit -> !qco.qubit + qco.yield %x : !qco.qubit + } : ({!qco.qubit}, {!qco.qubit}) + -> ({!qco.qubit}, {!qco.qubit}) + %h = qco.h %controlOut : !qco.qubit -> !qco.qubit + qco.yield %h, %targetOut : !qco.qubit, !qco.qubit + } else args(%control = %q0, %target = %q1) { + %x0 = qco.x %control : !qco.qubit -> !qco.qubit + %x1 = qco.x %target : !qco.qubit -> !qco.qubit + qco.yield %x0, %x1 : !qco.qubit, !qco.qubit + } + qco.sink %q2 : !qco.qubit + qco.sink %q3 : !qco.qubit + return + } + } + )mlir"; + + auto program = QCOProgram::fromMLIRString(source.str()); + ASSERT_TRUE(program); + using TargetOperation = CompilerTarget::Operation; + std::vector operations{llvm::cantFail(TargetOperation::create("u", 1, 3)), + llvm::cantFail(TargetOperation::create("cz", 2, 0))}; + auto target = llvm::cantFail(CompilerTarget::create( + 2, std::vector{{0, 1}}, std::move(operations))); + + ASSERT_TRUE(program->compileForTarget(target)); + const std::string before = program->str(); + EXPECT_NE(before.find("func.func private @forward"), std::string::npos); + EXPECT_NE(before.find("call @forward"), std::string::npos); + EXPECT_NE(before.find("qco.if"), std::string::npos); + EXPECT_NE(before.find("qco.u"), std::string::npos); + EXPECT_NE(before.find("qco.ctrl"), std::string::npos); + EXPECT_NE(before.find("qco.z"), std::string::npos); + EXPECT_EQ(before.find("qco.h"), std::string::npos); + EXPECT_EQ(before.find("qco.x"), std::string::npos); + + PassManager pm(program->module().getContext()); + pm.addPass(createRemoveDeadValuesPass()); + ASSERT_TRUE(pm.run(program->module()).succeeded()); + EXPECT_EQ(program->str(), before); +} + TEST_F(CompilerPipelineTest, QCOProgramCompilesDynamicRunForSupportedTargets) { constexpr llvm::StringLiteral source = R"mlir(module { func.func @main(%theta: f64 {mqt.input_name = "theta"}) attributes {mqt.entry_point} {