From bcfe36d8116af88c330a961212ba693a27200435 Mon Sep 17 00:00:00 2001 From: Ian Davis Date: Mon, 23 Dec 2024 11:12:18 -0800 Subject: [PATCH 1/9] Adding floating-point qir support --- compiler/qsc/src/codegen/tests.rs | 1023 +++++++++++------ compiler/qsc/src/interpret/tests.rs | 19 +- compiler/qsc/src/target.rs | 9 + compiler/qsc_codegen/src/qir.rs | 174 ++- .../src/qir/instruction_tests/double.rs | 487 +++++++- .../src/qir/instruction_tests/invalid.rs | 16 +- compiler/qsc_codegen/src/qir/tests.rs | 9 +- compiler/qsc_partial_eval/src/lib.rs | 293 ++++- .../qsc_partial_eval/src/tests/assigns.rs | 331 ++++++ .../qsc_partial_eval/src/tests/bindings.rs | 75 ++ .../qsc_partial_eval/src/tests/branching.rs | 249 ++++ .../src/tests/dynamic_vars.rs | 265 +++++ compiler/qsc_partial_eval/src/tests/loops.rs | 77 +- .../qsc_partial_eval/src/tests/operators.rs | 981 +++++++++++++++- .../src/tests/output_recording.rs | 42 + compiler/qsc_passes/src/capabilitiesck.rs | 3 + ...tests_adaptive_plus_integers_and_floats.rs | 607 ++++++++++ compiler/qsc_qasm3/src/tests/output.rs | 10 +- .../src/tests/statement/gate_call.rs | 10 +- .../qsc_qasm3/src/tests/statement/reset.rs | 10 +- compiler/qsc_rir/src/builder.rs | 11 + compiler/qsc_rir/src/passes/ssa_check.rs | 21 + compiler/qsc_rir/src/passes/ssa_transform.rs | 5 + compiler/qsc_rir/src/passes/type_check.rs | 6 +- compiler/qsc_rir/src/rir.rs | 88 +- compiler/qsc_rir/src/utils.rs | 5 + npm/qsharp/src/compiler/compiler.ts | 8 +- pip/qsharp/_native.pyi | 12 +- pip/qsharp/_qsharp.py | 2 + pip/src/interpreter.rs | 8 + .../resources/custom_intrinsics.ll | 10 +- .../output/Adaptive_RI/ArithmeticOps.ll | 10 +- .../Adaptive_RI/BernsteinVaziraniNISQ.ll | 10 +- .../output/Adaptive_RI/ConstantFolding.ll | 10 +- .../Adaptive_RI/CopyAndUpdateExpressions.ll | 10 +- .../output/Adaptive_RI/DeutschJozsaNISQ.ll | 10 +- .../output/Adaptive_RI/ExpandedTests.ll | 10 +- .../resources/output/Adaptive_RI/Functors.ll | 10 +- .../output/Adaptive_RI/HiddenShiftNISQ.ll | 10 +- .../output/Adaptive_RI/IntegerComparison.ll | 10 +- .../output/Adaptive_RI/IntrinsicCCNOT.ll | 10 +- .../output/Adaptive_RI/IntrinsicCNOT.ll | 10 +- .../output/Adaptive_RI/IntrinsicHIXYZ.ll | 10 +- .../output/Adaptive_RI/IntrinsicM.ll | 10 +- .../IntrinsicMeasureWithBitFlipCode.ll | 10 +- .../IntrinsicMeasureWithPhaseFlipCode.ll | 10 +- .../IntrinsicRotationsWithPeriod.ll | 10 +- .../output/Adaptive_RI/IntrinsicSTSWAP.ll | 10 +- .../output/Adaptive_RI/MeasureAndReuse.ll | 10 +- .../Adaptive_RI/MeasurementComparison.ll | 10 +- .../output/Adaptive_RI/NestedBranching.ll | 10 +- .../resources/output/Adaptive_RI/RandomBit.ll | 10 +- .../output/Adaptive_RI/SampleTeleport.ll | 10 +- .../Adaptive_RI/ShortcuttingMeasurement.ll | 10 +- .../resources/output/Adaptive_RI/Slicing.ll | 10 +- .../output/Adaptive_RI/SuperdenseCoding.ll | 10 +- .../output/Adaptive_RI/SwitchHandling.ll | 10 +- .../Adaptive_RI/ThreeQubitRepetitionCode.ll | 10 +- .../output/Adaptive_RI/WithinApply.ll | 10 +- pip/tests/test_interpreter.py | 10 +- pip/tests/test_qsharp.py | 6 + playground/src/editor.tsx | 1 + vscode/package.json | 6 +- vscode/src/config.ts | 3 + vscode/src/language-service/activate.ts | 1 + vscode/src/statusbar.ts | 3 + wasm/src/language_service.rs | 2 +- wasm/src/lib.rs | 2 +- 68 files changed, 4388 insertions(+), 792 deletions(-) create mode 100644 compiler/qsc_passes/src/capabilitiesck/tests_adaptive_plus_integers_and_floats.rs diff --git a/compiler/qsc/src/codegen/tests.rs b/compiler/qsc/src/codegen/tests.rs index 6c82359c6a..1242511525 100644 --- a/compiler/qsc/src/codegen/tests.rs +++ b/compiler/qsc/src/codegen/tests.rs @@ -7,6 +7,21 @@ use qsc_frontend::compile::SourceMap; use crate::codegen::qir::get_qir; +fn compile_source_to_qir(source: &str, capabilities: TargetCapabilityFlags) -> String { + let sources = SourceMap::new([("test.qs".into(), source.into())], None); + let language_features = LanguageFeatures::default(); + + let (std_id, store) = crate::compile::package_store_with_stdlib(capabilities); + get_qir( + sources, + language_features, + capabilities, + store, + &[(std_id, None)], + ) + .expect("Failed to generate QIR") +} + #[test] fn code_with_errors_returns_errors() { let source = "namespace Test { @@ -61,10 +76,11 @@ fn code_with_errors_returns_errors() { mod base_profile { use expect_test::expect; - use qsc_data_structures::{language_features::LanguageFeatures, target::TargetCapabilityFlags}; - use qsc_frontend::compile::SourceMap; + use qsc_data_structures::target::TargetCapabilityFlags; - use crate::codegen::qir::get_qir; + use super::compile_source_to_qir; + static CAPABILITIES: std::sync::LazyLock = + std::sync::LazyLock::new(TargetCapabilityFlags::empty); #[test] fn simple() { @@ -83,19 +99,8 @@ mod base_profile { __quantum__qis__mresetz__body(q) } }"; - let sources = SourceMap::new([("test.qs".into(), source.into())], None); - let language_features = LanguageFeatures::default(); - let capabilities = TargetCapabilityFlags::empty(); - - let (std_id, store) = crate::compile::package_store_with_stdlib(capabilities); - let qir = get_qir( - sources, - language_features, - capabilities, - store, - &[(std_id, None)], - ) - .expect("Failed to generate QIR"); + + let qir = compile_source_to_qir(source, *CAPABILITIES); expect![[r#" %Result = type opaque %Qubit = type opaque @@ -140,19 +145,7 @@ mod base_profile { (MResetZ(q), MResetZ(q)) } }"; - let sources = SourceMap::new([("test.qs".into(), source.into())], None); - let language_features = LanguageFeatures::default(); - let capabilities = TargetCapabilityFlags::empty(); - - let (std_id, store) = crate::compile::package_store_with_stdlib(capabilities); - let qir = get_qir( - sources, - language_features, - capabilities, - store, - &[(std_id, None)], - ) - .expect("Failed to generate QIR"); + let qir = compile_source_to_qir(source, *CAPABILITIES); expect![[r#" %Result = type opaque %Qubit = type opaque @@ -200,19 +193,7 @@ mod base_profile { [r0, r1] } }"; - let sources = SourceMap::new([("test.qs".into(), source.into())], None); - let language_features = LanguageFeatures::default(); - let capabilities = TargetCapabilityFlags::empty(); - - let (std_id, store) = crate::compile::package_store_with_stdlib(capabilities); - let qir = get_qir( - sources, - language_features, - capabilities, - store, - &[(std_id, None)], - ) - .expect("Failed to generate QIR"); + let qir = compile_source_to_qir(source, *CAPABILITIES); expect![[r#" %Result = type opaque %Qubit = type opaque @@ -263,19 +244,7 @@ mod base_profile { (MResetZ(q0), MResetZ(q1)) } }"; - let sources = SourceMap::new([("test.qs".into(), source.into())], None); - let language_features = LanguageFeatures::default(); - let capabilities = TargetCapabilityFlags::empty(); - - let (std_id, store) = crate::compile::package_store_with_stdlib(capabilities); - let qir = get_qir( - sources, - language_features, - capabilities, - store, - &[(std_id, None)], - ) - .expect("Failed to generate QIR"); + let qir = compile_source_to_qir(source, *CAPABILITIES); expect![[r#" %Result = type opaque %Qubit = type opaque @@ -331,19 +300,7 @@ mod base_profile { (MResetZ(q0), MResetZ(q1)) } }"; - let sources = SourceMap::new([("test.qs".into(), source.into())], None); - let language_features = LanguageFeatures::default(); - let capabilities = TargetCapabilityFlags::empty(); - - let (std_id, store) = crate::compile::package_store_with_stdlib(capabilities); - let qir = get_qir( - sources, - language_features, - capabilities, - store, - &[(std_id, None)], - ) - .expect("Failed to generate QIR"); + let qir = compile_source_to_qir(source, *CAPABILITIES); expect![[r#" %Result = type opaque %Qubit = type opaque @@ -384,11 +341,11 @@ mod base_profile { } mod adaptive_profile { + use super::compile_source_to_qir; use expect_test::expect; - use qsc_data_structures::{language_features::LanguageFeatures, target::TargetCapabilityFlags}; - use qsc_frontend::compile::SourceMap; - - use crate::codegen::qir::get_qir; + use qsc_data_structures::target::TargetCapabilityFlags; + static CAPABILITIES: std::sync::LazyLock = + std::sync::LazyLock::new(|| TargetCapabilityFlags::Adaptive); #[test] fn simple() { @@ -407,19 +364,7 @@ mod adaptive_profile { __quantum__qis__mresetz__body(q) } }"; - let sources = SourceMap::new([("test.qs".into(), source.into())], None); - let language_features = LanguageFeatures::default(); - let capabilities = TargetCapabilityFlags::Adaptive; - - let (std_id, store) = crate::compile::package_store_with_stdlib(capabilities); - let qir = get_qir( - sources, - language_features, - capabilities, - store, - &[(std_id, None)], - ) - .expect("Failed to generate QIR"); + let qir = compile_source_to_qir(source, *CAPABILITIES); expect![[r#" %Result = type opaque %Qubit = type opaque @@ -445,19 +390,12 @@ mod adaptive_profile { ; module flags - !llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10} + !llvm.module.flags = !{!0, !1, !2, !3} !0 = !{i32 1, !"qir_major_version", i32 1} !1 = !{i32 7, !"qir_minor_version", i32 0} !2 = !{i32 1, !"dynamic_qubit_management", i1 false} !3 = !{i32 1, !"dynamic_result_management", i1 false} - !4 = !{i32 1, !"classical_ints", i1 false} - !5 = !{i32 1, !"classical_floats", i1 false} - !6 = !{i32 1, !"backwards_branching", i1 false} - !7 = !{i32 1, !"qubit_resetting", i1 false} - !8 = !{i32 1, !"classical_fixed_points", i1 false} - !9 = !{i32 1, !"user_functions", i1 false} - !10 = !{i32 1, !"multiple_target_branching", i1 false} "#]] .assert_eq(&qir); } @@ -471,19 +409,7 @@ mod adaptive_profile { (MResetZ(q), MResetZ(q)) } }"; - let sources = SourceMap::new([("test.qs".into(), source.into())], None); - let language_features = LanguageFeatures::default(); - let capabilities = TargetCapabilityFlags::Adaptive; - - let (std_id, store) = crate::compile::package_store_with_stdlib(capabilities); - let qir = get_qir( - sources, - language_features, - capabilities, - store, - &[(std_id, None)], - ) - .expect("Failed to generate QIR"); + let qir = compile_source_to_qir(source, *CAPABILITIES); expect![[r#" %Result = type opaque %Qubit = type opaque @@ -509,19 +435,12 @@ mod adaptive_profile { ; module flags - !llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10} + !llvm.module.flags = !{!0, !1, !2, !3} !0 = !{i32 1, !"qir_major_version", i32 1} !1 = !{i32 7, !"qir_minor_version", i32 0} !2 = !{i32 1, !"dynamic_qubit_management", i1 false} !3 = !{i32 1, !"dynamic_result_management", i1 false} - !4 = !{i32 1, !"classical_ints", i1 false} - !5 = !{i32 1, !"classical_floats", i1 false} - !6 = !{i32 1, !"backwards_branching", i1 false} - !7 = !{i32 1, !"qubit_resetting", i1 false} - !8 = !{i32 1, !"classical_fixed_points", i1 false} - !9 = !{i32 1, !"user_functions", i1 false} - !10 = !{i32 1, !"multiple_target_branching", i1 false} "#]].assert_eq(&qir); } @@ -539,19 +458,7 @@ mod adaptive_profile { body intrinsic; } }"; - let sources = SourceMap::new([("test.qs".into(), source.into())], None); - let language_features = LanguageFeatures::default(); - let capabilities = TargetCapabilityFlags::Adaptive; - - let (std_id, store) = crate::compile::package_store_with_stdlib(capabilities); - let qir = get_qir( - sources, - language_features, - capabilities, - store, - &[(std_id, None)], - ) - .expect("the input program set in the `source` variable should be valid Q#"); + let qir = compile_source_to_qir(source, *CAPABILITIES); expect![[r#" %Result = type opaque %Qubit = type opaque @@ -575,19 +482,12 @@ mod adaptive_profile { ; module flags - !llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10} + !llvm.module.flags = !{!0, !1, !2, !3} !0 = !{i32 1, !"qir_major_version", i32 1} !1 = !{i32 7, !"qir_minor_version", i32 0} !2 = !{i32 1, !"dynamic_qubit_management", i1 false} !3 = !{i32 1, !"dynamic_result_management", i1 false} - !4 = !{i32 1, !"classical_ints", i1 false} - !5 = !{i32 1, !"classical_floats", i1 false} - !6 = !{i32 1, !"backwards_branching", i1 false} - !7 = !{i32 1, !"qubit_resetting", i1 false} - !8 = !{i32 1, !"classical_fixed_points", i1 false} - !9 = !{i32 1, !"user_functions", i1 false} - !10 = !{i32 1, !"multiple_target_branching", i1 false} "#]].assert_eq(&qir); } @@ -607,19 +507,7 @@ mod adaptive_profile { body intrinsic; } }"; - let sources = SourceMap::new([("test.qs".into(), source.into())], None); - let language_features = LanguageFeatures::default(); - let capabilities = TargetCapabilityFlags::Adaptive; - - let (std_id, store) = crate::compile::package_store_with_stdlib(capabilities); - let qir = get_qir( - sources, - language_features, - capabilities, - store, - &[(std_id, None)], - ) - .expect("the input program set in the `source` variable should be valid Q#"); + let qir = compile_source_to_qir(source, *CAPABILITIES); expect![[r#" %Result = type opaque %Qubit = type opaque @@ -648,19 +536,12 @@ mod adaptive_profile { ; module flags - !llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10} + !llvm.module.flags = !{!0, !1, !2, !3} !0 = !{i32 1, !"qir_major_version", i32 1} !1 = !{i32 7, !"qir_minor_version", i32 0} !2 = !{i32 1, !"dynamic_qubit_management", i1 false} !3 = !{i32 1, !"dynamic_result_management", i1 false} - !4 = !{i32 1, !"classical_ints", i1 false} - !5 = !{i32 1, !"classical_floats", i1 false} - !6 = !{i32 1, !"backwards_branching", i1 false} - !7 = !{i32 1, !"qubit_resetting", i1 false} - !8 = !{i32 1, !"classical_fixed_points", i1 false} - !9 = !{i32 1, !"user_functions", i1 false} - !10 = !{i32 1, !"multiple_target_branching", i1 false} "#]].assert_eq(&qir); } @@ -677,19 +558,7 @@ mod adaptive_profile { [r0, r1] } }"; - let sources = SourceMap::new([("test.qs".into(), source.into())], None); - let language_features = LanguageFeatures::default(); - let capabilities = TargetCapabilityFlags::Adaptive; - - let (std_id, store) = crate::compile::package_store_with_stdlib(capabilities); - let qir = get_qir( - sources, - language_features, - capabilities, - store, - &[(std_id, None)], - ) - .expect("Failed to generate QIR"); + let qir = compile_source_to_qir(source, *CAPABILITIES); expect![[r#" %Result = type opaque %Qubit = type opaque @@ -719,19 +588,12 @@ mod adaptive_profile { ; module flags - !llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10} + !llvm.module.flags = !{!0, !1, !2, !3} !0 = !{i32 1, !"qir_major_version", i32 1} !1 = !{i32 7, !"qir_minor_version", i32 0} !2 = !{i32 1, !"dynamic_qubit_management", i1 false} !3 = !{i32 1, !"dynamic_result_management", i1 false} - !4 = !{i32 1, !"classical_ints", i1 false} - !5 = !{i32 1, !"classical_floats", i1 false} - !6 = !{i32 1, !"backwards_branching", i1 false} - !7 = !{i32 1, !"qubit_resetting", i1 false} - !8 = !{i32 1, !"classical_fixed_points", i1 false} - !9 = !{i32 1, !"user_functions", i1 false} - !10 = !{i32 1, !"multiple_target_branching", i1 false} "#]].assert_eq(&qir); } } @@ -739,10 +601,15 @@ mod adaptive_profile { mod adaptive_ri_profile { use expect_test::expect; - use qsc_data_structures::{language_features::LanguageFeatures, target::TargetCapabilityFlags}; - use qsc_frontend::compile::SourceMap; + use qsc_data_structures::target::TargetCapabilityFlags; - use crate::codegen::qir::get_qir; + use super::compile_source_to_qir; + static CAPABILITIES: std::sync::LazyLock = + std::sync::LazyLock::new(|| { + TargetCapabilityFlags::Adaptive + | TargetCapabilityFlags::QubitReset + | TargetCapabilityFlags::IntegerComputations + }); #[test] fn simple() { @@ -761,21 +628,7 @@ mod adaptive_ri_profile { __quantum__qis__mresetz__body(q) } }"; - let sources = SourceMap::new([("test.qs".into(), source.into())], None); - let language_features = LanguageFeatures::default(); - let capabilities = TargetCapabilityFlags::Adaptive - | TargetCapabilityFlags::QubitReset - | TargetCapabilityFlags::IntegerComputations; - - let (std_id, store) = crate::compile::package_store_with_stdlib(capabilities); - let qir = get_qir( - sources, - language_features, - capabilities, - store, - &[(std_id, None)], - ) - .expect("Failed to generate QIR"); + let qir = compile_source_to_qir(source, *CAPABILITIES); expect![[r#" %Result = type opaque %Qubit = type opaque @@ -801,19 +654,13 @@ mod adaptive_ri_profile { ; module flags - !llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10} + !llvm.module.flags = !{!0, !1, !2, !3, !4} !0 = !{i32 1, !"qir_major_version", i32 1} !1 = !{i32 7, !"qir_minor_version", i32 0} !2 = !{i32 1, !"dynamic_qubit_management", i1 false} !3 = !{i32 1, !"dynamic_result_management", i1 false} - !4 = !{i32 1, !"classical_ints", i1 true} - !5 = !{i32 1, !"qubit_resetting", i1 true} - !6 = !{i32 1, !"classical_floats", i1 false} - !7 = !{i32 1, !"backwards_branching", i1 false} - !8 = !{i32 1, !"classical_fixed_points", i1 false} - !9 = !{i32 1, !"user_functions", i1 false} - !10 = !{i32 1, !"multiple_target_branching", i1 false} + !4 = !{i32 1, !"int_computations", !"i64"} "#]] .assert_eq(&qir); } @@ -827,21 +674,7 @@ mod adaptive_ri_profile { (MResetZ(q), MResetZ(q)) } }"; - let sources = SourceMap::new([("test.qs".into(), source.into())], None); - let language_features = LanguageFeatures::default(); - let capabilities = TargetCapabilityFlags::Adaptive - | TargetCapabilityFlags::QubitReset - | TargetCapabilityFlags::IntegerComputations; - - let (std_id, store) = crate::compile::package_store_with_stdlib(capabilities); - let qir = get_qir( - sources, - language_features, - capabilities, - store, - &[(std_id, None)], - ) - .expect("Failed to generate QIR"); + let qir = compile_source_to_qir(source, *CAPABILITIES); expect![[r#" %Result = type opaque %Qubit = type opaque @@ -867,19 +700,13 @@ mod adaptive_ri_profile { ; module flags - !llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10} + !llvm.module.flags = !{!0, !1, !2, !3, !4} !0 = !{i32 1, !"qir_major_version", i32 1} !1 = !{i32 7, !"qir_minor_version", i32 0} !2 = !{i32 1, !"dynamic_qubit_management", i1 false} !3 = !{i32 1, !"dynamic_result_management", i1 false} - !4 = !{i32 1, !"classical_ints", i1 true} - !5 = !{i32 1, !"qubit_resetting", i1 true} - !6 = !{i32 1, !"classical_floats", i1 false} - !7 = !{i32 1, !"backwards_branching", i1 false} - !8 = !{i32 1, !"classical_fixed_points", i1 false} - !9 = !{i32 1, !"user_functions", i1 false} - !10 = !{i32 1, !"multiple_target_branching", i1 false} + !4 = !{i32 1, !"int_computations", !"i64"} "#]].assert_eq(&qir); } @@ -896,21 +723,7 @@ mod adaptive_ri_profile { [r0, r1] } }"; - let sources = SourceMap::new([("test.qs".into(), source.into())], None); - let language_features = LanguageFeatures::default(); - let capabilities = TargetCapabilityFlags::Adaptive - | TargetCapabilityFlags::QubitReset - | TargetCapabilityFlags::IntegerComputations; - - let (std_id, store) = crate::compile::package_store_with_stdlib(capabilities); - let qir = get_qir( - sources, - language_features, - capabilities, - store, - &[(std_id, None)], - ) - .expect("Failed to generate QIR"); + let qir = compile_source_to_qir(source, *CAPABILITIES); expect![[r#" %Result = type opaque %Qubit = type opaque @@ -940,19 +753,13 @@ mod adaptive_ri_profile { ; module flags - !llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10} + !llvm.module.flags = !{!0, !1, !2, !3, !4} !0 = !{i32 1, !"qir_major_version", i32 1} !1 = !{i32 7, !"qir_minor_version", i32 0} !2 = !{i32 1, !"dynamic_qubit_management", i1 false} !3 = !{i32 1, !"dynamic_result_management", i1 false} - !4 = !{i32 1, !"classical_ints", i1 true} - !5 = !{i32 1, !"qubit_resetting", i1 true} - !6 = !{i32 1, !"classical_floats", i1 false} - !7 = !{i32 1, !"backwards_branching", i1 false} - !8 = !{i32 1, !"classical_fixed_points", i1 false} - !9 = !{i32 1, !"user_functions", i1 false} - !10 = !{i32 1, !"multiple_target_branching", i1 false} + !4 = !{i32 1, !"int_computations", !"i64"} "#]].assert_eq(&qir); } @@ -968,21 +775,7 @@ mod adaptive_ri_profile { (MResetZ(q0), MResetZ(q1)) } }"; - let sources = SourceMap::new([("test.qs".into(), source.into())], None); - let language_features = LanguageFeatures::default(); - let capabilities = TargetCapabilityFlags::Adaptive - | TargetCapabilityFlags::QubitReset - | TargetCapabilityFlags::IntegerComputations; - - let (std_id, store) = crate::compile::package_store_with_stdlib(capabilities); - let qir = get_qir( - sources, - language_features, - capabilities, - store, - &[(std_id, None)], - ) - .expect("Failed to generate QIR"); + let qir = compile_source_to_qir(source, *CAPABILITIES); expect![[r#" %Result = type opaque %Qubit = type opaque @@ -1012,19 +805,13 @@ mod adaptive_ri_profile { ; module flags - !llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10} + !llvm.module.flags = !{!0, !1, !2, !3, !4} !0 = !{i32 1, !"qir_major_version", i32 1} !1 = !{i32 7, !"qir_minor_version", i32 0} !2 = !{i32 1, !"dynamic_qubit_management", i1 false} !3 = !{i32 1, !"dynamic_result_management", i1 false} - !4 = !{i32 1, !"classical_ints", i1 true} - !5 = !{i32 1, !"qubit_resetting", i1 true} - !6 = !{i32 1, !"classical_floats", i1 false} - !7 = !{i32 1, !"backwards_branching", i1 false} - !8 = !{i32 1, !"classical_fixed_points", i1 false} - !9 = !{i32 1, !"user_functions", i1 false} - !10 = !{i32 1, !"multiple_target_branching", i1 false} + !4 = !{i32 1, !"int_computations", !"i64"} "#]].assert_eq(&qir); } @@ -1045,21 +832,7 @@ mod adaptive_ri_profile { (MResetZ(q0), MResetZ(q1)) } }"; - let sources = SourceMap::new([("test.qs".into(), source.into())], None); - let language_features = LanguageFeatures::default(); - let capabilities = TargetCapabilityFlags::Adaptive - | TargetCapabilityFlags::QubitReset - | TargetCapabilityFlags::IntegerComputations; - - let (std_id, store) = crate::compile::package_store_with_stdlib(capabilities); - let qir = get_qir( - sources, - language_features, - capabilities, - store, - &[(std_id, None)], - ) - .expect("Failed to generate QIR"); + let qir = compile_source_to_qir(source, *CAPABILITIES); expect![[r#" %Result = type opaque %Qubit = type opaque @@ -1093,19 +866,13 @@ mod adaptive_ri_profile { ; module flags - !llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10} + !llvm.module.flags = !{!0, !1, !2, !3, !4} !0 = !{i32 1, !"qir_major_version", i32 1} !1 = !{i32 7, !"qir_minor_version", i32 0} !2 = !{i32 1, !"dynamic_qubit_management", i1 false} !3 = !{i32 1, !"dynamic_result_management", i1 false} - !4 = !{i32 1, !"classical_ints", i1 true} - !5 = !{i32 1, !"qubit_resetting", i1 true} - !6 = !{i32 1, !"classical_floats", i1 false} - !7 = !{i32 1, !"backwards_branching", i1 false} - !8 = !{i32 1, !"classical_fixed_points", i1 false} - !9 = !{i32 1, !"user_functions", i1 false} - !10 = !{i32 1, !"multiple_target_branching", i1 false} + !4 = !{i32 1, !"int_computations", !"i64"} "#]].assert_eq(&qir); } @@ -1127,21 +894,7 @@ mod adaptive_ri_profile { (MResetZ(q3), MResetZ(q1)) } }"; - let sources = SourceMap::new([("test.qs".into(), source.into())], None); - let language_features = LanguageFeatures::default(); - let capabilities = TargetCapabilityFlags::Adaptive - | TargetCapabilityFlags::QubitReset - | TargetCapabilityFlags::IntegerComputations; - - let (std_id, store) = crate::compile::package_store_with_stdlib(capabilities); - let qir = get_qir( - sources, - language_features, - capabilities, - store, - &[(std_id, None)], - ) - .expect("Failed to generate QIR"); + let qir = compile_source_to_qir(source, *CAPABILITIES); expect![[r#" %Result = type opaque %Qubit = type opaque @@ -1173,19 +926,13 @@ mod adaptive_ri_profile { ; module flags - !llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10} + !llvm.module.flags = !{!0, !1, !2, !3, !4} !0 = !{i32 1, !"qir_major_version", i32 1} !1 = !{i32 7, !"qir_minor_version", i32 0} !2 = !{i32 1, !"dynamic_qubit_management", i1 false} !3 = !{i32 1, !"dynamic_result_management", i1 false} - !4 = !{i32 1, !"classical_ints", i1 true} - !5 = !{i32 1, !"qubit_resetting", i1 true} - !6 = !{i32 1, !"classical_floats", i1 false} - !7 = !{i32 1, !"backwards_branching", i1 false} - !8 = !{i32 1, !"classical_fixed_points", i1 false} - !9 = !{i32 1, !"user_functions", i1 false} - !10 = !{i32 1, !"multiple_target_branching", i1 false} + !4 = !{i32 1, !"int_computations", !"i64"} "#]].assert_eq(&qir); } @@ -1199,21 +946,7 @@ mod adaptive_ri_profile { MResetZ(q) == Zero ? 0 | 1 } }"; - let sources = SourceMap::new([("test.qs".into(), source.into())], None); - let language_features = LanguageFeatures::default(); - let capabilities = TargetCapabilityFlags::Adaptive - | TargetCapabilityFlags::QubitReset - | TargetCapabilityFlags::IntegerComputations; - - let (std_id, store) = crate::compile::package_store_with_stdlib(capabilities); - let qir = get_qir( - sources, - language_features, - capabilities, - store, - &[(std_id, None)], - ) - .expect("Failed to generate QIR"); + let qir = compile_source_to_qir(source, *CAPABILITIES); expect![[r#" %Result = type opaque %Qubit = type opaque @@ -1248,19 +981,13 @@ mod adaptive_ri_profile { ; module flags - !llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10} + !llvm.module.flags = !{!0, !1, !2, !3, !4} !0 = !{i32 1, !"qir_major_version", i32 1} !1 = !{i32 7, !"qir_minor_version", i32 0} !2 = !{i32 1, !"dynamic_qubit_management", i1 false} !3 = !{i32 1, !"dynamic_result_management", i1 false} - !4 = !{i32 1, !"classical_ints", i1 true} - !5 = !{i32 1, !"qubit_resetting", i1 true} - !6 = !{i32 1, !"classical_floats", i1 false} - !7 = !{i32 1, !"backwards_branching", i1 false} - !8 = !{i32 1, !"classical_fixed_points", i1 false} - !9 = !{i32 1, !"user_functions", i1 false} - !10 = !{i32 1, !"multiple_target_branching", i1 false} + !4 = !{i32 1, !"int_computations", !"i64"} "#]].assert_eq(&qir); } @@ -1278,21 +1005,7 @@ mod adaptive_ri_profile { body intrinsic; } }"; - let sources = SourceMap::new([("test.qs".into(), source.into())], None); - let language_features = LanguageFeatures::default(); - let capabilities = TargetCapabilityFlags::Adaptive - | TargetCapabilityFlags::QubitReset - | TargetCapabilityFlags::IntegerComputations; - - let (std_id, store) = crate::compile::package_store_with_stdlib(capabilities); - let qir = get_qir( - sources, - language_features, - capabilities, - store, - &[(std_id, None)], - ) - .expect("the input program set in the `source` variable should be valid Q#"); + let qir = compile_source_to_qir(source, *CAPABILITIES); expect![[r#" %Result = type opaque %Qubit = type opaque @@ -1316,20 +1029,602 @@ mod adaptive_ri_profile { ; module flags - !llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10} + !llvm.module.flags = !{!0, !1, !2, !3, !4} + + !0 = !{i32 1, !"qir_major_version", i32 1} + !1 = !{i32 7, !"qir_minor_version", i32 0} + !2 = !{i32 1, !"dynamic_qubit_management", i1 false} + !3 = !{i32 1, !"dynamic_result_management", i1 false} + !4 = !{i32 1, !"int_computations", !"i64"} + "#]] + .assert_eq(&qir); + } +} + +mod adaptive_rif_profile { + use super::compile_source_to_qir; + use expect_test::expect; + use qsc_data_structures::target::TargetCapabilityFlags; + static CAPABILITIES: std::sync::LazyLock = + std::sync::LazyLock::new(|| { + TargetCapabilityFlags::Adaptive + | TargetCapabilityFlags::QubitReset + | TargetCapabilityFlags::IntegerComputations + | TargetCapabilityFlags::FloatingPointComputations + }); + + #[test] + fn simple() { + let source = "namespace Test { + import Std.Math.*; + open QIR.Intrinsic; + @EntryPoint() + operation Main() : Result { + use q = Qubit(); + let pi_over_two = 4.0 / 2.0; + __quantum__qis__rz__body(pi_over_two, q); + mutable some_angle = ArcSin(0.0); + __quantum__qis__rz__body(some_angle, q); + set some_angle = ArcCos(-1.0) / PI(); + __quantum__qis__rz__body(some_angle, q); + __quantum__qis__mresetz__body(q) + } + }"; + let qir = compile_source_to_qir(source, *CAPABILITIES); + expect![[r#" + %Result = type opaque + %Qubit = type opaque + + define void @ENTRYPOINT__main() #0 { + block_0: + call void @__quantum__qis__rz__body(double 2.0, %Qubit* inttoptr (i64 0 to %Qubit*)) + call void @__quantum__qis__rz__body(double 0.0, %Qubit* inttoptr (i64 0 to %Qubit*)) + call void @__quantum__qis__rz__body(double 1.0, %Qubit* inttoptr (i64 0 to %Qubit*)) + call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*)) + call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null) + ret void + } + + declare void @__quantum__qis__rz__body(double, %Qubit*) + + declare void @__quantum__qis__mresetz__body(%Qubit*, %Result*) #1 + + declare void @__quantum__rt__result_record_output(%Result*, i8*) + + attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="adaptive_profile" "required_num_qubits"="1" "required_num_results"="1" } + attributes #1 = { "irreversible" } + + ; module flags + + !llvm.module.flags = !{!0, !1, !2, !3, !4, !5} !0 = !{i32 1, !"qir_major_version", i32 1} !1 = !{i32 7, !"qir_minor_version", i32 0} !2 = !{i32 1, !"dynamic_qubit_management", i1 false} !3 = !{i32 1, !"dynamic_result_management", i1 false} - !4 = !{i32 1, !"classical_ints", i1 true} - !5 = !{i32 1, !"qubit_resetting", i1 true} - !6 = !{i32 1, !"classical_floats", i1 false} - !7 = !{i32 1, !"backwards_branching", i1 false} - !8 = !{i32 1, !"classical_fixed_points", i1 false} - !9 = !{i32 1, !"user_functions", i1 false} - !10 = !{i32 1, !"multiple_target_branching", i1 false} + !4 = !{i32 1, !"int_computations", !"i64"} + !5 = !{i32 1, !"float_computations", !"f64"} "#]] .assert_eq(&qir); } + + #[test] + fn qubit_reuse_allowed() { + let source = "namespace Test { + @EntryPoint() + operation Main() : (Result, Result) { + use q = Qubit(); + (MResetZ(q), MResetZ(q)) + } + }"; + let qir = compile_source_to_qir(source, *CAPABILITIES); + expect![[r#" + %Result = type opaque + %Qubit = type opaque + + define void @ENTRYPOINT__main() #0 { + block_0: + call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*)) + call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 1 to %Result*)) + call void @__quantum__rt__tuple_record_output(i64 2, i8* null) + call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null) + call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 1 to %Result*), i8* null) + ret void + } + + declare void @__quantum__qis__mresetz__body(%Qubit*, %Result*) #1 + + declare void @__quantum__rt__tuple_record_output(i64, i8*) + + declare void @__quantum__rt__result_record_output(%Result*, i8*) + + attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="adaptive_profile" "required_num_qubits"="1" "required_num_results"="2" } + attributes #1 = { "irreversible" } + + ; module flags + + !llvm.module.flags = !{!0, !1, !2, !3, !4, !5} + + !0 = !{i32 1, !"qir_major_version", i32 1} + !1 = !{i32 7, !"qir_minor_version", i32 0} + !2 = !{i32 1, !"dynamic_qubit_management", i1 false} + !3 = !{i32 1, !"dynamic_result_management", i1 false} + !4 = !{i32 1, !"int_computations", !"i64"} + !5 = !{i32 1, !"float_computations", !"f64"} + "#]].assert_eq(&qir); + } + + #[test] + fn qubit_measurements_not_deferred() { + let source = "namespace Test { + @EntryPoint() + operation Main() : Result[] { + use (q0, q1) = (Qubit(), Qubit()); + X(q0); + let r0 = MResetZ(q0); + X(q1); + let r1 = MResetZ(q1); + [r0, r1] + } + }"; + let qir = compile_source_to_qir(source, *CAPABILITIES); + expect![[r#" + %Result = type opaque + %Qubit = type opaque + + define void @ENTRYPOINT__main() #0 { + block_0: + call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 0 to %Qubit*)) + call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*)) + call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 1 to %Qubit*)) + call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 1 to %Result*)) + call void @__quantum__rt__array_record_output(i64 2, i8* null) + call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null) + call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 1 to %Result*), i8* null) + ret void + } + + declare void @__quantum__qis__x__body(%Qubit*) + + declare void @__quantum__qis__mresetz__body(%Qubit*, %Result*) #1 + + declare void @__quantum__rt__array_record_output(i64, i8*) + + declare void @__quantum__rt__result_record_output(%Result*, i8*) + + attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="adaptive_profile" "required_num_qubits"="2" "required_num_results"="2" } + attributes #1 = { "irreversible" } + + ; module flags + + !llvm.module.flags = !{!0, !1, !2, !3, !4, !5} + + !0 = !{i32 1, !"qir_major_version", i32 1} + !1 = !{i32 7, !"qir_minor_version", i32 0} + !2 = !{i32 1, !"dynamic_qubit_management", i1 false} + !3 = !{i32 1, !"dynamic_result_management", i1 false} + !4 = !{i32 1, !"int_computations", !"i64"} + !5 = !{i32 1, !"float_computations", !"f64"} + "#]].assert_eq(&qir); + } + + #[test] + fn qubit_id_swap_results_in_different_id_usage() { + let source = "namespace Test { + @EntryPoint() + operation Main() : (Result, Result) { + use (q0, q1) = (Qubit(), Qubit()); + X(q0); + Relabel([q0, q1], [q1, q0]); + X(q1); + (MResetZ(q0), MResetZ(q1)) + } + }"; + let qir = compile_source_to_qir(source, *CAPABILITIES); + expect![[r#" + %Result = type opaque + %Qubit = type opaque + + define void @ENTRYPOINT__main() #0 { + block_0: + call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 0 to %Qubit*)) + call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 0 to %Qubit*)) + call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 0 to %Result*)) + call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 1 to %Result*)) + call void @__quantum__rt__tuple_record_output(i64 2, i8* null) + call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null) + call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 1 to %Result*), i8* null) + ret void + } + + declare void @__quantum__qis__x__body(%Qubit*) + + declare void @__quantum__qis__mresetz__body(%Qubit*, %Result*) #1 + + declare void @__quantum__rt__tuple_record_output(i64, i8*) + + declare void @__quantum__rt__result_record_output(%Result*, i8*) + + attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="adaptive_profile" "required_num_qubits"="2" "required_num_results"="2" } + attributes #1 = { "irreversible" } + + ; module flags + + !llvm.module.flags = !{!0, !1, !2, !3, !4, !5} + + !0 = !{i32 1, !"qir_major_version", i32 1} + !1 = !{i32 7, !"qir_minor_version", i32 0} + !2 = !{i32 1, !"dynamic_qubit_management", i1 false} + !3 = !{i32 1, !"dynamic_result_management", i1 false} + !4 = !{i32 1, !"int_computations", !"i64"} + !5 = !{i32 1, !"float_computations", !"f64"} + "#]].assert_eq(&qir); + } + + #[test] + fn qubit_id_swap_across_reset_uses_updated_ids() { + let source = "namespace Test { + @EntryPoint() + operation Main() : (Result, Result) { + { + use (q0, q1) = (Qubit(), Qubit()); + X(q0); + Relabel([q0, q1], [q1, q0]); + X(q1); + Reset(q0); + Reset(q1); + } + use (q0, q1) = (Qubit(), Qubit()); + (MResetZ(q0), MResetZ(q1)) + } + }"; + let qir = compile_source_to_qir(source, *CAPABILITIES); + expect![[r#" + %Result = type opaque + %Qubit = type opaque + + define void @ENTRYPOINT__main() #0 { + block_0: + call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 0 to %Qubit*)) + call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 0 to %Qubit*)) + call void @__quantum__qis__reset__body(%Qubit* inttoptr (i64 1 to %Qubit*)) + call void @__quantum__qis__reset__body(%Qubit* inttoptr (i64 0 to %Qubit*)) + call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*)) + call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 1 to %Result*)) + call void @__quantum__rt__tuple_record_output(i64 2, i8* null) + call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null) + call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 1 to %Result*), i8* null) + ret void + } + + declare void @__quantum__qis__x__body(%Qubit*) + + declare void @__quantum__qis__reset__body(%Qubit*) #1 + + declare void @__quantum__qis__mresetz__body(%Qubit*, %Result*) #1 + + declare void @__quantum__rt__tuple_record_output(i64, i8*) + + declare void @__quantum__rt__result_record_output(%Result*, i8*) + + attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="adaptive_profile" "required_num_qubits"="2" "required_num_results"="2" } + attributes #1 = { "irreversible" } + + ; module flags + + !llvm.module.flags = !{!0, !1, !2, !3, !4, !5} + + !0 = !{i32 1, !"qir_major_version", i32 1} + !1 = !{i32 7, !"qir_minor_version", i32 0} + !2 = !{i32 1, !"dynamic_qubit_management", i1 false} + !3 = !{i32 1, !"dynamic_result_management", i1 false} + !4 = !{i32 1, !"int_computations", !"i64"} + !5 = !{i32 1, !"float_computations", !"f64"} + "#]].assert_eq(&qir); + } + + #[test] + fn qubit_id_swap_with_out_of_order_release_uses_correct_ids() { + let source = "namespace Test { + @EntryPoint() + operation Main() : (Result, Result) { + let q0 = QIR.Runtime.__quantum__rt__qubit_allocate(); + let q1 = QIR.Runtime.__quantum__rt__qubit_allocate(); + let q2 = QIR.Runtime.__quantum__rt__qubit_allocate(); + X(q0); + X(q1); + X(q2); + Relabel([q0, q1], [q1, q0]); + QIR.Runtime.__quantum__rt__qubit_release(q0); + let q3 = QIR.Runtime.__quantum__rt__qubit_allocate(); + X(q3); + (MResetZ(q3), MResetZ(q1)) + } + }"; + let qir = compile_source_to_qir(source, *CAPABILITIES); + expect![[r#" + %Result = type opaque + %Qubit = type opaque + + define void @ENTRYPOINT__main() #0 { + block_0: + call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 0 to %Qubit*)) + call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 1 to %Qubit*)) + call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 2 to %Qubit*)) + call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 1 to %Qubit*)) + call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 0 to %Result*)) + call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 1 to %Result*)) + call void @__quantum__rt__tuple_record_output(i64 2, i8* null) + call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null) + call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 1 to %Result*), i8* null) + ret void + } + + declare void @__quantum__qis__x__body(%Qubit*) + + declare void @__quantum__qis__mresetz__body(%Qubit*, %Result*) #1 + + declare void @__quantum__rt__tuple_record_output(i64, i8*) + + declare void @__quantum__rt__result_record_output(%Result*, i8*) + + attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="adaptive_profile" "required_num_qubits"="3" "required_num_results"="2" } + attributes #1 = { "irreversible" } + + ; module flags + + !llvm.module.flags = !{!0, !1, !2, !3, !4, !5} + + !0 = !{i32 1, !"qir_major_version", i32 1} + !1 = !{i32 7, !"qir_minor_version", i32 0} + !2 = !{i32 1, !"dynamic_qubit_management", i1 false} + !3 = !{i32 1, !"dynamic_result_management", i1 false} + !4 = !{i32 1, !"int_computations", !"i64"} + !5 = !{i32 1, !"float_computations", !"f64"} + "#]].assert_eq(&qir); + } + + #[test] + fn dynamic_integer_with_branch_and_phi_supported() { + let source = "namespace Test { + @EntryPoint() + operation Main() : Int { + use q = Qubit(); + H(q); + MResetZ(q) == Zero ? 0 | 1 + } + }"; + let qir = compile_source_to_qir(source, *CAPABILITIES); + expect![[r#" + %Result = type opaque + %Qubit = type opaque + + define void @ENTRYPOINT__main() #0 { + block_0: + call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 0 to %Qubit*)) + call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*)) + %var_0 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 0 to %Result*)) + %var_1 = icmp eq i1 %var_0, false + br i1 %var_1, label %block_1, label %block_2 + block_1: + br label %block_3 + block_2: + br label %block_3 + block_3: + %var_3 = phi i64 [0, %block_1], [1, %block_2] + call void @__quantum__rt__int_record_output(i64 %var_3, i8* null) + ret void + } + + declare void @__quantum__qis__h__body(%Qubit*) + + declare void @__quantum__qis__mresetz__body(%Qubit*, %Result*) #1 + + declare i1 @__quantum__qis__read_result__body(%Result*) + + declare void @__quantum__rt__int_record_output(i64, i8*) + + attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="adaptive_profile" "required_num_qubits"="1" "required_num_results"="1" } + attributes #1 = { "irreversible" } + + ; module flags + + !llvm.module.flags = !{!0, !1, !2, !3, !4, !5} + + !0 = !{i32 1, !"qir_major_version", i32 1} + !1 = !{i32 7, !"qir_minor_version", i32 0} + !2 = !{i32 1, !"dynamic_qubit_management", i1 false} + !3 = !{i32 1, !"dynamic_result_management", i1 false} + !4 = !{i32 1, !"int_computations", !"i64"} + !5 = !{i32 1, !"float_computations", !"f64"} + "#]].assert_eq(&qir); + } + + #[test] + fn dynamic_double_with_branch_and_phi_supported() { + let source = "namespace Test { + @EntryPoint() + operation Main() : Double { + use q = Qubit(); + H(q); + MResetZ(q) == Zero ? 0.0 | 1.0 + } + }"; + let qir = compile_source_to_qir(source, *CAPABILITIES); + expect![[r#" + %Result = type opaque + %Qubit = type opaque + + define void @ENTRYPOINT__main() #0 { + block_0: + call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 0 to %Qubit*)) + call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*)) + %var_0 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 0 to %Result*)) + %var_1 = icmp eq i1 %var_0, false + br i1 %var_1, label %block_1, label %block_2 + block_1: + br label %block_3 + block_2: + br label %block_3 + block_3: + %var_3 = phi double [0.0, %block_1], [1.0, %block_2] + call void @__quantum__rt__double_record_output(double %var_3, i8* null) + ret void + } + + declare void @__quantum__qis__h__body(%Qubit*) + + declare void @__quantum__qis__mresetz__body(%Qubit*, %Result*) #1 + + declare i1 @__quantum__qis__read_result__body(%Result*) + + declare void @__quantum__rt__double_record_output(double, i8*) + + attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="adaptive_profile" "required_num_qubits"="1" "required_num_results"="1" } + attributes #1 = { "irreversible" } + + ; module flags + + !llvm.module.flags = !{!0, !1, !2, !3, !4, !5} + + !0 = !{i32 1, !"qir_major_version", i32 1} + !1 = !{i32 7, !"qir_minor_version", i32 0} + !2 = !{i32 1, !"dynamic_qubit_management", i1 false} + !3 = !{i32 1, !"dynamic_result_management", i1 false} + !4 = !{i32 1, !"int_computations", !"i64"} + !5 = !{i32 1, !"float_computations", !"f64"} + "#]].assert_eq(&qir); + } + + #[test] + fn custom_reset_generates_correct_qir() { + let source = "namespace Test { + operation Main() : Result { + use q = Qubit(); + __quantum__qis__custom_reset__body(q); + M(q) + } + + @Reset() + operation __quantum__qis__custom_reset__body(target: Qubit) : Unit { + body intrinsic; + } + }"; + let qir = compile_source_to_qir(source, *CAPABILITIES); + expect![[r#" + %Result = type opaque + %Qubit = type opaque + + define void @ENTRYPOINT__main() #0 { + block_0: + call void @__quantum__qis__custom_reset__body(%Qubit* inttoptr (i64 0 to %Qubit*)) + call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*)) + call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null) + ret void + } + + declare void @__quantum__qis__custom_reset__body(%Qubit*) #1 + + declare void @__quantum__qis__m__body(%Qubit*, %Result*) #1 + + declare void @__quantum__rt__result_record_output(%Result*, i8*) + + attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="adaptive_profile" "required_num_qubits"="1" "required_num_results"="1" } + attributes #1 = { "irreversible" } + + ; module flags + + !llvm.module.flags = !{!0, !1, !2, !3, !4, !5} + + !0 = !{i32 1, !"qir_major_version", i32 1} + !1 = !{i32 7, !"qir_minor_version", i32 0} + !2 = !{i32 1, !"dynamic_qubit_management", i1 false} + !3 = !{i32 1, !"dynamic_result_management", i1 false} + !4 = !{i32 1, !"int_computations", !"i64"} + !5 = !{i32 1, !"float_computations", !"f64"} + "#]] + .assert_eq(&qir); + } + + #[test] + fn dynamic_double_intrinsic() { + let source = "namespace Test { + operation OpA(theta: Double, q : Qubit) : Unit { body intrinsic; } + @EntryPoint() + operation Main() : Double { + use q = Qubit(); + H(q); + let theta = MResetZ(q) == Zero ? 0.0 | 1.0; + OpA(1.0 + theta, q); + Rx(2.0 * theta, q); + Ry(theta / 3.0, q); + Rz(theta - 4.0, q); + OpA(theta, q); + Rx(theta, q); + theta + } + }"; + let qir = compile_source_to_qir(source, *CAPABILITIES); + expect![[r#" + %Result = type opaque + %Qubit = type opaque + + define void @ENTRYPOINT__main() #0 { + block_0: + call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 0 to %Qubit*)) + call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*)) + %var_0 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 0 to %Result*)) + %var_1 = icmp eq i1 %var_0, false + br i1 %var_1, label %block_1, label %block_2 + block_1: + br label %block_3 + block_2: + br label %block_3 + block_3: + %var_7 = phi double [0.0, %block_1], [1.0, %block_2] + %var_3 = fadd double 1.0, %var_7 + call void @OpA(double %var_3, %Qubit* inttoptr (i64 0 to %Qubit*)) + %var_4 = fmul double 2.0, %var_7 + call void @__quantum__qis__rx__body(double %var_4, %Qubit* inttoptr (i64 0 to %Qubit*)) + %var_5 = fdiv double %var_7, 3.0 + call void @__quantum__qis__ry__body(double %var_5, %Qubit* inttoptr (i64 0 to %Qubit*)) + %var_6 = fsub double %var_7, 4.0 + call void @__quantum__qis__rz__body(double %var_6, %Qubit* inttoptr (i64 0 to %Qubit*)) + call void @OpA(double %var_7, %Qubit* inttoptr (i64 0 to %Qubit*)) + call void @__quantum__qis__rx__body(double %var_7, %Qubit* inttoptr (i64 0 to %Qubit*)) + call void @__quantum__rt__double_record_output(double %var_7, i8* null) + ret void + } + + declare void @__quantum__qis__h__body(%Qubit*) + + declare void @__quantum__qis__mresetz__body(%Qubit*, %Result*) #1 + + declare i1 @__quantum__qis__read_result__body(%Result*) + + declare void @OpA(double, %Qubit*) + + declare void @__quantum__qis__rx__body(double, %Qubit*) + + declare void @__quantum__qis__ry__body(double, %Qubit*) + + declare void @__quantum__qis__rz__body(double, %Qubit*) + + declare void @__quantum__rt__double_record_output(double, i8*) + + attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="adaptive_profile" "required_num_qubits"="1" "required_num_results"="1" } + attributes #1 = { "irreversible" } + + ; module flags + + !llvm.module.flags = !{!0, !1, !2, !3, !4, !5} + + !0 = !{i32 1, !"qir_major_version", i32 1} + !1 = !{i32 7, !"qir_minor_version", i32 0} + !2 = !{i32 1, !"dynamic_qubit_management", i1 false} + !3 = !{i32 1, !"dynamic_result_management", i1 false} + !4 = !{i32 1, !"int_computations", !"i64"} + !5 = !{i32 1, !"float_computations", !"f64"} + "#]].assert_eq(&qir); + } } diff --git a/compiler/qsc/src/interpret/tests.rs b/compiler/qsc/src/interpret/tests.rs index 2b82256ce3..0d2b52bcec 100644 --- a/compiler/qsc/src/interpret/tests.rs +++ b/compiler/qsc/src/interpret/tests.rs @@ -968,19 +968,13 @@ mod given_interpreter { ; module flags - !llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10} + !llvm.module.flags = !{!0, !1, !2, !3, !4} !0 = !{i32 1, !"qir_major_version", i32 1} !1 = !{i32 7, !"qir_minor_version", i32 0} !2 = !{i32 1, !"dynamic_qubit_management", i1 false} !3 = !{i32 1, !"dynamic_result_management", i1 false} - !4 = !{i32 1, !"classical_ints", i1 true} - !5 = !{i32 1, !"qubit_resetting", i1 true} - !6 = !{i32 1, !"classical_floats", i1 false} - !7 = !{i32 1, !"backwards_branching", i1 false} - !8 = !{i32 1, !"classical_fixed_points", i1 false} - !9 = !{i32 1, !"user_functions", i1 false} - !10 = !{i32 1, !"multiple_target_branching", i1 false} + !4 = !{i32 1, !"int_computations", !"i64"} "#]] .assert_eq(&res); } @@ -1039,19 +1033,12 @@ mod given_interpreter { ; module flags - !llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10} + !llvm.module.flags = !{!0, !1, !2, !3} !0 = !{i32 1, !"qir_major_version", i32 1} !1 = !{i32 7, !"qir_minor_version", i32 0} !2 = !{i32 1, !"dynamic_qubit_management", i1 false} !3 = !{i32 1, !"dynamic_result_management", i1 false} - !4 = !{i32 1, !"qubit_resetting", i1 true} - !5 = !{i32 1, !"classical_ints", i1 false} - !6 = !{i32 1, !"classical_floats", i1 false} - !7 = !{i32 1, !"backwards_branching", i1 false} - !8 = !{i32 1, !"classical_fixed_points", i1 false} - !9 = !{i32 1, !"user_functions", i1 false} - !10 = !{i32 1, !"multiple_target_branching", i1 false} "#]] .assert_eq(&res); } diff --git a/compiler/qsc/src/target.rs b/compiler/qsc/src/target.rs index 20684ca4b8..c8ba1c5057 100644 --- a/compiler/qsc/src/target.rs +++ b/compiler/qsc/src/target.rs @@ -10,6 +10,7 @@ pub enum Profile { Unrestricted, Base, AdaptiveRI, + AdaptiveRIF, } impl Profile { @@ -19,6 +20,7 @@ impl Profile { Self::Unrestricted => "Unrestricted", Self::Base => "Base", Self::AdaptiveRI => "Adaptive_RI", + Self::AdaptiveRIF => "Adaptive_RIF", } } } @@ -29,6 +31,12 @@ impl From for TargetCapabilityFlags { Profile::Unrestricted => Self::all(), Profile::Base => Self::empty(), Profile::AdaptiveRI => Self::Adaptive | Self::QubitReset | Self::IntegerComputations, + Profile::AdaptiveRIF => { + Self::Adaptive + | Self::QubitReset + | Self::IntegerComputations + | Self::FloatingPointComputations + } } } } @@ -39,6 +47,7 @@ impl FromStr for Profile { fn from_str(s: &str) -> Result { match s { "Adaptive_RI" | "adaptive_ri" => Ok(Self::AdaptiveRI), + "Adaptive_RIF" | "adaptive_rif" => Ok(Self::AdaptiveRIF), "Base" | "base" => Ok(Self::Base), "Unrestricted" | "unrestricted" => Ok(Self::Unrestricted), _ => Err(()), diff --git a/compiler/qsc_codegen/src/qir.rs b/compiler/qsc_codegen/src/qir.rs index e80fcc06e0..3dadc05475 100644 --- a/compiler/qsc_codegen/src/qir.rs +++ b/compiler/qsc_codegen/src/qir.rs @@ -13,7 +13,7 @@ use qsc_partial_eval::{partially_evaluate, ProgramEntry}; use qsc_rca::PackageStoreComputeProperties; use qsc_rir::{ passes::check_and_transform, - rir::{self, ConditionCode}, + rir::{self, ConditionCode, FcmpConditionCode}, utils::get_all_block_successors, }; @@ -136,6 +136,29 @@ impl ToQir for rir::Operand { } } +impl ToQir for rir::FcmpConditionCode { + fn to_qir(&self, _program: &rir::Program) -> String { + match self { + rir::FcmpConditionCode::False => "false".to_string(), + rir::FcmpConditionCode::OrderedAndEqual => "oeq".to_string(), + rir::FcmpConditionCode::OrderedAndGreaterThan => "ogt".to_string(), + rir::FcmpConditionCode::OrderedAndGreaterThanOrEqual => "oge".to_string(), + rir::FcmpConditionCode::OrderedAndLessThan => "olt".to_string(), + rir::FcmpConditionCode::OrderedAndLessThanOrEqual => "ole".to_string(), + rir::FcmpConditionCode::OrderedAndNotEqual => "one".to_string(), + rir::FcmpConditionCode::Ordered => "ord".to_string(), + rir::FcmpConditionCode::UnorderedOrEqual => "ueq".to_string(), + rir::FcmpConditionCode::UnorderedOrGreaterThan => "ugt".to_string(), + rir::FcmpConditionCode::UnorderedOrGreaterThanOrEqual => "uge".to_string(), + rir::FcmpConditionCode::UnorderedOrLessThan => "ult".to_string(), + rir::FcmpConditionCode::UnorderedOrLessThanOrEqual => "ule".to_string(), + rir::FcmpConditionCode::UnorderedOrNotEqual => "une".to_string(), + rir::FcmpConditionCode::Unordered => "uno".to_string(), + rir::FcmpConditionCode::True => "true".to_string(), + } + } +} + impl ToQir for rir::ConditionCode { fn to_qir(&self, _program: &rir::Program) -> String { match self { @@ -181,6 +204,18 @@ impl ToQir for rir::Instruction { rir::Instruction::Call(call_id, args, output) => { call_to_qir(args, *call_id, *output, program) } + rir::Instruction::Fadd(lhs, rhs, variable) => { + fbinop_to_qir("fadd", lhs, rhs, *variable, program) + } + rir::Instruction::Fdiv(lhs, rhs, variable) => { + fbinop_to_qir("fdiv", lhs, rhs, *variable, program) + } + rir::Instruction::Fmul(lhs, rhs, variable) => { + fbinop_to_qir("fmul", lhs, rhs, *variable, program) + } + rir::Instruction::Fsub(lhs, rhs, variable) => { + fbinop_to_qir("fsub", lhs, rhs, *variable, program) + } rir::Instruction::LogicalAnd(lhs, rhs, variable) => { logical_binop_to_qir("and", lhs, rhs, *variable, program) } @@ -193,6 +228,9 @@ impl ToQir for rir::Instruction { rir::Instruction::Mul(lhs, rhs, variable) => { binop_to_qir("mul", lhs, rhs, *variable, program) } + rir::Instruction::Fcmp(op, lhs, rhs, variable) => { + fcmp_to_qir(*op, lhs, rhs, *variable, program) + } rir::Instruction::Icmp(op, lhs, rhs, variable) => { icmp_to_qir(*op, lhs, rhs, *variable, program) } @@ -314,6 +352,31 @@ fn call_to_qir( } } +fn fcmp_to_qir( + op: FcmpConditionCode, + lhs: &rir::Operand, + rhs: &rir::Operand, + variable: rir::Variable, + program: &rir::Program, +) -> String { + let lhs_ty = get_value_ty(lhs); + let rhs_ty = get_value_ty(rhs); + let var_ty = get_variable_ty(variable); + assert_eq!( + lhs_ty, rhs_ty, + "mismatched input types ({lhs_ty}, {rhs_ty}) for icmp {op}" + ); + + assert_eq!(var_ty, "i1", "unsupported output type {var_ty} for icmp"); + format!( + " {} = fcmp {} {lhs_ty} {}, {}", + ToQir::::to_qir(&variable.variable_id, program), + ToQir::::to_qir(&op, program), + get_value_as_str(lhs, program), + get_value_as_str(rhs, program) + ) +} + fn icmp_to_qir( op: ConditionCode, lhs: &rir::Operand, @@ -367,6 +430,34 @@ fn binop_to_qir( ) } +fn fbinop_to_qir( + op: &str, + lhs: &rir::Operand, + rhs: &rir::Operand, + variable: rir::Variable, + program: &rir::Program, +) -> String { + let lhs_ty = get_value_ty(lhs); + let rhs_ty = get_value_ty(rhs); + let var_ty = get_variable_ty(variable); + assert_eq!( + lhs_ty, rhs_ty, + "mismatched input types ({lhs_ty}, {rhs_ty}) for {op}" + ); + assert_eq!( + lhs_ty, var_ty, + "mismatched input/output types ({lhs_ty}, {var_ty}) for {op}" + ); + assert_eq!(var_ty, "double", "unsupported type {var_ty} for {op}"); + + format!( + " {} = {op} {var_ty} {}, {}", + ToQir::::to_qir(&variable.variable_id, program), + get_value_as_str(lhs, program), + get_value_as_str(rhs, program) + ) +} + fn simple_bitwise_to_qir( op: &str, lhs: &rir::Operand, @@ -455,7 +546,7 @@ fn get_value_ty(lhs: &rir::Operand) -> &str { rir::Operand::Literal(lit) => match lit { rir::Literal::Integer(_) => "i64", rir::Literal::Bool(_) => "i1", - rir::Literal::Double(_) => "f64", + rir::Literal::Double(_) => get_f64_ty(), rir::Literal::Qubit(_) => "%Qubit*", rir::Literal::Result(_) => "%Result*", rir::Literal::Pointer => "i8*", @@ -468,13 +559,28 @@ fn get_variable_ty(variable: rir::Variable) -> &'static str { match variable.ty { rir::Ty::Integer => "i64", rir::Ty::Boolean => "i1", - rir::Ty::Double => "f64", + rir::Ty::Double => get_f64_ty(), rir::Ty::Qubit => "%Qubit*", rir::Ty::Result => "%Result*", rir::Ty::Pointer => "i8*", } } +/// phi only supports "Floating-Point Types" which are defined as: +/// - `half` (`f16`) +/// - `bfloat` +/// - `float` (`f32`) +/// - `double` (`f64`) +/// - `fp128` +/// +/// We only support `f64`, so we break the pattern used for integers +/// and have to use `double` here. +/// +/// This conflicts with the QIR spec which says f64. Need to follow up on this. +fn get_f64_ty() -> &'static str { + "double" +} + impl ToQir for rir::BlockId { fn to_qir(&self, _program: &rir::Program) -> String { format!("block_{}", self.0) @@ -580,51 +686,25 @@ fn get_module_metadata(program: &rir::Program) -> String { // loop through the capabilities and add them to the metadata // for values that we can generate. for cap in program.config.capabilities.iter() { - let name = match cap { - TargetCapabilityFlags::QubitReset => "qubit_resetting", - TargetCapabilityFlags::IntegerComputations => "classical_ints", - TargetCapabilityFlags::FloatingPointComputations => "classical_floats", - TargetCapabilityFlags::BackwardsBranching => "backwards_branching", - _ => continue, - }; - flags.push_str(&format!( - "!{} = !{{i32 {}, !\"{}\", i1 {}}}\n", - index, 1, name, true - )); - index += 1; - } - - // loop through the capabilities that are missing and add them to the metadata - // as not supported. - let missing = TargetCapabilityFlags::all().difference(program.config.capabilities); - for cap in missing.iter() { - let name = match cap { - TargetCapabilityFlags::QubitReset => "qubit_resetting", - TargetCapabilityFlags::IntegerComputations => "classical_ints", - TargetCapabilityFlags::FloatingPointComputations => "classical_floats", - TargetCapabilityFlags::BackwardsBranching => "backwards_branching", + match cap { + TargetCapabilityFlags::IntegerComputations => { + let name = "int_computations"; + flags.push_str(&format!( + "!{} = !{{i32 {}, !\"{}\", !\"i{}\"}}\n", + index, 1, name, 64 + )); + index += 1; + } + TargetCapabilityFlags::FloatingPointComputations => { + let name = "float_computations"; + flags.push_str(&format!( + "!{} = !{{i32 {}, !\"{}\", !\"f{}\"}}\n", + index, 1, name, 64 + )); + index += 1; + } _ => continue, - }; - flags.push_str(&format!( - "!{} = !{{i32 {}, !\"{}\", i1 {}}}\n", - index, 1, name, false - )); - index += 1; - } - - // Add the remaining extension capabilities as not supported. - // We can't generate these values yet so we just add them as false. - let unmapped_capabilities = [ - "classical_fixed_points", - "user_functions", - "multiple_target_branching", - ]; - for capability in unmapped_capabilities { - flags.push_str(&format!( - "!{} = !{{i32 {}, !\"{}\", i1 {}}}\n", - index, 1, capability, false - )); - index += 1; + } } } diff --git a/compiler/qsc_codegen/src/qir/instruction_tests/double.rs b/compiler/qsc_codegen/src/qir/instruction_tests/double.rs index a68741496f..1d6d90b77f 100644 --- a/compiler/qsc_codegen/src/qir/instruction_tests/double.rs +++ b/compiler/qsc_codegen/src/qir/instruction_tests/double.rs @@ -1,88 +1,479 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +use core::f64::consts::{E, PI}; + use crate::qir::ToQir; -use qsc_rir::rir; +use expect_test::expect; +use qsc_rir::rir::{ + FcmpConditionCode, Instruction, Literal, Operand, Program, Ty, Variable, VariableId, +}; #[test] -#[should_panic(expected = "unsupported type f64 for add")] +#[should_panic(expected = "unsupported type double for add")] fn add_double_literals() { - let inst = rir::Instruction::Add( - rir::Operand::Literal(rir::Literal::Double(core::f64::consts::PI)), - rir::Operand::Literal(rir::Literal::Double(core::f64::consts::E)), - rir::Variable { - variable_id: rir::VariableId(0), - ty: rir::Ty::Double, + let inst = Instruction::Add( + Operand::Literal(Literal::Double(PI)), + Operand::Literal(Literal::Double(E)), + Variable { + variable_id: VariableId(0), + ty: Ty::Double, + }, + ); + let _ = &inst.to_qir(&Program::default()); +} + +#[test] +#[should_panic(expected = "unsupported type double for sub")] +fn sub_double_literals() { + let inst = Instruction::Sub( + Operand::Literal(Literal::Double(PI)), + Operand::Literal(Literal::Double(E)), + Variable { + variable_id: VariableId(0), + ty: Ty::Double, + }, + ); + let _ = &inst.to_qir(&Program::default()); +} + +#[test] +#[should_panic(expected = "unsupported type double for mul")] +fn mul_double_literals() { + let inst = Instruction::Mul( + Operand::Literal(Literal::Double(PI)), + Operand::Literal(Literal::Double(E)), + Variable { + variable_id: VariableId(0), + ty: Ty::Double, + }, + ); + let _ = &inst.to_qir(&Program::default()); +} + +#[test] +#[should_panic(expected = "unsupported type double for sdiv")] +fn sdiv_double_literals() { + let inst = Instruction::Sdiv( + Operand::Literal(Literal::Double(PI)), + Operand::Literal(Literal::Double(E)), + Variable { + variable_id: VariableId(0), + ty: Ty::Double, + }, + ); + let _ = &inst.to_qir(&Program::default()); +} + +#[test] +fn fadd_double_literals() { + let inst = Instruction::Fadd( + Operand::Literal(Literal::Double(PI)), + Operand::Literal(Literal::Double(E)), + Variable { + variable_id: VariableId(0), + ty: Ty::Double, }, ); - let _ = &inst.to_qir(&rir::Program::default()); + expect![" %var_0 = fadd double 3.141592653589793, 2.718281828459045"] + .assert_eq(&inst.to_qir(&Program::default())); } #[test] -#[should_panic(expected = "unsupported type f64 for ashr")] +#[should_panic(expected = "unsupported type double for ashr")] fn ashr_double_literals() { - let inst = rir::Instruction::Ashr( - rir::Operand::Literal(rir::Literal::Double(core::f64::consts::PI)), - rir::Operand::Literal(rir::Literal::Double(core::f64::consts::E)), - rir::Variable { - variable_id: rir::VariableId(0), - ty: rir::Ty::Double, + let inst = Instruction::Ashr( + Operand::Literal(Literal::Double(PI)), + Operand::Literal(Literal::Double(E)), + Variable { + variable_id: VariableId(0), + ty: Ty::Double, }, ); - let _ = &inst.to_qir(&rir::Program::default()); + let _ = &inst.to_qir(&Program::default()); } #[test] -#[should_panic(expected = "unsupported type f64 for and")] +#[should_panic(expected = "unsupported type double for and")] fn bitwise_and_double_literals() { - let inst = rir::Instruction::BitwiseAnd( - rir::Operand::Literal(rir::Literal::Double(core::f64::consts::PI)), - rir::Operand::Literal(rir::Literal::Double(core::f64::consts::E)), - rir::Variable { - variable_id: rir::VariableId(0), - ty: rir::Ty::Double, + let inst = Instruction::BitwiseAnd( + Operand::Literal(Literal::Double(PI)), + Operand::Literal(Literal::Double(E)), + Variable { + variable_id: VariableId(0), + ty: Ty::Double, }, ); - let _ = &inst.to_qir(&rir::Program::default()); + let _ = &inst.to_qir(&Program::default()); } #[test] -#[should_panic(expected = "unsupported type f64 for not")] +#[should_panic(expected = "unsupported type double for not")] fn bitwise_not_double_literals() { - let inst = rir::Instruction::BitwiseNot( - rir::Operand::Literal(rir::Literal::Double(core::f64::consts::PI)), - rir::Variable { - variable_id: rir::VariableId(0), - ty: rir::Ty::Double, + let inst = Instruction::BitwiseNot( + Operand::Literal(Literal::Double(PI)), + Variable { + variable_id: VariableId(0), + ty: Ty::Double, }, ); - let _ = &inst.to_qir(&rir::Program::default()); + let _ = &inst.to_qir(&Program::default()); } #[test] -#[should_panic(expected = "unsupported type f64 for or")] +#[should_panic(expected = "unsupported type double for or")] fn bitwise_or_double_literals() { - let inst = rir::Instruction::BitwiseOr( - rir::Operand::Literal(rir::Literal::Double(core::f64::consts::PI)), - rir::Operand::Literal(rir::Literal::Double(core::f64::consts::E)), - rir::Variable { - variable_id: rir::VariableId(0), - ty: rir::Ty::Double, + let inst = Instruction::BitwiseOr( + Operand::Literal(Literal::Double(PI)), + Operand::Literal(Literal::Double(E)), + Variable { + variable_id: VariableId(0), + ty: Ty::Double, }, ); - let _ = &inst.to_qir(&rir::Program::default()); + let _ = &inst.to_qir(&Program::default()); } #[test] -#[should_panic(expected = "unsupported type f64 for xor")] +#[should_panic(expected = "unsupported type double for xor")] fn bitwise_xor_double_literals() { - let inst = rir::Instruction::BitwiseXor( - rir::Operand::Literal(rir::Literal::Double(core::f64::consts::PI)), - rir::Operand::Literal(rir::Literal::Double(core::f64::consts::E)), - rir::Variable { - variable_id: rir::VariableId(0), - ty: rir::Ty::Double, + let inst = Instruction::BitwiseXor( + Operand::Literal(Literal::Double(PI)), + Operand::Literal(Literal::Double(E)), + Variable { + variable_id: VariableId(0), + ty: Ty::Double, + }, + ); + let _ = &inst.to_qir(&Program::default()); +} + +#[test] +fn fadd_double_variables() { + let inst = Instruction::Fadd( + Operand::Variable(Variable { + variable_id: VariableId(1), + ty: Ty::Double, + }), + Operand::Variable(Variable { + variable_id: VariableId(2), + ty: Ty::Double, + }), + Variable { + variable_id: VariableId(0), + ty: Ty::Double, + }, + ); + expect![" %var_0 = fadd double %var_1, %var_2"].assert_eq(&inst.to_qir(&Program::default())); +} + +#[test] +fn fcmp_oeq_double_literals() { + let inst = Instruction::Fcmp( + FcmpConditionCode::OrderedAndEqual, + Operand::Literal(Literal::Double(PI)), + Operand::Literal(Literal::Double(E)), + Variable { + variable_id: VariableId(0), + ty: Ty::Boolean, + }, + ); + expect![" %var_0 = fcmp oeq double 3.141592653589793, 2.718281828459045"] + .assert_eq(&inst.to_qir(&Program::default())); +} + +#[test] +fn fcmp_oeq_double_variables() { + let inst = Instruction::Fcmp( + FcmpConditionCode::OrderedAndEqual, + Operand::Variable(Variable { + variable_id: VariableId(1), + ty: Ty::Double, + }), + Operand::Variable(Variable { + variable_id: VariableId(2), + ty: Ty::Double, + }), + Variable { + variable_id: VariableId(0), + ty: Ty::Boolean, + }, + ); + expect![" %var_0 = fcmp oeq double %var_1, %var_2"] + .assert_eq(&inst.to_qir(&Program::default())); +} + +#[test] +fn fcmp_one_double_literals() { + let inst = Instruction::Fcmp( + FcmpConditionCode::OrderedAndNotEqual, + Operand::Literal(Literal::Double(PI)), + Operand::Literal(Literal::Double(E)), + Variable { + variable_id: VariableId(0), + ty: Ty::Boolean, + }, + ); + expect![" %var_0 = fcmp one double 3.141592653589793, 2.718281828459045"] + .assert_eq(&inst.to_qir(&Program::default())); +} + +#[test] +fn fcmp_one_double_variables() { + let inst = Instruction::Fcmp( + FcmpConditionCode::OrderedAndNotEqual, + Operand::Variable(Variable { + variable_id: VariableId(1), + ty: Ty::Double, + }), + Operand::Variable(Variable { + variable_id: VariableId(2), + ty: Ty::Double, + }), + Variable { + variable_id: VariableId(0), + ty: Ty::Boolean, + }, + ); + expect![" %var_0 = fcmp one double %var_1, %var_2"] + .assert_eq(&inst.to_qir(&Program::default())); +} +#[test] +fn fcmp_olt_double_literals() { + let inst = Instruction::Fcmp( + FcmpConditionCode::OrderedAndLessThan, + Operand::Literal(Literal::Double(PI)), + Operand::Literal(Literal::Double(E)), + Variable { + variable_id: VariableId(0), + ty: Ty::Boolean, + }, + ); + expect![" %var_0 = fcmp olt double 3.141592653589793, 2.718281828459045"] + .assert_eq(&inst.to_qir(&Program::default())); +} + +#[test] +fn fcmp_olt_double_variables() { + let inst = Instruction::Fcmp( + FcmpConditionCode::OrderedAndLessThan, + Operand::Variable(Variable { + variable_id: VariableId(1), + ty: Ty::Double, + }), + Operand::Variable(Variable { + variable_id: VariableId(2), + ty: Ty::Double, + }), + Variable { + variable_id: VariableId(0), + ty: Ty::Boolean, + }, + ); + expect![" %var_0 = fcmp olt double %var_1, %var_2"] + .assert_eq(&inst.to_qir(&Program::default())); +} +#[test] +fn fcmp_ole_double_literals() { + let inst = Instruction::Fcmp( + FcmpConditionCode::OrderedAndLessThanOrEqual, + Operand::Literal(Literal::Double(PI)), + Operand::Literal(Literal::Double(E)), + Variable { + variable_id: VariableId(0), + ty: Ty::Boolean, + }, + ); + expect![" %var_0 = fcmp ole double 3.141592653589793, 2.718281828459045"] + .assert_eq(&inst.to_qir(&Program::default())); +} + +#[test] +fn fcmp_ole_double_variables() { + let inst = Instruction::Fcmp( + FcmpConditionCode::OrderedAndLessThanOrEqual, + Operand::Variable(Variable { + variable_id: VariableId(1), + ty: Ty::Double, + }), + Operand::Variable(Variable { + variable_id: VariableId(2), + ty: Ty::Double, + }), + Variable { + variable_id: VariableId(0), + ty: Ty::Boolean, + }, + ); + expect![" %var_0 = fcmp ole double %var_1, %var_2"] + .assert_eq(&inst.to_qir(&Program::default())); +} +#[test] +fn fcmp_ogt_double_literals() { + let inst = Instruction::Fcmp( + FcmpConditionCode::OrderedAndGreaterThan, + Operand::Literal(Literal::Double(PI)), + Operand::Literal(Literal::Double(E)), + Variable { + variable_id: VariableId(0), + ty: Ty::Boolean, + }, + ); + expect![" %var_0 = fcmp ogt double 3.141592653589793, 2.718281828459045"] + .assert_eq(&inst.to_qir(&Program::default())); +} + +#[test] +fn fcmp_ogt_double_variables() { + let inst = Instruction::Fcmp( + FcmpConditionCode::OrderedAndGreaterThan, + Operand::Variable(Variable { + variable_id: VariableId(1), + ty: Ty::Double, + }), + Operand::Variable(Variable { + variable_id: VariableId(2), + ty: Ty::Double, + }), + Variable { + variable_id: VariableId(0), + ty: Ty::Boolean, + }, + ); + expect![" %var_0 = fcmp ogt double %var_1, %var_2"] + .assert_eq(&inst.to_qir(&Program::default())); +} +#[test] +fn fcmp_oge_double_literals() { + let inst = Instruction::Fcmp( + FcmpConditionCode::OrderedAndGreaterThanOrEqual, + Operand::Literal(Literal::Double(PI)), + Operand::Literal(Literal::Double(E)), + Variable { + variable_id: VariableId(0), + ty: Ty::Boolean, + }, + ); + expect![" %var_0 = fcmp oge double 3.141592653589793, 2.718281828459045"] + .assert_eq(&inst.to_qir(&Program::default())); +} + +#[test] +fn fcmp_oge_double_variables() { + let inst = Instruction::Fcmp( + FcmpConditionCode::OrderedAndGreaterThanOrEqual, + Operand::Variable(Variable { + variable_id: VariableId(1), + ty: Ty::Double, + }), + Operand::Variable(Variable { + variable_id: VariableId(2), + ty: Ty::Double, + }), + Variable { + variable_id: VariableId(0), + ty: Ty::Boolean, + }, + ); + expect![" %var_0 = fcmp oge double %var_1, %var_2"] + .assert_eq(&inst.to_qir(&Program::default())); +} + +#[test] +fn fmul_double_literals() { + let inst = Instruction::Fmul( + Operand::Literal(Literal::Double(PI)), + Operand::Literal(Literal::Double(E)), + Variable { + variable_id: VariableId(0), + ty: Ty::Double, + }, + ); + expect![" %var_0 = fmul double 3.141592653589793, 2.718281828459045"] + .assert_eq(&inst.to_qir(&Program::default())); +} + +#[test] +fn fmul_double_variables() { + let inst = Instruction::Fmul( + Operand::Variable(Variable { + variable_id: VariableId(1), + ty: Ty::Double, + }), + Operand::Variable(Variable { + variable_id: VariableId(2), + ty: Ty::Double, + }), + Variable { + variable_id: VariableId(0), + ty: Ty::Double, + }, + ); + expect![" %var_0 = fmul double %var_1, %var_2"].assert_eq(&inst.to_qir(&Program::default())); +} + +#[test] +fn fdiv_double_literals() { + let inst = Instruction::Fdiv( + Operand::Literal(Literal::Double(PI)), + Operand::Literal(Literal::Double(E)), + Variable { + variable_id: VariableId(0), + ty: Ty::Double, + }, + ); + expect![" %var_0 = fdiv double 3.141592653589793, 2.718281828459045"] + .assert_eq(&inst.to_qir(&Program::default())); +} + +#[test] +fn fdiv_double_variables() { + let inst = Instruction::Fdiv( + Operand::Variable(Variable { + variable_id: VariableId(1), + ty: Ty::Double, + }), + Operand::Variable(Variable { + variable_id: VariableId(2), + ty: Ty::Double, + }), + Variable { + variable_id: VariableId(0), + ty: Ty::Double, + }, + ); + expect![" %var_0 = fdiv double %var_1, %var_2"].assert_eq(&inst.to_qir(&Program::default())); +} + +#[test] +fn fsub_double_literals() { + let inst = Instruction::Fsub( + Operand::Literal(Literal::Double(PI)), + Operand::Literal(Literal::Double(E)), + Variable { + variable_id: VariableId(0), + ty: Ty::Double, + }, + ); + expect![" %var_0 = fsub double 3.141592653589793, 2.718281828459045"] + .assert_eq(&inst.to_qir(&Program::default())); +} + +#[test] +fn fsub_double_variables() { + let inst = Instruction::Fsub( + Operand::Variable(Variable { + variable_id: VariableId(1), + ty: Ty::Double, + }), + Operand::Variable(Variable { + variable_id: VariableId(2), + ty: Ty::Double, + }), + Variable { + variable_id: VariableId(0), + ty: Ty::Double, }, ); - let _ = &inst.to_qir(&rir::Program::default()); + expect![" %var_0 = fsub double %var_1, %var_2"].assert_eq(&inst.to_qir(&Program::default())); } diff --git a/compiler/qsc_codegen/src/qir/instruction_tests/invalid.rs b/compiler/qsc_codegen/src/qir/instruction_tests/invalid.rs index d61dac08e6..c0f8683596 100644 --- a/compiler/qsc_codegen/src/qir/instruction_tests/invalid.rs +++ b/compiler/qsc_codegen/src/qir/instruction_tests/invalid.rs @@ -5,7 +5,7 @@ use crate::qir::ToQir; use qsc_rir::rir; #[test] -#[should_panic(expected = "mismatched input types (i64, f64) for add")] +#[should_panic(expected = "mismatched input types (i64, double) for add")] fn add_mismatched_literal_input_tys_should_panic() { let inst = rir::Instruction::Add( rir::Operand::Literal(rir::Literal::Integer(2)), @@ -19,7 +19,7 @@ fn add_mismatched_literal_input_tys_should_panic() { } #[test] -#[should_panic(expected = "mismatched input/output types (i64, f64) for add")] +#[should_panic(expected = "mismatched input/output types (i64, double) for add")] fn add_mismatched_literal_input_output_tys_should_panic() { let inst = rir::Instruction::Add( rir::Operand::Literal(rir::Literal::Integer(2)), @@ -33,7 +33,7 @@ fn add_mismatched_literal_input_output_tys_should_panic() { } #[test] -#[should_panic(expected = "mismatched input types (i64, f64) for add")] +#[should_panic(expected = "mismatched input types (i64, double) for add")] fn add_mismatched_variable_input_tys_should_panic() { let inst = rir::Instruction::Add( rir::Operand::Variable(rir::Variable { @@ -53,7 +53,7 @@ fn add_mismatched_variable_input_tys_should_panic() { } #[test] -#[should_panic(expected = "mismatched input/output types (i64, f64) for add")] +#[should_panic(expected = "mismatched input/output types (i64, double) for add")] fn add_mismatched_variable_input_output_tys_should_panic() { let inst = rir::Instruction::Add( rir::Operand::Variable(rir::Variable { @@ -73,7 +73,7 @@ fn add_mismatched_variable_input_output_tys_should_panic() { } #[test] -#[should_panic(expected = "mismatched input types (i64, f64) for and")] +#[should_panic(expected = "mismatched input types (i64, double) for and")] fn bitwise_and_mismatched_literal_input_tys_should_panic() { let inst = rir::Instruction::BitwiseAnd( rir::Operand::Literal(rir::Literal::Integer(2)), @@ -87,7 +87,7 @@ fn bitwise_and_mismatched_literal_input_tys_should_panic() { } #[test] -#[should_panic(expected = "mismatched input/output types (i64, f64) for and")] +#[should_panic(expected = "mismatched input/output types (i64, double) for and")] fn bitwise_and_mismatched_literal_input_output_tys_should_panic() { let inst = rir::Instruction::BitwiseAnd( rir::Operand::Literal(rir::Literal::Integer(2)), @@ -101,7 +101,7 @@ fn bitwise_and_mismatched_literal_input_output_tys_should_panic() { } #[test] -#[should_panic(expected = "mismatched input types (i64, f64) for and")] +#[should_panic(expected = "mismatched input types (i64, double) for and")] fn bitwise_and_mismatched_variable_input_tys_should_panic() { let inst = rir::Instruction::BitwiseAnd( rir::Operand::Variable(rir::Variable { @@ -121,7 +121,7 @@ fn bitwise_and_mismatched_variable_input_tys_should_panic() { } #[test] -#[should_panic(expected = "mismatched input/output types (i64, f64) for and")] +#[should_panic(expected = "mismatched input/output types (i64, double) for and")] fn bitwise_and_mismatched_variable_input_output_tys_should_panic() { let inst = rir::Instruction::BitwiseAnd( rir::Operand::Variable(rir::Variable { diff --git a/compiler/qsc_codegen/src/qir/tests.rs b/compiler/qsc_codegen/src/qir/tests.rs index dc0f67c5ff..59c2927e80 100644 --- a/compiler/qsc_codegen/src/qir/tests.rs +++ b/compiler/qsc_codegen/src/qir/tests.rs @@ -219,18 +219,11 @@ fn teleport_program() { ; module flags - !llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10} + !llvm.module.flags = !{!0, !1, !2, !3} !0 = !{i32 1, !"qir_major_version", i32 1} !1 = !{i32 7, !"qir_minor_version", i32 0} !2 = !{i32 1, !"dynamic_qubit_management", i1 false} !3 = !{i32 1, !"dynamic_result_management", i1 false} - !4 = !{i32 1, !"classical_ints", i1 false} - !5 = !{i32 1, !"classical_floats", i1 false} - !6 = !{i32 1, !"backwards_branching", i1 false} - !7 = !{i32 1, !"qubit_resetting", i1 false} - !8 = !{i32 1, !"classical_fixed_points", i1 false} - !9 = !{i32 1, !"user_functions", i1 false} - !10 = !{i32 1, !"multiple_target_branching", i1 false} "#]].assert_eq(&program.to_qir(&program)); } diff --git a/compiler/qsc_partial_eval/src/lib.rs b/compiler/qsc_partial_eval/src/lib.rs index d6f5768810..45caaa032d 100644 --- a/compiler/qsc_partial_eval/src/lib.rs +++ b/compiler/qsc_partial_eval/src/lib.rs @@ -50,8 +50,8 @@ use qsc_rca::{ use qsc_rir::{ builder, rir::{ - self, Callable, CallableId, CallableType, ConditionCode, Instruction, Literal, Operand, - Program, + self, Callable, CallableId, CallableType, ConditionCode, FcmpConditionCode, Instruction, + Literal, Operand, Program, }, }; use rustc_hash::FxHashMap; @@ -417,10 +417,15 @@ impl<'a> PartialEvaluator<'a> { bin_op_expr_span, ) } - Value::Double(_lhs_double) => Err(Error::Unimplemented( - "double binary operation".to_string(), - lhs_span, - )), + Value::Double(lhs_double) => { + let lhs_operand = Operand::Literal(Literal::Double(lhs_double)); + self.eval_bin_op_with_lhs_double_operand( + bin_op, + lhs_operand, + rhs_expr_id, + bin_op_expr_span, + ) + } Value::Var(lhs_eval_var) => { self.eval_bin_op_with_lhs_var(bin_op, lhs_eval_var, rhs_expr_id, bin_op_expr_span) } @@ -787,6 +792,62 @@ impl<'a> PartialEvaluator<'a> { Ok(result_eval_var) } + fn eval_bin_op_with_lhs_double_operand( + &mut self, + bin_op: BinOp, + lhs_operand: Operand, + rhs_expr_id: ExprId, + bin_op_expr_span: PackageSpan, // For diagnostic purposes only. + ) -> Result { + assert!( + matches!(lhs_operand.get_type(), rir::Ty::Double), + "LHS is expected to be of double type" + ); + + // Try to evaluate the RHS expression to get its value and construct its operand. + let rhs_control_flow = self.try_eval_expr(rhs_expr_id)?; + let EvalControlFlow::Continue(rhs_value) = rhs_control_flow else { + return Err(Error::Unexpected( + "embedded return in RHS expression".to_string(), + self.get_expr_package_span(rhs_expr_id), + )); + }; + let rhs_operand = self.map_eval_value_to_rir_operand(&rhs_value); + assert!( + matches!(rhs_operand.get_type(), rir::Ty::Double), + "LHS value is expected to be of double type" + ); + + // If both operands are literals, evaluate the binary operation and return its value. + if let (Operand::Literal(lhs_literal), Operand::Literal(rhs_literal)) = + (lhs_operand, rhs_operand) + { + let value = eval_bin_op_with_double_literals( + bin_op, + lhs_literal, + rhs_literal, + bin_op_expr_span, + )?; + return Ok(EvalControlFlow::Continue(value)); + } + + // Generate the instructions. + let bin_op_rir_variable = self + .generate_instructions_for_binary_operation_with_double_operands( + bin_op, + lhs_operand, + rhs_operand, + bin_op_expr_span, + )?; + let value = Value::Var(map_rir_var_to_eval_var(bin_op_rir_variable).map_err(|()| { + Error::Unexpected( + format!("{} type in binop", bin_op_rir_variable.ty), + bin_op_expr_span, + ) + })?); + Ok(EvalControlFlow::Continue(value)) + } + fn eval_bin_op_with_lhs_integer_operand( &mut self, bin_op: BinOp, @@ -864,10 +925,16 @@ impl<'a> PartialEvaluator<'a> { bin_op_expr_span, ) } - VarTy::Double => Err(Error::Unimplemented( - "double binary operation with dynamic LHS".to_string(), - bin_op_expr_span, - )), + VarTy::Double => { + let lhs_rir_var = map_eval_var_to_rir_var(lhs_eval_var); + let lhs_operand = Operand::Variable(lhs_rir_var); + self.eval_bin_op_with_lhs_double_operand( + bin_op, + lhs_operand, + rhs_expr_id, + bin_op_expr_span, + ) + } } } @@ -1739,14 +1806,17 @@ impl<'a> PartialEvaluator<'a> { // Generate the instruction depending on the unary operator. let value_operand = self.map_eval_value_to_rir_operand(&value); let instruction = match un_op { - UnOp::Neg => { - let constant = match rir_variable_type { - rir::Ty::Integer => Operand::Literal(Literal::Integer(-1)), - rir::Ty::Double => Operand::Literal(Literal::Double(-1.0)), - _ => panic!("invalid type for negation operator {rir_variable_type}"), - }; - Instruction::Mul(constant, value_operand, rir_variable) - } + UnOp::Neg => match rir_variable_type { + rir::Ty::Integer => { + let constant = Operand::Literal(Literal::Integer(-1)); + Instruction::Mul(constant, value_operand, rir_variable) + } + rir::Ty::Double => { + let constant = Operand::Literal(Literal::Double(-1.0)); + Instruction::Fmul(constant, value_operand, rir_variable) + } + _ => panic!("invalid type for negation operator {rir_variable_type}"), + }, UnOp::NotB => { assert!(matches!(rir_variable_type, rir::Ty::Integer)); Instruction::BitwiseNot(value_operand, rir_variable) @@ -1905,6 +1975,129 @@ impl<'a> PartialEvaluator<'a> { } } + #[allow(clippy::too_many_lines)] + fn generate_instructions_for_binary_operation_with_double_operands( + &mut self, + bin_op: BinOp, + lhs_operand: Operand, + rhs_operand: Operand, + bin_op_expr_span: PackageSpan, // For diagnostic purposes only. + ) -> Result { + let rir_variable = match bin_op { + BinOp::Add => { + let bin_op_variable_id = self.resource_manager.next_var(); + let bin_op_rir_variable = rir::Variable::new_double(bin_op_variable_id); + let bin_op_rir_ins = + Instruction::Fadd(lhs_operand, rhs_operand, bin_op_rir_variable); + self.get_current_rir_block_mut().0.push(bin_op_rir_ins); + bin_op_rir_variable + } + BinOp::Sub => { + let bin_op_variable_id = self.resource_manager.next_var(); + let bin_op_rir_variable = rir::Variable::new_double(bin_op_variable_id); + let bin_op_rir_ins = + Instruction::Fsub(lhs_operand, rhs_operand, bin_op_rir_variable); + self.get_current_rir_block_mut().0.push(bin_op_rir_ins); + bin_op_rir_variable + } + BinOp::Mul => { + let bin_op_variable_id = self.resource_manager.next_var(); + let bin_op_rir_variable = rir::Variable::new_double(bin_op_variable_id); + let bin_op_rir_ins = + Instruction::Fmul(lhs_operand, rhs_operand, bin_op_rir_variable); + self.get_current_rir_block_mut().0.push(bin_op_rir_ins); + bin_op_rir_variable + } + BinOp::Div => { + // Validate that the RHS is not a zero. + if let Operand::Literal(Literal::Double(0.0)) = rhs_operand { + let error = EvalError::DivZero(bin_op_expr_span).into(); + return Err(error); + } + let bin_op_variable_id = self.resource_manager.next_var(); + let bin_op_rir_variable = rir::Variable::new_double(bin_op_variable_id); + let bin_op_rir_ins = + Instruction::Fdiv(lhs_operand, rhs_operand, bin_op_rir_variable); + self.get_current_rir_block_mut().0.push(bin_op_rir_ins); + bin_op_rir_variable + } + BinOp::Eq => { + let bin_op_variable_id = self.resource_manager.next_var(); + let bin_op_rir_variable = rir::Variable::new_boolean(bin_op_variable_id); + let bin_op_rir_ins = Instruction::Fcmp( + FcmpConditionCode::OrderedAndEqual, + lhs_operand, + rhs_operand, + bin_op_rir_variable, + ); + self.get_current_rir_block_mut().0.push(bin_op_rir_ins); + bin_op_rir_variable + } + BinOp::Neq => { + let bin_op_variable_id = self.resource_manager.next_var(); + let bin_op_rir_variable = rir::Variable::new_boolean(bin_op_variable_id); + let bin_op_rir_ins = Instruction::Fcmp( + FcmpConditionCode::OrderedAndNotEqual, + lhs_operand, + rhs_operand, + bin_op_rir_variable, + ); + self.get_current_rir_block_mut().0.push(bin_op_rir_ins); + bin_op_rir_variable + } + BinOp::Gt => { + let bin_op_variable_id = self.resource_manager.next_var(); + let bin_op_rir_variable = rir::Variable::new_boolean(bin_op_variable_id); + let bin_op_rir_ins = Instruction::Fcmp( + FcmpConditionCode::OrderedAndGreaterThan, + lhs_operand, + rhs_operand, + bin_op_rir_variable, + ); + self.get_current_rir_block_mut().0.push(bin_op_rir_ins); + bin_op_rir_variable + } + BinOp::Gte => { + let bin_op_variable_id = self.resource_manager.next_var(); + let bin_op_rir_variable = rir::Variable::new_boolean(bin_op_variable_id); + let bin_op_rir_ins = Instruction::Fcmp( + FcmpConditionCode::OrderedAndGreaterThanOrEqual, + lhs_operand, + rhs_operand, + bin_op_rir_variable, + ); + self.get_current_rir_block_mut().0.push(bin_op_rir_ins); + bin_op_rir_variable + } + BinOp::Lt => { + let bin_op_variable_id = self.resource_manager.next_var(); + let bin_op_rir_variable = rir::Variable::new_boolean(bin_op_variable_id); + let bin_op_rir_ins = Instruction::Fcmp( + FcmpConditionCode::OrderedAndLessThan, + lhs_operand, + rhs_operand, + bin_op_rir_variable, + ); + self.get_current_rir_block_mut().0.push(bin_op_rir_ins); + bin_op_rir_variable + } + BinOp::Lte => { + let bin_op_variable_id = self.resource_manager.next_var(); + let bin_op_rir_variable = rir::Variable::new_boolean(bin_op_variable_id); + let bin_op_rir_ins = Instruction::Fcmp( + FcmpConditionCode::OrderedAndLessThanOrEqual, + lhs_operand, + rhs_operand, + bin_op_rir_variable, + ); + self.get_current_rir_block_mut().0.push(bin_op_rir_ins); + bin_op_rir_variable + } + _ => panic!("unsupported binary operation for double: {bin_op:?}"), + }; + Ok(rir_variable) + } + #[allow(clippy::too_many_lines)] fn generate_instructions_for_binary_operation_with_integer_operands( &mut self, @@ -2699,10 +2892,10 @@ impl<'a> PartialEvaluator<'a> { Value::Var(var) => self.record_variable(ty, &mut instrs, var), Value::Bool(val) => self.record_bool(&mut instrs, val), Value::Int(val) => self.record_int(&mut instrs, val), + Value::Double(val) => self.record_double(&mut instrs, val), Value::BigInt(_) | Value::Closure(_) - | Value::Double(_) | Value::Global(_, _) | Value::Pauli(_) | Value::Qubit(_) @@ -2725,6 +2918,18 @@ impl<'a> PartialEvaluator<'a> { )); } + fn record_double(&mut self, instrs: &mut Vec, val: f64) { + let int_record_callable_id = self.get_double_record_callable(); + instrs.push(Instruction::Call( + int_record_callable_id, + vec![ + Operand::Literal(Literal::Double(val)), + Operand::Literal(Literal::Pointer), + ], + None, + )); + } + fn record_bool(&mut self, instrs: &mut Vec, val: bool) { let bool_record_callable_id = self.get_bool_record_callable(); instrs.push(Instruction::Call( @@ -2741,6 +2946,7 @@ impl<'a> PartialEvaluator<'a> { let record_callable_id = match ty { Ty::Prim(Prim::Bool) => self.get_bool_record_callable(), Ty::Prim(Prim::Int) => self.get_int_record_callable(), + Ty::Prim(Prim::Double) => self.get_double_record_callable(), _ => panic!("unsupported variable type in output recording"), }; instrs.push(Instruction::Call( @@ -2882,6 +3088,22 @@ impl<'a> PartialEvaluator<'a> { callable_id } + fn get_double_record_callable(&mut self) -> CallableId { + if let Some(id) = self + .callables_map + .get("__quantum__rt__double_record_output") + { + return *id; + } + + let callable = builder::double_record_decl(); + let callable_id = self.resource_manager.next_callable(); + self.callables_map + .insert("__quantum__rt__double_record_output".into(), callable_id); + self.program.callables.insert(callable_id, callable); + callable_id + } + fn get_int_record_callable(&mut self) -> CallableId { if let Some(id) = self.callables_map.get("__quantum__rt__int_record_output") { return *id; @@ -2977,6 +3199,39 @@ fn eval_bin_op_with_bool_literals( Value::Bool(bin_op_result) } +fn eval_bin_op_with_double_literals( + bin_op: BinOp, + lhs_literal: Literal, + rhs_literal: Literal, + bin_op_expr_span: PackageSpan, // For diagnostic purposes only +) -> Result { + fn eval_double_div(lhs: f64, rhs: f64, span: PackageSpan) -> Result { + match (lhs, rhs) { + (_, 0.0) => Err(EvalError::DivZero(span).into()), + (lhs, rhs) => Ok(Value::Double(lhs / rhs)), + } + } + + // Validate that both literals are doubles. + let (Literal::Double(lhs), Literal::Double(rhs)) = (lhs_literal, rhs_literal) else { + panic!("at least one literal is not an double: {lhs_literal}, {rhs_literal}"); + }; + + match bin_op { + BinOp::Eq => Ok(Value::Bool((lhs - rhs).abs() < f64::EPSILON)), + BinOp::Neq => Ok(Value::Bool((lhs - rhs).abs() > f64::EPSILON)), + BinOp::Gt => Ok(Value::Bool(lhs > rhs)), + BinOp::Gte => Ok(Value::Bool(lhs >= rhs)), + BinOp::Lt => Ok(Value::Bool(lhs < rhs)), + BinOp::Lte => Ok(Value::Bool(lhs <= rhs)), + BinOp::Add => Ok(Value::Double(lhs + rhs)), + BinOp::Sub => Ok(Value::Double(lhs - rhs)), + BinOp::Mul => Ok(Value::Double(lhs * rhs)), + BinOp::Div => eval_double_div(lhs, rhs, bin_op_expr_span), + _ => panic!("invalid double operator: {bin_op:?}"), + } +} + fn eval_bin_op_with_integer_literals( bin_op: BinOp, lhs_literal: Literal, diff --git a/compiler/qsc_partial_eval/src/tests/assigns.rs b/compiler/qsc_partial_eval/src/tests/assigns.rs index 3a0e8e2ae3..594363902e 100644 --- a/compiler/qsc_partial_eval/src/tests/assigns.rs +++ b/compiler/qsc_partial_eval/src/tests/assigns.rs @@ -2657,3 +2657,334 @@ fn integer_assign_bitwise_right_shift_with_lhs_classical_integer_and_rhs_dynamic Jump(1)"#]], ); } + +#[test] +fn double_assign_add_with_lhs_classical_double_and_rhs_dynamic_double() { + let program = get_rir_program(indoc! { + r#" + namespace Test { + @EntryPoint() + operation Main() : Double { + use q = Qubit(); + mutable i = 0.0; + set i += MResetZ(q) == Zero ? 0.0 | 1.0; + i + } + } + "#, + }); + let measurement_callable_id = CallableId(1); + assert_callable( + &program, + measurement_callable_id, + &expect![[r#" + Callable: + name: __quantum__qis__mresetz__body + call_type: Measurement + input_type: + [0]: Qubit + [1]: Result + output_type: + body: "#]], + ); + let readout_callable_id = CallableId(2); + assert_callable( + &program, + readout_callable_id, + &expect![[r#" + Callable: + name: __quantum__qis__read_result__body + call_type: Readout + input_type: + [0]: Result + output_type: Boolean + body: "#]], + ); + let output_record_id = CallableId(3); + assert_callable( + &program, + output_record_id, + &expect![[r#" + Callable: + name: __quantum__rt__double_record_output + call_type: OutputRecording + input_type: + [0]: Double + [1]: Pointer + output_type: + body: "#]], + ); + assert_blocks( + &program, + &expect![[r#" + Blocks: + Block 0:Block: + Variable(0, Double) = Store Double(0) + Call id(1), args( Qubit(0), Result(0), ) + Variable(1, Boolean) = Call id(2), args( Result(0), ) + Variable(2, Boolean) = Icmp Eq, Variable(1, Boolean), Bool(false) + Branch Variable(2, Boolean), 2, 3 + Block 1:Block: + Variable(4, Double) = Fadd Double(0), Variable(3, Double) + Variable(0, Double) = Store Variable(4, Double) + Call id(3), args( Variable(0, Double), Pointer, ) + Return + Block 2:Block: + Variable(3, Double) = Store Double(0) + Jump(1) + Block 3:Block: + Variable(3, Double) = Store Double(1) + Jump(1)"#]], + ); +} + +#[test] +fn double_assign_sub_with_lhs_dynamic_double_and_rhs_classical_double() { + let program = get_rir_program(indoc! { + r#" + namespace Test { + @EntryPoint() + operation Main() : Double { + use q = Qubit(); + mutable i = MResetZ(q) == Zero ? 0.0 | 1.0; + set i -= 1.0; + i + } + } + "#, + }); + let measurement_callable_id = CallableId(1); + assert_callable( + &program, + measurement_callable_id, + &expect![[r#" + Callable: + name: __quantum__qis__mresetz__body + call_type: Measurement + input_type: + [0]: Qubit + [1]: Result + output_type: + body: "#]], + ); + let readout_callable_id = CallableId(2); + assert_callable( + &program, + readout_callable_id, + &expect![[r#" + Callable: + name: __quantum__qis__read_result__body + call_type: Readout + input_type: + [0]: Result + output_type: Boolean + body: "#]], + ); + let output_record_id = CallableId(3); + assert_callable( + &program, + output_record_id, + &expect![[r#" + Callable: + name: __quantum__rt__double_record_output + call_type: OutputRecording + input_type: + [0]: Double + [1]: Pointer + output_type: + body: "#]], + ); + assert_blocks( + &program, + &expect![[r#" + Blocks: + Block 0:Block: + Call id(1), args( Qubit(0), Result(0), ) + Variable(0, Boolean) = Call id(2), args( Result(0), ) + Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false) + Branch Variable(1, Boolean), 2, 3 + Block 1:Block: + Variable(3, Double) = Store Variable(2, Double) + Variable(4, Double) = Fsub Variable(3, Double), Double(1) + Variable(3, Double) = Store Variable(4, Double) + Call id(3), args( Variable(3, Double), Pointer, ) + Return + Block 2:Block: + Variable(2, Double) = Store Double(0) + Jump(1) + Block 3:Block: + Variable(2, Double) = Store Double(1) + Jump(1)"#]], + ); +} + +#[test] +fn double_assign_mul_with_lhs_dynamic_double_and_rhs_dynamic_double() { + let program = get_rir_program(indoc! { + r#" + namespace Test { + @EntryPoint() + operation Main() : Double { + use q = Qubit(); + mutable i = MResetZ(q) == Zero ? 0.0 | 1.0; + set i *= MResetZ(q) == Zero ? 1.1 | 0.1; + i + } + } + "#, + }); + let measurement_callable_id = CallableId(1); + assert_callable( + &program, + measurement_callable_id, + &expect![[r#" + Callable: + name: __quantum__qis__mresetz__body + call_type: Measurement + input_type: + [0]: Qubit + [1]: Result + output_type: + body: "#]], + ); + let readout_callable_id = CallableId(2); + assert_callable( + &program, + readout_callable_id, + &expect![[r#" + Callable: + name: __quantum__qis__read_result__body + call_type: Readout + input_type: + [0]: Result + output_type: Boolean + body: "#]], + ); + let output_record_id = CallableId(3); + assert_callable( + &program, + output_record_id, + &expect![[r#" + Callable: + name: __quantum__rt__double_record_output + call_type: OutputRecording + input_type: + [0]: Double + [1]: Pointer + output_type: + body: "#]], + ); + assert_blocks( + &program, + &expect![[r#" + Blocks: + Block 0:Block: + Call id(1), args( Qubit(0), Result(0), ) + Variable(0, Boolean) = Call id(2), args( Result(0), ) + Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false) + Branch Variable(1, Boolean), 2, 3 + Block 1:Block: + Variable(3, Double) = Store Variable(2, Double) + Call id(1), args( Qubit(0), Result(1), ) + Variable(4, Boolean) = Call id(2), args( Result(1), ) + Variable(5, Boolean) = Icmp Eq, Variable(4, Boolean), Bool(false) + Branch Variable(5, Boolean), 5, 6 + Block 2:Block: + Variable(2, Double) = Store Double(0) + Jump(1) + Block 3:Block: + Variable(2, Double) = Store Double(1) + Jump(1) + Block 4:Block: + Variable(7, Double) = Fmul Variable(3, Double), Variable(6, Double) + Variable(3, Double) = Store Variable(7, Double) + Call id(3), args( Variable(3, Double), Pointer, ) + Return + Block 5:Block: + Variable(6, Double) = Store Double(1.1) + Jump(4) + Block 6:Block: + Variable(6, Double) = Store Double(0.1) + Jump(4)"#]], + ); +} + +#[test] +fn double_assign_div_with_lhs_classical_double_and_rhs_dynamic_double() { + let program = get_rir_program(indoc! { + r#" + namespace Test { + @EntryPoint() + operation Main() : Double { + use q = Qubit(); + mutable i = 0.0; + set i /= MResetZ(q) == Zero ? 0.0 | 1.0; + i + } + } + "#, + }); + let measurement_callable_id = CallableId(1); + assert_callable( + &program, + measurement_callable_id, + &expect![[r#" + Callable: + name: __quantum__qis__mresetz__body + call_type: Measurement + input_type: + [0]: Qubit + [1]: Result + output_type: + body: "#]], + ); + let readout_callable_id = CallableId(2); + assert_callable( + &program, + readout_callable_id, + &expect![[r#" + Callable: + name: __quantum__qis__read_result__body + call_type: Readout + input_type: + [0]: Result + output_type: Boolean + body: "#]], + ); + let output_record_id = CallableId(3); + assert_callable( + &program, + output_record_id, + &expect![[r#" + Callable: + name: __quantum__rt__double_record_output + call_type: OutputRecording + input_type: + [0]: Double + [1]: Pointer + output_type: + body: "#]], + ); + assert_blocks( + &program, + &expect![[r#" + Blocks: + Block 0:Block: + Variable(0, Double) = Store Double(0) + Call id(1), args( Qubit(0), Result(0), ) + Variable(1, Boolean) = Call id(2), args( Result(0), ) + Variable(2, Boolean) = Icmp Eq, Variable(1, Boolean), Bool(false) + Branch Variable(2, Boolean), 2, 3 + Block 1:Block: + Variable(4, Double) = Fdiv Double(0), Variable(3, Double) + Variable(0, Double) = Store Variable(4, Double) + Call id(3), args( Variable(0, Double), Pointer, ) + Return + Block 2:Block: + Variable(3, Double) = Store Double(0) + Jump(1) + Block 3:Block: + Variable(3, Double) = Store Double(1) + Jump(1)"#]], + ); +} diff --git a/compiler/qsc_partial_eval/src/tests/bindings.rs b/compiler/qsc_partial_eval/src/tests/bindings.rs index a669d879c8..2afbea0373 100644 --- a/compiler/qsc_partial_eval/src/tests/bindings.rs +++ b/compiler/qsc_partial_eval/src/tests/bindings.rs @@ -481,3 +481,78 @@ fn mutable_variable_in_outer_scope_set_to_mutable_from_inner_scope() { Jump(1)"#]], ); } + +#[test] +fn mutable_double_binding_does_generate_store_instruction() { + let program = get_rir_program(indoc! {r#" + namespace Test { + @EntryPoint() + operation Main() : Double { + use q = Qubit(); + mutable d = MResetZ(q) == One ? 0.1 | 1.1; + d + } + } + "#}); + let measurement_callable_id = CallableId(1); + assert_callable( + &program, + measurement_callable_id, + &expect![[r#" + Callable: + name: __quantum__qis__mresetz__body + call_type: Measurement + input_type: + [0]: Qubit + [1]: Result + output_type: + body: "#]], + ); + let read_result_callable_id = CallableId(2); + assert_callable( + &program, + read_result_callable_id, + &expect![[r#" + Callable: + name: __quantum__qis__read_result__body + call_type: Readout + input_type: + [0]: Result + output_type: Boolean + body: "#]], + ); + let output_recording_callable_id = CallableId(3); + assert_callable( + &program, + output_recording_callable_id, + &expect![[r#" + Callable: + name: __quantum__rt__double_record_output + call_type: OutputRecording + input_type: + [0]: Double + [1]: Pointer + output_type: + body: "#]], + ); + assert_blocks( + &program, + &expect![[r#" + Blocks: + Block 0:Block: + Call id(1), args( Qubit(0), Result(0), ) + Variable(0, Boolean) = Call id(2), args( Result(0), ) + Variable(1, Boolean) = Store Variable(0, Boolean) + Branch Variable(1, Boolean), 2, 3 + Block 1:Block: + Variable(3, Double) = Store Variable(2, Double) + Call id(3), args( Variable(3, Double), Pointer, ) + Return + Block 2:Block: + Variable(2, Double) = Store Double(0.1) + Jump(1) + Block 3:Block: + Variable(2, Double) = Store Double(1.1) + Jump(1)"#]], + ); +} diff --git a/compiler/qsc_partial_eval/src/tests/branching.rs b/compiler/qsc_partial_eval/src/tests/branching.rs index b9b036ac36..76c739140f 100644 --- a/compiler/qsc_partial_eval/src/tests/branching.rs +++ b/compiler/qsc_partial_eval/src/tests/branching.rs @@ -2062,3 +2062,252 @@ fn if_expression_with_dynamic_operand_from_hybrid_integers_array() { Jump(6)"#]], ); } + +#[test] +fn if_expression_with_classical_operand_from_hybrid_doubles_array() { + let program = get_rir_program(indoc! {r#" + @EntryPoint() + operation Main() : Double[] { + mutable doubles = [0.0, 0.0]; + use (a, b) = (Qubit(), Qubit()); + set doubles w/= 0 <- MResetZ(a) == Zero ? 0.1 | 1.1; + // Use a static double in the condition. + if doubles[1] == 0.0 { + X(b); + } + set doubles w/= 1 <- MResetZ(b) == Zero ? 0.1 | 1.1; + doubles + } + "# + }); + + // Verify the callables added to the program. + let mresetz_callable_id = CallableId(1); + assert_callable( + &program, + mresetz_callable_id, + &expect![[r#" + Callable: + name: __quantum__qis__mresetz__body + call_type: Measurement + input_type: + [0]: Qubit + [1]: Result + output_type: + body: "#]], + ); + let read_result_callable_id = CallableId(2); + assert_callable( + &program, + read_result_callable_id, + &expect![[r#" + Callable: + name: __quantum__qis__read_result__body + call_type: Readout + input_type: + [0]: Result + output_type: Boolean + body: "#]], + ); + let x_callable_id = CallableId(3); + assert_callable( + &program, + x_callable_id, + &expect![[r#" + Callable: + name: __quantum__qis__x__body + call_type: Regular + input_type: + [0]: Qubit + output_type: + body: "#]], + ); + let record_array_callable_id = CallableId(4); + assert_callable( + &program, + record_array_callable_id, + &expect![[r#" + Callable: + name: __quantum__rt__array_record_output + call_type: OutputRecording + input_type: + [0]: Integer + [1]: Pointer + output_type: + body: "#]], + ); + let record_int_callable_id = CallableId(5); + assert_callable( + &program, + record_int_callable_id, + &expect![[r#" + Callable: + name: __quantum__rt__double_record_output + call_type: OutputRecording + input_type: + [0]: Double + [1]: Pointer + output_type: + body: "#]], + ); + assert_blocks( + &program, + &expect![[r#" + Blocks: + Block 0:Block: + Call id(1), args( Qubit(0), Result(0), ) + Variable(0, Boolean) = Call id(2), args( Result(0), ) + Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false) + Branch Variable(1, Boolean), 2, 3 + Block 1:Block: + Call id(3), args( Qubit(1), ) + Call id(1), args( Qubit(1), Result(1), ) + Variable(3, Boolean) = Call id(2), args( Result(1), ) + Variable(4, Boolean) = Icmp Eq, Variable(3, Boolean), Bool(false) + Branch Variable(4, Boolean), 5, 6 + Block 2:Block: + Variable(2, Double) = Store Double(0.1) + Jump(1) + Block 3:Block: + Variable(2, Double) = Store Double(1.1) + Jump(1) + Block 4:Block: + Call id(4), args( Integer(2), Pointer, ) + Call id(5), args( Variable(2, Double), Pointer, ) + Call id(5), args( Variable(5, Double), Pointer, ) + Return + Block 5:Block: + Variable(5, Double) = Store Double(0.1) + Jump(4) + Block 6:Block: + Variable(5, Double) = Store Double(1.1) + Jump(4)"#]], + ); +} + +#[test] +fn if_expression_with_dynamic_operand_from_hybrid_doubles_array() { + let program = get_rir_program(indoc! {r#" + @EntryPoint() + operation Main() : Double[] { + mutable doubles = [0.0, 0.0]; + use (a, b) = (Qubit(), Qubit()); + set doubles w/= 0 <- MResetZ(a) == Zero ? 0.1 | 1.1; + // Use a dynamic double in the condition. + if doubles[0] == 0.0 { + X(b); + } + set doubles w/= 1 <- MResetZ(b) == Zero ? 0.1 | 1.1; + doubles + } + "# + }); + + // Verify the callables added to the program. + let mresetz_callable_id = CallableId(1); + assert_callable( + &program, + mresetz_callable_id, + &expect![[r#" + Callable: + name: __quantum__qis__mresetz__body + call_type: Measurement + input_type: + [0]: Qubit + [1]: Result + output_type: + body: "#]], + ); + let read_result_callable_id = CallableId(2); + assert_callable( + &program, + read_result_callable_id, + &expect![[r#" + Callable: + name: __quantum__qis__read_result__body + call_type: Readout + input_type: + [0]: Result + output_type: Boolean + body: "#]], + ); + let x_callable_id = CallableId(3); + assert_callable( + &program, + x_callable_id, + &expect![[r#" + Callable: + name: __quantum__qis__x__body + call_type: Regular + input_type: + [0]: Qubit + output_type: + body: "#]], + ); + let record_array_callable_id = CallableId(4); + assert_callable( + &program, + record_array_callable_id, + &expect![[r#" + Callable: + name: __quantum__rt__array_record_output + call_type: OutputRecording + input_type: + [0]: Integer + [1]: Pointer + output_type: + body: "#]], + ); + let record_int_callable_id = CallableId(5); + assert_callable( + &program, + record_int_callable_id, + &expect![[r#" + Callable: + name: __quantum__rt__double_record_output + call_type: OutputRecording + input_type: + [0]: Double + [1]: Pointer + output_type: + body: "#]], + ); + assert_blocks( + &program, + &expect![[r#" + Blocks: + Block 0:Block: + Call id(1), args( Qubit(0), Result(0), ) + Variable(0, Boolean) = Call id(2), args( Result(0), ) + Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false) + Branch Variable(1, Boolean), 2, 3 + Block 1:Block: + Variable(3, Boolean) = Fcmp Oeq, Variable(2, Double), Double(0) + Branch Variable(3, Boolean), 5, 4 + Block 2:Block: + Variable(2, Double) = Store Double(0.1) + Jump(1) + Block 3:Block: + Variable(2, Double) = Store Double(1.1) + Jump(1) + Block 4:Block: + Call id(1), args( Qubit(1), Result(1), ) + Variable(4, Boolean) = Call id(2), args( Result(1), ) + Variable(5, Boolean) = Icmp Eq, Variable(4, Boolean), Bool(false) + Branch Variable(5, Boolean), 7, 8 + Block 5:Block: + Call id(3), args( Qubit(1), ) + Jump(4) + Block 6:Block: + Call id(4), args( Integer(2), Pointer, ) + Call id(5), args( Variable(2, Double), Pointer, ) + Call id(5), args( Variable(6, Double), Pointer, ) + Return + Block 7:Block: + Variable(6, Double) = Store Double(0.1) + Jump(6) + Block 8:Block: + Variable(6, Double) = Store Double(1.1) + Jump(6)"#]], + ); +} diff --git a/compiler/qsc_partial_eval/src/tests/dynamic_vars.rs b/compiler/qsc_partial_eval/src/tests/dynamic_vars.rs index d0b580f863..4a35257d19 100644 --- a/compiler/qsc_partial_eval/src/tests/dynamic_vars.rs +++ b/compiler/qsc_partial_eval/src/tests/dynamic_vars.rs @@ -172,3 +172,268 @@ fn dynamic_int_from_if_expression_with_single_measurement_comparison_and_non_cla Jump(1)"#]], ); } + +#[test] +fn dynamic_double_from_if_expression_with_single_measurement_comparison_and_classical_blocks() { + let program = get_rir_program(indoc! { + r#" + namespace Test { + @EntryPoint() + operation Main() : Unit { + use q = Qubit(); + let r = QIR.Intrinsic.__quantum__qis__mresetz__body(q); + let b = if r == Zero { 0.1 } else { 1.1 }; + } + } + "#, + }); + + // Verify the callables added to the program. + let mresetz_callable_id = CallableId(1); + assert_callable( + &program, + mresetz_callable_id, + &expect![[r#" + Callable: + name: __quantum__qis__mresetz__body + call_type: Measurement + input_type: + [0]: Qubit + [1]: Result + output_type: + body: "#]], + ); + let read_result_callable_id = CallableId(2); + assert_callable( + &program, + read_result_callable_id, + &expect![[r#" + Callable: + name: __quantum__qis__read_result__body + call_type: Readout + input_type: + [0]: Result + output_type: Boolean + body: "#]], + ); + + assert_blocks( + &program, + &expect![[r#" + Blocks: + Block 0:Block: + Call id(1), args( Qubit(0), Result(0), ) + Variable(0, Boolean) = Call id(2), args( Result(0), ) + Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false) + Branch Variable(1, Boolean), 2, 3 + Block 1:Block: + Call id(3), args( Integer(0), Pointer, ) + Return + Block 2:Block: + Variable(2, Double) = Store Double(0.1) + Jump(1) + Block 3:Block: + Variable(2, Double) = Store Double(1.1) + Jump(1)"#]], + ); +} + +#[test] +fn dynamic_double_from_if_expression_with_single_measurement_comparison_and_non_classical_blocks() { + let program = get_rir_program(indoc! { + r#" + namespace Test { + operation OpA(q : Qubit) : Unit { body intrinsic; } + operation OpB(q : Qubit) : Unit { body intrinsic; } + @EntryPoint() + operation Main() : Unit { + use (q0, q1) = (Qubit(), Qubit()); + let r = QIR.Intrinsic.__quantum__qis__mresetz__body(q0); + let b = if r == Zero { + OpA(q1); + 0.1 + } else { + OpB(q1); + 1.1 + }; + } + } + "#, + }); + + // Verify the callables added to the program. + let mresetz_callable_id = CallableId(1); + assert_callable( + &program, + mresetz_callable_id, + &expect![[r#" + Callable: + name: __quantum__qis__mresetz__body + call_type: Measurement + input_type: + [0]: Qubit + [1]: Result + output_type: + body: "#]], + ); + let read_result_callable_id = CallableId(2); + assert_callable( + &program, + read_result_callable_id, + &expect![[r#" + Callable: + name: __quantum__qis__read_result__body + call_type: Readout + input_type: + [0]: Result + output_type: Boolean + body: "#]], + ); + let op_a_callable_id = CallableId(3); + assert_callable( + &program, + op_a_callable_id, + &expect![[r#" + Callable: + name: OpA + call_type: Regular + input_type: + [0]: Qubit + output_type: + body: "#]], + ); + let op_b_callable_id = CallableId(4); + assert_callable( + &program, + op_b_callable_id, + &expect![[r#" + Callable: + name: OpB + call_type: Regular + input_type: + [0]: Qubit + output_type: + body: "#]], + ); + assert_blocks( + &program, + &expect![[r#" + Blocks: + Block 0:Block: + Call id(1), args( Qubit(0), Result(0), ) + Variable(0, Boolean) = Call id(2), args( Result(0), ) + Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false) + Branch Variable(1, Boolean), 2, 3 + Block 1:Block: + Call id(5), args( Integer(0), Pointer, ) + Return + Block 2:Block: + Call id(3), args( Qubit(1), ) + Variable(2, Double) = Store Double(0.1) + Jump(1) + Block 3:Block: + Call id(4), args( Qubit(1), ) + Variable(2, Double) = Store Double(1.1) + Jump(1)"#]], + ); +} + +#[test] +fn dynamic_double_from_if_expression_with_single_measurement_comparison_pass_dynamic_double_to_intrinsic( +) { + let program = get_rir_program(indoc! { + r#" + namespace Test { + operation OpA(theta: Double, q : Qubit) : Unit { body intrinsic; } + @EntryPoint() + operation Main() : Unit { + use (q0, q1) = (Qubit(), Qubit()); + let r = QIR.Intrinsic.__quantum__qis__mresetz__body(q0); + let b = if r == Zero { + 0.1 + } else { + 1.1 + }; + OpA(b, q1); + } + } + "#, + }); + + // Verify the callables added to the program. + let mresetz_callable_id = CallableId(1); + assert_callable( + &program, + mresetz_callable_id, + &expect![[r#" + Callable: + name: __quantum__qis__mresetz__body + call_type: Measurement + input_type: + [0]: Qubit + [1]: Result + output_type: + body: "#]], + ); + let read_result_callable_id = CallableId(2); + assert_callable( + &program, + read_result_callable_id, + &expect![[r#" + Callable: + name: __quantum__qis__read_result__body + call_type: Readout + input_type: + [0]: Result + output_type: Boolean + body: "#]], + ); + let op_a_callable_id = CallableId(3); + assert_callable( + &program, + op_a_callable_id, + &expect![[r#" + Callable: + name: OpA + call_type: Regular + input_type: + [0]: Double + [1]: Qubit + output_type: + body: "#]], + ); + let op_b_callable_id = CallableId(4); + assert_callable( + &program, + op_b_callable_id, + &expect![[r#" + Callable: + name: __quantum__rt__tuple_record_output + call_type: OutputRecording + input_type: + [0]: Integer + [1]: Pointer + output_type: + body: "#]], + ); + assert_blocks( + &program, + &expect![[r#" + Blocks: + Block 0:Block: + Call id(1), args( Qubit(0), Result(0), ) + Variable(0, Boolean) = Call id(2), args( Result(0), ) + Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false) + Branch Variable(1, Boolean), 2, 3 + Block 1:Block: + Call id(3), args( Variable(2, Double), Qubit(1), ) + Call id(4), args( Integer(0), Pointer, ) + Return + Block 2:Block: + Variable(2, Double) = Store Double(0.1) + Jump(1) + Block 3:Block: + Variable(2, Double) = Store Double(1.1) + Jump(1)"#]], + ); +} diff --git a/compiler/qsc_partial_eval/src/tests/loops.rs b/compiler/qsc_partial_eval/src/tests/loops.rs index eff1c2d226..ef2d9852a5 100644 --- a/compiler/qsc_partial_eval/src/tests/loops.rs +++ b/compiler/qsc_partial_eval/src/tests/loops.rs @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -use super::{assert_block_instructions, assert_callable, get_rir_program}; +use super::{assert_block_instructions, assert_blocks, assert_callable, get_rir_program}; use expect_test::expect; use indoc::indoc; use qsc_rir::rir::{BlockId, CallableId}; @@ -377,3 +377,78 @@ fn mutable_int_updated_in_loop() { Branch Variable(3, Boolean), 2, 1"#]], ); } + +#[test] +fn mutable_double_updated_in_loop() { + let program = get_rir_program(indoc! { + r#" + namespace Test { + @EntryPoint() + operation Main() : Unit { + use q = Qubit(); + mutable count = 1.1; + for _ in 1..3 { + if count > 0.1 and MResetZ(q) == One { + set count = -count; + } + } + } + } + "#, + }); + + assert_blocks( + &program, + //BlockId(0), + &expect![[r#" + Blocks: + Block 0:Block: + Variable(0, Double) = Store Double(1.1) + Variable(1, Integer) = Store Integer(1) + Call id(1), args( Qubit(0), Result(0), ) + Variable(2, Boolean) = Call id(2), args( Result(0), ) + Variable(3, Boolean) = Store Variable(2, Boolean) + Branch Variable(3, Boolean), 2, 1 + Block 1:Block: + Variable(1, Integer) = Store Integer(2) + Variable(4, Boolean) = Fcmp Ogt, Variable(0, Double), Double(0.1) + Variable(5, Boolean) = Store Bool(false) + Branch Variable(4, Boolean), 4, 3 + Block 2:Block: + Variable(0, Double) = Store Double(-1.1) + Jump(1) + Block 3:Block: + Branch Variable(5, Boolean), 6, 5 + Block 4:Block: + Call id(1), args( Qubit(0), Result(1), ) + Variable(6, Boolean) = Call id(2), args( Result(1), ) + Variable(7, Boolean) = Store Variable(6, Boolean) + Variable(5, Boolean) = Store Variable(7, Boolean) + Jump(3) + Block 5:Block: + Variable(1, Integer) = Store Integer(3) + Variable(9, Boolean) = Fcmp Ogt, Variable(0, Double), Double(0.1) + Variable(10, Boolean) = Store Bool(false) + Branch Variable(9, Boolean), 8, 7 + Block 6:Block: + Variable(8, Double) = Fmul Double(-1), Variable(0, Double) + Variable(0, Double) = Store Variable(8, Double) + Jump(5) + Block 7:Block: + Branch Variable(10, Boolean), 10, 9 + Block 8:Block: + Call id(1), args( Qubit(0), Result(2), ) + Variable(11, Boolean) = Call id(2), args( Result(2), ) + Variable(12, Boolean) = Store Variable(11, Boolean) + Variable(10, Boolean) = Store Variable(12, Boolean) + Jump(7) + Block 9:Block: + Variable(1, Integer) = Store Integer(4) + Call id(3), args( Integer(0), Pointer, ) + Return + Block 10:Block: + Variable(13, Double) = Fmul Double(-1), Variable(0, Double) + Variable(0, Double) = Store Variable(13, Double) + Jump(9)"#]], + ); +} diff --git a/compiler/qsc_partial_eval/src/tests/operators.rs b/compiler/qsc_partial_eval/src/tests/operators.rs index f3f5e5e7f5..9fb38b760c 100644 --- a/compiler/qsc_partial_eval/src/tests/operators.rs +++ b/compiler/qsc_partial_eval/src/tests/operators.rs @@ -10,7 +10,7 @@ use indoc::indoc; use qsc_rir::rir::{BlockId, CallableId}; #[test] -fn leading_positive_unary_operator_does_not_generate_rir_instruction() { +fn leading_positive_unary_operator_on_integer_does_not_generate_rir_instruction() { let program = get_rir_program(indoc! {r#" namespace Test { @EntryPoint() @@ -84,7 +84,7 @@ fn leading_positive_unary_operator_does_not_generate_rir_instruction() { } #[test] -fn leading_negative_unary_operator_generates_rir_instruction() { +fn leading_negative_unary_operator_on_integer_generates_rir_instruction() { let program = get_rir_program(indoc! {r#" namespace Test { @EntryPoint() @@ -3170,3 +3170,980 @@ fn integer_less_or_equal_than_comparison_with_lhs_classical_integer_and_rhs_dyna Jump(1)"#]], ); } + +#[test] +fn leading_positive_unary_operator_on_double_does_not_generate_rir_instruction() { + let program = get_rir_program(indoc! {r#" + namespace Test { + @EntryPoint() + operation Main() : Double { + use q = Qubit(); + let i = MResetZ(q) == Zero ? 0.0 | 1.0; + +i + } + } + "#}); + let mresetz_callable_id = CallableId(1); + assert_callable( + &program, + mresetz_callable_id, + &expect![[r#" + Callable: + name: __quantum__qis__mresetz__body + call_type: Measurement + input_type: + [0]: Qubit + [1]: Result + output_type: + body: "#]], + ); + let readout_callable_id = CallableId(2); + assert_callable( + &program, + readout_callable_id, + &expect![[r#" + Callable: + name: __quantum__qis__read_result__body + call_type: Readout + input_type: + [0]: Result + output_type: Boolean + body: "#]], + ); + let output_recording_callable_id = CallableId(3); + assert_callable( + &program, + output_recording_callable_id, + &expect![[r#" + Callable: + name: __quantum__rt__double_record_output + call_type: OutputRecording + input_type: + [0]: Double + [1]: Pointer + output_type: + body: "#]], + ); + assert_blocks( + &program, + &expect![[r#" + Blocks: + Block 0:Block: + Call id(1), args( Qubit(0), Result(0), ) + Variable(0, Boolean) = Call id(2), args( Result(0), ) + Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false) + Branch Variable(1, Boolean), 2, 3 + Block 1:Block: + Call id(3), args( Variable(2, Double), Pointer, ) + Return + Block 2:Block: + Variable(2, Double) = Store Double(0) + Jump(1) + Block 3:Block: + Variable(2, Double) = Store Double(1) + Jump(1)"#]], + ); +} + +#[test] +fn leading_negative_unary_operator_on_double_generates_rir_instruction() { + let program = get_rir_program(indoc! {r#" + namespace Test { + @EntryPoint() + operation Main() : Double { + use q = Qubit(); + let i = MResetZ(q) == Zero ? 0.0 | 1.0; + -i + } + } + "#}); + let mresetz_callable_id = CallableId(1); + assert_callable( + &program, + mresetz_callable_id, + &expect![[r#" + Callable: + name: __quantum__qis__mresetz__body + call_type: Measurement + input_type: + [0]: Qubit + [1]: Result + output_type: + body: "#]], + ); + let readout_callable_id = CallableId(2); + assert_callable( + &program, + readout_callable_id, + &expect![[r#" + Callable: + name: __quantum__qis__read_result__body + call_type: Readout + input_type: + [0]: Result + output_type: Boolean + body: "#]], + ); + let output_recording_callable_id = CallableId(3); + assert_callable( + &program, + output_recording_callable_id, + &expect![[r#" + Callable: + name: __quantum__rt__double_record_output + call_type: OutputRecording + input_type: + [0]: Double + [1]: Pointer + output_type: + body: "#]], + ); + assert_blocks( + &program, + &expect![[r#" + Blocks: + Block 0:Block: + Call id(1), args( Qubit(0), Result(0), ) + Variable(0, Boolean) = Call id(2), args( Result(0), ) + Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false) + Branch Variable(1, Boolean), 2, 3 + Block 1:Block: + Variable(3, Double) = Fmul Double(-1), Variable(2, Double) + Call id(3), args( Variable(3, Double), Pointer, ) + Return + Block 2:Block: + Variable(2, Double) = Store Double(0) + Jump(1) + Block 3:Block: + Variable(2, Double) = Store Double(1) + Jump(1)"#]], + ); +} + +#[test] +fn double_add_with_lhs_classical_double_and_rhs_dynamic_double() { + let program = get_rir_program(indoc! { + r#" + namespace Test { + @EntryPoint() + operation Main() : Double { + use q = Qubit(); + let i = MResetZ(q) == Zero ? 0.0 | 1.0; + 1.0 + i + } + } + "#, + }); + let measurement_callable_id = CallableId(1); + assert_callable( + &program, + measurement_callable_id, + &expect![[r#" + Callable: + name: __quantum__qis__mresetz__body + call_type: Measurement + input_type: + [0]: Qubit + [1]: Result + output_type: + body: "#]], + ); + let readout_callable_id = CallableId(2); + assert_callable( + &program, + readout_callable_id, + &expect![[r#" + Callable: + name: __quantum__qis__read_result__body + call_type: Readout + input_type: + [0]: Result + output_type: Boolean + body: "#]], + ); + let output_record_id = CallableId(3); + assert_callable( + &program, + output_record_id, + &expect![[r#" + Callable: + name: __quantum__rt__double_record_output + call_type: OutputRecording + input_type: + [0]: Double + [1]: Pointer + output_type: + body: "#]], + ); + assert_blocks( + &program, + &expect![[r#" + Blocks: + Block 0:Block: + Call id(1), args( Qubit(0), Result(0), ) + Variable(0, Boolean) = Call id(2), args( Result(0), ) + Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false) + Branch Variable(1, Boolean), 2, 3 + Block 1:Block: + Variable(3, Double) = Fadd Double(1), Variable(2, Double) + Call id(3), args( Variable(3, Double), Pointer, ) + Return + Block 2:Block: + Variable(2, Double) = Store Double(0) + Jump(1) + Block 3:Block: + Variable(2, Double) = Store Double(1) + Jump(1)"#]], + ); +} + +#[test] +fn double_sub_with_lhs_dynamic_double_and_rhs_classical_double() { + let program = get_rir_program(indoc! { + r#" + namespace Test { + @EntryPoint() + operation Main() : Double { + use q = Qubit(); + let i = MResetZ(q) == Zero ? 0.0 | 1.0; + i - 1.0 + } + } + "#, + }); + let measurement_callable_id = CallableId(1); + assert_callable( + &program, + measurement_callable_id, + &expect![[r#" + Callable: + name: __quantum__qis__mresetz__body + call_type: Measurement + input_type: + [0]: Qubit + [1]: Result + output_type: + body: "#]], + ); + let readout_callable_id = CallableId(2); + assert_callable( + &program, + readout_callable_id, + &expect![[r#" + Callable: + name: __quantum__qis__read_result__body + call_type: Readout + input_type: + [0]: Result + output_type: Boolean + body: "#]], + ); + let output_record_id = CallableId(3); + assert_callable( + &program, + output_record_id, + &expect![[r#" + Callable: + name: __quantum__rt__double_record_output + call_type: OutputRecording + input_type: + [0]: Double + [1]: Pointer + output_type: + body: "#]], + ); + assert_blocks( + &program, + &expect![[r#" + Blocks: + Block 0:Block: + Call id(1), args( Qubit(0), Result(0), ) + Variable(0, Boolean) = Call id(2), args( Result(0), ) + Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false) + Branch Variable(1, Boolean), 2, 3 + Block 1:Block: + Variable(3, Double) = Fsub Variable(2, Double), Double(1) + Call id(3), args( Variable(3, Double), Pointer, ) + Return + Block 2:Block: + Variable(2, Double) = Store Double(0) + Jump(1) + Block 3:Block: + Variable(2, Double) = Store Double(1) + Jump(1)"#]], + ); +} + +#[test] +fn double_mul_with_lhs_dynamic_double_and_rhs_dynamic_double() { + let program = get_rir_program(indoc! { + r#" + namespace Test { + @EntryPoint() + operation Main() : Double { + use q = Qubit(); + let a = MResetZ(q) == Zero ? 0.0 | 1.0; + let b = MResetZ(q) == Zero ? 1.1 | 0.1; + a * b + } + } + "#, + }); + let measurement_callable_id = CallableId(1); + assert_callable( + &program, + measurement_callable_id, + &expect![[r#" + Callable: + name: __quantum__qis__mresetz__body + call_type: Measurement + input_type: + [0]: Qubit + [1]: Result + output_type: + body: "#]], + ); + let readout_callable_id = CallableId(2); + assert_callable( + &program, + readout_callable_id, + &expect![[r#" + Callable: + name: __quantum__qis__read_result__body + call_type: Readout + input_type: + [0]: Result + output_type: Boolean + body: "#]], + ); + let output_record_id = CallableId(3); + assert_callable( + &program, + output_record_id, + &expect![[r#" + Callable: + name: __quantum__rt__double_record_output + call_type: OutputRecording + input_type: + [0]: Double + [1]: Pointer + output_type: + body: "#]], + ); + assert_blocks( + &program, + &expect![[r#" + Blocks: + Block 0:Block: + Call id(1), args( Qubit(0), Result(0), ) + Variable(0, Boolean) = Call id(2), args( Result(0), ) + Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false) + Branch Variable(1, Boolean), 2, 3 + Block 1:Block: + Call id(1), args( Qubit(0), Result(1), ) + Variable(3, Boolean) = Call id(2), args( Result(1), ) + Variable(4, Boolean) = Icmp Eq, Variable(3, Boolean), Bool(false) + Branch Variable(4, Boolean), 5, 6 + Block 2:Block: + Variable(2, Double) = Store Double(0) + Jump(1) + Block 3:Block: + Variable(2, Double) = Store Double(1) + Jump(1) + Block 4:Block: + Variable(6, Double) = Fmul Variable(2, Double), Variable(5, Double) + Call id(3), args( Variable(6, Double), Pointer, ) + Return + Block 5:Block: + Variable(5, Double) = Store Double(1.1) + Jump(4) + Block 6:Block: + Variable(5, Double) = Store Double(0.1) + Jump(4)"#]], + ); +} + +#[test] +fn double_div_with_lhs_classical_double_and_rhs_dynamic_double() { + let program = get_rir_program(indoc! { + r#" + namespace Test { + @EntryPoint() + operation Main() : Double { + use q = Qubit(); + let i = MResetZ(q) == Zero ? 0.0 | 1.0; + 1.0 / i + } + } + "#, + }); + let measurement_callable_id = CallableId(1); + assert_callable( + &program, + measurement_callable_id, + &expect![[r#" + Callable: + name: __quantum__qis__mresetz__body + call_type: Measurement + input_type: + [0]: Qubit + [1]: Result + output_type: + body: "#]], + ); + let readout_callable_id = CallableId(2); + assert_callable( + &program, + readout_callable_id, + &expect![[r#" + Callable: + name: __quantum__qis__read_result__body + call_type: Readout + input_type: + [0]: Result + output_type: Boolean + body: "#]], + ); + let output_record_id = CallableId(3); + assert_callable( + &program, + output_record_id, + &expect![[r#" + Callable: + name: __quantum__rt__double_record_output + call_type: OutputRecording + input_type: + [0]: Double + [1]: Pointer + output_type: + body: "#]], + ); + assert_blocks( + &program, + &expect![[r#" + Blocks: + Block 0:Block: + Call id(1), args( Qubit(0), Result(0), ) + Variable(0, Boolean) = Call id(2), args( Result(0), ) + Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false) + Branch Variable(1, Boolean), 2, 3 + Block 1:Block: + Variable(3, Double) = Fdiv Double(1), Variable(2, Double) + Call id(3), args( Variable(3, Double), Pointer, ) + Return + Block 2:Block: + Variable(2, Double) = Store Double(0) + Jump(1) + Block 3:Block: + Variable(2, Double) = Store Double(1) + Jump(1)"#]], + ); +} + +#[test] +fn double_div_with_lhs_dynamic_double_and_rhs_zero_raises_error() { + let error = get_partial_evaluation_error(indoc! { + r#" + namespace Test { + @EntryPoint() + operation Main() : Double { + use q = Qubit(); + let i = MResetZ(q) == Zero ? 0.0 | 1.0; + i / 0.0 + } + } + "#, + }); + assert_error( + &error, + &expect![[ + r#"EvaluationFailed("division by zero", PackageSpan { package: PackageId(2), span: Span { lo: 149, hi: 156 } })"# + ]], + ); +} + +#[test] +fn double_equality_comparison_with_lhs_dynamic_double_and_rhs_classical_double() { + let program = get_rir_program(indoc! { + r#" + namespace Test { + @EntryPoint() + operation Main() : Bool { + use q = Qubit(); + let i = MResetZ(q) == Zero ? 0.0 | 1.0; + i == 1.0 + } + } + "#, + }); + let measurement_callable_id = CallableId(1); + assert_callable( + &program, + measurement_callable_id, + &expect![[r#" + Callable: + name: __quantum__qis__mresetz__body + call_type: Measurement + input_type: + [0]: Qubit + [1]: Result + output_type: + body: "#]], + ); + let readout_callable_id = CallableId(2); + assert_callable( + &program, + readout_callable_id, + &expect![[r#" + Callable: + name: __quantum__qis__read_result__body + call_type: Readout + input_type: + [0]: Result + output_type: Boolean + body: "#]], + ); + let output_record_id = CallableId(3); + assert_callable( + &program, + output_record_id, + &expect![[r#" + Callable: + name: __quantum__rt__bool_record_output + call_type: OutputRecording + input_type: + [0]: Boolean + [1]: Pointer + output_type: + body: "#]], + ); + assert_blocks( + &program, + &expect![[r#" + Blocks: + Block 0:Block: + Call id(1), args( Qubit(0), Result(0), ) + Variable(0, Boolean) = Call id(2), args( Result(0), ) + Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false) + Branch Variable(1, Boolean), 2, 3 + Block 1:Block: + Variable(3, Boolean) = Fcmp Oeq, Variable(2, Double), Double(1) + Call id(3), args( Variable(3, Boolean), Pointer, ) + Return + Block 2:Block: + Variable(2, Double) = Store Double(0) + Jump(1) + Block 3:Block: + Variable(2, Double) = Store Double(1) + Jump(1)"#]], + ); +} + +#[test] +fn double_inequality_comparison_with_lhs_dynamic_double_and_rhs_dynamic_double() { + let program = get_rir_program(indoc! { + r#" + namespace Test { + @EntryPoint() + operation Main() : Bool { + use q = Qubit(); + let a = MResetZ(q) == Zero ? 0.0 | 1.0; + let b = MResetZ(q) == Zero ? 1.1 | 0.1; + a != b + } + } + "#, + }); + let measurement_callable_id = CallableId(1); + assert_callable( + &program, + measurement_callable_id, + &expect![[r#" + Callable: + name: __quantum__qis__mresetz__body + call_type: Measurement + input_type: + [0]: Qubit + [1]: Result + output_type: + body: "#]], + ); + let readout_callable_id = CallableId(2); + assert_callable( + &program, + readout_callable_id, + &expect![[r#" + Callable: + name: __quantum__qis__read_result__body + call_type: Readout + input_type: + [0]: Result + output_type: Boolean + body: "#]], + ); + let output_record_id = CallableId(3); + assert_callable( + &program, + output_record_id, + &expect![[r#" + Callable: + name: __quantum__rt__bool_record_output + call_type: OutputRecording + input_type: + [0]: Boolean + [1]: Pointer + output_type: + body: "#]], + ); + assert_blocks( + &program, + &expect![[r#" + Blocks: + Block 0:Block: + Call id(1), args( Qubit(0), Result(0), ) + Variable(0, Boolean) = Call id(2), args( Result(0), ) + Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false) + Branch Variable(1, Boolean), 2, 3 + Block 1:Block: + Call id(1), args( Qubit(0), Result(1), ) + Variable(3, Boolean) = Call id(2), args( Result(1), ) + Variable(4, Boolean) = Icmp Eq, Variable(3, Boolean), Bool(false) + Branch Variable(4, Boolean), 5, 6 + Block 2:Block: + Variable(2, Double) = Store Double(0) + Jump(1) + Block 3:Block: + Variable(2, Double) = Store Double(1) + Jump(1) + Block 4:Block: + Variable(6, Boolean) = Fcmp One, Variable(2, Double), Variable(5, Double) + Call id(3), args( Variable(6, Boolean), Pointer, ) + Return + Block 5:Block: + Variable(5, Double) = Store Double(1.1) + Jump(4) + Block 6:Block: + Variable(5, Double) = Store Double(0.1) + Jump(4)"#]], + ); +} + +#[test] +fn double_greater_than_comparison_with_lhs_classical_double_and_rhs_dynamic_double() { + let program = get_rir_program(indoc! { + r#" + namespace Test { + @EntryPoint() + operation Main() : Bool { + use q = Qubit(); + let i = MResetZ(q) == Zero ? 0.0 | 1.0; + 1.0 > i + } + } + "#, + }); + let measurement_callable_id = CallableId(1); + assert_callable( + &program, + measurement_callable_id, + &expect![[r#" + Callable: + name: __quantum__qis__mresetz__body + call_type: Measurement + input_type: + [0]: Qubit + [1]: Result + output_type: + body: "#]], + ); + let readout_callable_id = CallableId(2); + assert_callable( + &program, + readout_callable_id, + &expect![[r#" + Callable: + name: __quantum__qis__read_result__body + call_type: Readout + input_type: + [0]: Result + output_type: Boolean + body: "#]], + ); + let output_record_id = CallableId(3); + assert_callable( + &program, + output_record_id, + &expect![[r#" + Callable: + name: __quantum__rt__bool_record_output + call_type: OutputRecording + input_type: + [0]: Boolean + [1]: Pointer + output_type: + body: "#]], + ); + assert_blocks( + &program, + &expect![[r#" + Blocks: + Block 0:Block: + Call id(1), args( Qubit(0), Result(0), ) + Variable(0, Boolean) = Call id(2), args( Result(0), ) + Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false) + Branch Variable(1, Boolean), 2, 3 + Block 1:Block: + Variable(3, Boolean) = Fcmp Ogt, Double(1), Variable(2, Double) + Call id(3), args( Variable(3, Boolean), Pointer, ) + Return + Block 2:Block: + Variable(2, Double) = Store Double(0) + Jump(1) + Block 3:Block: + Variable(2, Double) = Store Double(1) + Jump(1)"#]], + ); +} + +#[test] +fn double_greater_or_equal_than_comparison_with_lhs_dynamic_double_and_rhs_classical_double() { + let program = get_rir_program(indoc! { + r#" + namespace Test { + @EntryPoint() + operation Main() : Bool { + use q = Qubit(); + let i = MResetZ(q) == Zero ? 0.0 | 1.0; + i >= 1.0 + } + } + "#, + }); + let measurement_callable_id = CallableId(1); + assert_callable( + &program, + measurement_callable_id, + &expect![[r#" + Callable: + name: __quantum__qis__mresetz__body + call_type: Measurement + input_type: + [0]: Qubit + [1]: Result + output_type: + body: "#]], + ); + let readout_callable_id = CallableId(2); + assert_callable( + &program, + readout_callable_id, + &expect![[r#" + Callable: + name: __quantum__qis__read_result__body + call_type: Readout + input_type: + [0]: Result + output_type: Boolean + body: "#]], + ); + let output_record_id = CallableId(3); + assert_callable( + &program, + output_record_id, + &expect![[r#" + Callable: + name: __quantum__rt__bool_record_output + call_type: OutputRecording + input_type: + [0]: Boolean + [1]: Pointer + output_type: + body: "#]], + ); + assert_blocks( + &program, + &expect![[r#" + Blocks: + Block 0:Block: + Call id(1), args( Qubit(0), Result(0), ) + Variable(0, Boolean) = Call id(2), args( Result(0), ) + Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false) + Branch Variable(1, Boolean), 2, 3 + Block 1:Block: + Variable(3, Boolean) = Fcmp Oge, Variable(2, Double), Double(1) + Call id(3), args( Variable(3, Boolean), Pointer, ) + Return + Block 2:Block: + Variable(2, Double) = Store Double(0) + Jump(1) + Block 3:Block: + Variable(2, Double) = Store Double(1) + Jump(1)"#]], + ); +} + +#[test] +fn double_less_than_comparison_with_lhs_dynamic_double_and_rhs_dynamic_double() { + let program = get_rir_program(indoc! { + r#" + namespace Test { + @EntryPoint() + operation Main() : Bool { + use q = Qubit(); + let a = MResetZ(q) == Zero ? 0.0 | 1.0; + let b = MResetZ(q) == Zero ? 1.1 | 0.1; + a < b + } + } + "#, + }); + let measurement_callable_id = CallableId(1); + assert_callable( + &program, + measurement_callable_id, + &expect![[r#" + Callable: + name: __quantum__qis__mresetz__body + call_type: Measurement + input_type: + [0]: Qubit + [1]: Result + output_type: + body: "#]], + ); + let readout_callable_id = CallableId(2); + assert_callable( + &program, + readout_callable_id, + &expect![[r#" + Callable: + name: __quantum__qis__read_result__body + call_type: Readout + input_type: + [0]: Result + output_type: Boolean + body: "#]], + ); + let output_record_id = CallableId(3); + assert_callable( + &program, + output_record_id, + &expect![[r#" + Callable: + name: __quantum__rt__bool_record_output + call_type: OutputRecording + input_type: + [0]: Boolean + [1]: Pointer + output_type: + body: "#]], + ); + assert_blocks( + &program, + &expect![[r#" + Blocks: + Block 0:Block: + Call id(1), args( Qubit(0), Result(0), ) + Variable(0, Boolean) = Call id(2), args( Result(0), ) + Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false) + Branch Variable(1, Boolean), 2, 3 + Block 1:Block: + Call id(1), args( Qubit(0), Result(1), ) + Variable(3, Boolean) = Call id(2), args( Result(1), ) + Variable(4, Boolean) = Icmp Eq, Variable(3, Boolean), Bool(false) + Branch Variable(4, Boolean), 5, 6 + Block 2:Block: + Variable(2, Double) = Store Double(0) + Jump(1) + Block 3:Block: + Variable(2, Double) = Store Double(1) + Jump(1) + Block 4:Block: + Variable(6, Boolean) = Fcmp Olt, Variable(2, Double), Variable(5, Double) + Call id(3), args( Variable(6, Boolean), Pointer, ) + Return + Block 5:Block: + Variable(5, Double) = Store Double(1.1) + Jump(4) + Block 6:Block: + Variable(5, Double) = Store Double(0.1) + Jump(4)"#]], + ); +} + +#[test] +fn double_less_or_equal_than_comparison_with_lhs_classical_double_and_rhs_dynamic_double() { + let program = get_rir_program(indoc! { + r#" + namespace Test { + @EntryPoint() + operation Main() : Bool { + use q = Qubit(); + let i = MResetZ(q) == Zero ? 0.0 | 1.0; + 1.0 <= i + } + } + "#, + }); + let measurement_callable_id = CallableId(1); + assert_callable( + &program, + measurement_callable_id, + &expect![[r#" + Callable: + name: __quantum__qis__mresetz__body + call_type: Measurement + input_type: + [0]: Qubit + [1]: Result + output_type: + body: "#]], + ); + let readout_callable_id = CallableId(2); + assert_callable( + &program, + readout_callable_id, + &expect![[r#" + Callable: + name: __quantum__qis__read_result__body + call_type: Readout + input_type: + [0]: Result + output_type: Boolean + body: "#]], + ); + let output_record_id = CallableId(3); + assert_callable( + &program, + output_record_id, + &expect![[r#" + Callable: + name: __quantum__rt__bool_record_output + call_type: OutputRecording + input_type: + [0]: Boolean + [1]: Pointer + output_type: + body: "#]], + ); + assert_blocks( + &program, + &expect![[r#" + Blocks: + Block 0:Block: + Call id(1), args( Qubit(0), Result(0), ) + Variable(0, Boolean) = Call id(2), args( Result(0), ) + Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false) + Branch Variable(1, Boolean), 2, 3 + Block 1:Block: + Variable(3, Boolean) = Fcmp Ole, Double(1), Variable(2, Double) + Call id(3), args( Variable(3, Boolean), Pointer, ) + Return + Block 2:Block: + Variable(2, Double) = Store Double(0) + Jump(1) + Block 3:Block: + Variable(2, Double) = Store Double(1) + Jump(1)"#]], + ); +} diff --git a/compiler/qsc_partial_eval/src/tests/output_recording.rs b/compiler/qsc_partial_eval/src/tests/output_recording.rs index 364aec51bd..3cae8ea70d 100644 --- a/compiler/qsc_partial_eval/src/tests/output_recording.rs +++ b/compiler/qsc_partial_eval/src/tests/output_recording.rs @@ -401,6 +401,48 @@ fn output_recording_for_literal_bool() { .assert_eq(&program.to_string()); } +#[test] +fn output_recording_for_literal_double() { + let program = get_rir_program(indoc! { + r#" + namespace Test { + @EntryPoint() + operation Main() : Double { + 42.1 + } + } + "#, + }); + + expect![[r#" + Program: + entry: 0 + callables: + Callable 0: Callable: + name: main + call_type: Regular + input_type: + output_type: + body: 0 + Callable 1: Callable: + name: __quantum__rt__double_record_output + call_type: OutputRecording + input_type: + [0]: Double + [1]: Pointer + output_type: + body: + blocks: + Block 0: Block: + Call id(1), args( Double(42.1), Pointer, ) + Return + config: Config: + capabilities: TargetCapabilityFlags(Adaptive | IntegerComputations | FloatingPointComputations | BackwardsBranching | HigherLevelConstructs | QubitReset) + num_qubits: 0 + num_results: 0"#]] + .assert_eq(&program.to_string()); +} + #[test] fn output_recording_for_literal_int() { let program = get_rir_program(indoc! { diff --git a/compiler/qsc_passes/src/capabilitiesck.rs b/compiler/qsc_passes/src/capabilitiesck.rs index 3ccfac3195..e10df9d8a4 100644 --- a/compiler/qsc_passes/src/capabilitiesck.rs +++ b/compiler/qsc_passes/src/capabilitiesck.rs @@ -10,6 +10,9 @@ mod tests_adaptive; #[cfg(test)] mod tests_adaptive_plus_integers; +#[cfg(test)] +mod tests_adaptive_plus_integers_and_floats; + #[cfg(test)] pub mod tests_common; diff --git a/compiler/qsc_passes/src/capabilitiesck/tests_adaptive_plus_integers_and_floats.rs b/compiler/qsc_passes/src/capabilitiesck/tests_adaptive_plus_integers_and_floats.rs new file mode 100644 index 0000000000..53e331051a --- /dev/null +++ b/compiler/qsc_passes/src/capabilitiesck/tests_adaptive_plus_integers_and_floats.rs @@ -0,0 +1,607 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +use crate::capabilitiesck::tests_common::USE_DYNAMIC_RANGE; + +use super::tests_common::{ + check, check_for_exe, CALL_DYNAMIC_FUNCTION, CALL_DYNAMIC_OPERATION, + CALL_TO_CYCLIC_FUNCTION_WITH_CLASSICAL_ARGUMENT, CALL_TO_CYCLIC_FUNCTION_WITH_DYNAMIC_ARGUMENT, + CALL_TO_CYCLIC_OPERATION_WITH_CLASSICAL_ARGUMENT, + CALL_TO_CYCLIC_OPERATION_WITH_DYNAMIC_ARGUMENT, CALL_UNRESOLVED_FUNCTION, CUSTOM_MEASUREMENT, + LOOP_WITH_DYNAMIC_CONDITION, MEASUREMENT_WITHIN_DYNAMIC_SCOPE, MINIMAL, + RETURN_WITHIN_DYNAMIC_SCOPE, USE_CLOSURE_FUNCTION, USE_DYNAMICALLY_SIZED_ARRAY, + USE_DYNAMIC_BIG_INT, USE_DYNAMIC_BOOLEAN, USE_DYNAMIC_DOUBLE, USE_DYNAMIC_FUNCTION, + USE_DYNAMIC_INDEX, USE_DYNAMIC_INT, USE_DYNAMIC_LHS_EXP_BINOP, USE_DYNAMIC_OPERATION, + USE_DYNAMIC_PAULI, USE_DYNAMIC_QUBIT, USE_DYNAMIC_RHS_EXP_BINOP, USE_DYNAMIC_STRING, + USE_DYNAMIC_UDT, USE_ENTRY_POINT_INT_ARRAY_IN_TUPLE, USE_ENTRY_POINT_STATIC_BIG_INT, + USE_ENTRY_POINT_STATIC_BOOL, USE_ENTRY_POINT_STATIC_DOUBLE, USE_ENTRY_POINT_STATIC_INT, + USE_ENTRY_POINT_STATIC_INT_IN_TUPLE, USE_ENTRY_POINT_STATIC_PAULI, + USE_ENTRY_POINT_STATIC_RANGE, USE_ENTRY_POINT_STATIC_STRING, +}; +use expect_test::{expect, Expect}; +use qsc_data_structures::target::TargetCapabilityFlags; + +fn check_profile(source: &str, expect: &Expect) { + check( + source, + expect, + TargetCapabilityFlags::Adaptive + | TargetCapabilityFlags::IntegerComputations + | TargetCapabilityFlags::FloatingPointComputations, + ); +} + +fn check_profile_for_exe(source: &str, expect: &Expect) { + check_for_exe( + source, + expect, + TargetCapabilityFlags::Adaptive + | TargetCapabilityFlags::IntegerComputations + | TargetCapabilityFlags::FloatingPointComputations, + ); +} + +#[test] +fn minimal_program_yields_no_errors() { + check_profile( + MINIMAL, + &expect![[r#" + [] + "#]], + ); +} + +#[test] +fn use_of_dynamic_boolean_yields_no_errors() { + check_profile( + USE_DYNAMIC_BOOLEAN, + &expect![[r#" + [] + "#]], + ); +} + +#[test] +fn use_of_dynamic_int_yields_no_errors() { + check_profile( + USE_DYNAMIC_INT, + &expect![[r#" + [] + "#]], + ); +} + +#[test] +fn use_of_dynamic_pauli_yields_error() { + check_profile( + USE_DYNAMIC_PAULI, + &expect![[r#" + [ + UseOfDynamicPauli( + Span { + lo: 104, + hi: 134, + }, + ), + ] + "#]], + ); +} + +#[test] +fn use_of_dynamic_range_yields_error() { + check_profile( + USE_DYNAMIC_RANGE, + &expect![[r#" + [ + UseOfDynamicRange( + Span { + lo: 108, + hi: 137, + }, + ), + ] + "#]], + ); +} + +#[test] +fn use_of_dynamic_double_yields_no_errors() { + check_profile( + USE_DYNAMIC_DOUBLE, + &expect![[r#" + [] + "#]], + ); +} + +#[test] +fn use_of_dynamic_qubit_yields_errors() { + check_profile( + USE_DYNAMIC_QUBIT, + &expect![[r#" + [ + UseOfDynamicQubit( + Span { + lo: 146, + hi: 162, + }, + ), + ] + "#]], + ); +} + +#[test] +fn use_of_dynamic_big_int_yields_errors() { + check_profile( + USE_DYNAMIC_BIG_INT, + &expect![[r#" + [ + UseOfDynamicBigInt( + Span { + lo: 227, + hi: 265, + }, + ), + ] + "#]], + ); +} + +#[test] +fn use_of_dynamic_string_yields_errors() { + check_profile( + USE_DYNAMIC_STRING, + &expect![[r#" + [ + UseOfDynamicString( + Span { + lo: 130, + hi: 144, + }, + ), + ] + "#]], + ); +} + +#[test] +fn use_of_dynamically_sized_array_yields_error() { + check_profile( + USE_DYNAMICALLY_SIZED_ARRAY, + &expect![[r#" + [ + UseOfDynamicallySizedArray( + Span { + lo: 104, + hi: 136, + }, + ), + ] + "#]], + ); +} + +#[test] +fn use_of_dynamic_udt_yields_errors() { + check_profile( + USE_DYNAMIC_UDT, + &expect![[r#" + [ + UseOfDynamicUdt( + Span { + lo: 253, + hi: 305, + }, + ), + ] + "#]], + ); +} + +#[test] +fn use_of_dynamic_function_yields_errors() { + check_profile( + USE_DYNAMIC_FUNCTION, + &expect![[r#" + [ + UseOfDynamicArrowFunction( + Span { + lo: 132, + hi: 156, + }, + ), + ] + "#]], + ); +} + +#[test] +fn use_of_dynamic_operation_yields_errors() { + check_profile( + USE_DYNAMIC_OPERATION, + &expect![[r#" + [ + UseOfDynamicArrowOperation( + Span { + lo: 132, + hi: 152, + }, + ), + ] + "#]], + ); +} + +#[test] +fn call_cyclic_function_with_classical_argument_yields_no_errors() { + check_profile( + CALL_TO_CYCLIC_FUNCTION_WITH_CLASSICAL_ARGUMENT, + &expect![[r#" + [] + "#]], + ); +} + +#[test] +fn call_cyclic_function_with_dynamic_argument_yields_error() { + check_profile( + CALL_TO_CYCLIC_FUNCTION_WITH_DYNAMIC_ARGUMENT, + &expect![[r#" + [ + CallToCyclicFunctionWithDynamicArg( + Span { + lo: 211, + hi: 243, + }, + ), + ] + "#]], + ); +} + +#[test] +fn call_cyclic_operation_with_classical_argument_yields_errors() { + check_profile( + CALL_TO_CYCLIC_OPERATION_WITH_CLASSICAL_ARGUMENT, + &expect![[r#" + [ + CyclicOperationSpec( + Span { + lo: 15, + hi: 23, + }, + ), + CallToCyclicOperation( + Span { + lo: 187, + hi: 199, + }, + ), + ] + "#]], + ); +} + +#[test] +fn call_cyclic_operation_with_dynamic_argument_yields_errors() { + check_profile( + CALL_TO_CYCLIC_OPERATION_WITH_DYNAMIC_ARGUMENT, + &expect![[r#" + [ + CyclicOperationSpec( + Span { + lo: 15, + hi: 23, + }, + ), + CallToCyclicOperation( + Span { + lo: 212, + hi: 244, + }, + ), + ] + "#]], + ); +} + +#[test] +fn call_to_dynamic_function_yields_errors() { + check_profile( + CALL_DYNAMIC_FUNCTION, + &expect![[r#" + [ + UseOfDynamicArrowFunction( + Span { + lo: 132, + hi: 156, + }, + ), + UseOfDynamicArrowFunction( + Span { + lo: 170, + hi: 178, + }, + ), + CallToDynamicCallee( + Span { + lo: 170, + hi: 178, + }, + ), + ] + "#]], + ); +} + +#[test] +fn call_to_dynamic_operation_yields_errors() { + check_profile( + CALL_DYNAMIC_OPERATION, + &expect![[r#" + [ + UseOfDynamicArrowOperation( + Span { + lo: 132, + hi: 152, + }, + ), + UseOfDynamicArrowOperation( + Span { + lo: 166, + hi: 171, + }, + ), + CallToDynamicCallee( + Span { + lo: 166, + hi: 171, + }, + ), + ] + "#]], + ); +} + +#[test] +fn call_to_unresolved_allowed() { + check_profile( + CALL_UNRESOLVED_FUNCTION, + &expect![[r#" + [] + "#]], + ); +} + +#[test] +fn measurement_within_dynamic_scope_yields_no_errors() { + check_profile( + MEASUREMENT_WITHIN_DYNAMIC_SCOPE, + &expect![[r#" + [] + "#]], + ); +} + +#[test] +fn custom_measurement_yields_no_errors() { + check_profile( + CUSTOM_MEASUREMENT, + &expect![[r#" + [] + "#]], + ); +} + +#[test] +fn use_of_dynamic_index_yields_errors() { + check_profile( + USE_DYNAMIC_INDEX, + &expect![[r#" + [ + UseOfDynamicIndex( + Span { + lo: 299, + hi: 303, + }, + ), + ] + "#]], + ); +} + +#[test] +fn use_of_dynamic_lhs_exp_binop_allowed() { + check_profile( + USE_DYNAMIC_LHS_EXP_BINOP, + &expect![[r#" + [] + "#]], + ); +} + +#[test] +fn use_of_dynamic_rhs_exp_binop_yields_errors() { + check_profile( + USE_DYNAMIC_RHS_EXP_BINOP, + &expect![[r#" + [ + UseOfDynamicExponent( + Span { + lo: 138, + hi: 143, + }, + ), + ] + "#]], + ); +} + +#[test] +fn return_within_dynamic_scope_yields_no_errors() { + check_profile( + RETURN_WITHIN_DYNAMIC_SCOPE, + &expect![[r#" + [] + "#]], + ); +} + +#[test] +fn loop_with_dynamic_condition_yields_errors() { + check_profile( + LOOP_WITH_DYNAMIC_CONDITION, + &expect![[r#" + [ + UseOfDynamicRange( + Span { + lo: 141, + hi: 159, + }, + ), + LoopWithDynamicCondition( + Span { + lo: 141, + hi: 159, + }, + ), + UseOfDynamicRange( + Span { + lo: 150, + hi: 156, + }, + ), + ] + "#]], + ); +} + +#[test] +fn use_closure_allowed() { + check_profile( + USE_CLOSURE_FUNCTION, + &expect![[r#" + [] + "#]], + ); +} + +#[test] +fn use_of_static_int_return_from_entry_point_allowed() { + check_profile_for_exe( + USE_ENTRY_POINT_STATIC_INT, + &expect![[r#" + [] + "#]], + ); +} + +#[test] +fn use_of_static_double_return_from_entry_point_errors() { + check_profile_for_exe( + USE_ENTRY_POINT_STATIC_DOUBLE, + &expect![[r#" + [] + "#]], + ); +} + +#[test] +fn use_of_static_string_return_from_entry_point_errors() { + check_profile_for_exe( + USE_ENTRY_POINT_STATIC_STRING, + &expect![[r#" + [ + UseOfAdvancedOutput( + Span { + lo: 63, + hi: 66, + }, + ), + ] + "#]], + ); +} + +#[test] +fn use_of_static_bool_return_from_entry_point_supported() { + check_profile_for_exe( + USE_ENTRY_POINT_STATIC_BOOL, + &expect![[r#" + [] + "#]], + ); +} + +#[test] +fn use_of_static_big_int_return_from_entry_point_errors() { + check_profile_for_exe( + USE_ENTRY_POINT_STATIC_BIG_INT, + &expect![[r#" + [ + UseOfAdvancedOutput( + Span { + lo: 63, + hi: 66, + }, + ), + ] + "#]], + ); +} + +#[test] +fn use_of_static_pauli_return_from_entry_point_errors() { + check_profile_for_exe( + USE_ENTRY_POINT_STATIC_PAULI, + &expect![[r#" + [ + UseOfAdvancedOutput( + Span { + lo: 63, + hi: 66, + }, + ), + ] + "#]], + ); +} + +#[test] +fn use_of_static_range_return_from_entry_point_errors() { + check_profile_for_exe( + USE_ENTRY_POINT_STATIC_RANGE, + &expect![[r#" + [ + UseOfAdvancedOutput( + Span { + lo: 63, + hi: 66, + }, + ), + ] + "#]], + ); +} + +#[test] +fn use_of_static_int_in_tuple_return_from_entry_point_allowed() { + check_profile_for_exe( + USE_ENTRY_POINT_STATIC_INT_IN_TUPLE, + &expect![[r#" + [] + "#]], + ); +} + +#[test] +fn use_of_static_sized_array_in_tuple_allowed() { + check_profile_for_exe( + USE_ENTRY_POINT_INT_ARRAY_IN_TUPLE, + &expect![[r#" + [] + "#]], + ); +} diff --git a/compiler/qsc_qasm3/src/tests/output.rs b/compiler/qsc_qasm3/src/tests/output.rs index 41bf86966f..711b64e9ad 100644 --- a/compiler/qsc_qasm3/src/tests/output.rs +++ b/compiler/qsc_qasm3/src/tests/output.rs @@ -320,19 +320,13 @@ attributes #1 = { "irreversible" } ; module flags -!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10} +!llvm.module.flags = !{!0, !1, !2, !3, !4} !0 = !{i32 1, !"qir_major_version", i32 1} !1 = !{i32 7, !"qir_minor_version", i32 0} !2 = !{i32 1, !"dynamic_qubit_management", i1 false} !3 = !{i32 1, !"dynamic_result_management", i1 false} -!4 = !{i32 1, !"classical_ints", i1 true} -!5 = !{i32 1, !"qubit_resetting", i1 true} -!6 = !{i32 1, !"classical_floats", i1 false} -!7 = !{i32 1, !"backwards_branching", i1 false} -!8 = !{i32 1, !"classical_fixed_points", i1 false} -!9 = !{i32 1, !"user_functions", i1 false} -!10 = !{i32 1, !"multiple_target_branching", i1 false} +!4 = !{i32 1, !"int_computations", !"i64"} "#]] .assert_eq(&qir); diff --git a/compiler/qsc_qasm3/src/tests/statement/gate_call.rs b/compiler/qsc_qasm3/src/tests/statement/gate_call.rs index e114bd36ae..3165ccd847 100644 --- a/compiler/qsc_qasm3/src/tests/statement/gate_call.rs +++ b/compiler/qsc_qasm3/src/tests/statement/gate_call.rs @@ -111,19 +111,13 @@ fn barrier_generates_qir() -> miette::Result<(), Vec> { ; module flags - !llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10} + !llvm.module.flags = !{!0, !1, !2, !3, !4} !0 = !{i32 1, !"qir_major_version", i32 1} !1 = !{i32 7, !"qir_minor_version", i32 0} !2 = !{i32 1, !"dynamic_qubit_management", i1 false} !3 = !{i32 1, !"dynamic_result_management", i1 false} - !4 = !{i32 1, !"classical_ints", i1 true} - !5 = !{i32 1, !"qubit_resetting", i1 true} - !6 = !{i32 1, !"classical_floats", i1 false} - !7 = !{i32 1, !"backwards_branching", i1 false} - !8 = !{i32 1, !"classical_fixed_points", i1 false} - !9 = !{i32 1, !"user_functions", i1 false} - !10 = !{i32 1, !"multiple_target_branching", i1 false} + !4 = !{i32 1, !"int_computations", !"i64"} "# ] .assert_eq(&qsharp); diff --git a/compiler/qsc_qasm3/src/tests/statement/reset.rs b/compiler/qsc_qasm3/src/tests/statement/reset.rs index 9965803d87..c6d9a7b86a 100644 --- a/compiler/qsc_qasm3/src/tests/statement/reset.rs +++ b/compiler/qsc_qasm3/src/tests/statement/reset.rs @@ -154,19 +154,13 @@ fn reset_with_adaptive_ri_profile_generates_reset_qir() -> miette::Result<(), Ve ; module flags - !llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10} + !llvm.module.flags = !{!0, !1, !2, !3, !4} !0 = !{i32 1, !"qir_major_version", i32 1} !1 = !{i32 7, !"qir_minor_version", i32 0} !2 = !{i32 1, !"dynamic_qubit_management", i1 false} !3 = !{i32 1, !"dynamic_result_management", i1 false} - !4 = !{i32 1, !"classical_ints", i1 true} - !5 = !{i32 1, !"qubit_resetting", i1 true} - !6 = !{i32 1, !"classical_floats", i1 false} - !7 = !{i32 1, !"backwards_branching", i1 false} - !8 = !{i32 1, !"classical_fixed_points", i1 false} - !9 = !{i32 1, !"user_functions", i1 false} - !10 = !{i32 1, !"multiple_target_branching", i1 false} + !4 = !{i32 1, !"int_computations", !"i64"} "# ] .assert_eq(&qir); diff --git a/compiler/qsc_rir/src/builder.rs b/compiler/qsc_rir/src/builder.rs index 16cee6766a..d2ee3a74bf 100644 --- a/compiler/qsc_rir/src/builder.rs +++ b/compiler/qsc_rir/src/builder.rs @@ -118,6 +118,17 @@ pub fn result_record_decl() -> Callable { } } +#[must_use] +pub fn double_record_decl() -> Callable { + Callable { + name: "__quantum__rt__double_record_output".to_string(), + input_type: vec![Ty::Double, Ty::Pointer], + output_type: None, + body: None, + call_type: CallableType::OutputRecording, + } +} + #[must_use] pub fn int_record_decl() -> Callable { Callable { diff --git a/compiler/qsc_rir/src/passes/ssa_check.rs b/compiler/qsc_rir/src/passes/ssa_check.rs index a4a487c1c9..218725650d 100644 --- a/compiler/qsc_rir/src/passes/ssa_check.rs +++ b/compiler/qsc_rir/src/passes/ssa_check.rs @@ -95,6 +95,7 @@ fn check_phi_nodes(program: &Program, preds: &IndexMap>) { } } +#[allow(clippy::too_many_lines)] fn get_variable_uses(program: &Program) -> IndexMap> { let mut uses: IndexMap> = IndexMap::default(); let mut add_use = |var_id, block_id, idx| { @@ -122,6 +123,16 @@ fn get_variable_uses(program: &Program) -> IndexMap IndexMap IndexMap { + Instruction::Fcmp(_, opr1, opr2, var) | Instruction::Icmp(_, opr1, opr2, var) => { assert_eq!(opr1.get_type(), opr2.get_type()); assert_eq!(Ty::Boolean, var.ty); } diff --git a/compiler/qsc_rir/src/rir.rs b/compiler/qsc_rir/src/rir.rs index 5d529042a6..acb6793ef7 100644 --- a/compiler/qsc_rir/src/rir.rs +++ b/compiler/qsc_rir/src/rir.rs @@ -214,6 +214,19 @@ pub enum CallableType { Regular, } +impl Display for CallableType { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + match &self { + Self::Measurement => write!(f, "Measurement")?, + Self::Readout => write!(f, "Readout")?, + Self::OutputRecording => write!(f, "OutputRecording")?, + Self::Regular => write!(f, "Regular")?, + Self::Reset => write!(f, "Reset")?, + }; + Ok(()) + } +} + #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum ConditionCode { Eq, @@ -238,14 +251,45 @@ impl Display for ConditionCode { } } -impl Display for CallableType { +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum FcmpConditionCode { + False, + OrderedAndEqual, + OrderedAndGreaterThan, + OrderedAndGreaterThanOrEqual, + OrderedAndLessThan, + OrderedAndLessThanOrEqual, + OrderedAndNotEqual, + Ordered, + UnorderedOrEqual, + UnorderedOrGreaterThan, + UnorderedOrGreaterThanOrEqual, + UnorderedOrLessThan, + UnorderedOrLessThanOrEqual, + UnorderedOrNotEqual, + Unordered, + True, +} + +impl Display for FcmpConditionCode { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match &self { - Self::Measurement => write!(f, "Measurement")?, - Self::Readout => write!(f, "Readout")?, - Self::OutputRecording => write!(f, "OutputRecording")?, - Self::Regular => write!(f, "Regular")?, - Self::Reset => write!(f, "Reset")?, + Self::False => write!(f, "False")?, + Self::OrderedAndEqual => write!(f, "Oeq")?, + Self::OrderedAndGreaterThan => write!(f, "Ogt")?, + Self::OrderedAndGreaterThanOrEqual => write!(f, "Oge")?, + Self::OrderedAndLessThan => write!(f, "Olt")?, + Self::OrderedAndLessThanOrEqual => write!(f, "Ole")?, + Self::OrderedAndNotEqual => write!(f, "One")?, + Self::Ordered => write!(f, "Ord")?, + Self::UnorderedOrEqual => write!(f, "Ueq")?, + Self::UnorderedOrGreaterThan => write!(f, "Ugt")?, + Self::UnorderedOrGreaterThanOrEqual => write!(f, "Uge")?, + Self::UnorderedOrLessThan => write!(f, "Ult")?, + Self::UnorderedOrLessThanOrEqual => write!(f, "Ule")?, + Self::UnorderedOrNotEqual => write!(f, "Une")?, + Self::Unordered => write!(f, "Uno")?, + Self::True => write!(f, "True")?, }; Ok(()) } @@ -264,6 +308,11 @@ pub enum Instruction { Srem(Operand, Operand, Variable), Shl(Operand, Operand, Variable), Ashr(Operand, Operand, Variable), + Fadd(Operand, Operand, Variable), + Fsub(Operand, Operand, Variable), + Fmul(Operand, Operand, Variable), + Fdiv(Operand, Operand, Variable), + Fcmp(FcmpConditionCode, Operand, Operand, Variable), Icmp(ConditionCode, Operand, Operand, Variable), LogicalNot(Operand, Variable), LogicalAnd(Operand, Operand, Variable), @@ -331,6 +380,18 @@ impl Display for Instruction { Ok(()) } + fn write_fcmp_instruction( + f: &mut Formatter, + condition: FcmpConditionCode, + lhs: &Operand, + rhs: &Operand, + variable: Variable, + ) -> fmt::Result { + let mut indent = set_indentation(indented(f), 0); + write!(indent, "{variable} = Fcmp {condition}, {lhs}, {rhs}")?; + Ok(()) + } + fn write_icmp_instruction( f: &mut Formatter, condition: ConditionCode, @@ -408,6 +469,21 @@ impl Display for Instruction { Self::Ashr(lhs, rhs, variable) => { write_binary_instruction(f, "Ashr", lhs, rhs, *variable)?; } + Self::Fadd(lhs, rhs, variable) => { + write_binary_instruction(f, "Fadd", lhs, rhs, *variable)?; + } + Self::Fsub(lhs, rhs, variable) => { + write_binary_instruction(f, "Fsub", lhs, rhs, *variable)?; + } + Self::Fmul(lhs, rhs, variable) => { + write_binary_instruction(f, "Fmul", lhs, rhs, *variable)?; + } + Self::Fdiv(lhs, rhs, variable) => { + write_binary_instruction(f, "Fdiv", lhs, rhs, *variable)?; + } + Self::Fcmp(op, lhs, rhs, variable) => { + write_fcmp_instruction(f, *op, lhs, rhs, *variable)?; + } Self::Icmp(op, lhs, rhs, variable) => { write_icmp_instruction(f, *op, lhs, rhs, *variable)?; } diff --git a/compiler/qsc_rir/src/utils.rs b/compiler/qsc_rir/src/utils.rs index f38f2d43ac..1a5c99e575 100644 --- a/compiler/qsc_rir/src/utils.rs +++ b/compiler/qsc_rir/src/utils.rs @@ -85,6 +85,11 @@ pub fn get_variable_assignments(program: &Program) -> IndexMap for TargetProfile { match profile { Profile::Base => TargetProfile::Base, Profile::AdaptiveRI => TargetProfile::Adaptive_RI, + Profile::AdaptiveRIF => TargetProfile::Adaptive_RIF, Profile::Unrestricted => TargetProfile::Unrestricted, } } @@ -146,6 +153,7 @@ impl From for Profile { match profile { TargetProfile::Base => Profile::Base, TargetProfile::Adaptive_RI => Profile::AdaptiveRI, + TargetProfile::Adaptive_RIF => Profile::AdaptiveRIF, TargetProfile::Unrestricted => Profile::Unrestricted, } } diff --git a/pip/tests-integration/interop_qiskit/resources/custom_intrinsics.ll b/pip/tests-integration/interop_qiskit/resources/custom_intrinsics.ll index aeaeae4fce..ec42527787 100644 --- a/pip/tests-integration/interop_qiskit/resources/custom_intrinsics.ll +++ b/pip/tests-integration/interop_qiskit/resources/custom_intrinsics.ll @@ -23,16 +23,10 @@ attributes #1 = { "irreversible" } ; module flags -!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10} +!llvm.module.flags = !{!0, !1, !2, !3, !4} !0 = !{i32 1, !"qir_major_version", i32 1} !1 = !{i32 7, !"qir_minor_version", i32 0} !2 = !{i32 1, !"dynamic_qubit_management", i1 false} !3 = !{i32 1, !"dynamic_result_management", i1 false} -!4 = !{i32 1, !"classical_ints", i1 true} -!5 = !{i32 1, !"qubit_resetting", i1 true} -!6 = !{i32 1, !"classical_floats", i1 false} -!7 = !{i32 1, !"backwards_branching", i1 false} -!8 = !{i32 1, !"classical_fixed_points", i1 false} -!9 = !{i32 1, !"user_functions", i1 false} -!10 = !{i32 1, !"multiple_target_branching", i1 false} +!4 = !{i32 1, !"int_computations", !"i64"} diff --git a/pip/tests-integration/resources/output/Adaptive_RI/ArithmeticOps.ll b/pip/tests-integration/resources/output/Adaptive_RI/ArithmeticOps.ll index cf12385b1c..48cb6e99ca 100644 --- a/pip/tests-integration/resources/output/Adaptive_RI/ArithmeticOps.ll +++ b/pip/tests-integration/resources/output/Adaptive_RI/ArithmeticOps.ll @@ -104,16 +104,10 @@ attributes #1 = { "irreversible" } ; module flags -!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10} +!llvm.module.flags = !{!0, !1, !2, !3, !4} !0 = !{i32 1, !"qir_major_version", i32 1} !1 = !{i32 7, !"qir_minor_version", i32 0} !2 = !{i32 1, !"dynamic_qubit_management", i1 false} !3 = !{i32 1, !"dynamic_result_management", i1 false} -!4 = !{i32 1, !"classical_ints", i1 true} -!5 = !{i32 1, !"qubit_resetting", i1 true} -!6 = !{i32 1, !"classical_floats", i1 false} -!7 = !{i32 1, !"backwards_branching", i1 false} -!8 = !{i32 1, !"classical_fixed_points", i1 false} -!9 = !{i32 1, !"user_functions", i1 false} -!10 = !{i32 1, !"multiple_target_branching", i1 false} +!4 = !{i32 1, !"int_computations", !"i64"} diff --git a/pip/tests-integration/resources/output/Adaptive_RI/BernsteinVaziraniNISQ.ll b/pip/tests-integration/resources/output/Adaptive_RI/BernsteinVaziraniNISQ.ll index 5090b31980..69cf1cc955 100644 --- a/pip/tests-integration/resources/output/Adaptive_RI/BernsteinVaziraniNISQ.ll +++ b/pip/tests-integration/resources/output/Adaptive_RI/BernsteinVaziraniNISQ.ll @@ -52,16 +52,10 @@ attributes #1 = { "irreversible" } ; module flags -!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10} +!llvm.module.flags = !{!0, !1, !2, !3, !4} !0 = !{i32 1, !"qir_major_version", i32 1} !1 = !{i32 7, !"qir_minor_version", i32 0} !2 = !{i32 1, !"dynamic_qubit_management", i1 false} !3 = !{i32 1, !"dynamic_result_management", i1 false} -!4 = !{i32 1, !"classical_ints", i1 true} -!5 = !{i32 1, !"qubit_resetting", i1 true} -!6 = !{i32 1, !"classical_floats", i1 false} -!7 = !{i32 1, !"backwards_branching", i1 false} -!8 = !{i32 1, !"classical_fixed_points", i1 false} -!9 = !{i32 1, !"user_functions", i1 false} -!10 = !{i32 1, !"multiple_target_branching", i1 false} +!4 = !{i32 1, !"int_computations", !"i64"} diff --git a/pip/tests-integration/resources/output/Adaptive_RI/ConstantFolding.ll b/pip/tests-integration/resources/output/Adaptive_RI/ConstantFolding.ll index b0f16a396a..27f3219d4c 100644 --- a/pip/tests-integration/resources/output/Adaptive_RI/ConstantFolding.ll +++ b/pip/tests-integration/resources/output/Adaptive_RI/ConstantFolding.ll @@ -58,16 +58,10 @@ attributes #1 = { "irreversible" } ; module flags -!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10} +!llvm.module.flags = !{!0, !1, !2, !3, !4} !0 = !{i32 1, !"qir_major_version", i32 1} !1 = !{i32 7, !"qir_minor_version", i32 0} !2 = !{i32 1, !"dynamic_qubit_management", i1 false} !3 = !{i32 1, !"dynamic_result_management", i1 false} -!4 = !{i32 1, !"classical_ints", i1 true} -!5 = !{i32 1, !"qubit_resetting", i1 true} -!6 = !{i32 1, !"classical_floats", i1 false} -!7 = !{i32 1, !"backwards_branching", i1 false} -!8 = !{i32 1, !"classical_fixed_points", i1 false} -!9 = !{i32 1, !"user_functions", i1 false} -!10 = !{i32 1, !"multiple_target_branching", i1 false} +!4 = !{i32 1, !"int_computations", !"i64"} diff --git a/pip/tests-integration/resources/output/Adaptive_RI/CopyAndUpdateExpressions.ll b/pip/tests-integration/resources/output/Adaptive_RI/CopyAndUpdateExpressions.ll index 089078113a..d41ab82173 100644 --- a/pip/tests-integration/resources/output/Adaptive_RI/CopyAndUpdateExpressions.ll +++ b/pip/tests-integration/resources/output/Adaptive_RI/CopyAndUpdateExpressions.ll @@ -43,16 +43,10 @@ attributes #1 = { "irreversible" } ; module flags -!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10} +!llvm.module.flags = !{!0, !1, !2, !3, !4} !0 = !{i32 1, !"qir_major_version", i32 1} !1 = !{i32 7, !"qir_minor_version", i32 0} !2 = !{i32 1, !"dynamic_qubit_management", i1 false} !3 = !{i32 1, !"dynamic_result_management", i1 false} -!4 = !{i32 1, !"classical_ints", i1 true} -!5 = !{i32 1, !"qubit_resetting", i1 true} -!6 = !{i32 1, !"classical_floats", i1 false} -!7 = !{i32 1, !"backwards_branching", i1 false} -!8 = !{i32 1, !"classical_fixed_points", i1 false} -!9 = !{i32 1, !"user_functions", i1 false} -!10 = !{i32 1, !"multiple_target_branching", i1 false} +!4 = !{i32 1, !"int_computations", !"i64"} diff --git a/pip/tests-integration/resources/output/Adaptive_RI/DeutschJozsaNISQ.ll b/pip/tests-integration/resources/output/Adaptive_RI/DeutschJozsaNISQ.ll index 93f74a3fcf..4f038c599c 100644 --- a/pip/tests-integration/resources/output/Adaptive_RI/DeutschJozsaNISQ.ll +++ b/pip/tests-integration/resources/output/Adaptive_RI/DeutschJozsaNISQ.ll @@ -78,16 +78,10 @@ attributes #1 = { "irreversible" } ; module flags -!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10} +!llvm.module.flags = !{!0, !1, !2, !3, !4} !0 = !{i32 1, !"qir_major_version", i32 1} !1 = !{i32 7, !"qir_minor_version", i32 0} !2 = !{i32 1, !"dynamic_qubit_management", i1 false} !3 = !{i32 1, !"dynamic_result_management", i1 false} -!4 = !{i32 1, !"classical_ints", i1 true} -!5 = !{i32 1, !"qubit_resetting", i1 true} -!6 = !{i32 1, !"classical_floats", i1 false} -!7 = !{i32 1, !"backwards_branching", i1 false} -!8 = !{i32 1, !"classical_fixed_points", i1 false} -!9 = !{i32 1, !"user_functions", i1 false} -!10 = !{i32 1, !"multiple_target_branching", i1 false} +!4 = !{i32 1, !"int_computations", !"i64"} diff --git a/pip/tests-integration/resources/output/Adaptive_RI/ExpandedTests.ll b/pip/tests-integration/resources/output/Adaptive_RI/ExpandedTests.ll index 621ceaa380..4794a9960c 100644 --- a/pip/tests-integration/resources/output/Adaptive_RI/ExpandedTests.ll +++ b/pip/tests-integration/resources/output/Adaptive_RI/ExpandedTests.ll @@ -75,16 +75,10 @@ attributes #1 = { "irreversible" } ; module flags -!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10} +!llvm.module.flags = !{!0, !1, !2, !3, !4} !0 = !{i32 1, !"qir_major_version", i32 1} !1 = !{i32 7, !"qir_minor_version", i32 0} !2 = !{i32 1, !"dynamic_qubit_management", i1 false} !3 = !{i32 1, !"dynamic_result_management", i1 false} -!4 = !{i32 1, !"classical_ints", i1 true} -!5 = !{i32 1, !"qubit_resetting", i1 true} -!6 = !{i32 1, !"classical_floats", i1 false} -!7 = !{i32 1, !"backwards_branching", i1 false} -!8 = !{i32 1, !"classical_fixed_points", i1 false} -!9 = !{i32 1, !"user_functions", i1 false} -!10 = !{i32 1, !"multiple_target_branching", i1 false} +!4 = !{i32 1, !"int_computations", !"i64"} diff --git a/pip/tests-integration/resources/output/Adaptive_RI/Functors.ll b/pip/tests-integration/resources/output/Adaptive_RI/Functors.ll index b30fe0aeb3..7901410523 100644 --- a/pip/tests-integration/resources/output/Adaptive_RI/Functors.ll +++ b/pip/tests-integration/resources/output/Adaptive_RI/Functors.ll @@ -108,16 +108,10 @@ attributes #1 = { "irreversible" } ; module flags -!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10} +!llvm.module.flags = !{!0, !1, !2, !3, !4} !0 = !{i32 1, !"qir_major_version", i32 1} !1 = !{i32 7, !"qir_minor_version", i32 0} !2 = !{i32 1, !"dynamic_qubit_management", i1 false} !3 = !{i32 1, !"dynamic_result_management", i1 false} -!4 = !{i32 1, !"classical_ints", i1 true} -!5 = !{i32 1, !"qubit_resetting", i1 true} -!6 = !{i32 1, !"classical_floats", i1 false} -!7 = !{i32 1, !"backwards_branching", i1 false} -!8 = !{i32 1, !"classical_fixed_points", i1 false} -!9 = !{i32 1, !"user_functions", i1 false} -!10 = !{i32 1, !"multiple_target_branching", i1 false} +!4 = !{i32 1, !"int_computations", !"i64"} diff --git a/pip/tests-integration/resources/output/Adaptive_RI/HiddenShiftNISQ.ll b/pip/tests-integration/resources/output/Adaptive_RI/HiddenShiftNISQ.ll index 15ea0bfe99..8bc3b5d4d0 100644 --- a/pip/tests-integration/resources/output/Adaptive_RI/HiddenShiftNISQ.ll +++ b/pip/tests-integration/resources/output/Adaptive_RI/HiddenShiftNISQ.ll @@ -64,16 +64,10 @@ attributes #1 = { "irreversible" } ; module flags -!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10} +!llvm.module.flags = !{!0, !1, !2, !3, !4} !0 = !{i32 1, !"qir_major_version", i32 1} !1 = !{i32 7, !"qir_minor_version", i32 0} !2 = !{i32 1, !"dynamic_qubit_management", i1 false} !3 = !{i32 1, !"dynamic_result_management", i1 false} -!4 = !{i32 1, !"classical_ints", i1 true} -!5 = !{i32 1, !"qubit_resetting", i1 true} -!6 = !{i32 1, !"classical_floats", i1 false} -!7 = !{i32 1, !"backwards_branching", i1 false} -!8 = !{i32 1, !"classical_fixed_points", i1 false} -!9 = !{i32 1, !"user_functions", i1 false} -!10 = !{i32 1, !"multiple_target_branching", i1 false} +!4 = !{i32 1, !"int_computations", !"i64"} diff --git a/pip/tests-integration/resources/output/Adaptive_RI/IntegerComparison.ll b/pip/tests-integration/resources/output/Adaptive_RI/IntegerComparison.ll index 600b675c2c..95e95a7e64 100644 --- a/pip/tests-integration/resources/output/Adaptive_RI/IntegerComparison.ll +++ b/pip/tests-integration/resources/output/Adaptive_RI/IntegerComparison.ll @@ -130,16 +130,10 @@ attributes #1 = { "irreversible" } ; module flags -!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10} +!llvm.module.flags = !{!0, !1, !2, !3, !4} !0 = !{i32 1, !"qir_major_version", i32 1} !1 = !{i32 7, !"qir_minor_version", i32 0} !2 = !{i32 1, !"dynamic_qubit_management", i1 false} !3 = !{i32 1, !"dynamic_result_management", i1 false} -!4 = !{i32 1, !"classical_ints", i1 true} -!5 = !{i32 1, !"qubit_resetting", i1 true} -!6 = !{i32 1, !"classical_floats", i1 false} -!7 = !{i32 1, !"backwards_branching", i1 false} -!8 = !{i32 1, !"classical_fixed_points", i1 false} -!9 = !{i32 1, !"user_functions", i1 false} -!10 = !{i32 1, !"multiple_target_branching", i1 false} +!4 = !{i32 1, !"int_computations", !"i64"} diff --git a/pip/tests-integration/resources/output/Adaptive_RI/IntrinsicCCNOT.ll b/pip/tests-integration/resources/output/Adaptive_RI/IntrinsicCCNOT.ll index 54f8807727..bb5df300ae 100644 --- a/pip/tests-integration/resources/output/Adaptive_RI/IntrinsicCCNOT.ll +++ b/pip/tests-integration/resources/output/Adaptive_RI/IntrinsicCCNOT.ll @@ -62,16 +62,10 @@ attributes #1 = { "irreversible" } ; module flags -!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10} +!llvm.module.flags = !{!0, !1, !2, !3, !4} !0 = !{i32 1, !"qir_major_version", i32 1} !1 = !{i32 7, !"qir_minor_version", i32 0} !2 = !{i32 1, !"dynamic_qubit_management", i1 false} !3 = !{i32 1, !"dynamic_result_management", i1 false} -!4 = !{i32 1, !"classical_ints", i1 true} -!5 = !{i32 1, !"qubit_resetting", i1 true} -!6 = !{i32 1, !"classical_floats", i1 false} -!7 = !{i32 1, !"backwards_branching", i1 false} -!8 = !{i32 1, !"classical_fixed_points", i1 false} -!9 = !{i32 1, !"user_functions", i1 false} -!10 = !{i32 1, !"multiple_target_branching", i1 false} +!4 = !{i32 1, !"int_computations", !"i64"} diff --git a/pip/tests-integration/resources/output/Adaptive_RI/IntrinsicCNOT.ll b/pip/tests-integration/resources/output/Adaptive_RI/IntrinsicCNOT.ll index 1d86c703f2..cd0a097c28 100644 --- a/pip/tests-integration/resources/output/Adaptive_RI/IntrinsicCNOT.ll +++ b/pip/tests-integration/resources/output/Adaptive_RI/IntrinsicCNOT.ll @@ -43,16 +43,10 @@ attributes #1 = { "irreversible" } ; module flags -!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10} +!llvm.module.flags = !{!0, !1, !2, !3, !4} !0 = !{i32 1, !"qir_major_version", i32 1} !1 = !{i32 7, !"qir_minor_version", i32 0} !2 = !{i32 1, !"dynamic_qubit_management", i1 false} !3 = !{i32 1, !"dynamic_result_management", i1 false} -!4 = !{i32 1, !"classical_ints", i1 true} -!5 = !{i32 1, !"qubit_resetting", i1 true} -!6 = !{i32 1, !"classical_floats", i1 false} -!7 = !{i32 1, !"backwards_branching", i1 false} -!8 = !{i32 1, !"classical_fixed_points", i1 false} -!9 = !{i32 1, !"user_functions", i1 false} -!10 = !{i32 1, !"multiple_target_branching", i1 false} +!4 = !{i32 1, !"int_computations", !"i64"} diff --git a/pip/tests-integration/resources/output/Adaptive_RI/IntrinsicHIXYZ.ll b/pip/tests-integration/resources/output/Adaptive_RI/IntrinsicHIXYZ.ll index 9f1a925dd7..7572e852f8 100644 --- a/pip/tests-integration/resources/output/Adaptive_RI/IntrinsicHIXYZ.ll +++ b/pip/tests-integration/resources/output/Adaptive_RI/IntrinsicHIXYZ.ll @@ -50,16 +50,10 @@ attributes #1 = { "irreversible" } ; module flags -!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10} +!llvm.module.flags = !{!0, !1, !2, !3, !4} !0 = !{i32 1, !"qir_major_version", i32 1} !1 = !{i32 7, !"qir_minor_version", i32 0} !2 = !{i32 1, !"dynamic_qubit_management", i1 false} !3 = !{i32 1, !"dynamic_result_management", i1 false} -!4 = !{i32 1, !"classical_ints", i1 true} -!5 = !{i32 1, !"qubit_resetting", i1 true} -!6 = !{i32 1, !"classical_floats", i1 false} -!7 = !{i32 1, !"backwards_branching", i1 false} -!8 = !{i32 1, !"classical_fixed_points", i1 false} -!9 = !{i32 1, !"user_functions", i1 false} -!10 = !{i32 1, !"multiple_target_branching", i1 false} +!4 = !{i32 1, !"int_computations", !"i64"} diff --git a/pip/tests-integration/resources/output/Adaptive_RI/IntrinsicM.ll b/pip/tests-integration/resources/output/Adaptive_RI/IntrinsicM.ll index 1d479f1e0c..26915f37e2 100644 --- a/pip/tests-integration/resources/output/Adaptive_RI/IntrinsicM.ll +++ b/pip/tests-integration/resources/output/Adaptive_RI/IntrinsicM.ll @@ -29,16 +29,10 @@ attributes #1 = { "irreversible" } ; module flags -!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10} +!llvm.module.flags = !{!0, !1, !2, !3, !4} !0 = !{i32 1, !"qir_major_version", i32 1} !1 = !{i32 7, !"qir_minor_version", i32 0} !2 = !{i32 1, !"dynamic_qubit_management", i1 false} !3 = !{i32 1, !"dynamic_result_management", i1 false} -!4 = !{i32 1, !"classical_ints", i1 true} -!5 = !{i32 1, !"qubit_resetting", i1 true} -!6 = !{i32 1, !"classical_floats", i1 false} -!7 = !{i32 1, !"backwards_branching", i1 false} -!8 = !{i32 1, !"classical_fixed_points", i1 false} -!9 = !{i32 1, !"user_functions", i1 false} -!10 = !{i32 1, !"multiple_target_branching", i1 false} +!4 = !{i32 1, !"int_computations", !"i64"} diff --git a/pip/tests-integration/resources/output/Adaptive_RI/IntrinsicMeasureWithBitFlipCode.ll b/pip/tests-integration/resources/output/Adaptive_RI/IntrinsicMeasureWithBitFlipCode.ll index 8560efe53a..f7b45de39a 100644 --- a/pip/tests-integration/resources/output/Adaptive_RI/IntrinsicMeasureWithBitFlipCode.ll +++ b/pip/tests-integration/resources/output/Adaptive_RI/IntrinsicMeasureWithBitFlipCode.ll @@ -66,16 +66,10 @@ attributes #1 = { "irreversible" } ; module flags -!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10} +!llvm.module.flags = !{!0, !1, !2, !3, !4} !0 = !{i32 1, !"qir_major_version", i32 1} !1 = !{i32 7, !"qir_minor_version", i32 0} !2 = !{i32 1, !"dynamic_qubit_management", i1 false} !3 = !{i32 1, !"dynamic_result_management", i1 false} -!4 = !{i32 1, !"classical_ints", i1 true} -!5 = !{i32 1, !"qubit_resetting", i1 true} -!6 = !{i32 1, !"classical_floats", i1 false} -!7 = !{i32 1, !"backwards_branching", i1 false} -!8 = !{i32 1, !"classical_fixed_points", i1 false} -!9 = !{i32 1, !"user_functions", i1 false} -!10 = !{i32 1, !"multiple_target_branching", i1 false} +!4 = !{i32 1, !"int_computations", !"i64"} diff --git a/pip/tests-integration/resources/output/Adaptive_RI/IntrinsicMeasureWithPhaseFlipCode.ll b/pip/tests-integration/resources/output/Adaptive_RI/IntrinsicMeasureWithPhaseFlipCode.ll index 08323047b5..f537083df5 100644 --- a/pip/tests-integration/resources/output/Adaptive_RI/IntrinsicMeasureWithPhaseFlipCode.ll +++ b/pip/tests-integration/resources/output/Adaptive_RI/IntrinsicMeasureWithPhaseFlipCode.ll @@ -70,16 +70,10 @@ attributes #1 = { "irreversible" } ; module flags -!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10} +!llvm.module.flags = !{!0, !1, !2, !3, !4} !0 = !{i32 1, !"qir_major_version", i32 1} !1 = !{i32 7, !"qir_minor_version", i32 0} !2 = !{i32 1, !"dynamic_qubit_management", i1 false} !3 = !{i32 1, !"dynamic_result_management", i1 false} -!4 = !{i32 1, !"classical_ints", i1 true} -!5 = !{i32 1, !"qubit_resetting", i1 true} -!6 = !{i32 1, !"classical_floats", i1 false} -!7 = !{i32 1, !"backwards_branching", i1 false} -!8 = !{i32 1, !"classical_fixed_points", i1 false} -!9 = !{i32 1, !"user_functions", i1 false} -!10 = !{i32 1, !"multiple_target_branching", i1 false} +!4 = !{i32 1, !"int_computations", !"i64"} diff --git a/pip/tests-integration/resources/output/Adaptive_RI/IntrinsicRotationsWithPeriod.ll b/pip/tests-integration/resources/output/Adaptive_RI/IntrinsicRotationsWithPeriod.ll index a8296c64d8..e8a9984785 100644 --- a/pip/tests-integration/resources/output/Adaptive_RI/IntrinsicRotationsWithPeriod.ll +++ b/pip/tests-integration/resources/output/Adaptive_RI/IntrinsicRotationsWithPeriod.ll @@ -107,16 +107,10 @@ attributes #1 = { "irreversible" } ; module flags -!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10} +!llvm.module.flags = !{!0, !1, !2, !3, !4} !0 = !{i32 1, !"qir_major_version", i32 1} !1 = !{i32 7, !"qir_minor_version", i32 0} !2 = !{i32 1, !"dynamic_qubit_management", i1 false} !3 = !{i32 1, !"dynamic_result_management", i1 false} -!4 = !{i32 1, !"classical_ints", i1 true} -!5 = !{i32 1, !"qubit_resetting", i1 true} -!6 = !{i32 1, !"classical_floats", i1 false} -!7 = !{i32 1, !"backwards_branching", i1 false} -!8 = !{i32 1, !"classical_fixed_points", i1 false} -!9 = !{i32 1, !"user_functions", i1 false} -!10 = !{i32 1, !"multiple_target_branching", i1 false} +!4 = !{i32 1, !"int_computations", !"i64"} diff --git a/pip/tests-integration/resources/output/Adaptive_RI/IntrinsicSTSWAP.ll b/pip/tests-integration/resources/output/Adaptive_RI/IntrinsicSTSWAP.ll index ce83460a6d..6dc5de3e4b 100644 --- a/pip/tests-integration/resources/output/Adaptive_RI/IntrinsicSTSWAP.ll +++ b/pip/tests-integration/resources/output/Adaptive_RI/IntrinsicSTSWAP.ll @@ -51,16 +51,10 @@ attributes #1 = { "irreversible" } ; module flags -!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10} +!llvm.module.flags = !{!0, !1, !2, !3, !4} !0 = !{i32 1, !"qir_major_version", i32 1} !1 = !{i32 7, !"qir_minor_version", i32 0} !2 = !{i32 1, !"dynamic_qubit_management", i1 false} !3 = !{i32 1, !"dynamic_result_management", i1 false} -!4 = !{i32 1, !"classical_ints", i1 true} -!5 = !{i32 1, !"qubit_resetting", i1 true} -!6 = !{i32 1, !"classical_floats", i1 false} -!7 = !{i32 1, !"backwards_branching", i1 false} -!8 = !{i32 1, !"classical_fixed_points", i1 false} -!9 = !{i32 1, !"user_functions", i1 false} -!10 = !{i32 1, !"multiple_target_branching", i1 false} +!4 = !{i32 1, !"int_computations", !"i64"} diff --git a/pip/tests-integration/resources/output/Adaptive_RI/MeasureAndReuse.ll b/pip/tests-integration/resources/output/Adaptive_RI/MeasureAndReuse.ll index b6de7049fb..b13143b88d 100644 --- a/pip/tests-integration/resources/output/Adaptive_RI/MeasureAndReuse.ll +++ b/pip/tests-integration/resources/output/Adaptive_RI/MeasureAndReuse.ll @@ -44,16 +44,10 @@ attributes #1 = { "irreversible" } ; module flags -!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10} +!llvm.module.flags = !{!0, !1, !2, !3, !4} !0 = !{i32 1, !"qir_major_version", i32 1} !1 = !{i32 7, !"qir_minor_version", i32 0} !2 = !{i32 1, !"dynamic_qubit_management", i1 false} !3 = !{i32 1, !"dynamic_result_management", i1 false} -!4 = !{i32 1, !"classical_ints", i1 true} -!5 = !{i32 1, !"qubit_resetting", i1 true} -!6 = !{i32 1, !"classical_floats", i1 false} -!7 = !{i32 1, !"backwards_branching", i1 false} -!8 = !{i32 1, !"classical_fixed_points", i1 false} -!9 = !{i32 1, !"user_functions", i1 false} -!10 = !{i32 1, !"multiple_target_branching", i1 false} +!4 = !{i32 1, !"int_computations", !"i64"} diff --git a/pip/tests-integration/resources/output/Adaptive_RI/MeasurementComparison.ll b/pip/tests-integration/resources/output/Adaptive_RI/MeasurementComparison.ll index 725e3ae6e8..a3fb0c09a6 100644 --- a/pip/tests-integration/resources/output/Adaptive_RI/MeasurementComparison.ll +++ b/pip/tests-integration/resources/output/Adaptive_RI/MeasurementComparison.ll @@ -51,16 +51,10 @@ attributes #1 = { "irreversible" } ; module flags -!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10} +!llvm.module.flags = !{!0, !1, !2, !3, !4} !0 = !{i32 1, !"qir_major_version", i32 1} !1 = !{i32 7, !"qir_minor_version", i32 0} !2 = !{i32 1, !"dynamic_qubit_management", i1 false} !3 = !{i32 1, !"dynamic_result_management", i1 false} -!4 = !{i32 1, !"classical_ints", i1 true} -!5 = !{i32 1, !"qubit_resetting", i1 true} -!6 = !{i32 1, !"classical_floats", i1 false} -!7 = !{i32 1, !"backwards_branching", i1 false} -!8 = !{i32 1, !"classical_fixed_points", i1 false} -!9 = !{i32 1, !"user_functions", i1 false} -!10 = !{i32 1, !"multiple_target_branching", i1 false} +!4 = !{i32 1, !"int_computations", !"i64"} diff --git a/pip/tests-integration/resources/output/Adaptive_RI/NestedBranching.ll b/pip/tests-integration/resources/output/Adaptive_RI/NestedBranching.ll index 7c07f5a282..760f3c737e 100644 --- a/pip/tests-integration/resources/output/Adaptive_RI/NestedBranching.ll +++ b/pip/tests-integration/resources/output/Adaptive_RI/NestedBranching.ll @@ -328,16 +328,10 @@ attributes #1 = { "irreversible" } ; module flags -!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10} +!llvm.module.flags = !{!0, !1, !2, !3, !4} !0 = !{i32 1, !"qir_major_version", i32 1} !1 = !{i32 7, !"qir_minor_version", i32 0} !2 = !{i32 1, !"dynamic_qubit_management", i1 false} !3 = !{i32 1, !"dynamic_result_management", i1 false} -!4 = !{i32 1, !"classical_ints", i1 true} -!5 = !{i32 1, !"qubit_resetting", i1 true} -!6 = !{i32 1, !"classical_floats", i1 false} -!7 = !{i32 1, !"backwards_branching", i1 false} -!8 = !{i32 1, !"classical_fixed_points", i1 false} -!9 = !{i32 1, !"user_functions", i1 false} -!10 = !{i32 1, !"multiple_target_branching", i1 false} +!4 = !{i32 1, !"int_computations", !"i64"} diff --git a/pip/tests-integration/resources/output/Adaptive_RI/RandomBit.ll b/pip/tests-integration/resources/output/Adaptive_RI/RandomBit.ll index f1c5eccec5..c232922cea 100644 --- a/pip/tests-integration/resources/output/Adaptive_RI/RandomBit.ll +++ b/pip/tests-integration/resources/output/Adaptive_RI/RandomBit.ll @@ -23,16 +23,10 @@ attributes #1 = { "irreversible" } ; module flags -!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10} +!llvm.module.flags = !{!0, !1, !2, !3, !4} !0 = !{i32 1, !"qir_major_version", i32 1} !1 = !{i32 7, !"qir_minor_version", i32 0} !2 = !{i32 1, !"dynamic_qubit_management", i1 false} !3 = !{i32 1, !"dynamic_result_management", i1 false} -!4 = !{i32 1, !"classical_ints", i1 true} -!5 = !{i32 1, !"qubit_resetting", i1 true} -!6 = !{i32 1, !"classical_floats", i1 false} -!7 = !{i32 1, !"backwards_branching", i1 false} -!8 = !{i32 1, !"classical_fixed_points", i1 false} -!9 = !{i32 1, !"user_functions", i1 false} -!10 = !{i32 1, !"multiple_target_branching", i1 false} +!4 = !{i32 1, !"int_computations", !"i64"} diff --git a/pip/tests-integration/resources/output/Adaptive_RI/SampleTeleport.ll b/pip/tests-integration/resources/output/Adaptive_RI/SampleTeleport.ll index 65f847d570..558b2e544a 100644 --- a/pip/tests-integration/resources/output/Adaptive_RI/SampleTeleport.ll +++ b/pip/tests-integration/resources/output/Adaptive_RI/SampleTeleport.ll @@ -55,16 +55,10 @@ attributes #1 = { "irreversible" } ; module flags -!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10} +!llvm.module.flags = !{!0, !1, !2, !3, !4} !0 = !{i32 1, !"qir_major_version", i32 1} !1 = !{i32 7, !"qir_minor_version", i32 0} !2 = !{i32 1, !"dynamic_qubit_management", i1 false} !3 = !{i32 1, !"dynamic_result_management", i1 false} -!4 = !{i32 1, !"classical_ints", i1 true} -!5 = !{i32 1, !"qubit_resetting", i1 true} -!6 = !{i32 1, !"classical_floats", i1 false} -!7 = !{i32 1, !"backwards_branching", i1 false} -!8 = !{i32 1, !"classical_fixed_points", i1 false} -!9 = !{i32 1, !"user_functions", i1 false} -!10 = !{i32 1, !"multiple_target_branching", i1 false} +!4 = !{i32 1, !"int_computations", !"i64"} diff --git a/pip/tests-integration/resources/output/Adaptive_RI/ShortcuttingMeasurement.ll b/pip/tests-integration/resources/output/Adaptive_RI/ShortcuttingMeasurement.ll index d946deb2dd..99917a8eca 100644 --- a/pip/tests-integration/resources/output/Adaptive_RI/ShortcuttingMeasurement.ll +++ b/pip/tests-integration/resources/output/Adaptive_RI/ShortcuttingMeasurement.ll @@ -49,16 +49,10 @@ attributes #1 = { "irreversible" } ; module flags -!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10} +!llvm.module.flags = !{!0, !1, !2, !3, !4} !0 = !{i32 1, !"qir_major_version", i32 1} !1 = !{i32 7, !"qir_minor_version", i32 0} !2 = !{i32 1, !"dynamic_qubit_management", i1 false} !3 = !{i32 1, !"dynamic_result_management", i1 false} -!4 = !{i32 1, !"classical_ints", i1 true} -!5 = !{i32 1, !"qubit_resetting", i1 true} -!6 = !{i32 1, !"classical_floats", i1 false} -!7 = !{i32 1, !"backwards_branching", i1 false} -!8 = !{i32 1, !"classical_fixed_points", i1 false} -!9 = !{i32 1, !"user_functions", i1 false} -!10 = !{i32 1, !"multiple_target_branching", i1 false} +!4 = !{i32 1, !"int_computations", !"i64"} diff --git a/pip/tests-integration/resources/output/Adaptive_RI/Slicing.ll b/pip/tests-integration/resources/output/Adaptive_RI/Slicing.ll index 038810da9b..41f496f2e0 100644 --- a/pip/tests-integration/resources/output/Adaptive_RI/Slicing.ll +++ b/pip/tests-integration/resources/output/Adaptive_RI/Slicing.ll @@ -47,16 +47,10 @@ attributes #1 = { "irreversible" } ; module flags -!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10} +!llvm.module.flags = !{!0, !1, !2, !3, !4} !0 = !{i32 1, !"qir_major_version", i32 1} !1 = !{i32 7, !"qir_minor_version", i32 0} !2 = !{i32 1, !"dynamic_qubit_management", i1 false} !3 = !{i32 1, !"dynamic_result_management", i1 false} -!4 = !{i32 1, !"classical_ints", i1 true} -!5 = !{i32 1, !"qubit_resetting", i1 true} -!6 = !{i32 1, !"classical_floats", i1 false} -!7 = !{i32 1, !"backwards_branching", i1 false} -!8 = !{i32 1, !"classical_fixed_points", i1 false} -!9 = !{i32 1, !"user_functions", i1 false} -!10 = !{i32 1, !"multiple_target_branching", i1 false} +!4 = !{i32 1, !"int_computations", !"i64"} diff --git a/pip/tests-integration/resources/output/Adaptive_RI/SuperdenseCoding.ll b/pip/tests-integration/resources/output/Adaptive_RI/SuperdenseCoding.ll index 03607bf23f..54d1da31d5 100644 --- a/pip/tests-integration/resources/output/Adaptive_RI/SuperdenseCoding.ll +++ b/pip/tests-integration/resources/output/Adaptive_RI/SuperdenseCoding.ll @@ -70,16 +70,10 @@ attributes #1 = { "irreversible" } ; module flags -!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10} +!llvm.module.flags = !{!0, !1, !2, !3, !4} !0 = !{i32 1, !"qir_major_version", i32 1} !1 = !{i32 7, !"qir_minor_version", i32 0} !2 = !{i32 1, !"dynamic_qubit_management", i1 false} !3 = !{i32 1, !"dynamic_result_management", i1 false} -!4 = !{i32 1, !"classical_ints", i1 true} -!5 = !{i32 1, !"qubit_resetting", i1 true} -!6 = !{i32 1, !"classical_floats", i1 false} -!7 = !{i32 1, !"backwards_branching", i1 false} -!8 = !{i32 1, !"classical_fixed_points", i1 false} -!9 = !{i32 1, !"user_functions", i1 false} -!10 = !{i32 1, !"multiple_target_branching", i1 false} +!4 = !{i32 1, !"int_computations", !"i64"} diff --git a/pip/tests-integration/resources/output/Adaptive_RI/SwitchHandling.ll b/pip/tests-integration/resources/output/Adaptive_RI/SwitchHandling.ll index 325d88bb56..acf58afd49 100644 --- a/pip/tests-integration/resources/output/Adaptive_RI/SwitchHandling.ll +++ b/pip/tests-integration/resources/output/Adaptive_RI/SwitchHandling.ll @@ -75,16 +75,10 @@ attributes #1 = { "irreversible" } ; module flags -!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10} +!llvm.module.flags = !{!0, !1, !2, !3, !4} !0 = !{i32 1, !"qir_major_version", i32 1} !1 = !{i32 7, !"qir_minor_version", i32 0} !2 = !{i32 1, !"dynamic_qubit_management", i1 false} !3 = !{i32 1, !"dynamic_result_management", i1 false} -!4 = !{i32 1, !"classical_ints", i1 true} -!5 = !{i32 1, !"qubit_resetting", i1 true} -!6 = !{i32 1, !"classical_floats", i1 false} -!7 = !{i32 1, !"backwards_branching", i1 false} -!8 = !{i32 1, !"classical_fixed_points", i1 false} -!9 = !{i32 1, !"user_functions", i1 false} -!10 = !{i32 1, !"multiple_target_branching", i1 false} +!4 = !{i32 1, !"int_computations", !"i64"} diff --git a/pip/tests-integration/resources/output/Adaptive_RI/ThreeQubitRepetitionCode.ll b/pip/tests-integration/resources/output/Adaptive_RI/ThreeQubitRepetitionCode.ll index 2d136271f9..3a2c53811b 100644 --- a/pip/tests-integration/resources/output/Adaptive_RI/ThreeQubitRepetitionCode.ll +++ b/pip/tests-integration/resources/output/Adaptive_RI/ThreeQubitRepetitionCode.ll @@ -296,16 +296,10 @@ attributes #1 = { "irreversible" } ; module flags -!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10} +!llvm.module.flags = !{!0, !1, !2, !3, !4} !0 = !{i32 1, !"qir_major_version", i32 1} !1 = !{i32 7, !"qir_minor_version", i32 0} !2 = !{i32 1, !"dynamic_qubit_management", i1 false} !3 = !{i32 1, !"dynamic_result_management", i1 false} -!4 = !{i32 1, !"classical_ints", i1 true} -!5 = !{i32 1, !"qubit_resetting", i1 true} -!6 = !{i32 1, !"classical_floats", i1 false} -!7 = !{i32 1, !"backwards_branching", i1 false} -!8 = !{i32 1, !"classical_fixed_points", i1 false} -!9 = !{i32 1, !"user_functions", i1 false} -!10 = !{i32 1, !"multiple_target_branching", i1 false} +!4 = !{i32 1, !"int_computations", !"i64"} diff --git a/pip/tests-integration/resources/output/Adaptive_RI/WithinApply.ll b/pip/tests-integration/resources/output/Adaptive_RI/WithinApply.ll index 544d8f4f24..ff8de72dfe 100644 --- a/pip/tests-integration/resources/output/Adaptive_RI/WithinApply.ll +++ b/pip/tests-integration/resources/output/Adaptive_RI/WithinApply.ll @@ -38,16 +38,10 @@ attributes #1 = { "irreversible" } ; module flags -!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10} +!llvm.module.flags = !{!0, !1, !2, !3, !4} !0 = !{i32 1, !"qir_major_version", i32 1} !1 = !{i32 7, !"qir_minor_version", i32 0} !2 = !{i32 1, !"dynamic_qubit_management", i1 false} !3 = !{i32 1, !"dynamic_result_management", i1 false} -!4 = !{i32 1, !"classical_ints", i1 true} -!5 = !{i32 1, !"qubit_resetting", i1 true} -!6 = !{i32 1, !"classical_floats", i1 false} -!7 = !{i32 1, !"backwards_branching", i1 false} -!8 = !{i32 1, !"classical_fixed_points", i1 false} -!9 = !{i32 1, !"user_functions", i1 false} -!10 = !{i32 1, !"multiple_target_branching", i1 false} +!4 = !{i32 1, !"int_computations", !"i64"} diff --git a/pip/tests/test_interpreter.py b/pip/tests/test_interpreter.py index 816cce04ee..7c8b28ce77 100644 --- a/pip/tests/test_interpreter.py +++ b/pip/tests/test_interpreter.py @@ -392,19 +392,13 @@ def test_adaptive_ri_qir_can_be_generated() -> None: ; module flags - !llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10} + !llvm.module.flags = !{!0, !1, !2, !3, !4} !0 = !{i32 1, !"qir_major_version", i32 1} !1 = !{i32 7, !"qir_minor_version", i32 0} !2 = !{i32 1, !"dynamic_qubit_management", i1 false} !3 = !{i32 1, !"dynamic_result_management", i1 false} - !4 = !{i32 1, !"classical_ints", i1 true} - !5 = !{i32 1, !"qubit_resetting", i1 true} - !6 = !{i32 1, !"classical_floats", i1 false} - !7 = !{i32 1, !"backwards_branching", i1 false} - !8 = !{i32 1, !"classical_fixed_points", i1 false} - !9 = !{i32 1, !"user_functions", i1 false} - !10 = !{i32 1, !"multiple_target_branching", i1 false} + !4 = !{i32 1, !"int_computations", !"i64"} """ ) diff --git a/pip/tests/test_qsharp.py b/pip/tests/test_qsharp.py index f79541b070..eb414389e6 100644 --- a/pip/tests/test_qsharp.py +++ b/pip/tests/test_qsharp.py @@ -388,6 +388,9 @@ def test_target_profile_str_values_match_enum_values() -> None: target_profile = qsharp.TargetProfile.Adaptive_RI str_value = str(target_profile) assert str_value == "Adaptive_RI" + target_profile = qsharp.TargetProfile.Adaptive_RIF + str_value = str(target_profile) + assert str_value == "Adaptive_RIF" target_profile = qsharp.TargetProfile.Unrestricted str_value = str(target_profile) assert str_value == "Unrestricted" @@ -400,6 +403,9 @@ def test_target_profile_from_str_match_enum_values() -> None: target_profile = qsharp.TargetProfile.Adaptive_RI str_value = str(target_profile) assert qsharp.TargetProfile.from_str(str_value) == target_profile + target_profile = qsharp.TargetProfile.Adaptive_RIF + str_value = str(target_profile) + assert qsharp.TargetProfile.from_str(str_value) == target_profile target_profile = qsharp.TargetProfile.Unrestricted str_value = str(target_profile) assert qsharp.TargetProfile.from_str(str_value) == target_profile diff --git a/playground/src/editor.tsx b/playground/src/editor.tsx index d8929e6126..f0a690dc8f 100644 --- a/playground/src/editor.tsx +++ b/playground/src/editor.tsx @@ -448,6 +448,7 @@ export function Editor(props: { Profile diff --git a/vscode/package.json b/vscode/package.json index a96876a704..25401a71a7 100644 --- a/vscode/package.json +++ b/vscode/package.json @@ -102,12 +102,14 @@ "enum": [ "unrestricted", "base", - "adaptive_ri" + "adaptive_ri", + "adaptive_rif" ], "enumDescriptions": [ "The set of all capabilities required to run any Q# program.", "The minimal set of capabilities required to run a quantum program. This option maps to the Base Profile as defined by the QIR specification.", - "The Adaptive_RI target profile includes all of the required Adaptive Profile capabilities, as well as the optional integer computation and qubit reset capabilities, as defined by the QIR specification." + "The Adaptive_RI target profile includes all of the required Adaptive Profile capabilities, as well as the optional integer computation and qubit reset capabilities, as defined by the QIR specification.", + "The Adaptive_RIF target profile includes all of the required Adaptive Profile capabilities, as well as the optional integer & floating point computation and qubit reset capabilities, as defined by the QIR specification." ], "markdownDescription": "Setting the target profile allows the Q# extension to generate programs that are compatible with a specific target. The target is the hardware or simulator which will be used to run the Q# program. [Learn more](https://aka.ms/qdk.qir)" }, diff --git a/vscode/src/config.ts b/vscode/src/config.ts index 14a5d6559a..1f5348e73a 100644 --- a/vscode/src/config.ts +++ b/vscode/src/config.ts @@ -11,6 +11,7 @@ export function getTarget(): TargetProfile { switch (target) { case "base": case "adaptive_ri": + case "adaptive_rif": case "unrestricted": return target; default: @@ -34,6 +35,8 @@ export function getTargetFriendlyName(targetProfile?: string) { return "Q#: QIR base"; case "adaptive_ri": return "Q#: QIR Adaptive RI"; + case "adaptive_rif": + return "Q#: QIR Adaptive RIF"; case "unrestricted": return "Q#: unrestricted"; default: diff --git a/vscode/src/language-service/activate.ts b/vscode/src/language-service/activate.ts index d4815d8713..89d407af7e 100644 --- a/vscode/src/language-service/activate.ts +++ b/vscode/src/language-service/activate.ts @@ -288,6 +288,7 @@ async function updateLanguageServiceProfile(languageService: ILanguageService) { switch (targetProfile) { case "base": case "adaptive_ri": + case "adaptive_rif": case "unrestricted": break; default: diff --git a/vscode/src/statusbar.ts b/vscode/src/statusbar.ts index ecd7f9eb99..be695192ca 100644 --- a/vscode/src/statusbar.ts +++ b/vscode/src/statusbar.ts @@ -94,6 +94,7 @@ function registerTargetProfileCommand() { const targetProfiles = [ { configName: "base", uiText: "Q#: QIR base" }, { configName: "adaptive_ri", uiText: "Q#: QIR Adaptive RI" }, + { configName: "adaptive_rif", uiText: "Q#: QIR Adaptive RIF" }, { configName: "unrestricted", uiText: "Q#: unrestricted" }, ]; @@ -103,6 +104,8 @@ function getTargetProfileSetting(uiText: string): TargetProfile { return "base"; case "Q#: QIR Adaptive RI": return "adaptive_ri"; + case "Q#: QIR Adaptive RIF": + return "adaptive_rif"; case "Q#: unrestricted": return "unrestricted"; default: diff --git a/wasm/src/language_service.rs b/wasm/src/language_service.rs index 5e60a3f9fb..6f2f807920 100644 --- a/wasm/src/language_service.rs +++ b/wasm/src/language_service.rs @@ -572,7 +572,7 @@ serializable_type! { pub projectRoot: Option, }, r#"export interface INotebookMetadata { - targetProfile?: "base" | "adaptive_ri" | "unrestricted"; + targetProfile?: "base" | "adaptive_ri" | "adaptive_rif" | "unrestricted"; languageFeatures?: "v2-preview-syntax"[]; manifest?: string; projectRoot?: string; diff --git a/wasm/src/lib.rs b/wasm/src/lib.rs index ad09a451e2..a4f42cf585 100644 --- a/wasm/src/lib.rs +++ b/wasm/src/lib.rs @@ -558,7 +558,7 @@ pub fn generate_docs(additional_program: Option) -> Vec #[wasm_bindgen(typescript_custom_section)] const TARGET_PROFILE: &'static str = r#" -export type TargetProfile = "base" | "adaptive_ri" | "unrestricted"; +export type TargetProfile = "base" | "adaptive_ri" | "adaptive_rif" | "unrestricted"; "#; #[wasm_bindgen(typescript_custom_section)] From 525e8604e81f5c7ba60ddc5aff0380118608ab93 Mon Sep 17 00:00:00 2001 From: Ian Davis Date: Thu, 2 Jan 2025 16:39:40 -0800 Subject: [PATCH 2/9] Fix op name in string --- compiler/qsc_codegen/src/qir.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/qsc_codegen/src/qir.rs b/compiler/qsc_codegen/src/qir.rs index 3dadc05475..efd0fd4036 100644 --- a/compiler/qsc_codegen/src/qir.rs +++ b/compiler/qsc_codegen/src/qir.rs @@ -364,10 +364,10 @@ fn fcmp_to_qir( let var_ty = get_variable_ty(variable); assert_eq!( lhs_ty, rhs_ty, - "mismatched input types ({lhs_ty}, {rhs_ty}) for icmp {op}" + "mismatched input types ({lhs_ty}, {rhs_ty}) for fcmp {op}" ); - assert_eq!(var_ty, "i1", "unsupported output type {var_ty} for icmp"); + assert_eq!(var_ty, "i1", "unsupported output type {var_ty} for fcmp"); format!( " {} = fcmp {} {lhs_ty} {}, {}", ToQir::::to_qir(&variable.variable_id, program), From d687b0364a4e26ecd4b2fcb7c7a3a8dd010a99c9 Mon Sep 17 00:00:00 2001 From: Ian Davis Date: Thu, 2 Jan 2025 16:42:00 -0800 Subject: [PATCH 3/9] simplify casing logic --- compiler/qsc/src/target.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/qsc/src/target.rs b/compiler/qsc/src/target.rs index c8ba1c5057..ba91df9b6d 100644 --- a/compiler/qsc/src/target.rs +++ b/compiler/qsc/src/target.rs @@ -45,11 +45,11 @@ impl FromStr for Profile { type Err = (); fn from_str(s: &str) -> Result { - match s { - "Adaptive_RI" | "adaptive_ri" => Ok(Self::AdaptiveRI), - "Adaptive_RIF" | "adaptive_rif" => Ok(Self::AdaptiveRIF), - "Base" | "base" => Ok(Self::Base), - "Unrestricted" | "unrestricted" => Ok(Self::Unrestricted), + match s.to_lowercase().as_str() { + "adaptive_ri" => Ok(Self::AdaptiveRI), + "adaptive_rif" => Ok(Self::AdaptiveRIF), + "base" => Ok(Self::Base), + "unrestricted" => Ok(Self::Unrestricted), _ => Err(()), } } From cccd88efc8727a69033e409b94b9e5ba6047e982 Mon Sep 17 00:00:00 2001 From: Ian Davis Date: Fri, 3 Jan 2025 13:39:17 -0800 Subject: [PATCH 4/9] Updating fp partial eval binoq cmps --- compiler/qsc_partial_eval/src/lib.rs | 29 ++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/compiler/qsc_partial_eval/src/lib.rs b/compiler/qsc_partial_eval/src/lib.rs index 45caaa032d..4b9e3d5588 100644 --- a/compiler/qsc_partial_eval/src/lib.rs +++ b/compiler/qsc_partial_eval/src/lib.rs @@ -3218,12 +3218,12 @@ fn eval_bin_op_with_double_literals( }; match bin_op { - BinOp::Eq => Ok(Value::Bool((lhs - rhs).abs() < f64::EPSILON)), - BinOp::Neq => Ok(Value::Bool((lhs - rhs).abs() > f64::EPSILON)), + BinOp::Eq => Ok(Value::Bool(f64_approx_eq(lhs, rhs))), + BinOp::Neq => Ok(Value::Bool(f64_approx_neq(lhs, rhs))), BinOp::Gt => Ok(Value::Bool(lhs > rhs)), - BinOp::Gte => Ok(Value::Bool(lhs >= rhs)), + BinOp::Gte => Ok(Value::Bool(f64_approx_gte(lhs, rhs))), BinOp::Lt => Ok(Value::Bool(lhs < rhs)), - BinOp::Lte => Ok(Value::Bool(lhs <= rhs)), + BinOp::Lte => Ok(Value::Bool(f64_approx_lte(lhs, rhs))), BinOp::Add => Ok(Value::Double(lhs + rhs)), BinOp::Sub => Ok(Value::Double(lhs - rhs)), BinOp::Mul => Ok(Value::Double(lhs * rhs)), @@ -3378,3 +3378,24 @@ fn try_get_eval_var_type(value: &Value) -> Option { _ => None, } } + +fn f64_approx_lte(lhs: f64, rhs: f64) -> bool { + lhs < rhs || f64_approx_eq(lhs, rhs) +} + +fn f64_approx_gte(lhs: f64, rhs: f64) -> bool { + lhs > rhs || f64_approx_eq(lhs, rhs) +} + +fn f64_approx_neq(lhs: f64, rhs: f64) -> bool { + !f64_approx_eq(lhs, rhs) +} + +fn f64_approx_eq(lhs: f64, rhs: f64) -> bool { + // check equality, this is fastest and handles +0.0 == -0.0 + // also lets us avoid constly math operations in the true case + lhs == rhs || { + // not equal, check if they are close enough + (lhs - rhs).abs() <= f64::EPSILON + } +} From fc7d1e29f57fa65dc19f24de9da98f972efef491 Mon Sep 17 00:00:00 2001 From: Ian Davis Date: Fri, 3 Jan 2025 13:49:22 -0800 Subject: [PATCH 5/9] Updating API docs --- pip/qsharp/_native.pyi | 15 ++++++++------- pip/src/interpreter.rs | 15 ++++++++------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/pip/qsharp/_native.pyi b/pip/qsharp/_native.pyi index b294899346..9efbd723a5 100644 --- a/pip/qsharp/_native.pyi +++ b/pip/qsharp/_native.pyi @@ -90,20 +90,21 @@ class TargetProfile(Enum): Adaptive_RI: TargetProfile """ - Target supports the Adaptive profile with integer computation and qubit reset capabilities. + Target supports the Adaptive profile with the integer computation extension. This profile includes all of the required Adaptive Profile - capabilities, as well as the optional integer computation and qubit - reset capabilities, as defined by the QIR specification. + capabilities, as well as the optional integer computation + extension defined by the QIR specification. """ Adaptive_RIF: TargetProfile """ - Target supports the Adaptive profile with integer & floating point computation and qubit reset capabilities. + Target supports the Adaptive profile with integer & floating-point + computation extensions. - This profile includes all of the required Adaptive Profile and Adaptive_RI - capabilities, as well as the optional floating point computation and qubit - reset capabilities, as defined by the QIR specification. + This profile includes all required Adaptive Profile and `Adaptive_RI` + capabilities, as well as the optional floating-point computation + extension defined by the QIR specification. """ Unrestricted: TargetProfile diff --git a/pip/src/interpreter.rs b/pip/src/interpreter.rs index 80df7715aa..0a22140939 100644 --- a/pip/src/interpreter.rs +++ b/pip/src/interpreter.rs @@ -100,17 +100,18 @@ pub(crate) enum TargetProfile { /// /// This option maps to the Base Profile as defined by the QIR specification. Base, - /// Target supports the Adaptive profile with integer computation and qubit reset capabilities. + /// Target supports the Adaptive profile with the integer computation extension. /// /// This profile includes all of the required Adaptive Profile - /// capabilities, as well as the optional integer computation and qubit - /// reset capabilities, as defined by the QIR specification. + /// capabilities, as well as the optional integer computation + /// extension defined by the QIR specification. Adaptive_RI, - /// Target supports the Adaptive profile with integer & floating point computation and qubit reset capabilities. + /// Target supports the Adaptive profile with integer & floating-point + /// computation extensions. /// - /// This profile includes all of the required Adaptive Profile and Adaptive_RI - /// capabilities, as well as the optional floating point computation and qubit - /// reset capabilities, as defined by the QIR specification. + /// This profile includes all required Adaptive Profile and `Adaptive_RI` + /// capabilities, as well as the optional floating-point computation + /// extension defined by the QIR specification. Adaptive_RIF, /// Target supports the full set of capabilities required to run any Q# program. /// From 68370c36a2ce641e046e57f8a21b3200d9d6dd00 Mon Sep 17 00:00:00 2001 From: Ian Davis Date: Fri, 3 Jan 2025 14:20:52 -0800 Subject: [PATCH 6/9] Refactoring QIR integration tests. --- pip/tests-integration/test_adaptive_ri_qir.py | 162 ++--------------- pip/tests-integration/utils.py | 167 ++++++++++++++++++ 2 files changed, 177 insertions(+), 152 deletions(-) create mode 100644 pip/tests-integration/utils.py diff --git a/pip/tests-integration/test_adaptive_ri_qir.py b/pip/tests-integration/test_adaptive_ri_qir.py index 81662a3e4e..5ea704a6a1 100644 --- a/pip/tests-integration/test_adaptive_ri_qir.py +++ b/pip/tests-integration/test_adaptive_ri_qir.py @@ -1,163 +1,21 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. -import os import pytest -from qsharp._native import ( - Interpreter, - TargetProfile, - QSharpError, +from utils import ( + assert_strings_equal_ignore_line_endings, + compile_qsharp, + get_input_files, + get_output_ll_file, + get_output_out_file, + QIR_RUNNER_AVAILABLE, + read_file, + save_qir_to_temp_file_and_execute, + SKIP_REASON, ) -from typing import Optional, List - - -try: - from qirrunner import run, OutputHandler - - QIR_RUNNER_AVAILABLE = True -except ImportError: - QIR_RUNNER_AVAILABLE = False - -SKIP_REASON = "QIR runner is not available" - - -def execute_qir(file_path: str) -> str: - RNG_SEED = 42 - SHOTS = 1 - handler = OutputHandler() - run(file_path, None, SHOTS, RNG_SEED, output_fn=handler.handle) - return handler.get_output() - - -def get_interpreter( - target_profile: TargetProfile = TargetProfile.Unrestricted, - target_name: Optional[str] = None, -) -> Interpreter: - if isinstance(target_name, str): - target = target_name.split(".")[0].lower() - if target == "ionq" or target == "rigetti": - target_profile = TargetProfile.Base - elif target == "quantinuum": - target_profile = TargetProfile.Adaptive_RI - else: - raise QSharpError( - f'target_name "{target_name}" not recognized. Please set target_profile directly.' - ) - - manifest_descriptor = None - language_features = None - from qsharp._fs import read_file, list_directory - - interpreter = Interpreter( - target_profile, - language_features, - manifest_descriptor, - read_file, - list_directory, - ) - return interpreter - - -def compile_qsharp( - source: str, - target_profile: TargetProfile = TargetProfile.Adaptive_RI, - target_name: Optional[str] = None, -) -> str: - interpreter = get_interpreter(target_profile, target_name) - interpreter.interpret(source) - qir = interpreter.qir("Test.Main()") - return qir - - -def get_input_files() -> List[str]: - resources_dir = get_resource_dir() - input_files = [ - os.path.join(resources_dir, file_name) - for file_name in os.listdir(resources_dir) - if os.path.isfile(os.path.join(resources_dir, file_name)) - ] - return input_files - - -def get_resource_dir() -> str: - return os.path.join(os.path.dirname(__file__), "resources") - - -def get_output_dir() -> str: - return os.path.join(get_resource_dir(), "output", "Adaptive_RI") - - -def get_ouput_file_basename(file_path: str) -> str: - file_name, _ext = os.path.splitext(file_path) - output_dir = get_output_dir() - output_file = os.path.join(output_dir, os.path.basename(file_name)) - return output_file - - -def get_output_ll_file(file_path: str) -> str: - output_file = get_ouput_file_basename(file_path) - return output_file + ".ll" - - -def get_output_out_file(file_path: str) -> str: - output_file = get_ouput_file_basename(file_path) - return output_file + ".out" - - -# This function is used to generate the expected output files for the tests -# Rename the function to start with test_ to generate the expected output files -def generate_test_outputs() -> None: - input_files = get_input_files() - output_dir = get_output_dir() - os.makedirs(output_dir, exist_ok=True) - - for file_path in input_files: - ll_file_path = get_output_ll_file(file_path) - out_file_path = get_output_out_file(file_path) - with open(file_path, "rt", encoding="utf-8") as f: - source = f.read() - qir = compile_qsharp(source) - with open(ll_file_path, "wt", encoding="utf-8") as f: - f.write(qir) - output = execute_qir(ll_file_path) - with open(out_file_path, "wt", encoding="utf-8") as f: - f.write(output) - - -def read_file(file_name: str) -> str: - file_path = os.path.join(os.path.dirname(__file__), "resources", file_name) - with open(file_path, "rt", encoding="utf-8") as file: - source = file.read() - return source - - -def save_qir_to_temp_file_and_execute(qir: str) -> str: - - import tempfile - - # create a temporary file to store the qir - with tempfile.TemporaryDirectory() as tempdir: - # Create a temporary file in the temporary directory - with tempfile.NamedTemporaryFile( - dir=tempdir, delete=True, suffix=".ll" - ) as temp_file: - # You can write to the file or read from it - # encode the uf8 string to bytes - temp_file.write(qir.encode()) - temp_file.flush() - - actual_output = execute_qir(temp_file.name) - return actual_output - - -def assert_strings_equal_ignore_line_endings(lhs, rhs): - normalized_lhs = lhs.replace("\r\n", "\n") - normalized_rhs = rhs.replace("\r\n", "\n") - assert normalized_lhs == normalized_rhs - @pytest.mark.parametrize("file_path", get_input_files()) @pytest.mark.skipif(not QIR_RUNNER_AVAILABLE, reason=SKIP_REASON) diff --git a/pip/tests-integration/utils.py b/pip/tests-integration/utils.py new file mode 100644 index 0000000000..04154be614 --- /dev/null +++ b/pip/tests-integration/utils.py @@ -0,0 +1,167 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +""" +This file is used to configure pytest for the test suite. + +- It attempts to import necessary modules from test_circuits. + +Fixtures and other configurations for pytest can be added to this file to +be shared across multiple test files. +""" + +import os + +from qsharp._native import ( + Interpreter, + TargetProfile, + QSharpError, +) + +from typing import Optional, List + +from interop_qiskit.test_circuits import * + +try: + from qirrunner import run, OutputHandler + + QIR_RUNNER_AVAILABLE = True +except ImportError: + QIR_RUNNER_AVAILABLE = False + +SKIP_REASON = "QIR runner is not available" + + +# This function is used to generate the expected output files for the tests +# Rename the function to start with test_ to generate the expected output files +def generate_test_outputs() -> None: + input_files = get_input_files() + output_dir = get_output_dir() + os.makedirs(output_dir, exist_ok=True) + + for file_path in input_files: + ll_file_path = get_output_ll_file(file_path) + out_file_path = get_output_out_file(file_path) + with open(file_path, "rt", encoding="utf-8") as f: + source = f.read() + qir = compile_qsharp(source) + with open(ll_file_path, "wt", encoding="utf-8") as f: + f.write(qir) + output = execute_qir(ll_file_path) + with open(out_file_path, "wt", encoding="utf-8") as f: + f.write(output) + + +def read_file(file_name: str) -> str: + file_path = os.path.join(os.path.dirname(__file__), "resources", file_name) + with open(file_path, "rt", encoding="utf-8") as file: + source = file.read() + return source + + +def save_qir_to_temp_file_and_execute(qir: str) -> str: + + import tempfile + + # create a temporary file to store the qir + with tempfile.TemporaryDirectory() as tempdir: + # Create a temporary file in the temporary directory + with tempfile.NamedTemporaryFile( + dir=tempdir, delete=True, suffix=".ll" + ) as temp_file: + # You can write to the file or read from it + # encode the uf8 string to bytes + temp_file.write(qir.encode()) + temp_file.flush() + + actual_output = execute_qir(temp_file.name) + return actual_output + + +def assert_strings_equal_ignore_line_endings(lhs, rhs): + normalized_lhs = lhs.replace("\r\n", "\n") + normalized_rhs = rhs.replace("\r\n", "\n") + assert normalized_lhs == normalized_rhs + + +def execute_qir(file_path: str) -> str: + RNG_SEED = 42 + SHOTS = 1 + handler = OutputHandler() + run(file_path, None, SHOTS, RNG_SEED, output_fn=handler.handle) + return handler.get_output() + + +def get_interpreter( + target_profile: TargetProfile = TargetProfile.Unrestricted, + target_name: Optional[str] = None, +) -> Interpreter: + if isinstance(target_name, str): + target = target_name.split(".")[0].lower() + if target == "ionq" or target == "rigetti": + target_profile = TargetProfile.Base + elif target == "quantinuum": + target_profile = TargetProfile.Adaptive_RI + else: + raise QSharpError( + f'target_name "{target_name}" not recognized. Please set target_profile directly.' + ) + + manifest_descriptor = None + language_features = None + from qsharp._fs import read_file, list_directory + + interpreter = Interpreter( + target_profile, + language_features, + manifest_descriptor, + read_file, + list_directory, + ) + return interpreter + + +def compile_qsharp( + source: str, + target_profile: TargetProfile = TargetProfile.Adaptive_RI, + target_name: Optional[str] = None, +) -> str: + interpreter = get_interpreter(target_profile, target_name) + interpreter.interpret(source) + qir = interpreter.qir("Test.Main()") + return qir + + +def get_input_files() -> List[str]: + resources_dir = get_resource_dir() + input_files = [ + os.path.join(resources_dir, file_name) + for file_name in os.listdir(resources_dir) + if os.path.isfile(os.path.join(resources_dir, file_name)) + ] + return input_files + + +def get_resource_dir() -> str: + return os.path.join(os.path.dirname(__file__), "resources") + + +def get_output_dir() -> str: + return os.path.join(get_resource_dir(), "output", "Adaptive_RI") + + +def get_ouput_file_basename(file_path: str) -> str: + file_name, _ext = os.path.splitext(file_path) + output_dir = get_output_dir() + output_file = os.path.join(output_dir, os.path.basename(file_name)) + return output_file + + +def get_output_ll_file(file_path: str) -> str: + output_file = get_ouput_file_basename(file_path) + return output_file + ".ll" + + +def get_output_out_file(file_path: str) -> str: + output_file = get_ouput_file_basename(file_path) + return output_file + ".out" From 897023b5bb33d1f40f6ab06d88634acd0f056d67 Mon Sep 17 00:00:00 2001 From: Ian Davis Date: Fri, 3 Jan 2025 14:39:34 -0800 Subject: [PATCH 7/9] Move files around for per profile input/output --- .../{ => adaptive_ri/input}/ArithmeticOps.qs | 0 .../input}/BernsteinVaziraniNISQ.qs | 0 .../input}/ConstantFolding.qs | 0 .../input}/CopyAndUpdateExpressions.qs | 0 .../input}/DeutschJozsaNISQ.qs | 0 .../{ => adaptive_ri/input}/ExpandedTests.qs | 0 .../{ => adaptive_ri/input}/Functors.qs | 0 .../input}/HiddenShiftNISQ.qs | 0 .../input}/IntegerComparison.qs | 0 .../{ => adaptive_ri/input}/IntrinsicCCNOT.qs | 0 .../{ => adaptive_ri/input}/IntrinsicCNOT.qs | 0 .../{ => adaptive_ri/input}/IntrinsicHIXYZ.qs | 0 .../{ => adaptive_ri/input}/IntrinsicM.qs | 0 .../input}/IntrinsicMeasureWithBitFlipCode.qs | 0 .../IntrinsicMeasureWithPhaseFlipCode.qs | 0 .../input}/IntrinsicRotationsWithPeriod.qs | 0 .../input}/IntrinsicSTSWAP.qs | 0 .../input}/MeasureAndReuse.qs | 0 .../input}/MeasurementComparison.qs | 0 .../input}/NestedBranching.qs | 0 .../{ => adaptive_ri/input}/RandomBit.qs | 0 .../{ => adaptive_ri/input}/SampleTeleport.qs | 0 .../input}/ShortcuttingMeasurement.qs | 0 .../{ => adaptive_ri/input}/Slicing.qs | 0 .../input}/SuperdenseCoding.qs | 0 .../{ => adaptive_ri/input}/SwitchHandling.qs | 0 .../input}/ThreeQubitRepetitionCode.qs | 0 .../{ => adaptive_ri/input}/WithinApply.qs | 0 .../output}/ArithmeticOps.ll | 0 .../output}/ArithmeticOps.out | 0 .../output}/BernsteinVaziraniNISQ.ll | 0 .../output}/BernsteinVaziraniNISQ.out | 0 .../output}/ConstantFolding.ll | 0 .../output}/ConstantFolding.out | 0 .../output}/CopyAndUpdateExpressions.ll | 0 .../output}/CopyAndUpdateExpressions.out | 0 .../output}/DeutschJozsaNISQ.ll | 0 .../output}/DeutschJozsaNISQ.out | 0 .../output}/ExpandedTests.ll | 0 .../output}/ExpandedTests.out | 0 .../output}/Functors.ll | 0 .../output}/Functors.out | 0 .../output}/HiddenShiftNISQ.ll | 0 .../output}/HiddenShiftNISQ.out | 0 .../output}/IntegerComparison.ll | 0 .../output}/IntegerComparison.out | 0 .../output}/IntrinsicCCNOT.ll | 0 .../output}/IntrinsicCCNOT.out | 0 .../output}/IntrinsicCNOT.ll | 0 .../output}/IntrinsicCNOT.out | 0 .../output}/IntrinsicHIXYZ.ll | 0 .../output}/IntrinsicHIXYZ.out | 0 .../output}/IntrinsicM.ll | 0 .../output}/IntrinsicM.out | 0 .../IntrinsicMeasureWithBitFlipCode.ll | 0 .../IntrinsicMeasureWithBitFlipCode.out | 0 .../IntrinsicMeasureWithPhaseFlipCode.ll | 0 .../IntrinsicMeasureWithPhaseFlipCode.out | 0 .../output}/IntrinsicRotationsWithPeriod.ll | 0 .../output}/IntrinsicRotationsWithPeriod.out | 0 .../output}/IntrinsicSTSWAP.ll | 0 .../output}/IntrinsicSTSWAP.out | 0 .../output}/MeasureAndReuse.ll | 0 .../output}/MeasureAndReuse.out | 0 .../output}/MeasurementComparison.ll | 0 .../output}/MeasurementComparison.out | 0 .../output}/NestedBranching.ll | 0 .../output}/NestedBranching.out | 0 .../output}/RandomBit.ll | 0 .../output}/RandomBit.out | 0 .../output}/SampleTeleport.ll | 0 .../output}/SampleTeleport.out | 0 .../output}/ShortcuttingMeasurement.ll | 0 .../output}/ShortcuttingMeasurement.out | 0 .../output}/Slicing.ll | 0 .../output}/Slicing.out | 0 .../output}/SuperdenseCoding.ll | 0 .../output}/SuperdenseCoding.out | 0 .../output}/SwitchHandling.ll | 0 .../output}/SwitchHandling.out | 0 .../output}/ThreeQubitRepetitionCode.ll | 0 .../output}/ThreeQubitRepetitionCode.out | 0 .../output}/WithinApply.ll | 0 .../output}/WithinApply.out | 0 pip/tests-integration/test_adaptive_ri_qir.py | 23 ++++---- pip/tests-integration/utils.py | 54 ++++++++++--------- 86 files changed, 43 insertions(+), 34 deletions(-) rename pip/tests-integration/resources/{ => adaptive_ri/input}/ArithmeticOps.qs (100%) rename pip/tests-integration/resources/{ => adaptive_ri/input}/BernsteinVaziraniNISQ.qs (100%) rename pip/tests-integration/resources/{ => adaptive_ri/input}/ConstantFolding.qs (100%) rename pip/tests-integration/resources/{ => adaptive_ri/input}/CopyAndUpdateExpressions.qs (100%) rename pip/tests-integration/resources/{ => adaptive_ri/input}/DeutschJozsaNISQ.qs (100%) rename pip/tests-integration/resources/{ => adaptive_ri/input}/ExpandedTests.qs (100%) rename pip/tests-integration/resources/{ => adaptive_ri/input}/Functors.qs (100%) rename pip/tests-integration/resources/{ => adaptive_ri/input}/HiddenShiftNISQ.qs (100%) rename pip/tests-integration/resources/{ => adaptive_ri/input}/IntegerComparison.qs (100%) rename pip/tests-integration/resources/{ => adaptive_ri/input}/IntrinsicCCNOT.qs (100%) rename pip/tests-integration/resources/{ => adaptive_ri/input}/IntrinsicCNOT.qs (100%) rename pip/tests-integration/resources/{ => adaptive_ri/input}/IntrinsicHIXYZ.qs (100%) rename pip/tests-integration/resources/{ => adaptive_ri/input}/IntrinsicM.qs (100%) rename pip/tests-integration/resources/{ => adaptive_ri/input}/IntrinsicMeasureWithBitFlipCode.qs (100%) rename pip/tests-integration/resources/{ => adaptive_ri/input}/IntrinsicMeasureWithPhaseFlipCode.qs (100%) rename pip/tests-integration/resources/{ => adaptive_ri/input}/IntrinsicRotationsWithPeriod.qs (100%) rename pip/tests-integration/resources/{ => adaptive_ri/input}/IntrinsicSTSWAP.qs (100%) rename pip/tests-integration/resources/{ => adaptive_ri/input}/MeasureAndReuse.qs (100%) rename pip/tests-integration/resources/{ => adaptive_ri/input}/MeasurementComparison.qs (100%) rename pip/tests-integration/resources/{ => adaptive_ri/input}/NestedBranching.qs (100%) rename pip/tests-integration/resources/{ => adaptive_ri/input}/RandomBit.qs (100%) rename pip/tests-integration/resources/{ => adaptive_ri/input}/SampleTeleport.qs (100%) rename pip/tests-integration/resources/{ => adaptive_ri/input}/ShortcuttingMeasurement.qs (100%) rename pip/tests-integration/resources/{ => adaptive_ri/input}/Slicing.qs (100%) rename pip/tests-integration/resources/{ => adaptive_ri/input}/SuperdenseCoding.qs (100%) rename pip/tests-integration/resources/{ => adaptive_ri/input}/SwitchHandling.qs (100%) rename pip/tests-integration/resources/{ => adaptive_ri/input}/ThreeQubitRepetitionCode.qs (100%) rename pip/tests-integration/resources/{ => adaptive_ri/input}/WithinApply.qs (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/ArithmeticOps.ll (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/ArithmeticOps.out (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/BernsteinVaziraniNISQ.ll (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/BernsteinVaziraniNISQ.out (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/ConstantFolding.ll (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/ConstantFolding.out (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/CopyAndUpdateExpressions.ll (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/CopyAndUpdateExpressions.out (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/DeutschJozsaNISQ.ll (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/DeutschJozsaNISQ.out (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/ExpandedTests.ll (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/ExpandedTests.out (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/Functors.ll (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/Functors.out (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/HiddenShiftNISQ.ll (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/HiddenShiftNISQ.out (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/IntegerComparison.ll (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/IntegerComparison.out (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/IntrinsicCCNOT.ll (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/IntrinsicCCNOT.out (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/IntrinsicCNOT.ll (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/IntrinsicCNOT.out (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/IntrinsicHIXYZ.ll (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/IntrinsicHIXYZ.out (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/IntrinsicM.ll (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/IntrinsicM.out (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/IntrinsicMeasureWithBitFlipCode.ll (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/IntrinsicMeasureWithBitFlipCode.out (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/IntrinsicMeasureWithPhaseFlipCode.ll (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/IntrinsicMeasureWithPhaseFlipCode.out (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/IntrinsicRotationsWithPeriod.ll (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/IntrinsicRotationsWithPeriod.out (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/IntrinsicSTSWAP.ll (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/IntrinsicSTSWAP.out (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/MeasureAndReuse.ll (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/MeasureAndReuse.out (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/MeasurementComparison.ll (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/MeasurementComparison.out (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/NestedBranching.ll (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/NestedBranching.out (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/RandomBit.ll (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/RandomBit.out (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/SampleTeleport.ll (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/SampleTeleport.out (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/ShortcuttingMeasurement.ll (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/ShortcuttingMeasurement.out (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/Slicing.ll (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/Slicing.out (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/SuperdenseCoding.ll (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/SuperdenseCoding.out (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/SwitchHandling.ll (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/SwitchHandling.out (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/ThreeQubitRepetitionCode.ll (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/ThreeQubitRepetitionCode.out (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/WithinApply.ll (100%) rename pip/tests-integration/resources/{output/Adaptive_RI => adaptive_ri/output}/WithinApply.out (100%) diff --git a/pip/tests-integration/resources/ArithmeticOps.qs b/pip/tests-integration/resources/adaptive_ri/input/ArithmeticOps.qs similarity index 100% rename from pip/tests-integration/resources/ArithmeticOps.qs rename to pip/tests-integration/resources/adaptive_ri/input/ArithmeticOps.qs diff --git a/pip/tests-integration/resources/BernsteinVaziraniNISQ.qs b/pip/tests-integration/resources/adaptive_ri/input/BernsteinVaziraniNISQ.qs similarity index 100% rename from pip/tests-integration/resources/BernsteinVaziraniNISQ.qs rename to pip/tests-integration/resources/adaptive_ri/input/BernsteinVaziraniNISQ.qs diff --git a/pip/tests-integration/resources/ConstantFolding.qs b/pip/tests-integration/resources/adaptive_ri/input/ConstantFolding.qs similarity index 100% rename from pip/tests-integration/resources/ConstantFolding.qs rename to pip/tests-integration/resources/adaptive_ri/input/ConstantFolding.qs diff --git a/pip/tests-integration/resources/CopyAndUpdateExpressions.qs b/pip/tests-integration/resources/adaptive_ri/input/CopyAndUpdateExpressions.qs similarity index 100% rename from pip/tests-integration/resources/CopyAndUpdateExpressions.qs rename to pip/tests-integration/resources/adaptive_ri/input/CopyAndUpdateExpressions.qs diff --git a/pip/tests-integration/resources/DeutschJozsaNISQ.qs b/pip/tests-integration/resources/adaptive_ri/input/DeutschJozsaNISQ.qs similarity index 100% rename from pip/tests-integration/resources/DeutschJozsaNISQ.qs rename to pip/tests-integration/resources/adaptive_ri/input/DeutschJozsaNISQ.qs diff --git a/pip/tests-integration/resources/ExpandedTests.qs b/pip/tests-integration/resources/adaptive_ri/input/ExpandedTests.qs similarity index 100% rename from pip/tests-integration/resources/ExpandedTests.qs rename to pip/tests-integration/resources/adaptive_ri/input/ExpandedTests.qs diff --git a/pip/tests-integration/resources/Functors.qs b/pip/tests-integration/resources/adaptive_ri/input/Functors.qs similarity index 100% rename from pip/tests-integration/resources/Functors.qs rename to pip/tests-integration/resources/adaptive_ri/input/Functors.qs diff --git a/pip/tests-integration/resources/HiddenShiftNISQ.qs b/pip/tests-integration/resources/adaptive_ri/input/HiddenShiftNISQ.qs similarity index 100% rename from pip/tests-integration/resources/HiddenShiftNISQ.qs rename to pip/tests-integration/resources/adaptive_ri/input/HiddenShiftNISQ.qs diff --git a/pip/tests-integration/resources/IntegerComparison.qs b/pip/tests-integration/resources/adaptive_ri/input/IntegerComparison.qs similarity index 100% rename from pip/tests-integration/resources/IntegerComparison.qs rename to pip/tests-integration/resources/adaptive_ri/input/IntegerComparison.qs diff --git a/pip/tests-integration/resources/IntrinsicCCNOT.qs b/pip/tests-integration/resources/adaptive_ri/input/IntrinsicCCNOT.qs similarity index 100% rename from pip/tests-integration/resources/IntrinsicCCNOT.qs rename to pip/tests-integration/resources/adaptive_ri/input/IntrinsicCCNOT.qs diff --git a/pip/tests-integration/resources/IntrinsicCNOT.qs b/pip/tests-integration/resources/adaptive_ri/input/IntrinsicCNOT.qs similarity index 100% rename from pip/tests-integration/resources/IntrinsicCNOT.qs rename to pip/tests-integration/resources/adaptive_ri/input/IntrinsicCNOT.qs diff --git a/pip/tests-integration/resources/IntrinsicHIXYZ.qs b/pip/tests-integration/resources/adaptive_ri/input/IntrinsicHIXYZ.qs similarity index 100% rename from pip/tests-integration/resources/IntrinsicHIXYZ.qs rename to pip/tests-integration/resources/adaptive_ri/input/IntrinsicHIXYZ.qs diff --git a/pip/tests-integration/resources/IntrinsicM.qs b/pip/tests-integration/resources/adaptive_ri/input/IntrinsicM.qs similarity index 100% rename from pip/tests-integration/resources/IntrinsicM.qs rename to pip/tests-integration/resources/adaptive_ri/input/IntrinsicM.qs diff --git a/pip/tests-integration/resources/IntrinsicMeasureWithBitFlipCode.qs b/pip/tests-integration/resources/adaptive_ri/input/IntrinsicMeasureWithBitFlipCode.qs similarity index 100% rename from pip/tests-integration/resources/IntrinsicMeasureWithBitFlipCode.qs rename to pip/tests-integration/resources/adaptive_ri/input/IntrinsicMeasureWithBitFlipCode.qs diff --git a/pip/tests-integration/resources/IntrinsicMeasureWithPhaseFlipCode.qs b/pip/tests-integration/resources/adaptive_ri/input/IntrinsicMeasureWithPhaseFlipCode.qs similarity index 100% rename from pip/tests-integration/resources/IntrinsicMeasureWithPhaseFlipCode.qs rename to pip/tests-integration/resources/adaptive_ri/input/IntrinsicMeasureWithPhaseFlipCode.qs diff --git a/pip/tests-integration/resources/IntrinsicRotationsWithPeriod.qs b/pip/tests-integration/resources/adaptive_ri/input/IntrinsicRotationsWithPeriod.qs similarity index 100% rename from pip/tests-integration/resources/IntrinsicRotationsWithPeriod.qs rename to pip/tests-integration/resources/adaptive_ri/input/IntrinsicRotationsWithPeriod.qs diff --git a/pip/tests-integration/resources/IntrinsicSTSWAP.qs b/pip/tests-integration/resources/adaptive_ri/input/IntrinsicSTSWAP.qs similarity index 100% rename from pip/tests-integration/resources/IntrinsicSTSWAP.qs rename to pip/tests-integration/resources/adaptive_ri/input/IntrinsicSTSWAP.qs diff --git a/pip/tests-integration/resources/MeasureAndReuse.qs b/pip/tests-integration/resources/adaptive_ri/input/MeasureAndReuse.qs similarity index 100% rename from pip/tests-integration/resources/MeasureAndReuse.qs rename to pip/tests-integration/resources/adaptive_ri/input/MeasureAndReuse.qs diff --git a/pip/tests-integration/resources/MeasurementComparison.qs b/pip/tests-integration/resources/adaptive_ri/input/MeasurementComparison.qs similarity index 100% rename from pip/tests-integration/resources/MeasurementComparison.qs rename to pip/tests-integration/resources/adaptive_ri/input/MeasurementComparison.qs diff --git a/pip/tests-integration/resources/NestedBranching.qs b/pip/tests-integration/resources/adaptive_ri/input/NestedBranching.qs similarity index 100% rename from pip/tests-integration/resources/NestedBranching.qs rename to pip/tests-integration/resources/adaptive_ri/input/NestedBranching.qs diff --git a/pip/tests-integration/resources/RandomBit.qs b/pip/tests-integration/resources/adaptive_ri/input/RandomBit.qs similarity index 100% rename from pip/tests-integration/resources/RandomBit.qs rename to pip/tests-integration/resources/adaptive_ri/input/RandomBit.qs diff --git a/pip/tests-integration/resources/SampleTeleport.qs b/pip/tests-integration/resources/adaptive_ri/input/SampleTeleport.qs similarity index 100% rename from pip/tests-integration/resources/SampleTeleport.qs rename to pip/tests-integration/resources/adaptive_ri/input/SampleTeleport.qs diff --git a/pip/tests-integration/resources/ShortcuttingMeasurement.qs b/pip/tests-integration/resources/adaptive_ri/input/ShortcuttingMeasurement.qs similarity index 100% rename from pip/tests-integration/resources/ShortcuttingMeasurement.qs rename to pip/tests-integration/resources/adaptive_ri/input/ShortcuttingMeasurement.qs diff --git a/pip/tests-integration/resources/Slicing.qs b/pip/tests-integration/resources/adaptive_ri/input/Slicing.qs similarity index 100% rename from pip/tests-integration/resources/Slicing.qs rename to pip/tests-integration/resources/adaptive_ri/input/Slicing.qs diff --git a/pip/tests-integration/resources/SuperdenseCoding.qs b/pip/tests-integration/resources/adaptive_ri/input/SuperdenseCoding.qs similarity index 100% rename from pip/tests-integration/resources/SuperdenseCoding.qs rename to pip/tests-integration/resources/adaptive_ri/input/SuperdenseCoding.qs diff --git a/pip/tests-integration/resources/SwitchHandling.qs b/pip/tests-integration/resources/adaptive_ri/input/SwitchHandling.qs similarity index 100% rename from pip/tests-integration/resources/SwitchHandling.qs rename to pip/tests-integration/resources/adaptive_ri/input/SwitchHandling.qs diff --git a/pip/tests-integration/resources/ThreeQubitRepetitionCode.qs b/pip/tests-integration/resources/adaptive_ri/input/ThreeQubitRepetitionCode.qs similarity index 100% rename from pip/tests-integration/resources/ThreeQubitRepetitionCode.qs rename to pip/tests-integration/resources/adaptive_ri/input/ThreeQubitRepetitionCode.qs diff --git a/pip/tests-integration/resources/WithinApply.qs b/pip/tests-integration/resources/adaptive_ri/input/WithinApply.qs similarity index 100% rename from pip/tests-integration/resources/WithinApply.qs rename to pip/tests-integration/resources/adaptive_ri/input/WithinApply.qs diff --git a/pip/tests-integration/resources/output/Adaptive_RI/ArithmeticOps.ll b/pip/tests-integration/resources/adaptive_ri/output/ArithmeticOps.ll similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/ArithmeticOps.ll rename to pip/tests-integration/resources/adaptive_ri/output/ArithmeticOps.ll diff --git a/pip/tests-integration/resources/output/Adaptive_RI/ArithmeticOps.out b/pip/tests-integration/resources/adaptive_ri/output/ArithmeticOps.out similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/ArithmeticOps.out rename to pip/tests-integration/resources/adaptive_ri/output/ArithmeticOps.out diff --git a/pip/tests-integration/resources/output/Adaptive_RI/BernsteinVaziraniNISQ.ll b/pip/tests-integration/resources/adaptive_ri/output/BernsteinVaziraniNISQ.ll similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/BernsteinVaziraniNISQ.ll rename to pip/tests-integration/resources/adaptive_ri/output/BernsteinVaziraniNISQ.ll diff --git a/pip/tests-integration/resources/output/Adaptive_RI/BernsteinVaziraniNISQ.out b/pip/tests-integration/resources/adaptive_ri/output/BernsteinVaziraniNISQ.out similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/BernsteinVaziraniNISQ.out rename to pip/tests-integration/resources/adaptive_ri/output/BernsteinVaziraniNISQ.out diff --git a/pip/tests-integration/resources/output/Adaptive_RI/ConstantFolding.ll b/pip/tests-integration/resources/adaptive_ri/output/ConstantFolding.ll similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/ConstantFolding.ll rename to pip/tests-integration/resources/adaptive_ri/output/ConstantFolding.ll diff --git a/pip/tests-integration/resources/output/Adaptive_RI/ConstantFolding.out b/pip/tests-integration/resources/adaptive_ri/output/ConstantFolding.out similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/ConstantFolding.out rename to pip/tests-integration/resources/adaptive_ri/output/ConstantFolding.out diff --git a/pip/tests-integration/resources/output/Adaptive_RI/CopyAndUpdateExpressions.ll b/pip/tests-integration/resources/adaptive_ri/output/CopyAndUpdateExpressions.ll similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/CopyAndUpdateExpressions.ll rename to pip/tests-integration/resources/adaptive_ri/output/CopyAndUpdateExpressions.ll diff --git a/pip/tests-integration/resources/output/Adaptive_RI/CopyAndUpdateExpressions.out b/pip/tests-integration/resources/adaptive_ri/output/CopyAndUpdateExpressions.out similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/CopyAndUpdateExpressions.out rename to pip/tests-integration/resources/adaptive_ri/output/CopyAndUpdateExpressions.out diff --git a/pip/tests-integration/resources/output/Adaptive_RI/DeutschJozsaNISQ.ll b/pip/tests-integration/resources/adaptive_ri/output/DeutschJozsaNISQ.ll similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/DeutschJozsaNISQ.ll rename to pip/tests-integration/resources/adaptive_ri/output/DeutschJozsaNISQ.ll diff --git a/pip/tests-integration/resources/output/Adaptive_RI/DeutschJozsaNISQ.out b/pip/tests-integration/resources/adaptive_ri/output/DeutschJozsaNISQ.out similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/DeutschJozsaNISQ.out rename to pip/tests-integration/resources/adaptive_ri/output/DeutschJozsaNISQ.out diff --git a/pip/tests-integration/resources/output/Adaptive_RI/ExpandedTests.ll b/pip/tests-integration/resources/adaptive_ri/output/ExpandedTests.ll similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/ExpandedTests.ll rename to pip/tests-integration/resources/adaptive_ri/output/ExpandedTests.ll diff --git a/pip/tests-integration/resources/output/Adaptive_RI/ExpandedTests.out b/pip/tests-integration/resources/adaptive_ri/output/ExpandedTests.out similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/ExpandedTests.out rename to pip/tests-integration/resources/adaptive_ri/output/ExpandedTests.out diff --git a/pip/tests-integration/resources/output/Adaptive_RI/Functors.ll b/pip/tests-integration/resources/adaptive_ri/output/Functors.ll similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/Functors.ll rename to pip/tests-integration/resources/adaptive_ri/output/Functors.ll diff --git a/pip/tests-integration/resources/output/Adaptive_RI/Functors.out b/pip/tests-integration/resources/adaptive_ri/output/Functors.out similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/Functors.out rename to pip/tests-integration/resources/adaptive_ri/output/Functors.out diff --git a/pip/tests-integration/resources/output/Adaptive_RI/HiddenShiftNISQ.ll b/pip/tests-integration/resources/adaptive_ri/output/HiddenShiftNISQ.ll similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/HiddenShiftNISQ.ll rename to pip/tests-integration/resources/adaptive_ri/output/HiddenShiftNISQ.ll diff --git a/pip/tests-integration/resources/output/Adaptive_RI/HiddenShiftNISQ.out b/pip/tests-integration/resources/adaptive_ri/output/HiddenShiftNISQ.out similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/HiddenShiftNISQ.out rename to pip/tests-integration/resources/adaptive_ri/output/HiddenShiftNISQ.out diff --git a/pip/tests-integration/resources/output/Adaptive_RI/IntegerComparison.ll b/pip/tests-integration/resources/adaptive_ri/output/IntegerComparison.ll similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/IntegerComparison.ll rename to pip/tests-integration/resources/adaptive_ri/output/IntegerComparison.ll diff --git a/pip/tests-integration/resources/output/Adaptive_RI/IntegerComparison.out b/pip/tests-integration/resources/adaptive_ri/output/IntegerComparison.out similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/IntegerComparison.out rename to pip/tests-integration/resources/adaptive_ri/output/IntegerComparison.out diff --git a/pip/tests-integration/resources/output/Adaptive_RI/IntrinsicCCNOT.ll b/pip/tests-integration/resources/adaptive_ri/output/IntrinsicCCNOT.ll similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/IntrinsicCCNOT.ll rename to pip/tests-integration/resources/adaptive_ri/output/IntrinsicCCNOT.ll diff --git a/pip/tests-integration/resources/output/Adaptive_RI/IntrinsicCCNOT.out b/pip/tests-integration/resources/adaptive_ri/output/IntrinsicCCNOT.out similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/IntrinsicCCNOT.out rename to pip/tests-integration/resources/adaptive_ri/output/IntrinsicCCNOT.out diff --git a/pip/tests-integration/resources/output/Adaptive_RI/IntrinsicCNOT.ll b/pip/tests-integration/resources/adaptive_ri/output/IntrinsicCNOT.ll similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/IntrinsicCNOT.ll rename to pip/tests-integration/resources/adaptive_ri/output/IntrinsicCNOT.ll diff --git a/pip/tests-integration/resources/output/Adaptive_RI/IntrinsicCNOT.out b/pip/tests-integration/resources/adaptive_ri/output/IntrinsicCNOT.out similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/IntrinsicCNOT.out rename to pip/tests-integration/resources/adaptive_ri/output/IntrinsicCNOT.out diff --git a/pip/tests-integration/resources/output/Adaptive_RI/IntrinsicHIXYZ.ll b/pip/tests-integration/resources/adaptive_ri/output/IntrinsicHIXYZ.ll similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/IntrinsicHIXYZ.ll rename to pip/tests-integration/resources/adaptive_ri/output/IntrinsicHIXYZ.ll diff --git a/pip/tests-integration/resources/output/Adaptive_RI/IntrinsicHIXYZ.out b/pip/tests-integration/resources/adaptive_ri/output/IntrinsicHIXYZ.out similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/IntrinsicHIXYZ.out rename to pip/tests-integration/resources/adaptive_ri/output/IntrinsicHIXYZ.out diff --git a/pip/tests-integration/resources/output/Adaptive_RI/IntrinsicM.ll b/pip/tests-integration/resources/adaptive_ri/output/IntrinsicM.ll similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/IntrinsicM.ll rename to pip/tests-integration/resources/adaptive_ri/output/IntrinsicM.ll diff --git a/pip/tests-integration/resources/output/Adaptive_RI/IntrinsicM.out b/pip/tests-integration/resources/adaptive_ri/output/IntrinsicM.out similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/IntrinsicM.out rename to pip/tests-integration/resources/adaptive_ri/output/IntrinsicM.out diff --git a/pip/tests-integration/resources/output/Adaptive_RI/IntrinsicMeasureWithBitFlipCode.ll b/pip/tests-integration/resources/adaptive_ri/output/IntrinsicMeasureWithBitFlipCode.ll similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/IntrinsicMeasureWithBitFlipCode.ll rename to pip/tests-integration/resources/adaptive_ri/output/IntrinsicMeasureWithBitFlipCode.ll diff --git a/pip/tests-integration/resources/output/Adaptive_RI/IntrinsicMeasureWithBitFlipCode.out b/pip/tests-integration/resources/adaptive_ri/output/IntrinsicMeasureWithBitFlipCode.out similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/IntrinsicMeasureWithBitFlipCode.out rename to pip/tests-integration/resources/adaptive_ri/output/IntrinsicMeasureWithBitFlipCode.out diff --git a/pip/tests-integration/resources/output/Adaptive_RI/IntrinsicMeasureWithPhaseFlipCode.ll b/pip/tests-integration/resources/adaptive_ri/output/IntrinsicMeasureWithPhaseFlipCode.ll similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/IntrinsicMeasureWithPhaseFlipCode.ll rename to pip/tests-integration/resources/adaptive_ri/output/IntrinsicMeasureWithPhaseFlipCode.ll diff --git a/pip/tests-integration/resources/output/Adaptive_RI/IntrinsicMeasureWithPhaseFlipCode.out b/pip/tests-integration/resources/adaptive_ri/output/IntrinsicMeasureWithPhaseFlipCode.out similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/IntrinsicMeasureWithPhaseFlipCode.out rename to pip/tests-integration/resources/adaptive_ri/output/IntrinsicMeasureWithPhaseFlipCode.out diff --git a/pip/tests-integration/resources/output/Adaptive_RI/IntrinsicRotationsWithPeriod.ll b/pip/tests-integration/resources/adaptive_ri/output/IntrinsicRotationsWithPeriod.ll similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/IntrinsicRotationsWithPeriod.ll rename to pip/tests-integration/resources/adaptive_ri/output/IntrinsicRotationsWithPeriod.ll diff --git a/pip/tests-integration/resources/output/Adaptive_RI/IntrinsicRotationsWithPeriod.out b/pip/tests-integration/resources/adaptive_ri/output/IntrinsicRotationsWithPeriod.out similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/IntrinsicRotationsWithPeriod.out rename to pip/tests-integration/resources/adaptive_ri/output/IntrinsicRotationsWithPeriod.out diff --git a/pip/tests-integration/resources/output/Adaptive_RI/IntrinsicSTSWAP.ll b/pip/tests-integration/resources/adaptive_ri/output/IntrinsicSTSWAP.ll similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/IntrinsicSTSWAP.ll rename to pip/tests-integration/resources/adaptive_ri/output/IntrinsicSTSWAP.ll diff --git a/pip/tests-integration/resources/output/Adaptive_RI/IntrinsicSTSWAP.out b/pip/tests-integration/resources/adaptive_ri/output/IntrinsicSTSWAP.out similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/IntrinsicSTSWAP.out rename to pip/tests-integration/resources/adaptive_ri/output/IntrinsicSTSWAP.out diff --git a/pip/tests-integration/resources/output/Adaptive_RI/MeasureAndReuse.ll b/pip/tests-integration/resources/adaptive_ri/output/MeasureAndReuse.ll similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/MeasureAndReuse.ll rename to pip/tests-integration/resources/adaptive_ri/output/MeasureAndReuse.ll diff --git a/pip/tests-integration/resources/output/Adaptive_RI/MeasureAndReuse.out b/pip/tests-integration/resources/adaptive_ri/output/MeasureAndReuse.out similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/MeasureAndReuse.out rename to pip/tests-integration/resources/adaptive_ri/output/MeasureAndReuse.out diff --git a/pip/tests-integration/resources/output/Adaptive_RI/MeasurementComparison.ll b/pip/tests-integration/resources/adaptive_ri/output/MeasurementComparison.ll similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/MeasurementComparison.ll rename to pip/tests-integration/resources/adaptive_ri/output/MeasurementComparison.ll diff --git a/pip/tests-integration/resources/output/Adaptive_RI/MeasurementComparison.out b/pip/tests-integration/resources/adaptive_ri/output/MeasurementComparison.out similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/MeasurementComparison.out rename to pip/tests-integration/resources/adaptive_ri/output/MeasurementComparison.out diff --git a/pip/tests-integration/resources/output/Adaptive_RI/NestedBranching.ll b/pip/tests-integration/resources/adaptive_ri/output/NestedBranching.ll similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/NestedBranching.ll rename to pip/tests-integration/resources/adaptive_ri/output/NestedBranching.ll diff --git a/pip/tests-integration/resources/output/Adaptive_RI/NestedBranching.out b/pip/tests-integration/resources/adaptive_ri/output/NestedBranching.out similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/NestedBranching.out rename to pip/tests-integration/resources/adaptive_ri/output/NestedBranching.out diff --git a/pip/tests-integration/resources/output/Adaptive_RI/RandomBit.ll b/pip/tests-integration/resources/adaptive_ri/output/RandomBit.ll similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/RandomBit.ll rename to pip/tests-integration/resources/adaptive_ri/output/RandomBit.ll diff --git a/pip/tests-integration/resources/output/Adaptive_RI/RandomBit.out b/pip/tests-integration/resources/adaptive_ri/output/RandomBit.out similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/RandomBit.out rename to pip/tests-integration/resources/adaptive_ri/output/RandomBit.out diff --git a/pip/tests-integration/resources/output/Adaptive_RI/SampleTeleport.ll b/pip/tests-integration/resources/adaptive_ri/output/SampleTeleport.ll similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/SampleTeleport.ll rename to pip/tests-integration/resources/adaptive_ri/output/SampleTeleport.ll diff --git a/pip/tests-integration/resources/output/Adaptive_RI/SampleTeleport.out b/pip/tests-integration/resources/adaptive_ri/output/SampleTeleport.out similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/SampleTeleport.out rename to pip/tests-integration/resources/adaptive_ri/output/SampleTeleport.out diff --git a/pip/tests-integration/resources/output/Adaptive_RI/ShortcuttingMeasurement.ll b/pip/tests-integration/resources/adaptive_ri/output/ShortcuttingMeasurement.ll similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/ShortcuttingMeasurement.ll rename to pip/tests-integration/resources/adaptive_ri/output/ShortcuttingMeasurement.ll diff --git a/pip/tests-integration/resources/output/Adaptive_RI/ShortcuttingMeasurement.out b/pip/tests-integration/resources/adaptive_ri/output/ShortcuttingMeasurement.out similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/ShortcuttingMeasurement.out rename to pip/tests-integration/resources/adaptive_ri/output/ShortcuttingMeasurement.out diff --git a/pip/tests-integration/resources/output/Adaptive_RI/Slicing.ll b/pip/tests-integration/resources/adaptive_ri/output/Slicing.ll similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/Slicing.ll rename to pip/tests-integration/resources/adaptive_ri/output/Slicing.ll diff --git a/pip/tests-integration/resources/output/Adaptive_RI/Slicing.out b/pip/tests-integration/resources/adaptive_ri/output/Slicing.out similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/Slicing.out rename to pip/tests-integration/resources/adaptive_ri/output/Slicing.out diff --git a/pip/tests-integration/resources/output/Adaptive_RI/SuperdenseCoding.ll b/pip/tests-integration/resources/adaptive_ri/output/SuperdenseCoding.ll similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/SuperdenseCoding.ll rename to pip/tests-integration/resources/adaptive_ri/output/SuperdenseCoding.ll diff --git a/pip/tests-integration/resources/output/Adaptive_RI/SuperdenseCoding.out b/pip/tests-integration/resources/adaptive_ri/output/SuperdenseCoding.out similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/SuperdenseCoding.out rename to pip/tests-integration/resources/adaptive_ri/output/SuperdenseCoding.out diff --git a/pip/tests-integration/resources/output/Adaptive_RI/SwitchHandling.ll b/pip/tests-integration/resources/adaptive_ri/output/SwitchHandling.ll similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/SwitchHandling.ll rename to pip/tests-integration/resources/adaptive_ri/output/SwitchHandling.ll diff --git a/pip/tests-integration/resources/output/Adaptive_RI/SwitchHandling.out b/pip/tests-integration/resources/adaptive_ri/output/SwitchHandling.out similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/SwitchHandling.out rename to pip/tests-integration/resources/adaptive_ri/output/SwitchHandling.out diff --git a/pip/tests-integration/resources/output/Adaptive_RI/ThreeQubitRepetitionCode.ll b/pip/tests-integration/resources/adaptive_ri/output/ThreeQubitRepetitionCode.ll similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/ThreeQubitRepetitionCode.ll rename to pip/tests-integration/resources/adaptive_ri/output/ThreeQubitRepetitionCode.ll diff --git a/pip/tests-integration/resources/output/Adaptive_RI/ThreeQubitRepetitionCode.out b/pip/tests-integration/resources/adaptive_ri/output/ThreeQubitRepetitionCode.out similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/ThreeQubitRepetitionCode.out rename to pip/tests-integration/resources/adaptive_ri/output/ThreeQubitRepetitionCode.out diff --git a/pip/tests-integration/resources/output/Adaptive_RI/WithinApply.ll b/pip/tests-integration/resources/adaptive_ri/output/WithinApply.ll similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/WithinApply.ll rename to pip/tests-integration/resources/adaptive_ri/output/WithinApply.ll diff --git a/pip/tests-integration/resources/output/Adaptive_RI/WithinApply.out b/pip/tests-integration/resources/adaptive_ri/output/WithinApply.out similarity index 100% rename from pip/tests-integration/resources/output/Adaptive_RI/WithinApply.out rename to pip/tests-integration/resources/adaptive_ri/output/WithinApply.out diff --git a/pip/tests-integration/test_adaptive_ri_qir.py b/pip/tests-integration/test_adaptive_ri_qir.py index 5ea704a6a1..7098ec57bf 100644 --- a/pip/tests-integration/test_adaptive_ri_qir.py +++ b/pip/tests-integration/test_adaptive_ri_qir.py @@ -4,6 +4,7 @@ import pytest +from qsharp import TargetProfile from utils import ( assert_strings_equal_ignore_line_endings, compile_qsharp, @@ -17,22 +18,24 @@ ) -@pytest.mark.parametrize("file_path", get_input_files()) +@pytest.mark.parametrize("file_path", get_input_files(TargetProfile.Adaptive_RI)) @pytest.mark.skipif(not QIR_RUNNER_AVAILABLE, reason=SKIP_REASON) def test_adaptive_ri_qir(file_path: str) -> None: - source = read_file(file_path) - ll_file_path = get_output_ll_file(file_path) - expected_qir = read_file(ll_file_path) - actual_qir = compile_qsharp(source) + source = read_file(file_path, TargetProfile.Adaptive_RI) + ll_file_path = get_output_ll_file(file_path, TargetProfile.Adaptive_RI) + expected_qir = read_file(ll_file_path, TargetProfile.Adaptive_RI) + actual_qir = compile_qsharp( + source, + ) assert actual_qir == expected_qir -@pytest.mark.parametrize("file_path", get_input_files()) +@pytest.mark.parametrize("file_path", get_input_files(TargetProfile.Adaptive_RI)) @pytest.mark.skipif(not QIR_RUNNER_AVAILABLE, reason=SKIP_REASON) def test_adaptive_ri_output(file_path: str) -> None: - source = read_file(file_path) - qir = compile_qsharp(source) - output_file_path = get_output_out_file(file_path) - expected_output = read_file(output_file_path) + source = read_file(file_path, TargetProfile.Adaptive_RI) + qir = compile_qsharp(source, TargetProfile.Adaptive_RI) + output_file_path = get_output_out_file(file_path, TargetProfile.Adaptive_RI) + expected_output = read_file(output_file_path, TargetProfile.Adaptive_RI) actual_output = save_qir_to_temp_file_and_execute(qir) assert_strings_equal_ignore_line_endings(actual_output, expected_output) diff --git a/pip/tests-integration/utils.py b/pip/tests-integration/utils.py index 04154be614..de8cd1ccf7 100644 --- a/pip/tests-integration/utils.py +++ b/pip/tests-integration/utils.py @@ -32,19 +32,33 @@ SKIP_REASON = "QIR runner is not available" +def get_resource_dir(target_profile: TargetProfile) -> str: + return os.path.join( + os.path.dirname(__file__), "resources", str(target_profile).lower() + ) + + +def get_input_dir(target_profile: TargetProfile) -> str: + return os.path.join(get_resource_dir(target_profile), "input") + + +def get_output_dir(target_profile: TargetProfile) -> str: + return os.path.join(get_resource_dir(target_profile), "output") + + # This function is used to generate the expected output files for the tests # Rename the function to start with test_ to generate the expected output files -def generate_test_outputs() -> None: - input_files = get_input_files() - output_dir = get_output_dir() +def generate_test_outputs(target_profile: TargetProfile) -> None: + input_files = get_input_files(target_profile) + output_dir = get_output_dir(target_profile) os.makedirs(output_dir, exist_ok=True) for file_path in input_files: - ll_file_path = get_output_ll_file(file_path) - out_file_path = get_output_out_file(file_path) + ll_file_path = get_output_ll_file(file_path, target_profile) + out_file_path = get_output_out_file(file_path, target_profile) with open(file_path, "rt", encoding="utf-8") as f: source = f.read() - qir = compile_qsharp(source) + qir = compile_qsharp(source, target_profile) with open(ll_file_path, "wt", encoding="utf-8") as f: f.write(qir) output = execute_qir(ll_file_path) @@ -52,8 +66,8 @@ def generate_test_outputs() -> None: f.write(output) -def read_file(file_name: str) -> str: - file_path = os.path.join(os.path.dirname(__file__), "resources", file_name) +def read_file(file_name: str, target_profile: TargetProfile) -> str: + file_path = os.path.join(get_input_dir(target_profile), file_name) with open(file_path, "rt", encoding="utf-8") as file: source = file.read() return source @@ -132,8 +146,8 @@ def compile_qsharp( return qir -def get_input_files() -> List[str]: - resources_dir = get_resource_dir() +def get_input_files(target_profile: TargetProfile) -> List[str]: + resources_dir = get_input_dir(target_profile) input_files = [ os.path.join(resources_dir, file_name) for file_name in os.listdir(resources_dir) @@ -142,26 +156,18 @@ def get_input_files() -> List[str]: return input_files -def get_resource_dir() -> str: - return os.path.join(os.path.dirname(__file__), "resources") - - -def get_output_dir() -> str: - return os.path.join(get_resource_dir(), "output", "Adaptive_RI") - - -def get_ouput_file_basename(file_path: str) -> str: +def get_ouput_file_basename(file_path: str, target_profile: TargetProfile) -> str: file_name, _ext = os.path.splitext(file_path) - output_dir = get_output_dir() + output_dir = get_output_dir(target_profile) output_file = os.path.join(output_dir, os.path.basename(file_name)) return output_file -def get_output_ll_file(file_path: str) -> str: - output_file = get_ouput_file_basename(file_path) +def get_output_ll_file(file_path: str, target_profile: TargetProfile) -> str: + output_file = get_ouput_file_basename(file_path, target_profile) return output_file + ".ll" -def get_output_out_file(file_path: str) -> str: - output_file = get_ouput_file_basename(file_path) +def get_output_out_file(file_path: str, target_profile: TargetProfile) -> str: + output_file = get_ouput_file_basename(file_path, target_profile) return output_file + ".out" From ef44f65283dcc4a92ee072a684ffb39bb7492b02 Mon Sep 17 00:00:00 2001 From: Ian Davis Date: Fri, 3 Jan 2025 15:05:14 -0800 Subject: [PATCH 8/9] Adding RIF integration test case. --- .../resources/adaptive_rif/input/Doubles.qs | 28 ++++ .../resources/adaptive_rif/output/Doubles.ll | 147 ++++++++++++++++++ .../resources/adaptive_rif/output/Doubles.out | 14 ++ pip/tests-integration/test_adaptive_ri_qir.py | 36 +++-- .../test_adaptive_rif_qir.py | 49 ++++++ pip/tests-integration/utils.py | 2 - 6 files changed, 260 insertions(+), 16 deletions(-) create mode 100644 pip/tests-integration/resources/adaptive_rif/input/Doubles.qs create mode 100644 pip/tests-integration/resources/adaptive_rif/output/Doubles.ll create mode 100644 pip/tests-integration/resources/adaptive_rif/output/Doubles.out create mode 100644 pip/tests-integration/test_adaptive_rif_qir.py diff --git a/pip/tests-integration/resources/adaptive_rif/input/Doubles.qs b/pip/tests-integration/resources/adaptive_rif/input/Doubles.qs new file mode 100644 index 0000000000..0bb80a8183 --- /dev/null +++ b/pip/tests-integration/resources/adaptive_rif/input/Doubles.qs @@ -0,0 +1,28 @@ +namespace Test { + + import Std.Intrinsic.*; + + // Demonstrates use of double comparisons. + // Expected output: (10.0, true, false, true, true, false) + @EntryPoint() + operation Main() : (Double, Bool, Bool, Bool, Bool, Bool) { + mutable count = 0.0; + use q = Qubit(); + for _ in 1..10 { + X(q); + if M(q) == One { + X(q); + set count += 1.0; + // These are all valid operations on doubles. + // they will be uncommented and tested in the future. + // once we fix the issue with the QIR generation. + //set count *= 1.0; + //set count /= 1.0; + //set count -= 1.0; + //set count += 1.0; + } + } + Reset(q); + return (count, count > 5.0, count < 5.0, count >= 10.0, count == 10.0, count != 10.0); + } +} diff --git a/pip/tests-integration/resources/adaptive_rif/output/Doubles.ll b/pip/tests-integration/resources/adaptive_rif/output/Doubles.ll new file mode 100644 index 0000000000..3005717a1b --- /dev/null +++ b/pip/tests-integration/resources/adaptive_rif/output/Doubles.ll @@ -0,0 +1,147 @@ +%Result = type opaque +%Qubit = type opaque + +define void @ENTRYPOINT__main() #0 { +block_0: + call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 0 to %Qubit*)) + call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*)) + %var_2 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 0 to %Result*)) + br i1 %var_2, label %block_1, label %block_2 +block_1: + call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 0 to %Qubit*)) + br label %block_2 +block_2: + %var_36 = phi double [0.0, %block_0], [1.0, %block_1] + call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 0 to %Qubit*)) + call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 1 to %Result*)) + %var_4 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 1 to %Result*)) + br i1 %var_4, label %block_3, label %block_4 +block_3: + call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 0 to %Qubit*)) + %var_6 = fadd double %var_36, 1.0 + br label %block_4 +block_4: + %var_37 = phi double [%var_36, %block_2], [%var_6, %block_3] + call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 0 to %Qubit*)) + call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 2 to %Result*)) + %var_7 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 2 to %Result*)) + br i1 %var_7, label %block_5, label %block_6 +block_5: + call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 0 to %Qubit*)) + %var_9 = fadd double %var_37, 1.0 + br label %block_6 +block_6: + %var_38 = phi double [%var_37, %block_4], [%var_9, %block_5] + call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 0 to %Qubit*)) + call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 3 to %Result*)) + %var_10 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 3 to %Result*)) + br i1 %var_10, label %block_7, label %block_8 +block_7: + call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 0 to %Qubit*)) + %var_12 = fadd double %var_38, 1.0 + br label %block_8 +block_8: + %var_39 = phi double [%var_38, %block_6], [%var_12, %block_7] + call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 0 to %Qubit*)) + call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 4 to %Result*)) + %var_13 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 4 to %Result*)) + br i1 %var_13, label %block_9, label %block_10 +block_9: + call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 0 to %Qubit*)) + %var_15 = fadd double %var_39, 1.0 + br label %block_10 +block_10: + %var_40 = phi double [%var_39, %block_8], [%var_15, %block_9] + call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 0 to %Qubit*)) + call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 5 to %Result*)) + %var_16 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 5 to %Result*)) + br i1 %var_16, label %block_11, label %block_12 +block_11: + call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 0 to %Qubit*)) + %var_18 = fadd double %var_40, 1.0 + br label %block_12 +block_12: + %var_41 = phi double [%var_40, %block_10], [%var_18, %block_11] + call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 0 to %Qubit*)) + call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 6 to %Result*)) + %var_19 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 6 to %Result*)) + br i1 %var_19, label %block_13, label %block_14 +block_13: + call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 0 to %Qubit*)) + %var_21 = fadd double %var_41, 1.0 + br label %block_14 +block_14: + %var_42 = phi double [%var_41, %block_12], [%var_21, %block_13] + call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 0 to %Qubit*)) + call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 7 to %Result*)) + %var_22 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 7 to %Result*)) + br i1 %var_22, label %block_15, label %block_16 +block_15: + call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 0 to %Qubit*)) + %var_24 = fadd double %var_42, 1.0 + br label %block_16 +block_16: + %var_43 = phi double [%var_42, %block_14], [%var_24, %block_15] + call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 0 to %Qubit*)) + call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 8 to %Result*)) + %var_25 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 8 to %Result*)) + br i1 %var_25, label %block_17, label %block_18 +block_17: + call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 0 to %Qubit*)) + %var_27 = fadd double %var_43, 1.0 + br label %block_18 +block_18: + %var_44 = phi double [%var_43, %block_16], [%var_27, %block_17] + call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 0 to %Qubit*)) + call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 9 to %Result*)) + %var_28 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 9 to %Result*)) + br i1 %var_28, label %block_19, label %block_20 +block_19: + call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 0 to %Qubit*)) + %var_30 = fadd double %var_44, 1.0 + br label %block_20 +block_20: + %var_45 = phi double [%var_44, %block_18], [%var_30, %block_19] + call void @__quantum__qis__reset__body(%Qubit* inttoptr (i64 0 to %Qubit*)) + %var_31 = fcmp ogt double %var_45, 5.0 + %var_32 = fcmp olt double %var_45, 5.0 + %var_33 = fcmp oge double %var_45, 10.0 + %var_34 = fcmp oeq double %var_45, 10.0 + %var_35 = fcmp one double %var_45, 10.0 + call void @__quantum__rt__tuple_record_output(i64 6, i8* null) + call void @__quantum__rt__double_record_output(double %var_45, i8* null) + call void @__quantum__rt__bool_record_output(i1 %var_31, i8* null) + call void @__quantum__rt__bool_record_output(i1 %var_32, i8* null) + call void @__quantum__rt__bool_record_output(i1 %var_33, i8* null) + call void @__quantum__rt__bool_record_output(i1 %var_34, i8* null) + call void @__quantum__rt__bool_record_output(i1 %var_35, i8* null) + ret void +} + +declare void @__quantum__qis__x__body(%Qubit*) + +declare void @__quantum__qis__m__body(%Qubit*, %Result*) #1 + +declare i1 @__quantum__qis__read_result__body(%Result*) + +declare void @__quantum__qis__reset__body(%Qubit*) #1 + +declare void @__quantum__rt__tuple_record_output(i64, i8*) + +declare void @__quantum__rt__double_record_output(double, i8*) + +declare void @__quantum__rt__bool_record_output(i1, i8*) + +attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="adaptive_profile" "required_num_qubits"="1" "required_num_results"="10" } +attributes #1 = { "irreversible" } + +; module flags + +!llvm.module.flags = !{!0, !1, !2, !3, !4, !5} + +!0 = !{i32 1, !"qir_major_version", i32 1} +!1 = !{i32 7, !"qir_minor_version", i32 0} +!2 = !{i32 1, !"dynamic_qubit_management", i1 false} +!3 = !{i32 1, !"dynamic_result_management", i1 false} +!4 = !{i32 1, !"int_computations", !"i64"} +!5 = !{i32 1, !"float_computations", !"f64"} diff --git a/pip/tests-integration/resources/adaptive_rif/output/Doubles.out b/pip/tests-integration/resources/adaptive_rif/output/Doubles.out new file mode 100644 index 0000000000..ac07504f19 --- /dev/null +++ b/pip/tests-integration/resources/adaptive_rif/output/Doubles.out @@ -0,0 +1,14 @@ +START +METADATA entry_point +METADATA output_labeling_schema +METADATA qir_profiles adaptive_profile +METADATA required_num_qubits 1 +METADATA required_num_results 10 +OUTPUT TUPLE 6 +OUTPUT DOUBLE 10.0 +OUTPUT BOOL true +OUTPUT BOOL false +OUTPUT BOOL true +OUTPUT BOOL true +OUTPUT BOOL false +END 0 diff --git a/pip/tests-integration/test_adaptive_ri_qir.py b/pip/tests-integration/test_adaptive_ri_qir.py index 7098ec57bf..3fc2c9f117 100644 --- a/pip/tests-integration/test_adaptive_ri_qir.py +++ b/pip/tests-integration/test_adaptive_ri_qir.py @@ -17,25 +17,33 @@ SKIP_REASON, ) +TARGET_PROFILE = TargetProfile.Adaptive_RI -@pytest.mark.parametrize("file_path", get_input_files(TargetProfile.Adaptive_RI)) + +# This function is used to generate the expected output files for the tests +# Rename the function to start with test_ to generate the expected output files +def generate_test_outputs(): + from utils import generate_test_outputs + + generate_test_outputs(TARGET_PROFILE) + + +@pytest.mark.parametrize("file_path", get_input_files(TARGET_PROFILE)) @pytest.mark.skipif(not QIR_RUNNER_AVAILABLE, reason=SKIP_REASON) -def test_adaptive_ri_qir(file_path: str) -> None: - source = read_file(file_path, TargetProfile.Adaptive_RI) - ll_file_path = get_output_ll_file(file_path, TargetProfile.Adaptive_RI) - expected_qir = read_file(ll_file_path, TargetProfile.Adaptive_RI) - actual_qir = compile_qsharp( - source, - ) +def test_adaptive_rif_qir(file_path: str) -> None: + source = read_file(file_path, TARGET_PROFILE) + ll_file_path = get_output_ll_file(file_path, TARGET_PROFILE) + expected_qir = read_file(ll_file_path, TARGET_PROFILE) + actual_qir = compile_qsharp(source, TARGET_PROFILE) assert actual_qir == expected_qir -@pytest.mark.parametrize("file_path", get_input_files(TargetProfile.Adaptive_RI)) +@pytest.mark.parametrize("file_path", get_input_files(TARGET_PROFILE)) @pytest.mark.skipif(not QIR_RUNNER_AVAILABLE, reason=SKIP_REASON) -def test_adaptive_ri_output(file_path: str) -> None: - source = read_file(file_path, TargetProfile.Adaptive_RI) - qir = compile_qsharp(source, TargetProfile.Adaptive_RI) - output_file_path = get_output_out_file(file_path, TargetProfile.Adaptive_RI) - expected_output = read_file(output_file_path, TargetProfile.Adaptive_RI) +def test_adaptive_rif_output(file_path: str) -> None: + source = read_file(file_path, TARGET_PROFILE) + qir = compile_qsharp(source, TARGET_PROFILE) + output_file_path = get_output_out_file(file_path, TARGET_PROFILE) + expected_output = read_file(output_file_path, TARGET_PROFILE) actual_output = save_qir_to_temp_file_and_execute(qir) assert_strings_equal_ignore_line_endings(actual_output, expected_output) diff --git a/pip/tests-integration/test_adaptive_rif_qir.py b/pip/tests-integration/test_adaptive_rif_qir.py new file mode 100644 index 0000000000..87891f549a --- /dev/null +++ b/pip/tests-integration/test_adaptive_rif_qir.py @@ -0,0 +1,49 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + + +import pytest + +from qsharp import TargetProfile +from utils import ( + assert_strings_equal_ignore_line_endings, + compile_qsharp, + get_input_files, + get_output_ll_file, + get_output_out_file, + QIR_RUNNER_AVAILABLE, + read_file, + save_qir_to_temp_file_and_execute, + SKIP_REASON, +) + +TARGET_PROFILE = TargetProfile.Adaptive_RIF + + +# This function is used to generate the expected output files for the tests +# Rename the function to start with test_ to generate the expected output files +def generate_test_outputs(): + from utils import generate_test_outputs + + generate_test_outputs(TARGET_PROFILE) + + +@pytest.mark.parametrize("file_path", get_input_files(TARGET_PROFILE)) +@pytest.mark.skipif(not QIR_RUNNER_AVAILABLE, reason=SKIP_REASON) +def test_adaptive_rif_qir(file_path: str) -> None: + source = read_file(file_path, TARGET_PROFILE) + ll_file_path = get_output_ll_file(file_path, TARGET_PROFILE) + expected_qir = read_file(ll_file_path, TARGET_PROFILE) + actual_qir = compile_qsharp(source, TARGET_PROFILE) + assert actual_qir == expected_qir + + +@pytest.mark.parametrize("file_path", get_input_files(TARGET_PROFILE)) +@pytest.mark.skipif(not QIR_RUNNER_AVAILABLE, reason=SKIP_REASON) +def test_adaptive_rif_output(file_path: str) -> None: + source = read_file(file_path, TARGET_PROFILE) + qir = compile_qsharp(source, TARGET_PROFILE) + output_file_path = get_output_out_file(file_path, TARGET_PROFILE) + expected_output = read_file(output_file_path, TARGET_PROFILE) + actual_output = save_qir_to_temp_file_and_execute(qir) + assert_strings_equal_ignore_line_endings(actual_output, expected_output) diff --git a/pip/tests-integration/utils.py b/pip/tests-integration/utils.py index de8cd1ccf7..796e8db57b 100644 --- a/pip/tests-integration/utils.py +++ b/pip/tests-integration/utils.py @@ -46,8 +46,6 @@ def get_output_dir(target_profile: TargetProfile) -> str: return os.path.join(get_resource_dir(target_profile), "output") -# This function is used to generate the expected output files for the tests -# Rename the function to start with test_ to generate the expected output files def generate_test_outputs(target_profile: TargetProfile) -> None: input_files = get_input_files(target_profile) output_dir = get_output_dir(target_profile) From f75f79b31ff37edb5f6e880d041952cfc9befe17 Mon Sep 17 00:00:00 2001 From: Ian Davis Date: Mon, 6 Jan 2025 20:12:07 -0800 Subject: [PATCH 9/9] Feedback updates --- compiler/qsc_partial_eval/src/lib.rs | 157 +++++++++------------------ npm/qsharp/src/compiler/compiler.ts | 30 ++--- npm/qsharp/test/basics.js | 48 ++++++-- playground/src/editor.tsx | 4 +- 4 files changed, 105 insertions(+), 134 deletions(-) diff --git a/compiler/qsc_partial_eval/src/lib.rs b/compiler/qsc_partial_eval/src/lib.rs index 4b9e3d5588..1f1fd55732 100644 --- a/compiler/qsc_partial_eval/src/lib.rs +++ b/compiler/qsc_partial_eval/src/lib.rs @@ -1975,7 +1975,6 @@ impl<'a> PartialEvaluator<'a> { } } - #[allow(clippy::too_many_lines)] fn generate_instructions_for_binary_operation_with_double_operands( &mut self, bin_op: BinOp, @@ -1983,119 +1982,71 @@ impl<'a> PartialEvaluator<'a> { rhs_operand: Operand, bin_op_expr_span: PackageSpan, // For diagnostic purposes only. ) -> Result { - let rir_variable = match bin_op { - BinOp::Add => { - let bin_op_variable_id = self.resource_manager.next_var(); - let bin_op_rir_variable = rir::Variable::new_double(bin_op_variable_id); - let bin_op_rir_ins = - Instruction::Fadd(lhs_operand, rhs_operand, bin_op_rir_variable); - self.get_current_rir_block_mut().0.push(bin_op_rir_ins); - bin_op_rir_variable + let bin_op_variable_id = self.resource_manager.next_var(); + + let bin_op_rir_variable = match bin_op { + BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div => { + rir::Variable::new_double(bin_op_variable_id) } - BinOp::Sub => { - let bin_op_variable_id = self.resource_manager.next_var(); - let bin_op_rir_variable = rir::Variable::new_double(bin_op_variable_id); - let bin_op_rir_ins = - Instruction::Fsub(lhs_operand, rhs_operand, bin_op_rir_variable); - self.get_current_rir_block_mut().0.push(bin_op_rir_ins); - bin_op_rir_variable - } - BinOp::Mul => { - let bin_op_variable_id = self.resource_manager.next_var(); - let bin_op_rir_variable = rir::Variable::new_double(bin_op_variable_id); - let bin_op_rir_ins = - Instruction::Fmul(lhs_operand, rhs_operand, bin_op_rir_variable); - self.get_current_rir_block_mut().0.push(bin_op_rir_ins); - bin_op_rir_variable + BinOp::Eq | BinOp::Neq | BinOp::Gt | BinOp::Gte | BinOp::Lt | BinOp::Lte => { + rir::Variable::new_boolean(bin_op_variable_id) } + _ => panic!("unsupported binary operation for double: {bin_op:?}"), + }; + + let bin_op_rir_ins = match bin_op { + BinOp::Add => Instruction::Fadd(lhs_operand, rhs_operand, bin_op_rir_variable), + BinOp::Sub => Instruction::Fsub(lhs_operand, rhs_operand, bin_op_rir_variable), + BinOp::Mul => Instruction::Fmul(lhs_operand, rhs_operand, bin_op_rir_variable), BinOp::Div => { // Validate that the RHS is not a zero. if let Operand::Literal(Literal::Double(0.0)) = rhs_operand { let error = EvalError::DivZero(bin_op_expr_span).into(); return Err(error); } - let bin_op_variable_id = self.resource_manager.next_var(); - let bin_op_rir_variable = rir::Variable::new_double(bin_op_variable_id); - let bin_op_rir_ins = - Instruction::Fdiv(lhs_operand, rhs_operand, bin_op_rir_variable); - self.get_current_rir_block_mut().0.push(bin_op_rir_ins); - bin_op_rir_variable - } - BinOp::Eq => { - let bin_op_variable_id = self.resource_manager.next_var(); - let bin_op_rir_variable = rir::Variable::new_boolean(bin_op_variable_id); - let bin_op_rir_ins = Instruction::Fcmp( - FcmpConditionCode::OrderedAndEqual, - lhs_operand, - rhs_operand, - bin_op_rir_variable, - ); - self.get_current_rir_block_mut().0.push(bin_op_rir_ins); - bin_op_rir_variable - } - BinOp::Neq => { - let bin_op_variable_id = self.resource_manager.next_var(); - let bin_op_rir_variable = rir::Variable::new_boolean(bin_op_variable_id); - let bin_op_rir_ins = Instruction::Fcmp( - FcmpConditionCode::OrderedAndNotEqual, - lhs_operand, - rhs_operand, - bin_op_rir_variable, - ); - self.get_current_rir_block_mut().0.push(bin_op_rir_ins); - bin_op_rir_variable - } - BinOp::Gt => { - let bin_op_variable_id = self.resource_manager.next_var(); - let bin_op_rir_variable = rir::Variable::new_boolean(bin_op_variable_id); - let bin_op_rir_ins = Instruction::Fcmp( - FcmpConditionCode::OrderedAndGreaterThan, - lhs_operand, - rhs_operand, - bin_op_rir_variable, - ); - self.get_current_rir_block_mut().0.push(bin_op_rir_ins); - bin_op_rir_variable - } - BinOp::Gte => { - let bin_op_variable_id = self.resource_manager.next_var(); - let bin_op_rir_variable = rir::Variable::new_boolean(bin_op_variable_id); - let bin_op_rir_ins = Instruction::Fcmp( - FcmpConditionCode::OrderedAndGreaterThanOrEqual, - lhs_operand, - rhs_operand, - bin_op_rir_variable, - ); - self.get_current_rir_block_mut().0.push(bin_op_rir_ins); - bin_op_rir_variable - } - BinOp::Lt => { - let bin_op_variable_id = self.resource_manager.next_var(); - let bin_op_rir_variable = rir::Variable::new_boolean(bin_op_variable_id); - let bin_op_rir_ins = Instruction::Fcmp( - FcmpConditionCode::OrderedAndLessThan, - lhs_operand, - rhs_operand, - bin_op_rir_variable, - ); - self.get_current_rir_block_mut().0.push(bin_op_rir_ins); - bin_op_rir_variable - } - BinOp::Lte => { - let bin_op_variable_id = self.resource_manager.next_var(); - let bin_op_rir_variable = rir::Variable::new_boolean(bin_op_variable_id); - let bin_op_rir_ins = Instruction::Fcmp( - FcmpConditionCode::OrderedAndLessThanOrEqual, - lhs_operand, - rhs_operand, - bin_op_rir_variable, - ); - self.get_current_rir_block_mut().0.push(bin_op_rir_ins); - bin_op_rir_variable + + Instruction::Fdiv(lhs_operand, rhs_operand, bin_op_rir_variable) } + BinOp::Eq => Instruction::Fcmp( + FcmpConditionCode::OrderedAndEqual, + lhs_operand, + rhs_operand, + bin_op_rir_variable, + ), + BinOp::Neq => Instruction::Fcmp( + FcmpConditionCode::OrderedAndNotEqual, + lhs_operand, + rhs_operand, + bin_op_rir_variable, + ), + BinOp::Gt => Instruction::Fcmp( + FcmpConditionCode::OrderedAndGreaterThan, + lhs_operand, + rhs_operand, + bin_op_rir_variable, + ), + BinOp::Gte => Instruction::Fcmp( + FcmpConditionCode::OrderedAndGreaterThanOrEqual, + lhs_operand, + rhs_operand, + bin_op_rir_variable, + ), + BinOp::Lt => Instruction::Fcmp( + FcmpConditionCode::OrderedAndLessThan, + lhs_operand, + rhs_operand, + bin_op_rir_variable, + ), + BinOp::Lte => Instruction::Fcmp( + FcmpConditionCode::OrderedAndLessThanOrEqual, + lhs_operand, + rhs_operand, + bin_op_rir_variable, + ), _ => panic!("unsupported binary operation for double: {bin_op:?}"), }; - Ok(rir_variable) + self.get_current_rir_block_mut().0.push(bin_op_rir_ins); + Ok(bin_op_rir_variable) } #[allow(clippy::too_many_lines)] diff --git a/npm/qsharp/src/compiler/compiler.ts b/npm/qsharp/src/compiler/compiler.ts index c5a5cca211..334b1d7cb5 100644 --- a/npm/qsharp/src/compiler/compiler.ts +++ b/npm/qsharp/src/compiler/compiler.ts @@ -35,14 +35,14 @@ export interface ICompiler { getAst( code: string, - languageFeatures?: string[], - profile?: TargetProfile, + languageFeatures: string[], + profile: TargetProfile, ): Promise; getHir( code: string, - languageFeatures?: string[], - profile?: TargetProfile, + languageFeatures: string[], + profile: TargetProfile, ): Promise; run( @@ -88,7 +88,7 @@ export type ProgramConfig = ( /** An array of source objects, each containing a name and contents. */ sources: [string, string][]; /** An array of language features to be opted in to in this compilation. */ - languageFeatures?: string[]; + languageFeatures: string[]; } | { /** Sources from all resolved dependencies, along with their languageFeatures configuration */ @@ -103,10 +103,6 @@ export type ProgramConfig = ( export type ICompilerWorker = ICompiler & IServiceProxy; export type CompilerState = ServiceState; -function get_default_profile(): string { - return "adaptive_ri"; -} - export class Compiler implements ICompiler { private wasm: Wasm; @@ -144,14 +140,10 @@ export class Compiler implements ICompiler { async getAst( code: string, - languageFeatures?: string[], - profile?: TargetProfile, + languageFeatures: string[], + profile: TargetProfile, ): Promise { - return this.wasm.get_ast( - code, - languageFeatures ?? [], - profile ?? get_default_profile(), - ); + return this.wasm.get_ast(code, languageFeatures, profile); } async getHir( @@ -159,11 +151,7 @@ export class Compiler implements ICompiler { languageFeatures: string[], profile: TargetProfile, ): Promise { - return this.wasm.get_hir( - code, - languageFeatures ?? [], - profile ?? get_default_profile(), - ); + return this.wasm.get_hir(code, languageFeatures, profile); } async run( diff --git a/npm/qsharp/test/basics.js b/npm/qsharp/test/basics.js index 5372aa65d0..eae272142e 100644 --- a/npm/qsharp/test/basics.js +++ b/npm/qsharp/test/basics.js @@ -14,6 +14,7 @@ import { getDebugServiceWorker, utils, } from "../dist/main.js"; + import { QscEventTarget } from "../dist/compiler/events.js"; import { getAllKatas, getExerciseSources, getKata } from "../dist/katas.js"; import samples from "../dist/samples.generated.js"; @@ -36,7 +37,12 @@ export function runSingleShot(code, expr, useWorker) { const compiler = useWorker ? getCompilerWorker() : getCompiler(); compiler - .run({ sources: [["test.qs", code]] }, expr, 1, resultsHandler) + .run( + { sources: [["test.qs", code]], languageFeatures: [] }, + expr, + 1, + resultsHandler, + ) .then(() => resolve(resultsHandler.getResults()[0])) .catch((err) => reject(err)) /* @ts-expect-error: ICompiler does not include 'terminate' */ @@ -334,7 +340,7 @@ test("worker 100 shots", async () => { const resultsHandler = new QscEventTarget(true); const compiler = getCompilerWorker(); await compiler.run( - { sources: [["test.qs", code]] }, + { sources: [["test.qs", code]], languageFeatures: [] }, expr, 100, resultsHandler, @@ -358,7 +364,7 @@ test("Run samples", async () => { for await (const sample of testCases) { await compiler.run( - { sources: [["main.qs", sample.code]] }, + { sources: [["main.qs", sample.code]], languageFeatures: [] }, "", 1, resultsHandler, @@ -387,7 +393,12 @@ test("state change", async () => { return M(q1); } }`; - await compiler.run({ sources: [["test.qs", code]] }, "", 10, resultsHandler); + await compiler.run( + { sources: [["test.qs", code]], languageFeatures: [] }, + "", + 10, + resultsHandler, + ); compiler.terminate(); // There SHOULDN'T be a race condition here between the 'run' promise completing and the // statechange events firing, as the run promise should 'resolve' in the next microtask, @@ -416,11 +427,19 @@ test("cancel worker", () => { // Queue some tasks that will never complete compiler - .run({ sources: [["test.qs", code]] }, "", 10, resultsHandler) + .run( + { + sources: [["test.qs", code]], + languageFeatures: [], + }, + "", + 10, + resultsHandler, + ) .catch((err) => { cancelledArray.push(err); }); - compiler.getHir(code, []).catch((err) => { + compiler.getHir(code, [], "adaptive_ri").catch((err) => { cancelledArray.push(err); }); @@ -431,7 +450,7 @@ test("cancel worker", () => { // Start a new compiler and ensure that works fine const compiler2 = getCompilerWorker(); - const result = await compiler2.getHir(code, []); + const result = await compiler2.getHir(code, [], "adaptive_ri"); compiler2.terminate(); // getHir should have worked @@ -707,7 +726,12 @@ async function testCompilerError(useWorker) { let promiseResult = undefined; let lastState = undefined; await compiler - .run({ sources: [["test.qs", "invalid code"]] }, "", 1, events) + .run( + { sources: [["test.qs", "invalid code"]], languageFeatures: [] }, + "", + 1, + events, + ) .then(() => { promiseResult = "success"; }) @@ -748,6 +772,7 @@ test("debug service loading source without entry point attr fails - web worker", }`, ], ], + languageFeatures: [], profile: "base", }, undefined, @@ -772,6 +797,7 @@ test("debug service loading source with syntax error fails - web worker", async }`, ], ], + languageFeatures: [], profile: "base", }, undefined, @@ -790,6 +816,7 @@ test("debug service loading source with bad entry expr fails - web worker", asyn sources: [ ["test.qs", `namespace Sample { operation main() : Unit { } }`], ], + languageFeatures: [], profile: "base", }, "SomeBadExpr()", @@ -811,6 +838,7 @@ test("debug service loading source that doesn't match profile fails - web worker `namespace A { operation Test() : Double { use q = Qubit(); mutable x = 1.0; if MResetZ(q) == One { set x = 2.0; } x } }`, ], ], + languageFeatures: [], profile: "adaptive_ri", }, "A.Test()", @@ -829,6 +857,7 @@ test("debug service loading source with good entry expr succeeds - web worker", sources: [ ["test.qs", `namespace Sample { operation Main() : Unit { } }`], ], + languageFeatures: [], profile: "unrestricted", }, "Sample.Main()", @@ -859,6 +888,7 @@ test("debug service loading source with entry point attr succeeds - web worker", }`, ], ], + languageFeatures: [], profile: "base", }, undefined, @@ -889,6 +919,7 @@ test("debug service getting breakpoints after loaded source succeeds when file n }`, ], ], + languageFeatures: [], profile: "base", }, undefined, @@ -928,6 +959,7 @@ test("debug service compiling multiple sources - web worker", async () => { }`, ], ], + languageFeatures: [], profile: "unrestricted", }, undefined, diff --git a/playground/src/editor.tsx b/playground/src/editor.tsx index f0a690dc8f..83d1e3c3fd 100644 --- a/playground/src/editor.tsx +++ b/playground/src/editor.tsx @@ -144,7 +144,7 @@ export function Editor(props: { props.setAst( await props.compiler.getAst( code, - config.languageFeatures ?? [], + config.languageFeatures, config.profile, ), ); @@ -153,7 +153,7 @@ export function Editor(props: { props.setHir( await props.compiler.getHir( code, - config.languageFeatures ?? [], + config.languageFeatures, config.profile, ), );