microsoft/qdk

Public

mirrored fromhttps://github.com/microsoft/qdkAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
billti/bloch

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

compiler/qsc/src/codegen/tests.rs

1335lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4use expect_test::expect;
5use qsc_data_structures::{language_features::LanguageFeatures, target::TargetCapabilityFlags};
6use qsc_frontend::compile::SourceMap;
7
8use crate::codegen::qir::get_qir;
9
10#[test]
11fn code_with_errors_returns_errors() {
12 let source = "namespace Test {
13 @EntryPoint()
14 operation Main() : Unit {
15 use q = Qubit()
16 let pi_over_two = 4.0 / 2.0;
17 }
18 }";
19 let sources = SourceMap::new([("test.qs".into(), source.into())], None);
20 let language_features = LanguageFeatures::default();
21 let capabilities = TargetCapabilityFlags::empty();
22 let (std_id, store) = crate::compile::package_store_with_stdlib(capabilities);
23
24 expect![[r#"
25 Err(
26 [
27 Compile(
28 WithSource {
29 sources: [
30 Source {
31 name: "test.qs",
32 contents: "namespace Test {\n @EntryPoint()\n operation Main() : Unit {\n use q = Qubit()\n let pi_over_two = 4.0 / 2.0;\n }\n }",
33 offset: 0,
34 },
35 ],
36 error: Frontend(
37 Error(
38 Parse(
39 Error(
40 Token(
41 Semi,
42 Keyword(
43 Let,
44 ),
45 Span {
46 lo: 129,
47 hi: 132,
48 },
49 ),
50 ),
51 ),
52 ),
53 ),
54 },
55 ),
56 ],
57 )
58 "#]]
59 .assert_debug_eq(&get_qir(sources, language_features, capabilities, store, &[(std_id, None)]));
60}
61
62mod base_profile {
63 use expect_test::expect;
64 use qsc_data_structures::{language_features::LanguageFeatures, target::TargetCapabilityFlags};
65 use qsc_frontend::compile::SourceMap;
66
67 use crate::codegen::qir::get_qir;
68
69 #[test]
70 fn simple() {
71 let source = "namespace Test {
72 import Std.Math.*;
73 open QIR.Intrinsic;
74 @EntryPoint()
75 operation Main() : Result {
76 use q = Qubit();
77 let pi_over_two = 4.0 / 2.0;
78 __quantum__qis__rz__body(pi_over_two, q);
79 mutable some_angle = ArcSin(0.0);
80 __quantum__qis__rz__body(some_angle, q);
81 set some_angle = ArcCos(-1.0) / PI();
82 __quantum__qis__rz__body(some_angle, q);
83 __quantum__qis__mresetz__body(q)
84 }
85 }";
86 let sources = SourceMap::new([("test.qs".into(), source.into())], None);
87 let language_features = LanguageFeatures::default();
88 let capabilities = TargetCapabilityFlags::empty();
89
90 let (std_id, store) = crate::compile::package_store_with_stdlib(capabilities);
91 let qir = get_qir(
92 sources,
93 language_features,
94 capabilities,
95 store,
96 &[(std_id, None)],
97 )
98 .expect("Failed to generate QIR");
99 expect![[r#"
100 %Result = type opaque
101 %Qubit = type opaque
102
103 define void @ENTRYPOINT__main() #0 {
104 block_0:
105 call void @__quantum__qis__rz__body(double 2.0, %Qubit* inttoptr (i64 0 to %Qubit*))
106 call void @__quantum__qis__rz__body(double 0.0, %Qubit* inttoptr (i64 0 to %Qubit*))
107 call void @__quantum__qis__rz__body(double 1.0, %Qubit* inttoptr (i64 0 to %Qubit*))
108 call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
109 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null)
110 ret void
111 }
112
113 declare void @__quantum__qis__rz__body(double, %Qubit*)
114
115 declare void @__quantum__rt__result_record_output(%Result*, i8*)
116
117 declare void @__quantum__qis__m__body(%Qubit*, %Result*) #1
118
119 attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="base_profile" "required_num_qubits"="1" "required_num_results"="1" }
120 attributes #1 = { "irreversible" }
121
122 ; module flags
123
124 !llvm.module.flags = !{!0, !1, !2, !3}
125
126 !0 = !{i32 1, !"qir_major_version", i32 1}
127 !1 = !{i32 7, !"qir_minor_version", i32 0}
128 !2 = !{i32 1, !"dynamic_qubit_management", i1 false}
129 !3 = !{i32 1, !"dynamic_result_management", i1 false}
130 "#]]
131 .assert_eq(&qir);
132 }
133
134 #[test]
135 fn qubit_reuse_triggers_reindexing() {
136 let source = "namespace Test {
137 @EntryPoint()
138 operation Main() : (Result, Result) {
139 use q = Qubit();
140 (MResetZ(q), MResetZ(q))
141 }
142 }";
143 let sources = SourceMap::new([("test.qs".into(), source.into())], None);
144 let language_features = LanguageFeatures::default();
145 let capabilities = TargetCapabilityFlags::empty();
146
147 let (std_id, store) = crate::compile::package_store_with_stdlib(capabilities);
148 let qir = get_qir(
149 sources,
150 language_features,
151 capabilities,
152 store,
153 &[(std_id, None)],
154 )
155 .expect("Failed to generate QIR");
156 expect![[r#"
157 %Result = type opaque
158 %Qubit = type opaque
159
160 define void @ENTRYPOINT__main() #0 {
161 block_0:
162 call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
163 call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 1 to %Result*))
164 call void @__quantum__rt__tuple_record_output(i64 2, i8* null)
165 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null)
166 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 1 to %Result*), i8* null)
167 ret void
168 }
169
170 declare void @__quantum__rt__tuple_record_output(i64, i8*)
171
172 declare void @__quantum__rt__result_record_output(%Result*, i8*)
173
174 declare void @__quantum__qis__m__body(%Qubit*, %Result*) #1
175
176 attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="base_profile" "required_num_qubits"="2" "required_num_results"="2" }
177 attributes #1 = { "irreversible" }
178
179 ; module flags
180
181 !llvm.module.flags = !{!0, !1, !2, !3}
182
183 !0 = !{i32 1, !"qir_major_version", i32 1}
184 !1 = !{i32 7, !"qir_minor_version", i32 0}
185 !2 = !{i32 1, !"dynamic_qubit_management", i1 false}
186 !3 = !{i32 1, !"dynamic_result_management", i1 false}
187 "#]].assert_eq(&qir);
188 }
189
190 #[test]
191 fn qubit_measurements_get_deferred() {
192 let source = "namespace Test {
193 @EntryPoint()
194 operation Main() : Result[] {
195 use (q0, q1) = (Qubit(), Qubit());
196 X(q0);
197 let r0 = MResetZ(q0);
198 X(q1);
199 let r1 = MResetZ(q1);
200 [r0, r1]
201 }
202 }";
203 let sources = SourceMap::new([("test.qs".into(), source.into())], None);
204 let language_features = LanguageFeatures::default();
205 let capabilities = TargetCapabilityFlags::empty();
206
207 let (std_id, store) = crate::compile::package_store_with_stdlib(capabilities);
208 let qir = get_qir(
209 sources,
210 language_features,
211 capabilities,
212 store,
213 &[(std_id, None)],
214 )
215 .expect("Failed to generate QIR");
216 expect![[r#"
217 %Result = type opaque
218 %Qubit = type opaque
219
220 define void @ENTRYPOINT__main() #0 {
221 block_0:
222 call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 0 to %Qubit*))
223 call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 1 to %Qubit*))
224 call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
225 call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 1 to %Result*))
226 call void @__quantum__rt__array_record_output(i64 2, i8* null)
227 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null)
228 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 1 to %Result*), i8* null)
229 ret void
230 }
231
232 declare void @__quantum__qis__x__body(%Qubit*)
233
234 declare void @__quantum__rt__array_record_output(i64, i8*)
235
236 declare void @__quantum__rt__result_record_output(%Result*, i8*)
237
238 declare void @__quantum__qis__m__body(%Qubit*, %Result*) #1
239
240 attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="base_profile" "required_num_qubits"="2" "required_num_results"="2" }
241 attributes #1 = { "irreversible" }
242
243 ; module flags
244
245 !llvm.module.flags = !{!0, !1, !2, !3}
246
247 !0 = !{i32 1, !"qir_major_version", i32 1}
248 !1 = !{i32 7, !"qir_minor_version", i32 0}
249 !2 = !{i32 1, !"dynamic_qubit_management", i1 false}
250 !3 = !{i32 1, !"dynamic_result_management", i1 false}
251 "#]].assert_eq(&qir);
252 }
253
254 #[test]
255 fn qubit_id_swap_results_in_different_id_usage() {
256 let source = "namespace Test {
257 @EntryPoint()
258 operation Main() : (Result, Result) {
259 use (q0, q1) = (Qubit(), Qubit());
260 X(q0);
261 Relabel([q0, q1], [q1, q0]);
262 X(q1);
263 (MResetZ(q0), MResetZ(q1))
264 }
265 }";
266 let sources = SourceMap::new([("test.qs".into(), source.into())], None);
267 let language_features = LanguageFeatures::default();
268 let capabilities = TargetCapabilityFlags::empty();
269
270 let (std_id, store) = crate::compile::package_store_with_stdlib(capabilities);
271 let qir = get_qir(
272 sources,
273 language_features,
274 capabilities,
275 store,
276 &[(std_id, None)],
277 )
278 .expect("Failed to generate QIR");
279 expect![[r#"
280 %Result = type opaque
281 %Qubit = type opaque
282
283 define void @ENTRYPOINT__main() #0 {
284 block_0:
285 call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 0 to %Qubit*))
286 call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 0 to %Qubit*))
287 call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
288 call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 1 to %Result*))
289 call void @__quantum__rt__tuple_record_output(i64 2, i8* null)
290 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null)
291 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 1 to %Result*), i8* null)
292 ret void
293 }
294
295 declare void @__quantum__qis__x__body(%Qubit*)
296
297 declare void @__quantum__rt__tuple_record_output(i64, i8*)
298
299 declare void @__quantum__rt__result_record_output(%Result*, i8*)
300
301 declare void @__quantum__qis__m__body(%Qubit*, %Result*) #1
302
303 attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="base_profile" "required_num_qubits"="2" "required_num_results"="2" }
304 attributes #1 = { "irreversible" }
305
306 ; module flags
307
308 !llvm.module.flags = !{!0, !1, !2, !3}
309
310 !0 = !{i32 1, !"qir_major_version", i32 1}
311 !1 = !{i32 7, !"qir_minor_version", i32 0}
312 !2 = !{i32 1, !"dynamic_qubit_management", i1 false}
313 !3 = !{i32 1, !"dynamic_result_management", i1 false}
314 "#]].assert_eq(&qir);
315 }
316
317 #[test]
318 fn qubit_id_swap_across_reset_uses_updated_ids() {
319 let source = "namespace Test {
320 @EntryPoint()
321 operation Main() : (Result, Result) {
322 {
323 use (q0, q1) = (Qubit(), Qubit());
324 X(q0);
325 Relabel([q0, q1], [q1, q0]);
326 X(q1);
327 Reset(q0);
328 Reset(q1);
329 }
330 use (q0, q1) = (Qubit(), Qubit());
331 (MResetZ(q0), MResetZ(q1))
332 }
333 }";
334 let sources = SourceMap::new([("test.qs".into(), source.into())], None);
335 let language_features = LanguageFeatures::default();
336 let capabilities = TargetCapabilityFlags::empty();
337
338 let (std_id, store) = crate::compile::package_store_with_stdlib(capabilities);
339 let qir = get_qir(
340 sources,
341 language_features,
342 capabilities,
343 store,
344 &[(std_id, None)],
345 )
346 .expect("Failed to generate QIR");
347 expect![[r#"
348 %Result = type opaque
349 %Qubit = type opaque
350
351 define void @ENTRYPOINT__main() #0 {
352 block_0:
353 call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 0 to %Qubit*))
354 call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 0 to %Qubit*))
355 call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 3 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
356 call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 2 to %Qubit*), %Result* inttoptr (i64 1 to %Result*))
357 call void @__quantum__rt__tuple_record_output(i64 2, i8* null)
358 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null)
359 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 1 to %Result*), i8* null)
360 ret void
361 }
362
363 declare void @__quantum__qis__x__body(%Qubit*)
364
365 declare void @__quantum__rt__tuple_record_output(i64, i8*)
366
367 declare void @__quantum__rt__result_record_output(%Result*, i8*)
368
369 declare void @__quantum__qis__m__body(%Qubit*, %Result*) #1
370
371 attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="base_profile" "required_num_qubits"="4" "required_num_results"="2" }
372 attributes #1 = { "irreversible" }
373
374 ; module flags
375
376 !llvm.module.flags = !{!0, !1, !2, !3}
377
378 !0 = !{i32 1, !"qir_major_version", i32 1}
379 !1 = !{i32 7, !"qir_minor_version", i32 0}
380 !2 = !{i32 1, !"dynamic_qubit_management", i1 false}
381 !3 = !{i32 1, !"dynamic_result_management", i1 false}
382 "#]].assert_eq(&qir);
383 }
384}
385
386mod adaptive_profile {
387 use expect_test::expect;
388 use qsc_data_structures::{language_features::LanguageFeatures, target::TargetCapabilityFlags};
389 use qsc_frontend::compile::SourceMap;
390
391 use crate::codegen::qir::get_qir;
392
393 #[test]
394 fn simple() {
395 let source = "namespace Test {
396 import Std.Math.*;
397 open QIR.Intrinsic;
398 @EntryPoint()
399 operation Main() : Result {
400 use q = Qubit();
401 let pi_over_two = 4.0 / 2.0;
402 __quantum__qis__rz__body(pi_over_two, q);
403 mutable some_angle = ArcSin(0.0);
404 __quantum__qis__rz__body(some_angle, q);
405 set some_angle = ArcCos(-1.0) / PI();
406 __quantum__qis__rz__body(some_angle, q);
407 __quantum__qis__mresetz__body(q)
408 }
409 }";
410 let sources = SourceMap::new([("test.qs".into(), source.into())], None);
411 let language_features = LanguageFeatures::default();
412 let capabilities = TargetCapabilityFlags::Adaptive;
413
414 let (std_id, store) = crate::compile::package_store_with_stdlib(capabilities);
415 let qir = get_qir(
416 sources,
417 language_features,
418 capabilities,
419 store,
420 &[(std_id, None)],
421 )
422 .expect("Failed to generate QIR");
423 expect![[r#"
424 %Result = type opaque
425 %Qubit = type opaque
426
427 define void @ENTRYPOINT__main() #0 {
428 block_0:
429 call void @__quantum__qis__rz__body(double 2.0, %Qubit* inttoptr (i64 0 to %Qubit*))
430 call void @__quantum__qis__rz__body(double 0.0, %Qubit* inttoptr (i64 0 to %Qubit*))
431 call void @__quantum__qis__rz__body(double 1.0, %Qubit* inttoptr (i64 0 to %Qubit*))
432 call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
433 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null)
434 ret void
435 }
436
437 declare void @__quantum__qis__rz__body(double, %Qubit*)
438
439 declare void @__quantum__rt__result_record_output(%Result*, i8*)
440
441 declare void @__quantum__qis__m__body(%Qubit*, %Result*) #1
442
443 attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="adaptive_profile" "required_num_qubits"="1" "required_num_results"="1" }
444 attributes #1 = { "irreversible" }
445
446 ; module flags
447
448 !llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10}
449
450 !0 = !{i32 1, !"qir_major_version", i32 1}
451 !1 = !{i32 7, !"qir_minor_version", i32 0}
452 !2 = !{i32 1, !"dynamic_qubit_management", i1 false}
453 !3 = !{i32 1, !"dynamic_result_management", i1 false}
454 !4 = !{i32 1, !"classical_ints", i1 false}
455 !5 = !{i32 1, !"classical_floats", i1 false}
456 !6 = !{i32 1, !"backwards_branching", i1 false}
457 !7 = !{i32 1, !"qubit_resetting", i1 false}
458 !8 = !{i32 1, !"classical_fixed_points", i1 false}
459 !9 = !{i32 1, !"user_functions", i1 false}
460 !10 = !{i32 1, !"multiple_target_branching", i1 false}
461 "#]]
462 .assert_eq(&qir);
463 }
464
465 #[test]
466 fn qubit_reuse_triggers_reindexing() {
467 let source = "namespace Test {
468 @EntryPoint()
469 operation Main() : (Result, Result) {
470 use q = Qubit();
471 (MResetZ(q), MResetZ(q))
472 }
473 }";
474 let sources = SourceMap::new([("test.qs".into(), source.into())], None);
475 let language_features = LanguageFeatures::default();
476 let capabilities = TargetCapabilityFlags::Adaptive;
477
478 let (std_id, store) = crate::compile::package_store_with_stdlib(capabilities);
479 let qir = get_qir(
480 sources,
481 language_features,
482 capabilities,
483 store,
484 &[(std_id, None)],
485 )
486 .expect("Failed to generate QIR");
487 expect![[r#"
488 %Result = type opaque
489 %Qubit = type opaque
490
491 define void @ENTRYPOINT__main() #0 {
492 block_0:
493 call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
494 call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 1 to %Result*))
495 call void @__quantum__rt__tuple_record_output(i64 2, i8* null)
496 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null)
497 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 1 to %Result*), i8* null)
498 ret void
499 }
500
501 declare void @__quantum__rt__tuple_record_output(i64, i8*)
502
503 declare void @__quantum__rt__result_record_output(%Result*, i8*)
504
505 declare void @__quantum__qis__m__body(%Qubit*, %Result*) #1
506
507 attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="adaptive_profile" "required_num_qubits"="2" "required_num_results"="2" }
508 attributes #1 = { "irreversible" }
509
510 ; module flags
511
512 !llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10}
513
514 !0 = !{i32 1, !"qir_major_version", i32 1}
515 !1 = !{i32 7, !"qir_minor_version", i32 0}
516 !2 = !{i32 1, !"dynamic_qubit_management", i1 false}
517 !3 = !{i32 1, !"dynamic_result_management", i1 false}
518 !4 = !{i32 1, !"classical_ints", i1 false}
519 !5 = !{i32 1, !"classical_floats", i1 false}
520 !6 = !{i32 1, !"backwards_branching", i1 false}
521 !7 = !{i32 1, !"qubit_resetting", i1 false}
522 !8 = !{i32 1, !"classical_fixed_points", i1 false}
523 !9 = !{i32 1, !"user_functions", i1 false}
524 !10 = !{i32 1, !"multiple_target_branching", i1 false}
525 "#]].assert_eq(&qir);
526 }
527
528 #[test]
529 fn custom_measurement_generates_correct_qir() {
530 let source = "namespace Test {
531 operation Main() : Result {
532 use q = Qubit();
533 H(q);
534 __quantum__qis__mx__body(q)
535 }
536
537 @Measurement()
538 operation __quantum__qis__mx__body(target: Qubit) : Result {
539 body intrinsic;
540 }
541 }";
542 let sources = SourceMap::new([("test.qs".into(), source.into())], None);
543 let language_features = LanguageFeatures::default();
544 let capabilities = TargetCapabilityFlags::Adaptive;
545
546 let (std_id, store) = crate::compile::package_store_with_stdlib(capabilities);
547 let qir = get_qir(
548 sources,
549 language_features,
550 capabilities,
551 store,
552 &[(std_id, None)],
553 )
554 .expect("the input program set in the `source` variable should be valid Q#");
555 expect![[r#"
556 %Result = type opaque
557 %Qubit = type opaque
558
559 define void @ENTRYPOINT__main() #0 {
560 block_0:
561 call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 0 to %Qubit*))
562 call void @__quantum__qis__mx__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
563 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null)
564 ret void
565 }
566
567 declare void @__quantum__qis__h__body(%Qubit*)
568
569 declare void @__quantum__qis__mx__body(%Qubit*, %Result*) #1
570
571 declare void @__quantum__rt__result_record_output(%Result*, i8*)
572
573 attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="adaptive_profile" "required_num_qubits"="1" "required_num_results"="1" }
574 attributes #1 = { "irreversible" }
575
576 ; module flags
577
578 !llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10}
579
580 !0 = !{i32 1, !"qir_major_version", i32 1}
581 !1 = !{i32 7, !"qir_minor_version", i32 0}
582 !2 = !{i32 1, !"dynamic_qubit_management", i1 false}
583 !3 = !{i32 1, !"dynamic_result_management", i1 false}
584 !4 = !{i32 1, !"classical_ints", i1 false}
585 !5 = !{i32 1, !"classical_floats", i1 false}
586 !6 = !{i32 1, !"backwards_branching", i1 false}
587 !7 = !{i32 1, !"qubit_resetting", i1 false}
588 !8 = !{i32 1, !"classical_fixed_points", i1 false}
589 !9 = !{i32 1, !"user_functions", i1 false}
590 !10 = !{i32 1, !"multiple_target_branching", i1 false}
591 "#]].assert_eq(&qir);
592 }
593
594 #[test]
595 fn custom_joint_measurement_generates_correct_qir() {
596 let source = "namespace Test {
597 operation Main() : (Result, Result) {
598 use q1 = Qubit();
599 use q2 = Qubit();
600 H(q1);
601 H(q2);
602 __quantum__qis__mzz__body(q1, q2)
603 }
604
605 @Measurement()
606 operation __quantum__qis__mzz__body(q1: Qubit, q2: Qubit) : (Result, Result) {
607 body intrinsic;
608 }
609 }";
610 let sources = SourceMap::new([("test.qs".into(), source.into())], None);
611 let language_features = LanguageFeatures::default();
612 let capabilities = TargetCapabilityFlags::Adaptive;
613
614 let (std_id, store) = crate::compile::package_store_with_stdlib(capabilities);
615 let qir = get_qir(
616 sources,
617 language_features,
618 capabilities,
619 store,
620 &[(std_id, None)],
621 )
622 .expect("the input program set in the `source` variable should be valid Q#");
623 expect![[r#"
624 %Result = type opaque
625 %Qubit = type opaque
626
627 define void @ENTRYPOINT__main() #0 {
628 block_0:
629 call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 0 to %Qubit*))
630 call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 1 to %Qubit*))
631 call void @__quantum__qis__mzz__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 0 to %Result*), %Result* inttoptr (i64 1 to %Result*))
632 call void @__quantum__rt__tuple_record_output(i64 2, i8* null)
633 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null)
634 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 1 to %Result*), i8* null)
635 ret void
636 }
637
638 declare void @__quantum__qis__h__body(%Qubit*)
639
640 declare void @__quantum__qis__mzz__body(%Qubit*, %Qubit*, %Result*, %Result*) #1
641
642 declare void @__quantum__rt__tuple_record_output(i64, i8*)
643
644 declare void @__quantum__rt__result_record_output(%Result*, i8*)
645
646 attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="adaptive_profile" "required_num_qubits"="2" "required_num_results"="2" }
647 attributes #1 = { "irreversible" }
648
649 ; module flags
650
651 !llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10}
652
653 !0 = !{i32 1, !"qir_major_version", i32 1}
654 !1 = !{i32 7, !"qir_minor_version", i32 0}
655 !2 = !{i32 1, !"dynamic_qubit_management", i1 false}
656 !3 = !{i32 1, !"dynamic_result_management", i1 false}
657 !4 = !{i32 1, !"classical_ints", i1 false}
658 !5 = !{i32 1, !"classical_floats", i1 false}
659 !6 = !{i32 1, !"backwards_branching", i1 false}
660 !7 = !{i32 1, !"qubit_resetting", i1 false}
661 !8 = !{i32 1, !"classical_fixed_points", i1 false}
662 !9 = !{i32 1, !"user_functions", i1 false}
663 !10 = !{i32 1, !"multiple_target_branching", i1 false}
664 "#]].assert_eq(&qir);
665 }
666
667 #[test]
668 fn qubit_measurements_not_deferred() {
669 let source = "namespace Test {
670 @EntryPoint()
671 operation Main() : Result[] {
672 use (q0, q1) = (Qubit(), Qubit());
673 X(q0);
674 let r0 = MResetZ(q0);
675 X(q1);
676 let r1 = MResetZ(q1);
677 [r0, r1]
678 }
679 }";
680 let sources = SourceMap::new([("test.qs".into(), source.into())], None);
681 let language_features = LanguageFeatures::default();
682 let capabilities = TargetCapabilityFlags::Adaptive;
683
684 let (std_id, store) = crate::compile::package_store_with_stdlib(capabilities);
685 let qir = get_qir(
686 sources,
687 language_features,
688 capabilities,
689 store,
690 &[(std_id, None)],
691 )
692 .expect("Failed to generate QIR");
693 expect![[r#"
694 %Result = type opaque
695 %Qubit = type opaque
696
697 define void @ENTRYPOINT__main() #0 {
698 block_0:
699 call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 0 to %Qubit*))
700 call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
701 call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 1 to %Qubit*))
702 call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 1 to %Result*))
703 call void @__quantum__rt__array_record_output(i64 2, i8* null)
704 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null)
705 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 1 to %Result*), i8* null)
706 ret void
707 }
708
709 declare void @__quantum__qis__x__body(%Qubit*)
710
711 declare void @__quantum__rt__array_record_output(i64, i8*)
712
713 declare void @__quantum__rt__result_record_output(%Result*, i8*)
714
715 declare void @__quantum__qis__m__body(%Qubit*, %Result*) #1
716
717 attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="adaptive_profile" "required_num_qubits"="2" "required_num_results"="2" }
718 attributes #1 = { "irreversible" }
719
720 ; module flags
721
722 !llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10}
723
724 !0 = !{i32 1, !"qir_major_version", i32 1}
725 !1 = !{i32 7, !"qir_minor_version", i32 0}
726 !2 = !{i32 1, !"dynamic_qubit_management", i1 false}
727 !3 = !{i32 1, !"dynamic_result_management", i1 false}
728 !4 = !{i32 1, !"classical_ints", i1 false}
729 !5 = !{i32 1, !"classical_floats", i1 false}
730 !6 = !{i32 1, !"backwards_branching", i1 false}
731 !7 = !{i32 1, !"qubit_resetting", i1 false}
732 !8 = !{i32 1, !"classical_fixed_points", i1 false}
733 !9 = !{i32 1, !"user_functions", i1 false}
734 !10 = !{i32 1, !"multiple_target_branching", i1 false}
735 "#]].assert_eq(&qir);
736 }
737}
738
739mod adaptive_ri_profile {
740
741 use expect_test::expect;
742 use qsc_data_structures::{language_features::LanguageFeatures, target::TargetCapabilityFlags};
743 use qsc_frontend::compile::SourceMap;
744
745 use crate::codegen::qir::get_qir;
746
747 #[test]
748 fn simple() {
749 let source = "namespace Test {
750 import Std.Math.*;
751 open QIR.Intrinsic;
752 @EntryPoint()
753 operation Main() : Result {
754 use q = Qubit();
755 let pi_over_two = 4.0 / 2.0;
756 __quantum__qis__rz__body(pi_over_two, q);
757 mutable some_angle = ArcSin(0.0);
758 __quantum__qis__rz__body(some_angle, q);
759 set some_angle = ArcCos(-1.0) / PI();
760 __quantum__qis__rz__body(some_angle, q);
761 __quantum__qis__mresetz__body(q)
762 }
763 }";
764 let sources = SourceMap::new([("test.qs".into(), source.into())], None);
765 let language_features = LanguageFeatures::default();
766 let capabilities = TargetCapabilityFlags::Adaptive
767 | TargetCapabilityFlags::QubitReset
768 | TargetCapabilityFlags::IntegerComputations;
769
770 let (std_id, store) = crate::compile::package_store_with_stdlib(capabilities);
771 let qir = get_qir(
772 sources,
773 language_features,
774 capabilities,
775 store,
776 &[(std_id, None)],
777 )
778 .expect("Failed to generate QIR");
779 expect![[r#"
780 %Result = type opaque
781 %Qubit = type opaque
782
783 define void @ENTRYPOINT__main() #0 {
784 block_0:
785 call void @__quantum__qis__rz__body(double 2.0, %Qubit* inttoptr (i64 0 to %Qubit*))
786 call void @__quantum__qis__rz__body(double 0.0, %Qubit* inttoptr (i64 0 to %Qubit*))
787 call void @__quantum__qis__rz__body(double 1.0, %Qubit* inttoptr (i64 0 to %Qubit*))
788 call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
789 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null)
790 ret void
791 }
792
793 declare void @__quantum__qis__rz__body(double, %Qubit*)
794
795 declare void @__quantum__qis__mresetz__body(%Qubit*, %Result*) #1
796
797 declare void @__quantum__rt__result_record_output(%Result*, i8*)
798
799 attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="adaptive_profile" "required_num_qubits"="1" "required_num_results"="1" }
800 attributes #1 = { "irreversible" }
801
802 ; module flags
803
804 !llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10}
805
806 !0 = !{i32 1, !"qir_major_version", i32 1}
807 !1 = !{i32 7, !"qir_minor_version", i32 0}
808 !2 = !{i32 1, !"dynamic_qubit_management", i1 false}
809 !3 = !{i32 1, !"dynamic_result_management", i1 false}
810 !4 = !{i32 1, !"classical_ints", i1 true}
811 !5 = !{i32 1, !"qubit_resetting", i1 true}
812 !6 = !{i32 1, !"classical_floats", i1 false}
813 !7 = !{i32 1, !"backwards_branching", i1 false}
814 !8 = !{i32 1, !"classical_fixed_points", i1 false}
815 !9 = !{i32 1, !"user_functions", i1 false}
816 !10 = !{i32 1, !"multiple_target_branching", i1 false}
817 "#]]
818 .assert_eq(&qir);
819 }
820
821 #[test]
822 fn qubit_reuse_allowed() {
823 let source = "namespace Test {
824 @EntryPoint()
825 operation Main() : (Result, Result) {
826 use q = Qubit();
827 (MResetZ(q), MResetZ(q))
828 }
829 }";
830 let sources = SourceMap::new([("test.qs".into(), source.into())], None);
831 let language_features = LanguageFeatures::default();
832 let capabilities = TargetCapabilityFlags::Adaptive
833 | TargetCapabilityFlags::QubitReset
834 | TargetCapabilityFlags::IntegerComputations;
835
836 let (std_id, store) = crate::compile::package_store_with_stdlib(capabilities);
837 let qir = get_qir(
838 sources,
839 language_features,
840 capabilities,
841 store,
842 &[(std_id, None)],
843 )
844 .expect("Failed to generate QIR");
845 expect![[r#"
846 %Result = type opaque
847 %Qubit = type opaque
848
849 define void @ENTRYPOINT__main() #0 {
850 block_0:
851 call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
852 call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 1 to %Result*))
853 call void @__quantum__rt__tuple_record_output(i64 2, i8* null)
854 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null)
855 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 1 to %Result*), i8* null)
856 ret void
857 }
858
859 declare void @__quantum__qis__mresetz__body(%Qubit*, %Result*) #1
860
861 declare void @__quantum__rt__tuple_record_output(i64, i8*)
862
863 declare void @__quantum__rt__result_record_output(%Result*, i8*)
864
865 attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="adaptive_profile" "required_num_qubits"="1" "required_num_results"="2" }
866 attributes #1 = { "irreversible" }
867
868 ; module flags
869
870 !llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10}
871
872 !0 = !{i32 1, !"qir_major_version", i32 1}
873 !1 = !{i32 7, !"qir_minor_version", i32 0}
874 !2 = !{i32 1, !"dynamic_qubit_management", i1 false}
875 !3 = !{i32 1, !"dynamic_result_management", i1 false}
876 !4 = !{i32 1, !"classical_ints", i1 true}
877 !5 = !{i32 1, !"qubit_resetting", i1 true}
878 !6 = !{i32 1, !"classical_floats", i1 false}
879 !7 = !{i32 1, !"backwards_branching", i1 false}
880 !8 = !{i32 1, !"classical_fixed_points", i1 false}
881 !9 = !{i32 1, !"user_functions", i1 false}
882 !10 = !{i32 1, !"multiple_target_branching", i1 false}
883 "#]].assert_eq(&qir);
884 }
885
886 #[test]
887 fn qubit_measurements_not_deferred() {
888 let source = "namespace Test {
889 @EntryPoint()
890 operation Main() : Result[] {
891 use (q0, q1) = (Qubit(), Qubit());
892 X(q0);
893 let r0 = MResetZ(q0);
894 X(q1);
895 let r1 = MResetZ(q1);
896 [r0, r1]
897 }
898 }";
899 let sources = SourceMap::new([("test.qs".into(), source.into())], None);
900 let language_features = LanguageFeatures::default();
901 let capabilities = TargetCapabilityFlags::Adaptive
902 | TargetCapabilityFlags::QubitReset
903 | TargetCapabilityFlags::IntegerComputations;
904
905 let (std_id, store) = crate::compile::package_store_with_stdlib(capabilities);
906 let qir = get_qir(
907 sources,
908 language_features,
909 capabilities,
910 store,
911 &[(std_id, None)],
912 )
913 .expect("Failed to generate QIR");
914 expect![[r#"
915 %Result = type opaque
916 %Qubit = type opaque
917
918 define void @ENTRYPOINT__main() #0 {
919 block_0:
920 call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 0 to %Qubit*))
921 call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
922 call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 1 to %Qubit*))
923 call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 1 to %Result*))
924 call void @__quantum__rt__array_record_output(i64 2, i8* null)
925 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null)
926 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 1 to %Result*), i8* null)
927 ret void
928 }
929
930 declare void @__quantum__qis__x__body(%Qubit*)
931
932 declare void @__quantum__qis__mresetz__body(%Qubit*, %Result*) #1
933
934 declare void @__quantum__rt__array_record_output(i64, i8*)
935
936 declare void @__quantum__rt__result_record_output(%Result*, i8*)
937
938 attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="adaptive_profile" "required_num_qubits"="2" "required_num_results"="2" }
939 attributes #1 = { "irreversible" }
940
941 ; module flags
942
943 !llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10}
944
945 !0 = !{i32 1, !"qir_major_version", i32 1}
946 !1 = !{i32 7, !"qir_minor_version", i32 0}
947 !2 = !{i32 1, !"dynamic_qubit_management", i1 false}
948 !3 = !{i32 1, !"dynamic_result_management", i1 false}
949 !4 = !{i32 1, !"classical_ints", i1 true}
950 !5 = !{i32 1, !"qubit_resetting", i1 true}
951 !6 = !{i32 1, !"classical_floats", i1 false}
952 !7 = !{i32 1, !"backwards_branching", i1 false}
953 !8 = !{i32 1, !"classical_fixed_points", i1 false}
954 !9 = !{i32 1, !"user_functions", i1 false}
955 !10 = !{i32 1, !"multiple_target_branching", i1 false}
956 "#]].assert_eq(&qir);
957 }
958
959 #[test]
960 fn qubit_id_swap_results_in_different_id_usage() {
961 let source = "namespace Test {
962 @EntryPoint()
963 operation Main() : (Result, Result) {
964 use (q0, q1) = (Qubit(), Qubit());
965 X(q0);
966 Relabel([q0, q1], [q1, q0]);
967 X(q1);
968 (MResetZ(q0), MResetZ(q1))
969 }
970 }";
971 let sources = SourceMap::new([("test.qs".into(), source.into())], None);
972 let language_features = LanguageFeatures::default();
973 let capabilities = TargetCapabilityFlags::Adaptive
974 | TargetCapabilityFlags::QubitReset
975 | TargetCapabilityFlags::IntegerComputations;
976
977 let (std_id, store) = crate::compile::package_store_with_stdlib(capabilities);
978 let qir = get_qir(
979 sources,
980 language_features,
981 capabilities,
982 store,
983 &[(std_id, None)],
984 )
985 .expect("Failed to generate QIR");
986 expect![[r#"
987 %Result = type opaque
988 %Qubit = type opaque
989
990 define void @ENTRYPOINT__main() #0 {
991 block_0:
992 call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 0 to %Qubit*))
993 call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 0 to %Qubit*))
994 call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
995 call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 1 to %Result*))
996 call void @__quantum__rt__tuple_record_output(i64 2, i8* null)
997 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null)
998 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 1 to %Result*), i8* null)
999 ret void
1000 }
1001
1002 declare void @__quantum__qis__x__body(%Qubit*)
1003
1004 declare void @__quantum__qis__mresetz__body(%Qubit*, %Result*) #1
1005
1006 declare void @__quantum__rt__tuple_record_output(i64, i8*)
1007
1008 declare void @__quantum__rt__result_record_output(%Result*, i8*)
1009
1010 attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="adaptive_profile" "required_num_qubits"="2" "required_num_results"="2" }
1011 attributes #1 = { "irreversible" }
1012
1013 ; module flags
1014
1015 !llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10}
1016
1017 !0 = !{i32 1, !"qir_major_version", i32 1}
1018 !1 = !{i32 7, !"qir_minor_version", i32 0}
1019 !2 = !{i32 1, !"dynamic_qubit_management", i1 false}
1020 !3 = !{i32 1, !"dynamic_result_management", i1 false}
1021 !4 = !{i32 1, !"classical_ints", i1 true}
1022 !5 = !{i32 1, !"qubit_resetting", i1 true}
1023 !6 = !{i32 1, !"classical_floats", i1 false}
1024 !7 = !{i32 1, !"backwards_branching", i1 false}
1025 !8 = !{i32 1, !"classical_fixed_points", i1 false}
1026 !9 = !{i32 1, !"user_functions", i1 false}
1027 !10 = !{i32 1, !"multiple_target_branching", i1 false}
1028 "#]].assert_eq(&qir);
1029 }
1030
1031 #[test]
1032 fn qubit_id_swap_across_reset_uses_updated_ids() {
1033 let source = "namespace Test {
1034 @EntryPoint()
1035 operation Main() : (Result, Result) {
1036 {
1037 use (q0, q1) = (Qubit(), Qubit());
1038 X(q0);
1039 Relabel([q0, q1], [q1, q0]);
1040 X(q1);
1041 Reset(q0);
1042 Reset(q1);
1043 }
1044 use (q0, q1) = (Qubit(), Qubit());
1045 (MResetZ(q0), MResetZ(q1))
1046 }
1047 }";
1048 let sources = SourceMap::new([("test.qs".into(), source.into())], None);
1049 let language_features = LanguageFeatures::default();
1050 let capabilities = TargetCapabilityFlags::Adaptive
1051 | TargetCapabilityFlags::QubitReset
1052 | TargetCapabilityFlags::IntegerComputations;
1053
1054 let (std_id, store) = crate::compile::package_store_with_stdlib(capabilities);
1055 let qir = get_qir(
1056 sources,
1057 language_features,
1058 capabilities,
1059 store,
1060 &[(std_id, None)],
1061 )
1062 .expect("Failed to generate QIR");
1063 expect![[r#"
1064 %Result = type opaque
1065 %Qubit = type opaque
1066
1067 define void @ENTRYPOINT__main() #0 {
1068 block_0:
1069 call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 0 to %Qubit*))
1070 call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 0 to %Qubit*))
1071 call void @__quantum__qis__reset__body(%Qubit* inttoptr (i64 1 to %Qubit*))
1072 call void @__quantum__qis__reset__body(%Qubit* inttoptr (i64 0 to %Qubit*))
1073 call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
1074 call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 1 to %Result*))
1075 call void @__quantum__rt__tuple_record_output(i64 2, i8* null)
1076 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null)
1077 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 1 to %Result*), i8* null)
1078 ret void
1079 }
1080
1081 declare void @__quantum__qis__x__body(%Qubit*)
1082
1083 declare void @__quantum__qis__reset__body(%Qubit*) #1
1084
1085 declare void @__quantum__qis__mresetz__body(%Qubit*, %Result*) #1
1086
1087 declare void @__quantum__rt__tuple_record_output(i64, i8*)
1088
1089 declare void @__quantum__rt__result_record_output(%Result*, i8*)
1090
1091 attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="adaptive_profile" "required_num_qubits"="2" "required_num_results"="2" }
1092 attributes #1 = { "irreversible" }
1093
1094 ; module flags
1095
1096 !llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10}
1097
1098 !0 = !{i32 1, !"qir_major_version", i32 1}
1099 !1 = !{i32 7, !"qir_minor_version", i32 0}
1100 !2 = !{i32 1, !"dynamic_qubit_management", i1 false}
1101 !3 = !{i32 1, !"dynamic_result_management", i1 false}
1102 !4 = !{i32 1, !"classical_ints", i1 true}
1103 !5 = !{i32 1, !"qubit_resetting", i1 true}
1104 !6 = !{i32 1, !"classical_floats", i1 false}
1105 !7 = !{i32 1, !"backwards_branching", i1 false}
1106 !8 = !{i32 1, !"classical_fixed_points", i1 false}
1107 !9 = !{i32 1, !"user_functions", i1 false}
1108 !10 = !{i32 1, !"multiple_target_branching", i1 false}
1109 "#]].assert_eq(&qir);
1110 }
1111
1112 #[test]
1113 fn qubit_id_swap_with_out_of_order_release_uses_correct_ids() {
1114 let source = "namespace Test {
1115 @EntryPoint()
1116 operation Main() : (Result, Result) {
1117 let q0 = QIR.Runtime.__quantum__rt__qubit_allocate();
1118 let q1 = QIR.Runtime.__quantum__rt__qubit_allocate();
1119 let q2 = QIR.Runtime.__quantum__rt__qubit_allocate();
1120 X(q0);
1121 X(q1);
1122 X(q2);
1123 Relabel([q0, q1], [q1, q0]);
1124 QIR.Runtime.__quantum__rt__qubit_release(q0);
1125 let q3 = QIR.Runtime.__quantum__rt__qubit_allocate();
1126 X(q3);
1127 (MResetZ(q3), MResetZ(q1))
1128 }
1129 }";
1130 let sources = SourceMap::new([("test.qs".into(), source.into())], None);
1131 let language_features = LanguageFeatures::default();
1132 let capabilities = TargetCapabilityFlags::Adaptive
1133 | TargetCapabilityFlags::QubitReset
1134 | TargetCapabilityFlags::IntegerComputations;
1135
1136 let (std_id, store) = crate::compile::package_store_with_stdlib(capabilities);
1137 let qir = get_qir(
1138 sources,
1139 language_features,
1140 capabilities,
1141 store,
1142 &[(std_id, None)],
1143 )
1144 .expect("Failed to generate QIR");
1145 expect![[r#"
1146 %Result = type opaque
1147 %Qubit = type opaque
1148
1149 define void @ENTRYPOINT__main() #0 {
1150 block_0:
1151 call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 0 to %Qubit*))
1152 call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 1 to %Qubit*))
1153 call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 2 to %Qubit*))
1154 call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 1 to %Qubit*))
1155 call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
1156 call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 1 to %Result*))
1157 call void @__quantum__rt__tuple_record_output(i64 2, i8* null)
1158 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null)
1159 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 1 to %Result*), i8* null)
1160 ret void
1161 }
1162
1163 declare void @__quantum__qis__x__body(%Qubit*)
1164
1165 declare void @__quantum__qis__mresetz__body(%Qubit*, %Result*) #1
1166
1167 declare void @__quantum__rt__tuple_record_output(i64, i8*)
1168
1169 declare void @__quantum__rt__result_record_output(%Result*, i8*)
1170
1171 attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="adaptive_profile" "required_num_qubits"="3" "required_num_results"="2" }
1172 attributes #1 = { "irreversible" }
1173
1174 ; module flags
1175
1176 !llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10}
1177
1178 !0 = !{i32 1, !"qir_major_version", i32 1}
1179 !1 = !{i32 7, !"qir_minor_version", i32 0}
1180 !2 = !{i32 1, !"dynamic_qubit_management", i1 false}
1181 !3 = !{i32 1, !"dynamic_result_management", i1 false}
1182 !4 = !{i32 1, !"classical_ints", i1 true}
1183 !5 = !{i32 1, !"qubit_resetting", i1 true}
1184 !6 = !{i32 1, !"classical_floats", i1 false}
1185 !7 = !{i32 1, !"backwards_branching", i1 false}
1186 !8 = !{i32 1, !"classical_fixed_points", i1 false}
1187 !9 = !{i32 1, !"user_functions", i1 false}
1188 !10 = !{i32 1, !"multiple_target_branching", i1 false}
1189 "#]].assert_eq(&qir);
1190 }
1191
1192 #[test]
1193 fn dynamic_integer_with_branch_and_phi_supported() {
1194 let source = "namespace Test {
1195 @EntryPoint()
1196 operation Main() : Int {
1197 use q = Qubit();
1198 H(q);
1199 MResetZ(q) == Zero ? 0 | 1
1200 }
1201 }";
1202 let sources = SourceMap::new([("test.qs".into(), source.into())], None);
1203 let language_features = LanguageFeatures::default();
1204 let capabilities = TargetCapabilityFlags::Adaptive
1205 | TargetCapabilityFlags::QubitReset
1206 | TargetCapabilityFlags::IntegerComputations;
1207
1208 let (std_id, store) = crate::compile::package_store_with_stdlib(capabilities);
1209 let qir = get_qir(
1210 sources,
1211 language_features,
1212 capabilities,
1213 store,
1214 &[(std_id, None)],
1215 )
1216 .expect("Failed to generate QIR");
1217 expect![[r#"
1218 %Result = type opaque
1219 %Qubit = type opaque
1220
1221 define void @ENTRYPOINT__main() #0 {
1222 block_0:
1223 call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 0 to %Qubit*))
1224 call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
1225 %var_0 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 0 to %Result*))
1226 %var_1 = icmp eq i1 %var_0, false
1227 br i1 %var_1, label %block_1, label %block_2
1228 block_1:
1229 br label %block_3
1230 block_2:
1231 br label %block_3
1232 block_3:
1233 %var_3 = phi i64 [0, %block_1], [1, %block_2]
1234 call void @__quantum__rt__int_record_output(i64 %var_3, i8* null)
1235 ret void
1236 }
1237
1238 declare void @__quantum__qis__h__body(%Qubit*)
1239
1240 declare void @__quantum__qis__mresetz__body(%Qubit*, %Result*) #1
1241
1242 declare i1 @__quantum__qis__read_result__body(%Result*)
1243
1244 declare void @__quantum__rt__int_record_output(i64, i8*)
1245
1246 attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="adaptive_profile" "required_num_qubits"="1" "required_num_results"="1" }
1247 attributes #1 = { "irreversible" }
1248
1249 ; module flags
1250
1251 !llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10}
1252
1253 !0 = !{i32 1, !"qir_major_version", i32 1}
1254 !1 = !{i32 7, !"qir_minor_version", i32 0}
1255 !2 = !{i32 1, !"dynamic_qubit_management", i1 false}
1256 !3 = !{i32 1, !"dynamic_result_management", i1 false}
1257 !4 = !{i32 1, !"classical_ints", i1 true}
1258 !5 = !{i32 1, !"qubit_resetting", i1 true}
1259 !6 = !{i32 1, !"classical_floats", i1 false}
1260 !7 = !{i32 1, !"backwards_branching", i1 false}
1261 !8 = !{i32 1, !"classical_fixed_points", i1 false}
1262 !9 = !{i32 1, !"user_functions", i1 false}
1263 !10 = !{i32 1, !"multiple_target_branching", i1 false}
1264 "#]].assert_eq(&qir);
1265 }
1266
1267 #[test]
1268 fn custom_reset_generates_correct_qir() {
1269 let source = "namespace Test {
1270 operation Main() : Result {
1271 use q = Qubit();
1272 __quantum__qis__custom_reset__body(q);
1273 M(q)
1274 }
1275
1276 @Reset()
1277 operation __quantum__qis__custom_reset__body(target: Qubit) : Unit {
1278 body intrinsic;
1279 }
1280 }";
1281 let sources = SourceMap::new([("test.qs".into(), source.into())], None);
1282 let language_features = LanguageFeatures::default();
1283 let capabilities = TargetCapabilityFlags::Adaptive
1284 | TargetCapabilityFlags::QubitReset
1285 | TargetCapabilityFlags::IntegerComputations;
1286
1287 let (std_id, store) = crate::compile::package_store_with_stdlib(capabilities);
1288 let qir = get_qir(
1289 sources,
1290 language_features,
1291 capabilities,
1292 store,
1293 &[(std_id, None)],
1294 )
1295 .expect("the input program set in the `source` variable should be valid Q#");
1296 expect![[r#"
1297 %Result = type opaque
1298 %Qubit = type opaque
1299
1300 define void @ENTRYPOINT__main() #0 {
1301 block_0:
1302 call void @__quantum__qis__custom_reset__body(%Qubit* inttoptr (i64 0 to %Qubit*))
1303 call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
1304 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null)
1305 ret void
1306 }
1307
1308 declare void @__quantum__qis__custom_reset__body(%Qubit*) #1
1309
1310 declare void @__quantum__qis__m__body(%Qubit*, %Result*) #1
1311
1312 declare void @__quantum__rt__result_record_output(%Result*, i8*)
1313
1314 attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="adaptive_profile" "required_num_qubits"="1" "required_num_results"="1" }
1315 attributes #1 = { "irreversible" }
1316
1317 ; module flags
1318
1319 !llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10}
1320
1321 !0 = !{i32 1, !"qir_major_version", i32 1}
1322 !1 = !{i32 7, !"qir_minor_version", i32 0}
1323 !2 = !{i32 1, !"dynamic_qubit_management", i1 false}
1324 !3 = !{i32 1, !"dynamic_result_management", i1 false}
1325 !4 = !{i32 1, !"classical_ints", i1 true}
1326 !5 = !{i32 1, !"qubit_resetting", i1 true}
1327 !6 = !{i32 1, !"classical_floats", i1 false}
1328 !7 = !{i32 1, !"backwards_branching", i1 false}
1329 !8 = !{i32 1, !"classical_fixed_points", i1 false}
1330 !9 = !{i32 1, !"user_functions", i1 false}
1331 !10 = !{i32 1, !"multiple_target_branching", i1 false}
1332 "#]]
1333 .assert_eq(&qir);
1334 }
1335}
1336