From 32c54e525da495f5947d41576268995db4d58f9f Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Thu, 7 Oct 2021 00:03:43 -0700 Subject: [PATCH 01/26] initial parser work --- Cargo.lock | 15 +- src/QirTools/pyqir/.gitignore | 3 + src/QirTools/pyqir/Cargo.toml.template | 1 + src/QirTools/pyqir/src/lib.rs | 1 + src/QirTools/pyqir/src/parser.rs | 284 ++ src/QirTools/pyqir/src/python.rs | 10 + .../tests/randwalkphaseest.baseprofile.bc | Bin 0 -> 2452 bytes .../randwalkphaseest.baseprofile.ll.reference | 78 + .../pyqir/tests/randwalkphaseest.ll.reference | 3388 +++++++++++++++++ src/QirTools/pyqir/tests/test_api.py | 20 + 10 files changed, 3799 insertions(+), 1 deletion(-) create mode 100644 src/QirTools/pyqir/src/parser.rs create mode 100644 src/QirTools/pyqir/tests/randwalkphaseest.baseprofile.bc create mode 100644 src/QirTools/pyqir/tests/randwalkphaseest.baseprofile.ll.reference create mode 100644 src/QirTools/pyqir/tests/randwalkphaseest.ll.reference diff --git a/Cargo.lock b/Cargo.lock index eb8f80a0a1..de8888b250 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -169,6 +169,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "llvm-ir" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73570190dd9c3c060f807366ad78bf8a08fbfd294ad95b60cd0b4d124064f483" +dependencies = [ + "either", + "llvm-sys", + "log", +] + [[package]] name = "llvm-sys" version = "110.0.1" @@ -336,9 +347,10 @@ dependencies = [ [[package]] name = "pyqir" -version = "0.1.0-alpha" +version = "0.9999.2110-alpha" dependencies = [ "env_logger", + "llvm-ir", "log", "pyo3", "qirlib", @@ -355,6 +367,7 @@ dependencies = [ "libloading", "llvm-sys", "log", + "rand", "serial_test", "tempfile", ] diff --git a/src/QirTools/pyqir/.gitignore b/src/QirTools/pyqir/.gitignore index 12bcf145dc..c8c07a73b5 100644 --- a/src/QirTools/pyqir/.gitignore +++ b/src/QirTools/pyqir/.gitignore @@ -156,3 +156,6 @@ Cargo.lock # We inject version numbers into Cargo.toml, so don't want them stored in repo. Cargo.toml + +# Ignore the IR files generated during testing +*.ll \ No newline at end of file diff --git a/src/QirTools/pyqir/Cargo.toml.template b/src/QirTools/pyqir/Cargo.toml.template index af069fb8f1..6952353648 100644 --- a/src/QirTools/pyqir/Cargo.toml.template +++ b/src/QirTools/pyqir/Cargo.toml.template @@ -28,6 +28,7 @@ classifier=[ qirlib = {path = "../qirlib"} env_logger = "0.9.0" log = "0.4.14" +llvm-ir = { version = "0.8.0", features = ["llvm-11"] } [dependencies.pyo3] version = "0.14.2" diff --git a/src/QirTools/pyqir/src/lib.rs b/src/QirTools/pyqir/src/lib.rs index 6fabbe5628..e20c5406bf 100644 --- a/src/QirTools/pyqir/src/lib.rs +++ b/src/QirTools/pyqir/src/lib.rs @@ -2,3 +2,4 @@ // Licensed under the MIT License. pub mod python; +pub mod parser; diff --git a/src/QirTools/pyqir/src/parser.rs b/src/QirTools/pyqir/src/parser.rs new file mode 100644 index 0000000000..2b36d9cba1 --- /dev/null +++ b/src/QirTools/pyqir/src/parser.rs @@ -0,0 +1,284 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +use pyo3::exceptions; +use pyo3::prelude::*; + +use llvm_ir; + +#[pyclass] +pub struct QirModule { + pub(super) module: llvm_ir::Module, +} + +#[pyclass] +pub struct QirFunction { + pub(super) function: llvm_ir::Function, +} + +#[pyclass] +pub struct QirParameter { + pub(super) param: llvm_ir::function::Parameter, +} + +#[pyclass] +pub struct QirType { + pub(super) typeref: llvm_ir::TypeRef, +} + +#[pyclass] +pub struct QirFunctionAttribute { + pub(super) attr: llvm_ir::function::FunctionAttribute, +} + +#[pyclass] +pub struct QirBasicBlock { + pub(super) block: llvm_ir::BasicBlock, +} + +#[pyclass] +pub struct QirInstruction { + pub(super) instr: llvm_ir::instruction::Instruction, +} + +#[pyclass] +pub struct QirTerminator { + pub(super) term: llvm_ir::terminator::Terminator, +} + +#[pymethods] +impl QirModule { + #[getter] + fn get_functions(&self) -> Vec { + self.module + .functions + .iter() + .map(|f| QirFunction { + function: f.clone(), + }) + .collect() + } + + fn get_func_by_name(&self, name: String) -> PyResult { + match self.module.get_func_by_name(&name) { + Some(f) => Ok(QirFunction { + function: f.clone(), + }), + None => Err(exceptions::PyTypeError::new_err(format!( + "Function with name '{}' not found", + name + ))), + } + } + + fn get_funcs_by_attr(&self, attr: String) -> Vec { + self.module + .functions + .iter() + .filter(|f| { + f.function_attributes.contains( + &llvm_ir::function::FunctionAttribute::StringAttribute { + kind: attr.clone(), + value: "".to_string(), + }, + ) + }) + .map(|f| QirFunction { + function: f.clone(), + }) + .collect() + } +} + +#[pymethods] +impl QirFunction { + #[getter] + fn get_name(&self) -> String { + self.function.name.clone() + } + + #[getter] + fn get_parameters(&self) -> Vec { + self.function + .parameters + .iter() + .map(|p| QirParameter { param: p.clone() }) + .collect() + } + + #[getter] + fn get_return_type(&self) -> QirType { + QirType { + typeref: self.function.return_type.clone(), + } + } + + #[getter] + fn get_attributes(&self) -> Vec { + self.function + .function_attributes + .iter() + .map(|a| QirFunctionAttribute { attr: a.clone() }) + .collect() + } + + #[getter] + fn get_blocks(&self) -> Vec { + self.function + .basic_blocks + .iter() + .map(|b| QirBasicBlock { block: b.clone() }) + .collect() + } + + #[getter] + fn get_required_qubits(&self) -> i64 { + match self.get_attribute_value("requiredQubits".to_string()) { + Ok(s) => s.parse().unwrap(), + Err(_) => 0, + } + } + + #[getter] + fn get_required_results(&self) -> i64 { + match self.get_attribute_value("requiredResults".to_string()) { + Ok(s) => s.parse().unwrap(), + Err(_) => 0, + } + } + + fn get_attribute_value(&self, attr_name: String) -> PyResult { + for attr in &self.function.function_attributes { + match attr { + llvm_ir::function::FunctionAttribute::StringAttribute { kind, value } => { + if kind.to_string() == attr_name { + return Ok(value.to_string()); + } + } + _ => continue, + } + } + Err(exceptions::PyTypeError::new_err(format!( + "Attribute with name '{}' not found", + attr_name + ))) + } + + fn get_block_by_name(&self, name: String) -> PyResult { + match self + .function + .get_bb_by_name(&llvm_ir::Name::from(name.clone())) + { + Some(b) => Ok(QirBasicBlock { block: b.clone() }), + None => Err(exceptions::PyTypeError::new_err(format!( + "Block with name '{}' not found", + name + ))), + } + } +} + +#[pymethods] +impl QirParameter { + #[getter] + fn get_name(&self) -> String { + name_to_string(&self.param.name) + } + + #[getter] + fn get_type(&self) -> QirType { + QirType { + typeref: self.param.ty.clone(), + } + } +} + +#[pymethods] +impl QirType { + #[getter] + fn get_is_void(&self) -> bool { + match self.typeref.as_ref() { + llvm_ir::Type::VoidType => true, + _ => false, + } + } + #[getter] + fn get_is_integer(&self) -> bool { + match self.typeref.as_ref() { + llvm_ir::Type::IntegerType { bits: _ } => true, + _ => false, + } + } + #[getter] + fn get_is_pointer(&self) -> bool { + match self.typeref.as_ref() { + llvm_ir::Type::PointerType { + pointee_type: _, + addr_space: _, + } => true, + _ => false, + } + } + #[getter] + fn get_is_floating_point(&self) -> bool { + match self.typeref.as_ref() { + llvm_ir::Type::FPType(_) => true, + _ => false, + } + } + #[getter] + fn get_is_func(&self) -> bool { + match self.typeref.as_ref() { + llvm_ir::Type::FuncType { + result_type: _, + param_types: _, + is_var_arg: _, + } => true, + _ => false, + } + } + #[getter] + fn get_is_vector(&self) -> bool { + match self.typeref.as_ref() { + llvm_ir::Type::VectorType { + element_type: _, + num_elements: _, + scalable: _, + } => true, + _ => false, + } + } + #[getter] + fn get_is_array(&self) -> bool { + match self.typeref.as_ref() { + llvm_ir::Type::ArrayType { + element_type: _, + num_elements: _, + } => true, + _ => false, + } + } + #[getter] + fn get_is_struct(&self) -> bool { + match self.typeref.as_ref() { + llvm_ir::Type::StructType { + element_types: _, + is_packed: _, + } => true, + _ => false, + } + } + #[getter] + fn get_is_named_struct(&self) -> bool { + match self.typeref.as_ref() { + llvm_ir::Type::NamedStructType { name: _ } => true, + _ => false, + } + } +} + +fn name_to_string(name: &llvm_ir::Name) -> String { + match name { + llvm_ir::name::Name::Name(n) => n.to_string(), + llvm_ir::name::Name::Number(n) => n.to_string(), + } +} diff --git a/src/QirTools/pyqir/src/python.rs b/src/QirTools/pyqir/src/python.rs index 1db3635fd7..f89ff2c117 100644 --- a/src/QirTools/pyqir/src/python.rs +++ b/src/QirTools/pyqir/src/python.rs @@ -10,10 +10,20 @@ use qirlib::interop::{ Single, }; +use crate::parser::QirModule; + #[pymodule] fn pyqir(_py: Python<'_>, m: &PyModule) -> PyResult<()> { m.add_class::()?; + #[pyfn(m)] #[pyo3(name = "module_from_bitcode")] + fn module_from_bitcode_py(_py: Python, bc_path: String) -> PyResult { + match llvm_ir::Module::from_bc_path(&bc_path) { + Ok(m) => Ok(QirModule { module: m }), + Err(s) => Err(exceptions::PyTypeError::new_err(s)), + } + } + Ok(()) } diff --git a/src/QirTools/pyqir/tests/randwalkphaseest.baseprofile.bc b/src/QirTools/pyqir/tests/randwalkphaseest.baseprofile.bc new file mode 100644 index 0000000000000000000000000000000000000000..0f82b1b0666a54fde4bf5e4e241302e1dfbdbe05 GIT binary patch literal 2452 zcma)7Yfu~46<(pou8q7}1R=smnw78}8dEF@w?PQ7&|(UX>@0~p#TmQO3JF6h^jL|f zJL!VttYXWJ{Fs&>WCAIjDL*>J8PC)|JPktFQHkP$lQcAOT?oRa9_%vlV>}ZQdUqji zM?+`2a3AN~d(ZjKch5bt5aYLgkOx6x2!b3^-HroC{?u~t>q{?XH!@ZM&}pO)^bwe3 zXKA1;Am@Vy_Z6M3Ns1aIn8A2X5SH!~BL!;FX$Pa&pJh3hZJERjdF6=W#jOTMq~15F zDXNvTQLN@%mNSW5%)^Pg2>xe*!4XzGU;KPb|MRh}SHp{vl~CM*2@45GR3dx-lz!E{D;U zAo_sFPQJ0zw^Wc-JSo>84X!3__;*?na%5)&F@@gNj_9u;(2Y}L?#XAU)5+b5_l%-n zQ8iie(`HdEDzXYvISdH6Q2{}6fT?f_f3gNXs$SeR#L_Xgi-BK>vB6@v3x_+CFcV|x z2-{l^_Y}i)ndD8DOybTfGSJ>+pcm0+T@L@c4_u5ZO&N9VU&~e%9cDqRfH%HC!!Vx z?&*dD1AggkNOliHA2Mi})S{kw6Zkl8P*qLeRjCB818%`24=e$)`qZt1xpXGJp+9u_gB#SbLgXS zbXg~KB!`vhVP%T%Z&J!BjdHS2HAPAO8Y7HJ!Z^V9mlNd|i1LWgbRn?^I9=^GeIhiC zC8Qs;vA!mj_JxA2aJQWeD!4Q)xc-XlJ|z2!MAI>J!7Q7{(Pa)7`i-;E|Ta2 zT~Yi-jXFL5?CiYi764FRU>XZmT?!S36Xj9Dm`YS$jvJE+5MyPk{*oVo0V+Qru!$}B z;u^Yam))C_tl+Xmooo@8Jtk2PhA!w(AU>Fr{BsUXljsv2G5@(nb$eL3BH)ozb)Wn# zQ4TI^EU{;ns7MhN5uyS_Jxx?Yqu>qafSk(SN*8l=pts34KvV(B#|YzeqW`w?+VHle z8ZMP?YgFqT} zr*H^54#r#&QNlg5?VyFD5cXgr}EV0yYHI5l{Je-OG0$@#QgGFLJ=?d^>4aA z_guNVrmKVcafJI{-51Sa)~EQlvhcvW^1LWS?ybWny0)BeT@8J+4|}x|nEY-J0*YRd zM2z*@$D2|mH9E3Sl8;H^=KW5=F&&w6#GEfZT$@jdpA*qm>_<9-gG4llB>KVNbTZPX z5912*==9)RG7{(J^%PeAX{1I2raJpvRH3jS{e6m~hsrii-BB7E#5xBF0TWK9>f>!8 zY*0R~KRX!MVkwkLU#QJ3NEt*H-_;$3VW9w00}dWv#N`eh^U@d9G$fv}=5z`g=A^T0 zpH(|{ZG9viuYD4EOOcF|)yKY$^c3?u|4~h6joP)Abp0XyH}4-1d{nDn`-667?Sxd@ z5czoZ{pSuMLTha=B)>@Qo|d9Q;pwl|`pWFD-^+d0aOBkdzUnWz-zJS7;%jm?Vn%iV znfv_sdQCT=m^Pffv|cQM{un4eQ83Dd7aUwEwAuU}lqcBHZnM!r&|HBIchGj+6|{Lh zuFV%+;DkG4$=~5<3)(2R+uKY9GtaFr(k{1)3S_QrIPCB_xpTCu#YMY3%`RKBx5ESQ zJO$@(3)pPUbg#|k@H%@k7g{%0cWUH{fjnryIYct+9=^ z+4i@$1p;ke510jlZS5cyvK0ht>3Ny*IKAyZq1->S*%~}S7wz@^7kG~Hc2^)k9na*& z>Fsd1UACat76{U9p5qyZHkAJ#ZS9+}20+s;%DHjldR-~^w}%FBy8u`phu#$kmb%>_ HNx=7SQCl+x literal 0 HcmV?d00001 diff --git a/src/QirTools/pyqir/tests/randwalkphaseest.baseprofile.ll.reference b/src/QirTools/pyqir/tests/randwalkphaseest.baseprofile.ll.reference new file mode 100644 index 0000000000..2181b26f46 --- /dev/null +++ b/src/QirTools/pyqir/tests/randwalkphaseest.baseprofile.ll.reference @@ -0,0 +1,78 @@ +; ModuleID = './randwalkphaseest.ll' +source_filename = "./randwalkphaseest.ll" + +%Result = type opaque +%Qubit = type opaque +%String = type opaque + +declare %Result* @__quantum__rt__result_get_one() local_unnamed_addr + +declare i1 @__quantum__rt__result_equal(%Result*, %Result*) local_unnamed_addr + +declare %Qubit* @__quantum__rt__qubit_allocate() local_unnamed_addr + +declare void @__quantum__rt__qubit_release(%Qubit*) local_unnamed_addr + +declare void @__quantum__rt__result_update_reference_count(%Result*, i32) local_unnamed_addr + +declare void @__quantum__qis__crz__body(double, %Qubit*, %Qubit*) local_unnamed_addr + +declare void @__quantum__qis__h__body(%Qubit*) local_unnamed_addr + +declare void @__quantum__qis__x__body(%Qubit*) local_unnamed_addr + +declare void @__quantum__qis__reset__body(%Qubit*) local_unnamed_addr + +declare void @__quantum__qis__rz__body(double, %Qubit*) local_unnamed_addr + +declare %Result* @__quantum__qis__m__body(%Qubit*) local_unnamed_addr + +define double @Microsoft__Quantum__Qir__Emission__EstimatePhaseByRandomWalk__Interop() local_unnamed_addr #0 { +entry: + tail call void @__quantum__qis__x__body(%Qubit* null) + br label %body__1.i + +body__1.i: ; preds = %body__1.i, %entry + %0 = phi i64 [ 1, %entry ], [ %11, %body__1.i ] + %sigma.03.i = phi double [ 6.065000e-01, %entry ], [ %10, %body__1.i ] + %isigma.02.i = phi double [ 0x3FFA6180F3204A49, %entry ], [ %9, %body__1.i ] + %mu.01.i = phi double [ 7.951000e-01, %entry ], [ %8, %body__1.i ] + %1 = fmul double %isigma.02.i, %mu.01.i + %2 = fsub double 1.000000e+00, %1 + %3 = fmul double %isigma.02.i, 5.000000e-01 + tail call void @__quantum__qis__h__body(%Qubit* nonnull inttoptr (i64 1 to %Qubit*)) + %4 = fmul double %2, 5.000000e-01 + tail call void @__quantum__qis__rz__body(double %4, %Qubit* nonnull inttoptr (i64 1 to %Qubit*)) + %5 = fmul double %3, 5.000000e-01 + tail call void @__quantum__qis__crz__body(double %5, %Qubit* nonnull inttoptr (i64 1 to %Qubit*), %Qubit* null) + tail call void @__quantum__qis__h__body(%Qubit* nonnull inttoptr (i64 1 to %Qubit*)) + tail call void @__quantum__qis__mz__body(%Qubit* nonnull inttoptr (i64 1 to %Qubit*), %Result* null) + tail call void @__quantum__qis__reset__body(%Qubit* nonnull inttoptr (i64 1 to %Qubit*)) + %update.i.i = fmul double %sigma.03.i, 6.065000e-01 + %6 = fneg double %update.i.i + %7 = tail call i1 @__quantum__qir__read_result(%Result* null) + %.p.i.i = select i1 %7, double %update.i.i, double %6 + %8 = fadd double %mu.01.i, %.p.i.i + %9 = fmul double %isigma.02.i, 1.257700e+00 + %10 = fmul double %sigma.03.i, 7.951000e-01 + %11 = add nuw nsw i64 %0, 1 + %12 = icmp ult i64 %0, 30 + br i1 %12, label %body__1.i, label %Microsoft__Quantum__Qir__Emission__EstimatePhaseByRandomWalk__body.1.exit + +Microsoft__Quantum__Qir__Emission__EstimatePhaseByRandomWalk__body.1.exit: ; preds = %body__1.i + %13 = fmul double %8, 2.000000e+00 + ret double %13 +} + +declare void @__quantum__rt__message(%String*) local_unnamed_addr + +declare %String* @__quantum__rt__double_to_string(double) local_unnamed_addr + +declare void @__quantum__rt__string_update_reference_count(%String*, i32) local_unnamed_addr + +declare void @__quantum__qis__mz__body(%Qubit*, %Result*) + +declare i1 @__quantum__qir__read_result(%Result*) + +attributes #0 = { "InteropFriendly" "requiredQubits"="2" } + diff --git a/src/QirTools/pyqir/tests/randwalkphaseest.ll.reference b/src/QirTools/pyqir/tests/randwalkphaseest.ll.reference new file mode 100644 index 0000000000..8be2539f08 --- /dev/null +++ b/src/QirTools/pyqir/tests/randwalkphaseest.ll.reference @@ -0,0 +1,3388 @@ + +%Range = type { i64, i64, i64 } +%Tuple = type opaque +%Result = type opaque +%Qubit = type opaque +%Array = type opaque +%String = type opaque +%Callable = type opaque + +@PauliI = internal constant i2 0 +@PauliX = internal constant i2 1 +@PauliY = internal constant i2 -1 +@PauliZ = internal constant i2 -2 +@EmptyRange = internal constant %Range { i64 0, i64 1, i64 -1 } +@0 = internal constant [18 x i8] c"Unsupported input\00" +@Microsoft__Quantum__Intrinsic__CNOT__FunctionTable = internal constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__CNOT__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__CNOT__adj__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__CNOT__ctl__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__CNOT__ctladj__wrapper] +@Microsoft__Quantum__Intrinsic__H__FunctionTable = internal constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__H__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__H__adj__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__H__ctl__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__H__ctladj__wrapper] +@Microsoft__Quantum__Intrinsic__Rx__FunctionTable = internal constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Rx__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Rx__adj__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Rx__ctl__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Rx__ctladj__wrapper] +@Microsoft__Quantum__Intrinsic__Ry__FunctionTable = internal constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Ry__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Ry__adj__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Ry__ctl__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Ry__ctladj__wrapper] +@Microsoft__Quantum__Intrinsic__Rz__FunctionTable = internal constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Rz__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Rz__adj__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Rz__ctl__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Rz__ctladj__wrapper] +@Microsoft__Quantum__Intrinsic__S__FunctionTable = internal constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__S__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__S__adj__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__S__ctl__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__S__ctladj__wrapper] +@Microsoft__Quantum__Intrinsic__T__FunctionTable = internal constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__T__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__T__adj__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__T__ctl__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__T__ctladj__wrapper] +@Microsoft__Quantum__Intrinsic__X__FunctionTable = internal constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__X__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__X__adj__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__X__ctl__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__X__ctladj__wrapper] +@Microsoft__Quantum__Intrinsic__Z__FunctionTable = internal constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Z__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Z__adj__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Z__ctl__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Z__ctladj__wrapper] + +define internal double @Microsoft__Quantum__Qir__Emission__ClassicalComputeInput1__body(double %mu, double %isigma) { +entry: + %0 = fmul double %mu, %isigma + %1 = fsub double 1.000000e+00, %0 + ret double %1 +} + +define internal double @Microsoft__Quantum__Qir__Emission__ClassicalComputeInput2__body(double %isigma) { +entry: + %0 = fmul double 5.000000e-01, %isigma + ret double %0 +} + +define internal double @Microsoft__Quantum__Qir__Emission__ClassicalUpdateiSigma__body(double %isigma) { +entry: + %0 = fmul double %isigma, 1.257700e+00 + ret double %0 +} + +define internal double @Microsoft__Quantum__Qir__Emission__ClassicalUpdateMu__body(double %mu, double %sigma, %Result* %res) { +entry: + %update = fmul double 6.065000e-01, %sigma + %0 = call %Result* @__quantum__rt__result_get_one() + %1 = call i1 @__quantum__rt__result_equal(%Result* %res, %Result* %0) + br i1 %1, label %condTrue__1, label %condFalse__1 + +condTrue__1: ; preds = %entry + %2 = fadd double %mu, %update + br label %condContinue__1 + +condFalse__1: ; preds = %entry + %3 = fsub double %mu, %update + br label %condContinue__1 + +condContinue__1: ; preds = %condFalse__1, %condTrue__1 + %4 = phi double [ %2, %condTrue__1 ], [ %3, %condFalse__1 ] + ret double %4 +} + +declare %Result* @__quantum__rt__result_get_one() + +declare i1 @__quantum__rt__result_equal(%Result*, %Result*) + +define internal double @Microsoft__Quantum__Qir__Emission__ClassicalUpdateSigma__body(double %sigma) { +entry: + %0 = fmul double %sigma, 7.951000e-01 + ret double %0 +} + +define internal double @Microsoft__Quantum__Qir__Emission__EstimatePhaseByRandomWalk__body() { +entry: + %mu = alloca double, align 8 + store double 7.951000e-01, double* %mu, align 8 + %isigma = alloca double, align 8 + store double 0x3FFA6180F3204A49, double* %isigma, align 8 + %sigma = alloca double, align 8 + store double 6.065000e-01, double* %sigma, align 8 + %target = call %Qubit* @__quantum__rt__qubit_allocate() + %aux = call %Qubit* @__quantum__rt__qubit_allocate() + call void @Microsoft__Quantum__Qir__Emission__Prepare__body(%Qubit* %target) + br label %header__1 + +header__1: ; preds = %exiting__1, %entry + %0 = phi i64 [ 1, %entry ], [ %8, %exiting__1 ] + %1 = icmp sle i64 %0, 30 + br i1 %1, label %body__1, label %exit__1 + +body__1: ; preds = %header__1 + %2 = load double, double* %mu, align 8 + %3 = load double, double* %isigma, align 8 + %c1 = call double @Microsoft__Quantum__Qir__Emission__ClassicalComputeInput1__body(double %2, double %3) + %c2 = call double @Microsoft__Quantum__Qir__Emission__ClassicalComputeInput2__body(double %3) + %datum = call %Result* @Microsoft__Quantum__Qir__Emission__Iterate__body(double %c1, double %c2, %Qubit* %target, %Qubit* %aux) + %4 = load double, double* %sigma, align 8 + %5 = call double @Microsoft__Quantum__Qir__Emission__ClassicalUpdateMu__body(double %2, double %4, %Result* %datum) + store double %5, double* %mu, align 8 + %6 = call double @Microsoft__Quantum__Qir__Emission__ClassicalUpdateiSigma__body(double %3) + store double %6, double* %isigma, align 8 + %7 = call double @Microsoft__Quantum__Qir__Emission__ClassicalUpdateSigma__body(double %4) + store double %7, double* %sigma, align 8 + call void @__quantum__rt__result_update_reference_count(%Result* %datum, i32 -1) + br label %exiting__1 + +exiting__1: ; preds = %body__1 + %8 = add i64 %0, 1 + br label %header__1 + +exit__1: ; preds = %header__1 + %9 = load double, double* %mu, align 8 + %10 = fmul double %9, 2.000000e+00 + call void @__quantum__rt__qubit_release(%Qubit* %aux) + call void @__quantum__rt__qubit_release(%Qubit* %target) + ret double %10 +} + +declare %Qubit* @__quantum__rt__qubit_allocate() + +declare %Array* @__quantum__rt__qubit_allocate_array(i64) + +declare void @__quantum__rt__qubit_release(%Qubit*) + +define internal void @Microsoft__Quantum__Qir__Emission__Prepare__body(%Qubit* %target) { +entry: + call void @Microsoft__Quantum__Intrinsic__X__body(%Qubit* %target) + ret void +} + +define internal %Result* @Microsoft__Quantum__Qir__Emission__Iterate__body(double %c1, double %c2, %Qubit* %target, %Qubit* %aux) { +entry: + call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %aux) + %0 = fdiv double %c1, 2.000000e+00 + call void @Microsoft__Quantum__Intrinsic__RzPi__body(double %0, %Qubit* %aux) + %1 = fdiv double %c2, 2.000000e+00 + call void @__quantum__qis__crz__body(double %1, %Qubit* %aux, %Qubit* %target) + call void @Microsoft__Quantum__Intrinsic__H__adj(%Qubit* %aux) + %2 = call %Result* @Microsoft__Quantum__Measurement__MResetZ__body(%Qubit* %aux) + ret %Result* %2 +} + +declare void @__quantum__rt__result_update_reference_count(%Result*, i32) + +define internal void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %qubit) { +entry: + call void @__quantum__qis__h__body(%Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__RzPi__body(double %theta, %Qubit* %qubit) { +entry: + call void @Microsoft__Quantum__Intrinsic__Rz__body(double %theta, %Qubit* %qubit) + ret void +} + +declare void @__quantum__qis__crz__body(double, %Qubit*, %Qubit*) + +define internal void @Microsoft__Quantum__Intrinsic__H__adj(%Qubit* %qubit) { +entry: + call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %qubit) + ret void +} + +define internal %Result* @Microsoft__Quantum__Measurement__MResetZ__body(%Qubit* %target) { +entry: + %result = call %Result* @__quantum__qis__m__body(%Qubit* %target) + call void @__quantum__qis__reset__body(%Qubit* %target) + ret %Result* %result +} + +define internal void @Microsoft__Quantum__Intrinsic__X__body(%Qubit* %qubit) { +entry: + call void @__quantum__qis__x__body(%Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Rz__body(double %theta, %Qubit* %qubit) { +entry: + call void @__quantum__qis__rz__body(double %theta, %Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic____QsRef23__ApplyControlledX____body(%Qubit* %control, %Qubit* %target) { +entry: + call void @__quantum__qis__cnot__body(%Qubit* %control, %Qubit* %target) + ret void +} + +declare void @__quantum__qis__cnot__body(%Qubit*, %Qubit*) + +define internal void @Microsoft__Quantum__Intrinsic____QsRef23__ApplyControlledX____adj(%Qubit* %control, %Qubit* %target) { +entry: + call void @__quantum__qis__cnot__body(%Qubit* %control, %Qubit* %target) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic____QsRef23__ApplyControlledZ____body(%Qubit* %control, %Qubit* %target) { +entry: + call void @__quantum__qis__cz__body(%Qubit* %control, %Qubit* %target) + ret void +} + +declare void @__quantum__qis__cz__body(%Qubit*, %Qubit*) + +define internal void @Microsoft__Quantum__Intrinsic____QsRef23__ApplyControlledZ____adj(%Qubit* %control, %Qubit* %target) { +entry: + call void @__quantum__qis__cz__body(%Qubit* %control, %Qubit* %target) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic____QsRef23__ApplyGlobalPhase____body(double %theta) { +entry: + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic____QsRef23__ApplyGlobalPhase____adj(double %theta) { +entry: + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic____QsRef23__ApplyGlobalPhase____ctl(%Array* %controls, double %theta) { +entry: + call void @__quantum__rt__array_update_alias_count(%Array* %controls, i32 1) + %0 = call i64 @__quantum__rt__array_get_size_1d(%Array* %controls) + %1 = icmp sgt i64 %0, 0 + br i1 %1, label %then0__1, label %continue__1 + +then0__1: ; preds = %entry + %2 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %controls, i64 0) + %3 = bitcast i8* %2 to %Qubit** + %qubit = load %Qubit*, %Qubit** %3, align 8 + %4 = sub i64 %0, 1 + %5 = load %Range, %Range* @EmptyRange, align 4 + %6 = insertvalue %Range %5, i64 1, 0 + %7 = insertvalue %Range %6, i64 1, 1 + %8 = insertvalue %Range %7, i64 %4, 2 + %rest = call %Array* @__quantum__rt__array_slice_1d(%Array* %controls, %Range %8, i1 true) + call void @__quantum__rt__array_update_alias_count(%Array* %rest, i32 1) + %9 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint ({ double, %Qubit* }* getelementptr ({ double, %Qubit* }, { double, %Qubit* }* null, i32 1) to i64)) + %10 = bitcast %Tuple* %9 to { double, %Qubit* }* + %11 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %10, i32 0, i32 0 + %12 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %10, i32 0, i32 1 + store double %theta, double* %11, align 8 + store %Qubit* %qubit, %Qubit** %12, align 8 + call void @Microsoft__Quantum__Intrinsic__R1__ctl(%Array* %rest, { double, %Qubit* }* %10) + call void @__quantum__rt__array_update_alias_count(%Array* %rest, i32 -1) + call void @__quantum__rt__array_update_reference_count(%Array* %rest, i32 -1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %9, i32 -1) + br label %continue__1 + +continue__1: ; preds = %then0__1, %entry + call void @__quantum__rt__array_update_alias_count(%Array* %controls, i32 -1) + ret void +} + +declare void @__quantum__rt__array_update_alias_count(%Array*, i32) + +declare i64 @__quantum__rt__array_get_size_1d(%Array*) + +declare i8* @__quantum__rt__array_get_element_ptr_1d(%Array*, i64) + +declare %Array* @__quantum__rt__array_slice_1d(%Array*, %Range, i1) + +define internal void @Microsoft__Quantum__Intrinsic__R1__ctl(%Array* %__controlQubits__, { double, %Qubit* }* %0) { +entry: + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 1) + %1 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 0 + %theta = load double, double* %1, align 8 + %2 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 1 + %qubit = load %Qubit*, %Qubit** %2, align 8 + %3 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint ({ i2, double, %Qubit* }* getelementptr ({ i2, double, %Qubit* }, { i2, double, %Qubit* }* null, i32 1) to i64)) + %4 = bitcast %Tuple* %3 to { i2, double, %Qubit* }* + %5 = getelementptr inbounds { i2, double, %Qubit* }, { i2, double, %Qubit* }* %4, i32 0, i32 0 + %6 = getelementptr inbounds { i2, double, %Qubit* }, { i2, double, %Qubit* }* %4, i32 0, i32 1 + %7 = getelementptr inbounds { i2, double, %Qubit* }, { i2, double, %Qubit* }* %4, i32 0, i32 2 + %8 = load i2, i2* @PauliZ, align 1 + store i2 %8, i2* %5, align 1 + store double %theta, double* %6, align 8 + store %Qubit* %qubit, %Qubit** %7, align 8 + call void @Microsoft__Quantum__Intrinsic__R__ctl(%Array* %__controlQubits__, { i2, double, %Qubit* }* %4) + %9 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint ({ i2, double, %Qubit* }* getelementptr ({ i2, double, %Qubit* }, { i2, double, %Qubit* }* null, i32 1) to i64)) + %10 = bitcast %Tuple* %9 to { i2, double, %Qubit* }* + %11 = getelementptr inbounds { i2, double, %Qubit* }, { i2, double, %Qubit* }* %10, i32 0, i32 0 + %12 = getelementptr inbounds { i2, double, %Qubit* }, { i2, double, %Qubit* }* %10, i32 0, i32 1 + %13 = getelementptr inbounds { i2, double, %Qubit* }, { i2, double, %Qubit* }* %10, i32 0, i32 2 + %14 = load i2, i2* @PauliI, align 1 + %15 = fneg double %theta + store i2 %14, i2* %11, align 1 + store double %15, double* %12, align 8 + store %Qubit* %qubit, %Qubit** %13, align 8 + call void @Microsoft__Quantum__Intrinsic__R__ctl(%Array* %__controlQubits__, { i2, double, %Qubit* }* %10) + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 -1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %3, i32 -1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %9, i32 -1) + ret void +} + +declare %Tuple* @__quantum__rt__tuple_create(i64) + +declare void @__quantum__rt__array_update_reference_count(%Array*, i32) + +declare void @__quantum__rt__tuple_update_reference_count(%Tuple*, i32) + +define internal void @Microsoft__Quantum__Intrinsic____QsRef23__ApplyGlobalPhase____ctladj(%Array* %controls, double %theta) { +entry: + call void @__quantum__rt__array_update_alias_count(%Array* %controls, i32 1) + %0 = call i64 @__quantum__rt__array_get_size_1d(%Array* %controls) + %1 = icmp sgt i64 %0, 0 + br i1 %1, label %then0__1, label %continue__1 + +then0__1: ; preds = %entry + %2 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %controls, i64 0) + %3 = bitcast i8* %2 to %Qubit** + %__qsVar0__qubit__ = load %Qubit*, %Qubit** %3, align 8 + %4 = sub i64 %0, 1 + %5 = load %Range, %Range* @EmptyRange, align 4 + %6 = insertvalue %Range %5, i64 1, 0 + %7 = insertvalue %Range %6, i64 1, 1 + %8 = insertvalue %Range %7, i64 %4, 2 + %__qsVar1__rest__ = call %Array* @__quantum__rt__array_slice_1d(%Array* %controls, %Range %8, i1 true) + call void @__quantum__rt__array_update_alias_count(%Array* %__qsVar1__rest__, i32 1) + %9 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint ({ double, %Qubit* }* getelementptr ({ double, %Qubit* }, { double, %Qubit* }* null, i32 1) to i64)) + %10 = bitcast %Tuple* %9 to { double, %Qubit* }* + %11 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %10, i32 0, i32 0 + %12 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %10, i32 0, i32 1 + store double %theta, double* %11, align 8 + store %Qubit* %__qsVar0__qubit__, %Qubit** %12, align 8 + call void @Microsoft__Quantum__Intrinsic__R1__ctladj(%Array* %__qsVar1__rest__, { double, %Qubit* }* %10) + call void @__quantum__rt__array_update_alias_count(%Array* %__qsVar1__rest__, i32 -1) + call void @__quantum__rt__array_update_reference_count(%Array* %__qsVar1__rest__, i32 -1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %9, i32 -1) + br label %continue__1 + +continue__1: ; preds = %then0__1, %entry + call void @__quantum__rt__array_update_alias_count(%Array* %controls, i32 -1) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__R1__ctladj(%Array* %__controlQubits__, { double, %Qubit* }* %0) { +entry: + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 1) + %1 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 0 + %theta = load double, double* %1, align 8 + %2 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 1 + %qubit = load %Qubit*, %Qubit** %2, align 8 + %3 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint ({ i2, double, %Qubit* }* getelementptr ({ i2, double, %Qubit* }, { i2, double, %Qubit* }* null, i32 1) to i64)) + %4 = bitcast %Tuple* %3 to { i2, double, %Qubit* }* + %5 = getelementptr inbounds { i2, double, %Qubit* }, { i2, double, %Qubit* }* %4, i32 0, i32 0 + %6 = getelementptr inbounds { i2, double, %Qubit* }, { i2, double, %Qubit* }* %4, i32 0, i32 1 + %7 = getelementptr inbounds { i2, double, %Qubit* }, { i2, double, %Qubit* }* %4, i32 0, i32 2 + %8 = load i2, i2* @PauliI, align 1 + %9 = fneg double %theta + store i2 %8, i2* %5, align 1 + store double %9, double* %6, align 8 + store %Qubit* %qubit, %Qubit** %7, align 8 + call void @Microsoft__Quantum__Intrinsic__R__ctladj(%Array* %__controlQubits__, { i2, double, %Qubit* }* %4) + %10 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint ({ i2, double, %Qubit* }* getelementptr ({ i2, double, %Qubit* }, { i2, double, %Qubit* }* null, i32 1) to i64)) + %11 = bitcast %Tuple* %10 to { i2, double, %Qubit* }* + %12 = getelementptr inbounds { i2, double, %Qubit* }, { i2, double, %Qubit* }* %11, i32 0, i32 0 + %13 = getelementptr inbounds { i2, double, %Qubit* }, { i2, double, %Qubit* }* %11, i32 0, i32 1 + %14 = getelementptr inbounds { i2, double, %Qubit* }, { i2, double, %Qubit* }* %11, i32 0, i32 2 + %15 = load i2, i2* @PauliZ, align 1 + store i2 %15, i2* %12, align 1 + store double %theta, double* %13, align 8 + store %Qubit* %qubit, %Qubit** %14, align 8 + call void @Microsoft__Quantum__Intrinsic__R__ctladj(%Array* %__controlQubits__, { i2, double, %Qubit* }* %11) + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 -1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %3, i32 -1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %10, i32 -1) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic____QsRef23__ApplyUncontrolledH____body(%Qubit* %qubit) { +entry: + call void @__quantum__qis__h__body(%Qubit* %qubit) + ret void +} + +declare void @__quantum__qis__h__body(%Qubit*) + +define internal void @Microsoft__Quantum__Intrinsic____QsRef23__ApplyUncontrolledH____adj(%Qubit* %qubit) { +entry: + call void @__quantum__qis__h__body(%Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic____QsRef23__ApplyUncontrolledX____body(%Qubit* %qubit) { +entry: + call void @__quantum__qis__x__body(%Qubit* %qubit) + ret void +} + +declare void @__quantum__qis__x__body(%Qubit*) + +define internal void @Microsoft__Quantum__Intrinsic____QsRef23__ApplyUncontrolledX____adj(%Qubit* %qubit) { +entry: + call void @__quantum__qis__x__body(%Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic____QsRef23__ApplyUncontrolledZ____body(%Qubit* %qubit) { +entry: + call void @__quantum__qis__z__body(%Qubit* %qubit) + ret void +} + +declare void @__quantum__qis__z__body(%Qubit*) + +define internal void @Microsoft__Quantum__Intrinsic____QsRef23__ApplyUncontrolledZ____adj(%Qubit* %qubit) { +entry: + call void @__quantum__qis__z__body(%Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic____QsRef23__MapPauli____body(%Qubit* %qubit, i2 %from, i2 %to) { +entry: + %0 = icmp eq i2 %from, %to + br i1 %0, label %then0__1, label %test1__1 + +then0__1: ; preds = %entry + br label %continue__1 + +test1__1: ; preds = %entry + %1 = load i2, i2* @PauliZ, align 1 + %2 = icmp eq i2 %from, %1 + br i1 %2, label %condTrue__1, label %condContinue__1 + +condTrue__1: ; preds = %test1__1 + %3 = load i2, i2* @PauliX, align 1 + %4 = icmp eq i2 %to, %3 + br label %condContinue__1 + +condContinue__1: ; preds = %condTrue__1, %test1__1 + %5 = phi i1 [ %4, %condTrue__1 ], [ %2, %test1__1 ] + %6 = xor i1 %5, true + br i1 %6, label %condTrue__2, label %condContinue__2 + +condTrue__2: ; preds = %condContinue__1 + %7 = load i2, i2* @PauliX, align 1 + %8 = icmp eq i2 %from, %7 + br i1 %8, label %condTrue__3, label %condContinue__3 + +condTrue__3: ; preds = %condTrue__2 + %9 = load i2, i2* @PauliZ, align 1 + %10 = icmp eq i2 %to, %9 + br label %condContinue__3 + +condContinue__3: ; preds = %condTrue__3, %condTrue__2 + %11 = phi i1 [ %10, %condTrue__3 ], [ %8, %condTrue__2 ] + br label %condContinue__2 + +condContinue__2: ; preds = %condContinue__3, %condContinue__1 + %12 = phi i1 [ %11, %condContinue__3 ], [ %5, %condContinue__1 ] + br i1 %12, label %then1__1, label %test2__1 + +then1__1: ; preds = %condContinue__2 + call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %qubit) + br label %continue__1 + +test2__1: ; preds = %condContinue__2 + %13 = load i2, i2* @PauliZ, align 1 + %14 = icmp eq i2 %from, %13 + br i1 %14, label %condTrue__4, label %condContinue__4 + +condTrue__4: ; preds = %test2__1 + %15 = load i2, i2* @PauliY, align 1 + %16 = icmp eq i2 %to, %15 + br label %condContinue__4 + +condContinue__4: ; preds = %condTrue__4, %test2__1 + %17 = phi i1 [ %16, %condTrue__4 ], [ %14, %test2__1 ] + br i1 %17, label %then2__1, label %test3__1 + +then2__1: ; preds = %condContinue__4 + call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %qubit) + call void @Microsoft__Quantum__Intrinsic__S__body(%Qubit* %qubit) + call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %qubit) + br label %continue__1 + +test3__1: ; preds = %condContinue__4 + %18 = load i2, i2* @PauliY, align 1 + %19 = icmp eq i2 %from, %18 + br i1 %19, label %condTrue__5, label %condContinue__5 + +condTrue__5: ; preds = %test3__1 + %20 = load i2, i2* @PauliZ, align 1 + %21 = icmp eq i2 %to, %20 + br label %condContinue__5 + +condContinue__5: ; preds = %condTrue__5, %test3__1 + %22 = phi i1 [ %21, %condTrue__5 ], [ %19, %test3__1 ] + br i1 %22, label %then3__1, label %test4__1 + +then3__1: ; preds = %condContinue__5 + call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %qubit) + call void @Microsoft__Quantum__Intrinsic__S__adj(%Qubit* %qubit) + call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %qubit) + br label %continue__1 + +test4__1: ; preds = %condContinue__5 + %23 = load i2, i2* @PauliY, align 1 + %24 = icmp eq i2 %from, %23 + br i1 %24, label %condTrue__6, label %condContinue__6 + +condTrue__6: ; preds = %test4__1 + %25 = load i2, i2* @PauliX, align 1 + %26 = icmp eq i2 %to, %25 + br label %condContinue__6 + +condContinue__6: ; preds = %condTrue__6, %test4__1 + %27 = phi i1 [ %26, %condTrue__6 ], [ %24, %test4__1 ] + br i1 %27, label %then4__1, label %test5__1 + +then4__1: ; preds = %condContinue__6 + call void @Microsoft__Quantum__Intrinsic__S__body(%Qubit* %qubit) + br label %continue__1 + +test5__1: ; preds = %condContinue__6 + %28 = load i2, i2* @PauliX, align 1 + %29 = icmp eq i2 %from, %28 + br i1 %29, label %condTrue__7, label %condContinue__7 + +condTrue__7: ; preds = %test5__1 + %30 = load i2, i2* @PauliY, align 1 + %31 = icmp eq i2 %to, %30 + br label %condContinue__7 + +condContinue__7: ; preds = %condTrue__7, %test5__1 + %32 = phi i1 [ %31, %condTrue__7 ], [ %29, %test5__1 ] + br i1 %32, label %then5__1, label %else__1 + +then5__1: ; preds = %condContinue__7 + call void @Microsoft__Quantum__Intrinsic__S__adj(%Qubit* %qubit) + br label %continue__1 + +else__1: ; preds = %condContinue__7 + %33 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @0, i32 0, i32 0)) + call void @__quantum__rt__fail(%String* %33) + unreachable + +continue__1: ; preds = %then5__1, %then4__1, %then3__1, %then2__1, %then1__1, %then0__1 + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__S__body(%Qubit* %qubit) { +entry: + call void @__quantum__qis__s__body(%Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__S__adj(%Qubit* %qubit) { +entry: + call void @__quantum__qis__s__adj(%Qubit* %qubit) + ret void +} + +declare %String* @__quantum__rt__string_create(i8*) + +declare void @__quantum__rt__fail(%String*) + +define internal void @Microsoft__Quantum__Intrinsic____QsRef23__MapPauli____adj(%Qubit* %qubit, i2 %from, i2 %to) { +entry: + %0 = icmp eq i2 %from, %to + br i1 %0, label %then0__1, label %test1__1 + +then0__1: ; preds = %entry + br label %continue__1 + +test1__1: ; preds = %entry + %1 = load i2, i2* @PauliZ, align 1 + %2 = icmp eq i2 %from, %1 + br i1 %2, label %condTrue__1, label %condContinue__1 + +condTrue__1: ; preds = %test1__1 + %3 = load i2, i2* @PauliX, align 1 + %4 = icmp eq i2 %to, %3 + br label %condContinue__1 + +condContinue__1: ; preds = %condTrue__1, %test1__1 + %5 = phi i1 [ %4, %condTrue__1 ], [ %2, %test1__1 ] + %6 = xor i1 %5, true + br i1 %6, label %condTrue__2, label %condContinue__2 + +condTrue__2: ; preds = %condContinue__1 + %7 = load i2, i2* @PauliX, align 1 + %8 = icmp eq i2 %from, %7 + br i1 %8, label %condTrue__3, label %condContinue__3 + +condTrue__3: ; preds = %condTrue__2 + %9 = load i2, i2* @PauliZ, align 1 + %10 = icmp eq i2 %to, %9 + br label %condContinue__3 + +condContinue__3: ; preds = %condTrue__3, %condTrue__2 + %11 = phi i1 [ %10, %condTrue__3 ], [ %8, %condTrue__2 ] + br label %condContinue__2 + +condContinue__2: ; preds = %condContinue__3, %condContinue__1 + %12 = phi i1 [ %11, %condContinue__3 ], [ %5, %condContinue__1 ] + br i1 %12, label %then1__1, label %test2__1 + +then1__1: ; preds = %condContinue__2 + call void @Microsoft__Quantum__Intrinsic__H__adj(%Qubit* %qubit) + br label %continue__1 + +test2__1: ; preds = %condContinue__2 + %13 = load i2, i2* @PauliZ, align 1 + %14 = icmp eq i2 %from, %13 + br i1 %14, label %condTrue__4, label %condContinue__4 + +condTrue__4: ; preds = %test2__1 + %15 = load i2, i2* @PauliY, align 1 + %16 = icmp eq i2 %to, %15 + br label %condContinue__4 + +condContinue__4: ; preds = %condTrue__4, %test2__1 + %17 = phi i1 [ %16, %condTrue__4 ], [ %14, %test2__1 ] + br i1 %17, label %then2__1, label %test3__1 + +then2__1: ; preds = %condContinue__4 + call void @Microsoft__Quantum__Intrinsic__H__adj(%Qubit* %qubit) + call void @Microsoft__Quantum__Intrinsic__S__adj(%Qubit* %qubit) + call void @Microsoft__Quantum__Intrinsic__H__adj(%Qubit* %qubit) + br label %continue__1 + +test3__1: ; preds = %condContinue__4 + %18 = load i2, i2* @PauliY, align 1 + %19 = icmp eq i2 %from, %18 + br i1 %19, label %condTrue__5, label %condContinue__5 + +condTrue__5: ; preds = %test3__1 + %20 = load i2, i2* @PauliZ, align 1 + %21 = icmp eq i2 %to, %20 + br label %condContinue__5 + +condContinue__5: ; preds = %condTrue__5, %test3__1 + %22 = phi i1 [ %21, %condTrue__5 ], [ %19, %test3__1 ] + br i1 %22, label %then3__1, label %test4__1 + +then3__1: ; preds = %condContinue__5 + call void @Microsoft__Quantum__Intrinsic__H__adj(%Qubit* %qubit) + call void @Microsoft__Quantum__Intrinsic__S__body(%Qubit* %qubit) + call void @Microsoft__Quantum__Intrinsic__H__adj(%Qubit* %qubit) + br label %continue__1 + +test4__1: ; preds = %condContinue__5 + %23 = load i2, i2* @PauliY, align 1 + %24 = icmp eq i2 %from, %23 + br i1 %24, label %condTrue__6, label %condContinue__6 + +condTrue__6: ; preds = %test4__1 + %25 = load i2, i2* @PauliX, align 1 + %26 = icmp eq i2 %to, %25 + br label %condContinue__6 + +condContinue__6: ; preds = %condTrue__6, %test4__1 + %27 = phi i1 [ %26, %condTrue__6 ], [ %24, %test4__1 ] + br i1 %27, label %then4__1, label %test5__1 + +then4__1: ; preds = %condContinue__6 + call void @Microsoft__Quantum__Intrinsic__S__adj(%Qubit* %qubit) + br label %continue__1 + +test5__1: ; preds = %condContinue__6 + %28 = load i2, i2* @PauliX, align 1 + %29 = icmp eq i2 %from, %28 + br i1 %29, label %condTrue__7, label %condContinue__7 + +condTrue__7: ; preds = %test5__1 + %30 = load i2, i2* @PauliY, align 1 + %31 = icmp eq i2 %to, %30 + br label %condContinue__7 + +condContinue__7: ; preds = %condTrue__7, %test5__1 + %32 = phi i1 [ %31, %condTrue__7 ], [ %29, %test5__1 ] + br i1 %32, label %then5__1, label %else__1 + +then5__1: ; preds = %condContinue__7 + call void @Microsoft__Quantum__Intrinsic__S__body(%Qubit* %qubit) + br label %continue__1 + +else__1: ; preds = %condContinue__7 + %33 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @0, i32 0, i32 0)) + call void @__quantum__rt__fail(%String* %33) + unreachable + +continue__1: ; preds = %then5__1, %then4__1, %then3__1, %then2__1, %then1__1, %then0__1 + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic____QsRef23__PhaseCCX____body(%Qubit* %control1, %Qubit* %control2, %Qubit* %target) { +entry: + call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %target) + call void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* %target, %Qubit* %control1) + call void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* %control1, %Qubit* %control2) + call void @Microsoft__Quantum__Intrinsic__T__body(%Qubit* %control2) + call void @Microsoft__Quantum__Intrinsic__T__adj(%Qubit* %control1) + call void @Microsoft__Quantum__Intrinsic__T__body(%Qubit* %target) + call void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* %target, %Qubit* %control1) + call void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* %control1, %Qubit* %control2) + call void @Microsoft__Quantum__Intrinsic__T__adj(%Qubit* %control2) + call void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* %target, %Qubit* %control2) + call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %target) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* %control, %Qubit* %target) { +entry: + call void @__quantum__qis__cnot__body(%Qubit* %control, %Qubit* %target) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__T__body(%Qubit* %qubit) { +entry: + call void @__quantum__qis__t__body(%Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__T__adj(%Qubit* %qubit) { +entry: + call void @__quantum__qis__t__adj(%Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic____QsRef23__PhaseCCX____adj(%Qubit* %control1, %Qubit* %control2, %Qubit* %target) { +entry: + call void @Microsoft__Quantum__Intrinsic__H__adj(%Qubit* %target) + call void @Microsoft__Quantum__Intrinsic__CNOT__adj(%Qubit* %target, %Qubit* %control2) + call void @Microsoft__Quantum__Intrinsic__T__body(%Qubit* %control2) + call void @Microsoft__Quantum__Intrinsic__CNOT__adj(%Qubit* %control1, %Qubit* %control2) + call void @Microsoft__Quantum__Intrinsic__CNOT__adj(%Qubit* %target, %Qubit* %control1) + call void @Microsoft__Quantum__Intrinsic__T__adj(%Qubit* %target) + call void @Microsoft__Quantum__Intrinsic__T__body(%Qubit* %control1) + call void @Microsoft__Quantum__Intrinsic__T__adj(%Qubit* %control2) + call void @Microsoft__Quantum__Intrinsic__CNOT__adj(%Qubit* %control1, %Qubit* %control2) + call void @Microsoft__Quantum__Intrinsic__CNOT__adj(%Qubit* %target, %Qubit* %control1) + call void @Microsoft__Quantum__Intrinsic__H__adj(%Qubit* %target) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__CNOT__adj(%Qubit* %control, %Qubit* %target) { +entry: + call void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* %control, %Qubit* %target) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__CCNOT__body(%Qubit* %control1, %Qubit* %control2, %Qubit* %target) { +entry: + call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %target) + %0 = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 2) + %1 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %0, i64 0) + %2 = bitcast i8* %1 to %Qubit** + %3 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %0, i64 1) + %4 = bitcast i8* %3 to %Qubit** + store %Qubit* %control1, %Qubit** %2, align 8 + store %Qubit* %control2, %Qubit** %4, align 8 + call void @Microsoft__Quantum__Intrinsic__Z__ctl(%Array* %0, %Qubit* %target) + call void @Microsoft__Quantum__Intrinsic__H__adj(%Qubit* %target) + call void @__quantum__rt__array_update_reference_count(%Array* %0, i32 -1) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Z__ctl(%Array* %ctls, %Qubit* %qubit) { +entry: + call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i32 1) + %0 = call i64 @__quantum__rt__array_get_size_1d(%Array* %ctls) + %1 = icmp eq i64 %0, 0 + br i1 %1, label %then0__1, label %test1__1 + +then0__1: ; preds = %entry + call void @__quantum__qis__z__body(%Qubit* %qubit) + br label %continue__1 + +test1__1: ; preds = %entry + %2 = call i64 @__quantum__rt__array_get_size_1d(%Array* %ctls) + %3 = icmp eq i64 %2, 1 + br i1 %3, label %then1__1, label %test2__1 + +then1__1: ; preds = %test1__1 + %4 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls, i64 0) + %5 = bitcast i8* %4 to %Qubit** + %control = load %Qubit*, %Qubit** %5, align 8 + call void @__quantum__qis__cz__body(%Qubit* %control, %Qubit* %qubit) + br label %continue__1 + +test2__1: ; preds = %test1__1 + %6 = call i64 @__quantum__rt__array_get_size_1d(%Array* %ctls) + %7 = icmp eq i64 %6, 2 + br i1 %7, label %then2__1, label %else__1 + +then2__1: ; preds = %test2__1 + %8 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls, i64 0) + %9 = bitcast i8* %8 to %Qubit** + %10 = load %Qubit*, %Qubit** %9, align 8 + call void @Microsoft__Quantum__Intrinsic__T__adj(%Qubit* %10) + %11 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls, i64 1) + %12 = bitcast i8* %11 to %Qubit** + %13 = load %Qubit*, %Qubit** %12, align 8 + call void @Microsoft__Quantum__Intrinsic__T__adj(%Qubit* %13) + %14 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls, i64 0) + %15 = bitcast i8* %14 to %Qubit** + %16 = load %Qubit*, %Qubit** %15, align 8 + call void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* %qubit, %Qubit* %16) + %17 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls, i64 0) + %18 = bitcast i8* %17 to %Qubit** + %19 = load %Qubit*, %Qubit** %18, align 8 + call void @Microsoft__Quantum__Intrinsic__T__body(%Qubit* %19) + %20 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls, i64 1) + %21 = bitcast i8* %20 to %Qubit** + %22 = load %Qubit*, %Qubit** %21, align 8 + call void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* %22, %Qubit* %qubit) + %23 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls, i64 1) + %24 = bitcast i8* %23 to %Qubit** + %25 = load %Qubit*, %Qubit** %24, align 8 + %26 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls, i64 0) + %27 = bitcast i8* %26 to %Qubit** + %28 = load %Qubit*, %Qubit** %27, align 8 + call void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* %25, %Qubit* %28) + call void @Microsoft__Quantum__Intrinsic__T__body(%Qubit* %qubit) + %29 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls, i64 0) + %30 = bitcast i8* %29 to %Qubit** + %31 = load %Qubit*, %Qubit** %30, align 8 + call void @Microsoft__Quantum__Intrinsic__T__adj(%Qubit* %31) + %32 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls, i64 1) + %33 = bitcast i8* %32 to %Qubit** + %34 = load %Qubit*, %Qubit** %33, align 8 + call void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* %34, %Qubit* %qubit) + %35 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls, i64 0) + %36 = bitcast i8* %35 to %Qubit** + %37 = load %Qubit*, %Qubit** %36, align 8 + call void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* %qubit, %Qubit* %37) + call void @Microsoft__Quantum__Intrinsic__T__adj(%Qubit* %qubit) + %38 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls, i64 0) + %39 = bitcast i8* %38 to %Qubit** + %40 = load %Qubit*, %Qubit** %39, align 8 + call void @Microsoft__Quantum__Intrinsic__T__body(%Qubit* %40) + %41 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls, i64 1) + %42 = bitcast i8* %41 to %Qubit** + %43 = load %Qubit*, %Qubit** %42, align 8 + %44 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls, i64 0) + %45 = bitcast i8* %44 to %Qubit** + %46 = load %Qubit*, %Qubit** %45, align 8 + call void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* %43, %Qubit* %46) + br label %continue__1 + +else__1: ; preds = %test2__1 + %47 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Intrinsic__Z__FunctionTable, [2 x void (%Tuple*, i32)*]* null, %Tuple* null) + call void @__quantum__rt__callable_make_controlled(%Callable* %47) + %48 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 2)) + %49 = bitcast %Tuple* %48 to { %Array*, %Qubit* }* + %50 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %49, i32 0, i32 0 + %51 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %49, i32 0, i32 1 + call void @__quantum__rt__array_update_reference_count(%Array* %ctls, i32 1) + store %Array* %ctls, %Array** %50, align 8 + store %Qubit* %qubit, %Qubit** %51, align 8 + call void @Microsoft__Quantum__Intrinsic___067288bb3b0f4c3fa16d90a27710fc06___QsRef23__ApplyWithLessControlsA____body(%Callable* %47, { %Array*, %Qubit* }* %49) + call void @__quantum__rt__capture_update_reference_count(%Callable* %47, i32 -1) + call void @__quantum__rt__callable_update_reference_count(%Callable* %47, i32 -1) + call void @__quantum__rt__array_update_reference_count(%Array* %ctls, i32 -1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %48, i32 -1) + br label %continue__1 + +continue__1: ; preds = %else__1, %then2__1, %then1__1, %then0__1 + call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i32 -1) + ret void +} + +declare %Array* @__quantum__rt__array_create_1d(i32, i64) + +define internal void @Microsoft__Quantum__Intrinsic__CCNOT__adj(%Qubit* %control1, %Qubit* %control2, %Qubit* %target) { +entry: + call void @Microsoft__Quantum__Intrinsic__CCNOT__body(%Qubit* %control1, %Qubit* %control2, %Qubit* %target) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__CCNOT__ctl(%Array* %ctls, { %Qubit*, %Qubit*, %Qubit* }* %0) { +entry: + call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i32 1) + %1 = getelementptr inbounds { %Qubit*, %Qubit*, %Qubit* }, { %Qubit*, %Qubit*, %Qubit* }* %0, i32 0, i32 0 + %control1 = load %Qubit*, %Qubit** %1, align 8 + %2 = getelementptr inbounds { %Qubit*, %Qubit*, %Qubit* }, { %Qubit*, %Qubit*, %Qubit* }* %0, i32 0, i32 1 + %control2 = load %Qubit*, %Qubit** %2, align 8 + %3 = getelementptr inbounds { %Qubit*, %Qubit*, %Qubit* }, { %Qubit*, %Qubit*, %Qubit* }* %0, i32 0, i32 2 + %target = load %Qubit*, %Qubit** %3, align 8 + %4 = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 2) + %5 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %4, i64 0) + %6 = bitcast i8* %5 to %Qubit** + %7 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %4, i64 1) + %8 = bitcast i8* %7 to %Qubit** + store %Qubit* %control1, %Qubit** %6, align 8 + store %Qubit* %control2, %Qubit** %8, align 8 + %9 = call %Array* @__quantum__rt__array_concatenate(%Array* %ctls, %Array* %4) + call void @Microsoft__Quantum__Intrinsic__X__ctl(%Array* %9, %Qubit* %target) + call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i32 -1) + call void @__quantum__rt__array_update_reference_count(%Array* %4, i32 -1) + call void @__quantum__rt__array_update_reference_count(%Array* %9, i32 -1) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__X__ctl(%Array* %ctls, %Qubit* %qubit) { +entry: + call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i32 1) + %0 = call i64 @__quantum__rt__array_get_size_1d(%Array* %ctls) + %1 = icmp eq i64 %0, 0 + br i1 %1, label %then0__1, label %test1__1 + +then0__1: ; preds = %entry + call void @__quantum__qis__x__body(%Qubit* %qubit) + br label %continue__1 + +test1__1: ; preds = %entry + %2 = call i64 @__quantum__rt__array_get_size_1d(%Array* %ctls) + %3 = icmp eq i64 %2, 1 + br i1 %3, label %then1__1, label %test2__1 + +then1__1: ; preds = %test1__1 + %4 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls, i64 0) + %5 = bitcast i8* %4 to %Qubit** + %control = load %Qubit*, %Qubit** %5, align 8 + call void @__quantum__qis__cnot__body(%Qubit* %control, %Qubit* %qubit) + br label %continue__1 + +test2__1: ; preds = %test1__1 + %6 = call i64 @__quantum__rt__array_get_size_1d(%Array* %ctls) + %7 = icmp eq i64 %6, 2 + br i1 %7, label %then2__1, label %else__1 + +then2__1: ; preds = %test2__1 + %8 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls, i64 0) + %9 = bitcast i8* %8 to %Qubit** + %10 = load %Qubit*, %Qubit** %9, align 8 + %11 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls, i64 1) + %12 = bitcast i8* %11 to %Qubit** + %13 = load %Qubit*, %Qubit** %12, align 8 + call void @Microsoft__Quantum__Intrinsic__CCNOT__body(%Qubit* %10, %Qubit* %13, %Qubit* %qubit) + br label %continue__1 + +else__1: ; preds = %test2__1 + %14 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Intrinsic__X__FunctionTable, [2 x void (%Tuple*, i32)*]* null, %Tuple* null) + call void @__quantum__rt__callable_make_controlled(%Callable* %14) + %15 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 2)) + %16 = bitcast %Tuple* %15 to { %Array*, %Qubit* }* + %17 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %16, i32 0, i32 0 + %18 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %16, i32 0, i32 1 + call void @__quantum__rt__array_update_reference_count(%Array* %ctls, i32 1) + store %Array* %ctls, %Array** %17, align 8 + store %Qubit* %qubit, %Qubit** %18, align 8 + call void @Microsoft__Quantum__Intrinsic___067288bb3b0f4c3fa16d90a27710fc06___QsRef23__ApplyWithLessControlsA____body(%Callable* %14, { %Array*, %Qubit* }* %16) + call void @__quantum__rt__capture_update_reference_count(%Callable* %14, i32 -1) + call void @__quantum__rt__callable_update_reference_count(%Callable* %14, i32 -1) + call void @__quantum__rt__array_update_reference_count(%Array* %ctls, i32 -1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %15, i32 -1) + br label %continue__1 + +continue__1: ; preds = %else__1, %then2__1, %then1__1, %then0__1 + call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i32 -1) + ret void +} + +declare %Array* @__quantum__rt__array_concatenate(%Array*, %Array*) + +define internal void @Microsoft__Quantum__Intrinsic__CCNOT__ctladj(%Array* %__controlQubits__, { %Qubit*, %Qubit*, %Qubit* }* %0) { +entry: + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 1) + %1 = getelementptr inbounds { %Qubit*, %Qubit*, %Qubit* }, { %Qubit*, %Qubit*, %Qubit* }* %0, i32 0, i32 0 + %control1 = load %Qubit*, %Qubit** %1, align 8 + %2 = getelementptr inbounds { %Qubit*, %Qubit*, %Qubit* }, { %Qubit*, %Qubit*, %Qubit* }* %0, i32 0, i32 1 + %control2 = load %Qubit*, %Qubit** %2, align 8 + %3 = getelementptr inbounds { %Qubit*, %Qubit*, %Qubit* }, { %Qubit*, %Qubit*, %Qubit* }* %0, i32 0, i32 2 + %target = load %Qubit*, %Qubit** %3, align 8 + %4 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 3)) + %5 = bitcast %Tuple* %4 to { %Qubit*, %Qubit*, %Qubit* }* + %6 = getelementptr inbounds { %Qubit*, %Qubit*, %Qubit* }, { %Qubit*, %Qubit*, %Qubit* }* %5, i32 0, i32 0 + %7 = getelementptr inbounds { %Qubit*, %Qubit*, %Qubit* }, { %Qubit*, %Qubit*, %Qubit* }* %5, i32 0, i32 1 + %8 = getelementptr inbounds { %Qubit*, %Qubit*, %Qubit* }, { %Qubit*, %Qubit*, %Qubit* }* %5, i32 0, i32 2 + store %Qubit* %control1, %Qubit** %6, align 8 + store %Qubit* %control2, %Qubit** %7, align 8 + store %Qubit* %target, %Qubit** %8, align 8 + call void @Microsoft__Quantum__Intrinsic__CCNOT__ctl(%Array* %__controlQubits__, { %Qubit*, %Qubit*, %Qubit* }* %5) + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 -1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %4, i32 -1) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__CNOT__ctl(%Array* %ctls, { %Qubit*, %Qubit* }* %0) { +entry: + call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i32 1) + %1 = getelementptr inbounds { %Qubit*, %Qubit* }, { %Qubit*, %Qubit* }* %0, i32 0, i32 0 + %control = load %Qubit*, %Qubit** %1, align 8 + %2 = getelementptr inbounds { %Qubit*, %Qubit* }, { %Qubit*, %Qubit* }* %0, i32 0, i32 1 + %target = load %Qubit*, %Qubit** %2, align 8 + %3 = call i64 @__quantum__rt__array_get_size_1d(%Array* %ctls) + %4 = icmp eq i64 %3, 0 + br i1 %4, label %then0__1, label %test1__1 + +then0__1: ; preds = %entry + call void @__quantum__qis__cnot__body(%Qubit* %control, %Qubit* %target) + br label %continue__1 + +test1__1: ; preds = %entry + %5 = call i64 @__quantum__rt__array_get_size_1d(%Array* %ctls) + %6 = icmp eq i64 %5, 1 + br i1 %6, label %then1__1, label %else__1 + +then1__1: ; preds = %test1__1 + %7 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls, i64 0) + %8 = bitcast i8* %7 to %Qubit** + %9 = load %Qubit*, %Qubit** %8, align 8 + call void @Microsoft__Quantum__Intrinsic__CCNOT__body(%Qubit* %9, %Qubit* %control, %Qubit* %target) + br label %continue__1 + +else__1: ; preds = %test1__1 + %10 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Intrinsic__CNOT__FunctionTable, [2 x void (%Tuple*, i32)*]* null, %Tuple* null) + call void @__quantum__rt__callable_make_controlled(%Callable* %10) + %11 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 2)) + %12 = bitcast %Tuple* %11 to { %Array*, { %Qubit*, %Qubit* }* }* + %13 = getelementptr inbounds { %Array*, { %Qubit*, %Qubit* }* }, { %Array*, { %Qubit*, %Qubit* }* }* %12, i32 0, i32 0 + %14 = getelementptr inbounds { %Array*, { %Qubit*, %Qubit* }* }, { %Array*, { %Qubit*, %Qubit* }* }* %12, i32 0, i32 1 + call void @__quantum__rt__array_update_reference_count(%Array* %ctls, i32 1) + %15 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 2)) + %16 = bitcast %Tuple* %15 to { %Qubit*, %Qubit* }* + %17 = getelementptr inbounds { %Qubit*, %Qubit* }, { %Qubit*, %Qubit* }* %16, i32 0, i32 0 + %18 = getelementptr inbounds { %Qubit*, %Qubit* }, { %Qubit*, %Qubit* }* %16, i32 0, i32 1 + store %Qubit* %control, %Qubit** %17, align 8 + store %Qubit* %target, %Qubit** %18, align 8 + store %Array* %ctls, %Array** %13, align 8 + store { %Qubit*, %Qubit* }* %16, { %Qubit*, %Qubit* }** %14, align 8 + call void @Microsoft__Quantum__Intrinsic___0d8cf5dbd1bf4f63a0469c30490db51e___QsRef23__ApplyWithLessControlsA____body(%Callable* %10, { %Array*, { %Qubit*, %Qubit* }* }* %12) + call void @__quantum__rt__capture_update_reference_count(%Callable* %10, i32 -1) + call void @__quantum__rt__callable_update_reference_count(%Callable* %10, i32 -1) + call void @__quantum__rt__array_update_reference_count(%Array* %ctls, i32 -1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %15, i32 -1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %11, i32 -1) + br label %continue__1 + +continue__1: ; preds = %else__1, %then1__1, %then0__1 + call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i32 -1) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic___0d8cf5dbd1bf4f63a0469c30490db51e___QsRef23__ApplyWithLessControlsA____body(%Callable* %op, { %Array*, { %Qubit*, %Qubit* }* }* %0) { +entry: + call void @__quantum__rt__capture_update_alias_count(%Callable* %op, i32 1) + call void @__quantum__rt__callable_update_alias_count(%Callable* %op, i32 1) + %1 = getelementptr inbounds { %Array*, { %Qubit*, %Qubit* }* }, { %Array*, { %Qubit*, %Qubit* }* }* %0, i32 0, i32 0 + %controls = load %Array*, %Array** %1, align 8 + call void @__quantum__rt__array_update_alias_count(%Array* %controls, i32 1) + %2 = getelementptr inbounds { %Array*, { %Qubit*, %Qubit* }* }, { %Array*, { %Qubit*, %Qubit* }* }* %0, i32 0, i32 1 + %arg = load { %Qubit*, %Qubit* }*, { %Qubit*, %Qubit* }** %2, align 8 + %3 = bitcast { %Qubit*, %Qubit* }* %arg to %Tuple* + call void @__quantum__rt__tuple_update_alias_count(%Tuple* %3, i32 1) + %numControls = call i64 @__quantum__rt__array_get_size_1d(%Array* %controls) + %numControlPairs = sdiv i64 %numControls, 2 + %temps = call %Array* @__quantum__rt__qubit_allocate_array(i64 %numControlPairs) + call void @__quantum__rt__array_update_alias_count(%Array* %temps, i32 1) + %4 = sub i64 %numControlPairs, 1 + br label %header__1 + +header__1: ; preds = %exiting__1, %entry + %__qsVar0__numPair__ = phi i64 [ 0, %entry ], [ %18, %exiting__1 ] + %5 = icmp sle i64 %__qsVar0__numPair__, %4 + br i1 %5, label %body__1, label %exit__1 + +body__1: ; preds = %header__1 + %6 = mul i64 2, %__qsVar0__numPair__ + %7 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %controls, i64 %6) + %8 = bitcast i8* %7 to %Qubit** + %9 = load %Qubit*, %Qubit** %8, align 8 + %10 = mul i64 2, %__qsVar0__numPair__ + %11 = add i64 %10, 1 + %12 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %controls, i64 %11) + %13 = bitcast i8* %12 to %Qubit** + %14 = load %Qubit*, %Qubit** %13, align 8 + %15 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %temps, i64 %__qsVar0__numPair__) + %16 = bitcast i8* %15 to %Qubit** + %17 = load %Qubit*, %Qubit** %16, align 8 + call void @Microsoft__Quantum__Intrinsic____QsRef23__PhaseCCX____body(%Qubit* %9, %Qubit* %14, %Qubit* %17) + br label %exiting__1 + +exiting__1: ; preds = %body__1 + %18 = add i64 %__qsVar0__numPair__, 1 + br label %header__1 + +exit__1: ; preds = %header__1 + %19 = srem i64 %numControls, 2 + %20 = icmp eq i64 %19, 0 + br i1 %20, label %condTrue__1, label %condFalse__1 + +condTrue__1: ; preds = %exit__1 + call void @__quantum__rt__array_update_reference_count(%Array* %temps, i32 1) + br label %condContinue__1 + +condFalse__1: ; preds = %exit__1 + %21 = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) + %22 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %21, i64 0) + %23 = bitcast i8* %22 to %Qubit** + %24 = sub i64 %numControls, 1 + %25 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %controls, i64 %24) + %26 = bitcast i8* %25 to %Qubit** + %27 = load %Qubit*, %Qubit** %26, align 8 + store %Qubit* %27, %Qubit** %23, align 8 + %28 = call %Array* @__quantum__rt__array_concatenate(%Array* %temps, %Array* %21) + call void @__quantum__rt__array_update_reference_count(%Array* %28, i32 1) + call void @__quantum__rt__array_update_reference_count(%Array* %21, i32 -1) + call void @__quantum__rt__array_update_reference_count(%Array* %28, i32 -1) + br label %condContinue__1 + +condContinue__1: ; preds = %condFalse__1, %condTrue__1 + %__qsVar1__newControls__ = phi %Array* [ %temps, %condTrue__1 ], [ %28, %condFalse__1 ] + call void @__quantum__rt__array_update_alias_count(%Array* %__qsVar1__newControls__, i32 1) + %29 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 2)) + %30 = bitcast %Tuple* %29 to { %Array*, { %Qubit*, %Qubit* }* }* + %31 = getelementptr inbounds { %Array*, { %Qubit*, %Qubit* }* }, { %Array*, { %Qubit*, %Qubit* }* }* %30, i32 0, i32 0 + %32 = getelementptr inbounds { %Array*, { %Qubit*, %Qubit* }* }, { %Array*, { %Qubit*, %Qubit* }* }* %30, i32 0, i32 1 + call void @__quantum__rt__array_update_reference_count(%Array* %__qsVar1__newControls__, i32 1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %3, i32 1) + store %Array* %__qsVar1__newControls__, %Array** %31, align 8 + store { %Qubit*, %Qubit* }* %arg, { %Qubit*, %Qubit* }** %32, align 8 + call void @__quantum__rt__callable_invoke(%Callable* %op, %Tuple* %29, %Tuple* null) + %33 = sub i64 %numControlPairs, 1 + %34 = sub i64 %33, 0 + %35 = sdiv i64 %34, 1 + %36 = mul i64 1, %35 + %37 = add i64 0, %36 + %38 = load %Range, %Range* @EmptyRange, align 4 + %39 = insertvalue %Range %38, i64 %37, 0 + %40 = insertvalue %Range %39, i64 -1, 1 + %41 = insertvalue %Range %40, i64 0, 2 + %42 = extractvalue %Range %41, 0 + %43 = extractvalue %Range %41, 1 + %44 = extractvalue %Range %41, 2 + br label %preheader__1 + +preheader__1: ; preds = %condContinue__1 + %45 = icmp sgt i64 %43, 0 + br label %header__2 + +header__2: ; preds = %exiting__2, %preheader__1 + %__qsVar0____qsVar0__numPair____ = phi i64 [ %42, %preheader__1 ], [ %61, %exiting__2 ] + %46 = icmp sle i64 %__qsVar0____qsVar0__numPair____, %44 + %47 = icmp sge i64 %__qsVar0____qsVar0__numPair____, %44 + %48 = select i1 %45, i1 %46, i1 %47 + br i1 %48, label %body__2, label %exit__2 + +body__2: ; preds = %header__2 + %49 = mul i64 2, %__qsVar0____qsVar0__numPair____ + %50 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %controls, i64 %49) + %51 = bitcast i8* %50 to %Qubit** + %52 = load %Qubit*, %Qubit** %51, align 8 + %53 = mul i64 2, %__qsVar0____qsVar0__numPair____ + %54 = add i64 %53, 1 + %55 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %controls, i64 %54) + %56 = bitcast i8* %55 to %Qubit** + %57 = load %Qubit*, %Qubit** %56, align 8 + %58 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %temps, i64 %__qsVar0____qsVar0__numPair____) + %59 = bitcast i8* %58 to %Qubit** + %60 = load %Qubit*, %Qubit** %59, align 8 + call void @Microsoft__Quantum__Intrinsic____QsRef23__PhaseCCX____adj(%Qubit* %52, %Qubit* %57, %Qubit* %60) + br label %exiting__2 + +exiting__2: ; preds = %body__2 + %61 = add i64 %__qsVar0____qsVar0__numPair____, %43 + br label %header__2 + +exit__2: ; preds = %header__2 + call void @__quantum__rt__array_update_alias_count(%Array* %temps, i32 -1) + call void @__quantum__rt__array_update_alias_count(%Array* %__qsVar1__newControls__, i32 -1) + call void @__quantum__rt__array_update_reference_count(%Array* %__qsVar1__newControls__, i32 -1) + call void @__quantum__rt__array_update_reference_count(%Array* %__qsVar1__newControls__, i32 -1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %3, i32 -1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %29, i32 -1) + call void @__quantum__rt__qubit_release_array(%Array* %temps) + call void @__quantum__rt__capture_update_alias_count(%Callable* %op, i32 -1) + call void @__quantum__rt__callable_update_alias_count(%Callable* %op, i32 -1) + call void @__quantum__rt__array_update_alias_count(%Array* %controls, i32 -1) + call void @__quantum__rt__tuple_update_alias_count(%Tuple* %3, i32 -1) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__CNOT__body__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { +entry: + %0 = bitcast %Tuple* %arg-tuple to { %Qubit*, %Qubit* }* + %1 = getelementptr inbounds { %Qubit*, %Qubit* }, { %Qubit*, %Qubit* }* %0, i32 0, i32 0 + %2 = getelementptr inbounds { %Qubit*, %Qubit* }, { %Qubit*, %Qubit* }* %0, i32 0, i32 1 + %3 = load %Qubit*, %Qubit** %1, align 8 + %4 = load %Qubit*, %Qubit** %2, align 8 + call void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* %3, %Qubit* %4) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__CNOT__adj__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { +entry: + %0 = bitcast %Tuple* %arg-tuple to { %Qubit*, %Qubit* }* + %1 = getelementptr inbounds { %Qubit*, %Qubit* }, { %Qubit*, %Qubit* }* %0, i32 0, i32 0 + %2 = getelementptr inbounds { %Qubit*, %Qubit* }, { %Qubit*, %Qubit* }* %0, i32 0, i32 1 + %3 = load %Qubit*, %Qubit** %1, align 8 + %4 = load %Qubit*, %Qubit** %2, align 8 + call void @Microsoft__Quantum__Intrinsic__CNOT__adj(%Qubit* %3, %Qubit* %4) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__CNOT__ctl__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { +entry: + %0 = bitcast %Tuple* %arg-tuple to { %Array*, { %Qubit*, %Qubit* }* }* + %1 = getelementptr inbounds { %Array*, { %Qubit*, %Qubit* }* }, { %Array*, { %Qubit*, %Qubit* }* }* %0, i32 0, i32 0 + %2 = getelementptr inbounds { %Array*, { %Qubit*, %Qubit* }* }, { %Array*, { %Qubit*, %Qubit* }* }* %0, i32 0, i32 1 + %3 = load %Array*, %Array** %1, align 8 + %4 = load { %Qubit*, %Qubit* }*, { %Qubit*, %Qubit* }** %2, align 8 + call void @Microsoft__Quantum__Intrinsic__CNOT__ctl(%Array* %3, { %Qubit*, %Qubit* }* %4) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__CNOT__ctladj__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { +entry: + %0 = bitcast %Tuple* %arg-tuple to { %Array*, { %Qubit*, %Qubit* }* }* + %1 = getelementptr inbounds { %Array*, { %Qubit*, %Qubit* }* }, { %Array*, { %Qubit*, %Qubit* }* }* %0, i32 0, i32 0 + %2 = getelementptr inbounds { %Array*, { %Qubit*, %Qubit* }* }, { %Array*, { %Qubit*, %Qubit* }* }* %0, i32 0, i32 1 + %3 = load %Array*, %Array** %1, align 8 + %4 = load { %Qubit*, %Qubit* }*, { %Qubit*, %Qubit* }** %2, align 8 + call void @Microsoft__Quantum__Intrinsic__CNOT__ctladj(%Array* %3, { %Qubit*, %Qubit* }* %4) + ret void +} + +declare %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]*, [2 x void (%Tuple*, i32)*]*, %Tuple*) + +declare void @__quantum__rt__callable_make_controlled(%Callable*) + +declare void @__quantum__rt__capture_update_reference_count(%Callable*, i32) + +declare void @__quantum__rt__callable_update_reference_count(%Callable*, i32) + +define internal void @Microsoft__Quantum__Intrinsic__CNOT__ctladj(%Array* %__controlQubits__, { %Qubit*, %Qubit* }* %0) { +entry: + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 1) + %1 = getelementptr inbounds { %Qubit*, %Qubit* }, { %Qubit*, %Qubit* }* %0, i32 0, i32 0 + %control = load %Qubit*, %Qubit** %1, align 8 + %2 = getelementptr inbounds { %Qubit*, %Qubit* }, { %Qubit*, %Qubit* }* %0, i32 0, i32 1 + %target = load %Qubit*, %Qubit** %2, align 8 + %3 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 2)) + %4 = bitcast %Tuple* %3 to { %Qubit*, %Qubit* }* + %5 = getelementptr inbounds { %Qubit*, %Qubit* }, { %Qubit*, %Qubit* }* %4, i32 0, i32 0 + %6 = getelementptr inbounds { %Qubit*, %Qubit* }, { %Qubit*, %Qubit* }* %4, i32 0, i32 1 + store %Qubit* %control, %Qubit** %5, align 8 + store %Qubit* %target, %Qubit** %6, align 8 + call void @Microsoft__Quantum__Intrinsic__CNOT__ctl(%Array* %__controlQubits__, { %Qubit*, %Qubit* }* %4) + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 -1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %3, i32 -1) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__H__ctl(%Array* %ctls, %Qubit* %qubit) { +entry: + call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i32 1) + %0 = call i64 @__quantum__rt__array_get_size_1d(%Array* %ctls) + %1 = icmp eq i64 %0, 0 + br i1 %1, label %then0__1, label %test1__1 + +then0__1: ; preds = %entry + call void @__quantum__qis__h__body(%Qubit* %qubit) + br label %continue__1 + +test1__1: ; preds = %entry + %2 = call i64 @__quantum__rt__array_get_size_1d(%Array* %ctls) + %3 = icmp eq i64 %2, 1 + br i1 %3, label %then1__1, label %else__1 + +then1__1: ; preds = %test1__1 + call void @Microsoft__Quantum__Intrinsic__S__body(%Qubit* %qubit) + call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %qubit) + call void @Microsoft__Quantum__Intrinsic__T__body(%Qubit* %qubit) + %4 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls, i64 0) + %5 = bitcast i8* %4 to %Qubit** + %6 = load %Qubit*, %Qubit** %5, align 8 + call void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* %6, %Qubit* %qubit) + call void @Microsoft__Quantum__Intrinsic__T__adj(%Qubit* %qubit) + call void @Microsoft__Quantum__Intrinsic__H__adj(%Qubit* %qubit) + call void @Microsoft__Quantum__Intrinsic__S__adj(%Qubit* %qubit) + br label %continue__1 + +else__1: ; preds = %test1__1 + %7 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Intrinsic__H__FunctionTable, [2 x void (%Tuple*, i32)*]* null, %Tuple* null) + call void @__quantum__rt__callable_make_controlled(%Callable* %7) + %8 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 2)) + %9 = bitcast %Tuple* %8 to { %Array*, %Qubit* }* + %10 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %9, i32 0, i32 0 + %11 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %9, i32 0, i32 1 + call void @__quantum__rt__array_update_reference_count(%Array* %ctls, i32 1) + store %Array* %ctls, %Array** %10, align 8 + store %Qubit* %qubit, %Qubit** %11, align 8 + call void @Microsoft__Quantum__Intrinsic___067288bb3b0f4c3fa16d90a27710fc06___QsRef23__ApplyWithLessControlsA____body(%Callable* %7, { %Array*, %Qubit* }* %9) + call void @__quantum__rt__capture_update_reference_count(%Callable* %7, i32 -1) + call void @__quantum__rt__callable_update_reference_count(%Callable* %7, i32 -1) + call void @__quantum__rt__array_update_reference_count(%Array* %ctls, i32 -1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %8, i32 -1) + br label %continue__1 + +continue__1: ; preds = %else__1, %then1__1, %then0__1 + call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i32 -1) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic___067288bb3b0f4c3fa16d90a27710fc06___QsRef23__ApplyWithLessControlsA____body(%Callable* %op, { %Array*, %Qubit* }* %0) { +entry: + call void @__quantum__rt__capture_update_alias_count(%Callable* %op, i32 1) + call void @__quantum__rt__callable_update_alias_count(%Callable* %op, i32 1) + %1 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 0 + %controls = load %Array*, %Array** %1, align 8 + call void @__quantum__rt__array_update_alias_count(%Array* %controls, i32 1) + %2 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 1 + %arg = load %Qubit*, %Qubit** %2, align 8 + %numControls = call i64 @__quantum__rt__array_get_size_1d(%Array* %controls) + %numControlPairs = sdiv i64 %numControls, 2 + %temps = call %Array* @__quantum__rt__qubit_allocate_array(i64 %numControlPairs) + call void @__quantum__rt__array_update_alias_count(%Array* %temps, i32 1) + %3 = sub i64 %numControlPairs, 1 + br label %header__1 + +header__1: ; preds = %exiting__1, %entry + %__qsVar0__numPair__ = phi i64 [ 0, %entry ], [ %17, %exiting__1 ] + %4 = icmp sle i64 %__qsVar0__numPair__, %3 + br i1 %4, label %body__1, label %exit__1 + +body__1: ; preds = %header__1 + %5 = mul i64 2, %__qsVar0__numPair__ + %6 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %controls, i64 %5) + %7 = bitcast i8* %6 to %Qubit** + %8 = load %Qubit*, %Qubit** %7, align 8 + %9 = mul i64 2, %__qsVar0__numPair__ + %10 = add i64 %9, 1 + %11 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %controls, i64 %10) + %12 = bitcast i8* %11 to %Qubit** + %13 = load %Qubit*, %Qubit** %12, align 8 + %14 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %temps, i64 %__qsVar0__numPair__) + %15 = bitcast i8* %14 to %Qubit** + %16 = load %Qubit*, %Qubit** %15, align 8 + call void @Microsoft__Quantum__Intrinsic____QsRef23__PhaseCCX____body(%Qubit* %8, %Qubit* %13, %Qubit* %16) + br label %exiting__1 + +exiting__1: ; preds = %body__1 + %17 = add i64 %__qsVar0__numPair__, 1 + br label %header__1 + +exit__1: ; preds = %header__1 + %18 = srem i64 %numControls, 2 + %19 = icmp eq i64 %18, 0 + br i1 %19, label %condTrue__1, label %condFalse__1 + +condTrue__1: ; preds = %exit__1 + call void @__quantum__rt__array_update_reference_count(%Array* %temps, i32 1) + br label %condContinue__1 + +condFalse__1: ; preds = %exit__1 + %20 = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) + %21 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %20, i64 0) + %22 = bitcast i8* %21 to %Qubit** + %23 = sub i64 %numControls, 1 + %24 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %controls, i64 %23) + %25 = bitcast i8* %24 to %Qubit** + %26 = load %Qubit*, %Qubit** %25, align 8 + store %Qubit* %26, %Qubit** %22, align 8 + %27 = call %Array* @__quantum__rt__array_concatenate(%Array* %temps, %Array* %20) + call void @__quantum__rt__array_update_reference_count(%Array* %27, i32 1) + call void @__quantum__rt__array_update_reference_count(%Array* %20, i32 -1) + call void @__quantum__rt__array_update_reference_count(%Array* %27, i32 -1) + br label %condContinue__1 + +condContinue__1: ; preds = %condFalse__1, %condTrue__1 + %__qsVar1__newControls__ = phi %Array* [ %temps, %condTrue__1 ], [ %27, %condFalse__1 ] + call void @__quantum__rt__array_update_alias_count(%Array* %__qsVar1__newControls__, i32 1) + %28 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 2)) + %29 = bitcast %Tuple* %28 to { %Array*, %Qubit* }* + %30 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %29, i32 0, i32 0 + %31 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %29, i32 0, i32 1 + call void @__quantum__rt__array_update_reference_count(%Array* %__qsVar1__newControls__, i32 1) + store %Array* %__qsVar1__newControls__, %Array** %30, align 8 + store %Qubit* %arg, %Qubit** %31, align 8 + call void @__quantum__rt__callable_invoke(%Callable* %op, %Tuple* %28, %Tuple* null) + %32 = sub i64 %numControlPairs, 1 + %33 = sub i64 %32, 0 + %34 = sdiv i64 %33, 1 + %35 = mul i64 1, %34 + %36 = add i64 0, %35 + %37 = load %Range, %Range* @EmptyRange, align 4 + %38 = insertvalue %Range %37, i64 %36, 0 + %39 = insertvalue %Range %38, i64 -1, 1 + %40 = insertvalue %Range %39, i64 0, 2 + %41 = extractvalue %Range %40, 0 + %42 = extractvalue %Range %40, 1 + %43 = extractvalue %Range %40, 2 + br label %preheader__1 + +preheader__1: ; preds = %condContinue__1 + %44 = icmp sgt i64 %42, 0 + br label %header__2 + +header__2: ; preds = %exiting__2, %preheader__1 + %__qsVar0____qsVar0__numPair____ = phi i64 [ %41, %preheader__1 ], [ %60, %exiting__2 ] + %45 = icmp sle i64 %__qsVar0____qsVar0__numPair____, %43 + %46 = icmp sge i64 %__qsVar0____qsVar0__numPair____, %43 + %47 = select i1 %44, i1 %45, i1 %46 + br i1 %47, label %body__2, label %exit__2 + +body__2: ; preds = %header__2 + %48 = mul i64 2, %__qsVar0____qsVar0__numPair____ + %49 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %controls, i64 %48) + %50 = bitcast i8* %49 to %Qubit** + %51 = load %Qubit*, %Qubit** %50, align 8 + %52 = mul i64 2, %__qsVar0____qsVar0__numPair____ + %53 = add i64 %52, 1 + %54 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %controls, i64 %53) + %55 = bitcast i8* %54 to %Qubit** + %56 = load %Qubit*, %Qubit** %55, align 8 + %57 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %temps, i64 %__qsVar0____qsVar0__numPair____) + %58 = bitcast i8* %57 to %Qubit** + %59 = load %Qubit*, %Qubit** %58, align 8 + call void @Microsoft__Quantum__Intrinsic____QsRef23__PhaseCCX____adj(%Qubit* %51, %Qubit* %56, %Qubit* %59) + br label %exiting__2 + +exiting__2: ; preds = %body__2 + %60 = add i64 %__qsVar0____qsVar0__numPair____, %42 + br label %header__2 + +exit__2: ; preds = %header__2 + call void @__quantum__rt__array_update_alias_count(%Array* %temps, i32 -1) + call void @__quantum__rt__array_update_alias_count(%Array* %__qsVar1__newControls__, i32 -1) + call void @__quantum__rt__array_update_reference_count(%Array* %__qsVar1__newControls__, i32 -1) + call void @__quantum__rt__array_update_reference_count(%Array* %__qsVar1__newControls__, i32 -1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %28, i32 -1) + call void @__quantum__rt__qubit_release_array(%Array* %temps) + call void @__quantum__rt__capture_update_alias_count(%Callable* %op, i32 -1) + call void @__quantum__rt__callable_update_alias_count(%Callable* %op, i32 -1) + call void @__quantum__rt__array_update_alias_count(%Array* %controls, i32 -1) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__H__body__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { +entry: + %0 = bitcast %Tuple* %arg-tuple to { %Qubit* }* + %1 = getelementptr inbounds { %Qubit* }, { %Qubit* }* %0, i32 0, i32 0 + %2 = load %Qubit*, %Qubit** %1, align 8 + call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %2) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__H__adj__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { +entry: + %0 = bitcast %Tuple* %arg-tuple to { %Qubit* }* + %1 = getelementptr inbounds { %Qubit* }, { %Qubit* }* %0, i32 0, i32 0 + %2 = load %Qubit*, %Qubit** %1, align 8 + call void @Microsoft__Quantum__Intrinsic__H__adj(%Qubit* %2) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__H__ctl__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { +entry: + %0 = bitcast %Tuple* %arg-tuple to { %Array*, %Qubit* }* + %1 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 0 + %2 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 1 + %3 = load %Array*, %Array** %1, align 8 + %4 = load %Qubit*, %Qubit** %2, align 8 + call void @Microsoft__Quantum__Intrinsic__H__ctl(%Array* %3, %Qubit* %4) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__H__ctladj__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { +entry: + %0 = bitcast %Tuple* %arg-tuple to { %Array*, %Qubit* }* + %1 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 0 + %2 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 1 + %3 = load %Array*, %Array** %1, align 8 + %4 = load %Qubit*, %Qubit** %2, align 8 + call void @Microsoft__Quantum__Intrinsic__H__ctladj(%Array* %3, %Qubit* %4) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__H__ctladj(%Array* %__controlQubits__, %Qubit* %qubit) { +entry: + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 1) + call void @Microsoft__Quantum__Intrinsic__H__ctl(%Array* %__controlQubits__, %Qubit* %qubit) + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 -1) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__R__body(i2 %pauli, double %theta, %Qubit* %qubit) { +entry: + %0 = load i2, i2* @PauliX, align 1 + %1 = icmp eq i2 %pauli, %0 + br i1 %1, label %then0__1, label %test1__1 + +then0__1: ; preds = %entry + call void @Microsoft__Quantum__Intrinsic__Rx__body(double %theta, %Qubit* %qubit) + br label %continue__1 + +test1__1: ; preds = %entry + %2 = load i2, i2* @PauliY, align 1 + %3 = icmp eq i2 %pauli, %2 + br i1 %3, label %then1__1, label %test2__1 + +then1__1: ; preds = %test1__1 + call void @Microsoft__Quantum__Intrinsic__Ry__body(double %theta, %Qubit* %qubit) + br label %continue__1 + +test2__1: ; preds = %test1__1 + %4 = load i2, i2* @PauliZ, align 1 + %5 = icmp eq i2 %pauli, %4 + br i1 %5, label %then2__1, label %else__1 + +then2__1: ; preds = %test2__1 + call void @Microsoft__Quantum__Intrinsic__Rz__body(double %theta, %Qubit* %qubit) + br label %continue__1 + +else__1: ; preds = %test2__1 + %6 = fneg double %theta + %7 = fdiv double %6, 2.000000e+00 + call void @Microsoft__Quantum__Intrinsic____QsRef23__ApplyGlobalPhase____body(double %7) + br label %continue__1 + +continue__1: ; preds = %else__1, %then2__1, %then1__1, %then0__1 + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Rx__body(double %theta, %Qubit* %qubit) { +entry: + call void @__quantum__qis__rx__body(double %theta, %Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Ry__body(double %theta, %Qubit* %qubit) { +entry: + call void @__quantum__qis__ry__body(double %theta, %Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__R__adj(i2 %pauli, double %theta, %Qubit* %qubit) { +entry: + %0 = load i2, i2* @PauliX, align 1 + %1 = icmp eq i2 %pauli, %0 + br i1 %1, label %then0__1, label %test1__1 + +then0__1: ; preds = %entry + call void @Microsoft__Quantum__Intrinsic__Rx__adj(double %theta, %Qubit* %qubit) + br label %continue__1 + +test1__1: ; preds = %entry + %2 = load i2, i2* @PauliY, align 1 + %3 = icmp eq i2 %pauli, %2 + br i1 %3, label %then1__1, label %test2__1 + +then1__1: ; preds = %test1__1 + call void @Microsoft__Quantum__Intrinsic__Ry__adj(double %theta, %Qubit* %qubit) + br label %continue__1 + +test2__1: ; preds = %test1__1 + %4 = load i2, i2* @PauliZ, align 1 + %5 = icmp eq i2 %pauli, %4 + br i1 %5, label %then2__1, label %else__1 + +then2__1: ; preds = %test2__1 + call void @Microsoft__Quantum__Intrinsic__Rz__adj(double %theta, %Qubit* %qubit) + br label %continue__1 + +else__1: ; preds = %test2__1 + %6 = fneg double %theta + %7 = fdiv double %6, 2.000000e+00 + call void @Microsoft__Quantum__Intrinsic____QsRef23__ApplyGlobalPhase____adj(double %7) + br label %continue__1 + +continue__1: ; preds = %else__1, %then2__1, %then1__1, %then0__1 + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Rx__adj(double %theta, %Qubit* %qubit) { +entry: + %0 = fneg double %theta + call void @Microsoft__Quantum__Intrinsic__Rx__body(double %0, %Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Ry__adj(double %theta, %Qubit* %qubit) { +entry: + %0 = fneg double %theta + call void @Microsoft__Quantum__Intrinsic__Ry__body(double %0, %Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Rz__adj(double %theta, %Qubit* %qubit) { +entry: + %0 = fneg double %theta + call void @Microsoft__Quantum__Intrinsic__Rz__body(double %0, %Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__R__ctl(%Array* %__controlQubits__, { i2, double, %Qubit* }* %0) { +entry: + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 1) + %1 = getelementptr inbounds { i2, double, %Qubit* }, { i2, double, %Qubit* }* %0, i32 0, i32 0 + %pauli = load i2, i2* %1, align 1 + %2 = getelementptr inbounds { i2, double, %Qubit* }, { i2, double, %Qubit* }* %0, i32 0, i32 1 + %theta = load double, double* %2, align 8 + %3 = getelementptr inbounds { i2, double, %Qubit* }, { i2, double, %Qubit* }* %0, i32 0, i32 2 + %qubit = load %Qubit*, %Qubit** %3, align 8 + %4 = load i2, i2* @PauliX, align 1 + %5 = icmp eq i2 %pauli, %4 + br i1 %5, label %then0__1, label %test1__1 + +then0__1: ; preds = %entry + %6 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint ({ double, %Qubit* }* getelementptr ({ double, %Qubit* }, { double, %Qubit* }* null, i32 1) to i64)) + %7 = bitcast %Tuple* %6 to { double, %Qubit* }* + %8 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %7, i32 0, i32 0 + %9 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %7, i32 0, i32 1 + store double %theta, double* %8, align 8 + store %Qubit* %qubit, %Qubit** %9, align 8 + call void @Microsoft__Quantum__Intrinsic__Rx__ctl(%Array* %__controlQubits__, { double, %Qubit* }* %7) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %6, i32 -1) + br label %continue__1 + +test1__1: ; preds = %entry + %10 = load i2, i2* @PauliY, align 1 + %11 = icmp eq i2 %pauli, %10 + br i1 %11, label %then1__1, label %test2__1 + +then1__1: ; preds = %test1__1 + %12 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint ({ double, %Qubit* }* getelementptr ({ double, %Qubit* }, { double, %Qubit* }* null, i32 1) to i64)) + %13 = bitcast %Tuple* %12 to { double, %Qubit* }* + %14 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %13, i32 0, i32 0 + %15 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %13, i32 0, i32 1 + store double %theta, double* %14, align 8 + store %Qubit* %qubit, %Qubit** %15, align 8 + call void @Microsoft__Quantum__Intrinsic__Ry__ctl(%Array* %__controlQubits__, { double, %Qubit* }* %13) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %12, i32 -1) + br label %continue__1 + +test2__1: ; preds = %test1__1 + %16 = load i2, i2* @PauliZ, align 1 + %17 = icmp eq i2 %pauli, %16 + br i1 %17, label %then2__1, label %else__1 + +then2__1: ; preds = %test2__1 + %18 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint ({ double, %Qubit* }* getelementptr ({ double, %Qubit* }, { double, %Qubit* }* null, i32 1) to i64)) + %19 = bitcast %Tuple* %18 to { double, %Qubit* }* + %20 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %19, i32 0, i32 0 + %21 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %19, i32 0, i32 1 + store double %theta, double* %20, align 8 + store %Qubit* %qubit, %Qubit** %21, align 8 + call void @Microsoft__Quantum__Intrinsic__Rz__ctl(%Array* %__controlQubits__, { double, %Qubit* }* %19) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %18, i32 -1) + br label %continue__1 + +else__1: ; preds = %test2__1 + %22 = fneg double %theta + %23 = fdiv double %22, 2.000000e+00 + call void @Microsoft__Quantum__Intrinsic____QsRef23__ApplyGlobalPhase____ctl(%Array* %__controlQubits__, double %23) + br label %continue__1 + +continue__1: ; preds = %else__1, %then2__1, %then1__1, %then0__1 + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 -1) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Rx__ctl(%Array* %ctls, { double, %Qubit* }* %0) { +entry: + call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i32 1) + %1 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 0 + %theta = load double, double* %1, align 8 + %2 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 1 + %qubit = load %Qubit*, %Qubit** %2, align 8 + %3 = call i64 @__quantum__rt__array_get_size_1d(%Array* %ctls) + %4 = icmp eq i64 %3, 0 + br i1 %4, label %then0__1, label %test1__1 + +then0__1: ; preds = %entry + call void @__quantum__qis__rx__body(double %theta, %Qubit* %qubit) + br label %continue__1 + +test1__1: ; preds = %entry + %5 = call i64 @__quantum__rt__array_get_size_1d(%Array* %ctls) + %6 = icmp eq i64 %5, 1 + br i1 %6, label %then1__1, label %else__1 + +then1__1: ; preds = %test1__1 + %7 = load i2, i2* @PauliZ, align 1 + %8 = load i2, i2* @PauliX, align 1 + call void @Microsoft__Quantum__Intrinsic____QsRef23__MapPauli____body(%Qubit* %qubit, i2 %7, i2 %8) + %9 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint ({ double, %Qubit* }* getelementptr ({ double, %Qubit* }, { double, %Qubit* }* null, i32 1) to i64)) + %10 = bitcast %Tuple* %9 to { double, %Qubit* }* + %11 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %10, i32 0, i32 0 + %12 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %10, i32 0, i32 1 + store double %theta, double* %11, align 8 + store %Qubit* %qubit, %Qubit** %12, align 8 + call void @Microsoft__Quantum__Intrinsic__Rz__ctl(%Array* %ctls, { double, %Qubit* }* %10) + %13 = load i2, i2* @PauliZ, align 1 + %14 = load i2, i2* @PauliX, align 1 + call void @Microsoft__Quantum__Intrinsic____QsRef23__MapPauli____adj(%Qubit* %qubit, i2 %13, i2 %14) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %9, i32 -1) + br label %continue__1 + +else__1: ; preds = %test1__1 + %15 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Intrinsic__Rx__FunctionTable, [2 x void (%Tuple*, i32)*]* null, %Tuple* null) + call void @__quantum__rt__callable_make_controlled(%Callable* %15) + %16 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 2)) + %17 = bitcast %Tuple* %16 to { %Array*, { double, %Qubit* }* }* + %18 = getelementptr inbounds { %Array*, { double, %Qubit* }* }, { %Array*, { double, %Qubit* }* }* %17, i32 0, i32 0 + %19 = getelementptr inbounds { %Array*, { double, %Qubit* }* }, { %Array*, { double, %Qubit* }* }* %17, i32 0, i32 1 + call void @__quantum__rt__array_update_reference_count(%Array* %ctls, i32 1) + %20 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint ({ double, %Qubit* }* getelementptr ({ double, %Qubit* }, { double, %Qubit* }* null, i32 1) to i64)) + %21 = bitcast %Tuple* %20 to { double, %Qubit* }* + %22 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %21, i32 0, i32 0 + %23 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %21, i32 0, i32 1 + store double %theta, double* %22, align 8 + store %Qubit* %qubit, %Qubit** %23, align 8 + store %Array* %ctls, %Array** %18, align 8 + store { double, %Qubit* }* %21, { double, %Qubit* }** %19, align 8 + call void @Microsoft__Quantum__Intrinsic___8f3359a2b69a47ffa9fd2508e6ea5641___QsRef23__ApplyWithLessControlsA____body(%Callable* %15, { %Array*, { double, %Qubit* }* }* %17) + call void @__quantum__rt__capture_update_reference_count(%Callable* %15, i32 -1) + call void @__quantum__rt__callable_update_reference_count(%Callable* %15, i32 -1) + call void @__quantum__rt__array_update_reference_count(%Array* %ctls, i32 -1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %20, i32 -1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %16, i32 -1) + br label %continue__1 + +continue__1: ; preds = %else__1, %then1__1, %then0__1 + call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i32 -1) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Ry__ctl(%Array* %ctls, { double, %Qubit* }* %0) { +entry: + call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i32 1) + %1 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 0 + %theta = load double, double* %1, align 8 + %2 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 1 + %qubit = load %Qubit*, %Qubit** %2, align 8 + %3 = call i64 @__quantum__rt__array_get_size_1d(%Array* %ctls) + %4 = icmp eq i64 %3, 0 + br i1 %4, label %then0__1, label %test1__1 + +then0__1: ; preds = %entry + call void @__quantum__qis__ry__body(double %theta, %Qubit* %qubit) + br label %continue__1 + +test1__1: ; preds = %entry + %5 = call i64 @__quantum__rt__array_get_size_1d(%Array* %ctls) + %6 = icmp eq i64 %5, 1 + br i1 %6, label %then1__1, label %else__1 + +then1__1: ; preds = %test1__1 + %7 = load i2, i2* @PauliZ, align 1 + %8 = load i2, i2* @PauliY, align 1 + call void @Microsoft__Quantum__Intrinsic____QsRef23__MapPauli____body(%Qubit* %qubit, i2 %7, i2 %8) + %9 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint ({ double, %Qubit* }* getelementptr ({ double, %Qubit* }, { double, %Qubit* }* null, i32 1) to i64)) + %10 = bitcast %Tuple* %9 to { double, %Qubit* }* + %11 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %10, i32 0, i32 0 + %12 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %10, i32 0, i32 1 + store double %theta, double* %11, align 8 + store %Qubit* %qubit, %Qubit** %12, align 8 + call void @Microsoft__Quantum__Intrinsic__Rz__ctl(%Array* %ctls, { double, %Qubit* }* %10) + %13 = load i2, i2* @PauliZ, align 1 + %14 = load i2, i2* @PauliY, align 1 + call void @Microsoft__Quantum__Intrinsic____QsRef23__MapPauli____adj(%Qubit* %qubit, i2 %13, i2 %14) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %9, i32 -1) + br label %continue__1 + +else__1: ; preds = %test1__1 + %15 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Intrinsic__Ry__FunctionTable, [2 x void (%Tuple*, i32)*]* null, %Tuple* null) + call void @__quantum__rt__callable_make_controlled(%Callable* %15) + %16 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 2)) + %17 = bitcast %Tuple* %16 to { %Array*, { double, %Qubit* }* }* + %18 = getelementptr inbounds { %Array*, { double, %Qubit* }* }, { %Array*, { double, %Qubit* }* }* %17, i32 0, i32 0 + %19 = getelementptr inbounds { %Array*, { double, %Qubit* }* }, { %Array*, { double, %Qubit* }* }* %17, i32 0, i32 1 + call void @__quantum__rt__array_update_reference_count(%Array* %ctls, i32 1) + %20 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint ({ double, %Qubit* }* getelementptr ({ double, %Qubit* }, { double, %Qubit* }* null, i32 1) to i64)) + %21 = bitcast %Tuple* %20 to { double, %Qubit* }* + %22 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %21, i32 0, i32 0 + %23 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %21, i32 0, i32 1 + store double %theta, double* %22, align 8 + store %Qubit* %qubit, %Qubit** %23, align 8 + store %Array* %ctls, %Array** %18, align 8 + store { double, %Qubit* }* %21, { double, %Qubit* }** %19, align 8 + call void @Microsoft__Quantum__Intrinsic___8f3359a2b69a47ffa9fd2508e6ea5641___QsRef23__ApplyWithLessControlsA____body(%Callable* %15, { %Array*, { double, %Qubit* }* }* %17) + call void @__quantum__rt__capture_update_reference_count(%Callable* %15, i32 -1) + call void @__quantum__rt__callable_update_reference_count(%Callable* %15, i32 -1) + call void @__quantum__rt__array_update_reference_count(%Array* %ctls, i32 -1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %20, i32 -1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %16, i32 -1) + br label %continue__1 + +continue__1: ; preds = %else__1, %then1__1, %then0__1 + call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i32 -1) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Rz__ctl(%Array* %ctls, { double, %Qubit* }* %0) { +entry: + call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i32 1) + %1 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 0 + %theta = load double, double* %1, align 8 + %2 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 1 + %qubit = load %Qubit*, %Qubit** %2, align 8 + %3 = call i64 @__quantum__rt__array_get_size_1d(%Array* %ctls) + %4 = icmp eq i64 %3, 0 + br i1 %4, label %then0__1, label %test1__1 + +then0__1: ; preds = %entry + call void @Microsoft__Quantum__Intrinsic__Rz__body(double %theta, %Qubit* %qubit) + br label %continue__1 + +test1__1: ; preds = %entry + %5 = call i64 @__quantum__rt__array_get_size_1d(%Array* %ctls) + %6 = icmp eq i64 %5, 1 + br i1 %6, label %then1__1, label %else__1 + +then1__1: ; preds = %test1__1 + %7 = fdiv double %theta, 2.000000e+00 + call void @Microsoft__Quantum__Intrinsic__Rz__body(double %7, %Qubit* %qubit) + %8 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls, i64 0) + %9 = bitcast i8* %8 to %Qubit** + %10 = load %Qubit*, %Qubit** %9, align 8 + call void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* %10, %Qubit* %qubit) + %11 = fneg double %theta + %12 = fdiv double %11, 2.000000e+00 + call void @Microsoft__Quantum__Intrinsic__Rz__body(double %12, %Qubit* %qubit) + %13 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls, i64 0) + %14 = bitcast i8* %13 to %Qubit** + %15 = load %Qubit*, %Qubit** %14, align 8 + call void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* %15, %Qubit* %qubit) + br label %continue__1 + +else__1: ; preds = %test1__1 + %16 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Intrinsic__Rz__FunctionTable, [2 x void (%Tuple*, i32)*]* null, %Tuple* null) + call void @__quantum__rt__callable_make_controlled(%Callable* %16) + %17 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 2)) + %18 = bitcast %Tuple* %17 to { %Array*, { double, %Qubit* }* }* + %19 = getelementptr inbounds { %Array*, { double, %Qubit* }* }, { %Array*, { double, %Qubit* }* }* %18, i32 0, i32 0 + %20 = getelementptr inbounds { %Array*, { double, %Qubit* }* }, { %Array*, { double, %Qubit* }* }* %18, i32 0, i32 1 + call void @__quantum__rt__array_update_reference_count(%Array* %ctls, i32 1) + %21 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint ({ double, %Qubit* }* getelementptr ({ double, %Qubit* }, { double, %Qubit* }* null, i32 1) to i64)) + %22 = bitcast %Tuple* %21 to { double, %Qubit* }* + %23 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %22, i32 0, i32 0 + %24 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %22, i32 0, i32 1 + store double %theta, double* %23, align 8 + store %Qubit* %qubit, %Qubit** %24, align 8 + store %Array* %ctls, %Array** %19, align 8 + store { double, %Qubit* }* %22, { double, %Qubit* }** %20, align 8 + call void @Microsoft__Quantum__Intrinsic___8f3359a2b69a47ffa9fd2508e6ea5641___QsRef23__ApplyWithLessControlsA____body(%Callable* %16, { %Array*, { double, %Qubit* }* }* %18) + call void @__quantum__rt__capture_update_reference_count(%Callable* %16, i32 -1) + call void @__quantum__rt__callable_update_reference_count(%Callable* %16, i32 -1) + call void @__quantum__rt__array_update_reference_count(%Array* %ctls, i32 -1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %21, i32 -1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %17, i32 -1) + br label %continue__1 + +continue__1: ; preds = %else__1, %then1__1, %then0__1 + call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i32 -1) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__R__ctladj(%Array* %__controlQubits__, { i2, double, %Qubit* }* %0) { +entry: + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 1) + %1 = getelementptr inbounds { i2, double, %Qubit* }, { i2, double, %Qubit* }* %0, i32 0, i32 0 + %pauli = load i2, i2* %1, align 1 + %2 = getelementptr inbounds { i2, double, %Qubit* }, { i2, double, %Qubit* }* %0, i32 0, i32 1 + %theta = load double, double* %2, align 8 + %3 = getelementptr inbounds { i2, double, %Qubit* }, { i2, double, %Qubit* }* %0, i32 0, i32 2 + %qubit = load %Qubit*, %Qubit** %3, align 8 + %4 = load i2, i2* @PauliX, align 1 + %5 = icmp eq i2 %pauli, %4 + br i1 %5, label %then0__1, label %test1__1 + +then0__1: ; preds = %entry + %6 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint ({ double, %Qubit* }* getelementptr ({ double, %Qubit* }, { double, %Qubit* }* null, i32 1) to i64)) + %7 = bitcast %Tuple* %6 to { double, %Qubit* }* + %8 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %7, i32 0, i32 0 + %9 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %7, i32 0, i32 1 + store double %theta, double* %8, align 8 + store %Qubit* %qubit, %Qubit** %9, align 8 + call void @Microsoft__Quantum__Intrinsic__Rx__ctladj(%Array* %__controlQubits__, { double, %Qubit* }* %7) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %6, i32 -1) + br label %continue__1 + +test1__1: ; preds = %entry + %10 = load i2, i2* @PauliY, align 1 + %11 = icmp eq i2 %pauli, %10 + br i1 %11, label %then1__1, label %test2__1 + +then1__1: ; preds = %test1__1 + %12 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint ({ double, %Qubit* }* getelementptr ({ double, %Qubit* }, { double, %Qubit* }* null, i32 1) to i64)) + %13 = bitcast %Tuple* %12 to { double, %Qubit* }* + %14 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %13, i32 0, i32 0 + %15 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %13, i32 0, i32 1 + store double %theta, double* %14, align 8 + store %Qubit* %qubit, %Qubit** %15, align 8 + call void @Microsoft__Quantum__Intrinsic__Ry__ctladj(%Array* %__controlQubits__, { double, %Qubit* }* %13) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %12, i32 -1) + br label %continue__1 + +test2__1: ; preds = %test1__1 + %16 = load i2, i2* @PauliZ, align 1 + %17 = icmp eq i2 %pauli, %16 + br i1 %17, label %then2__1, label %else__1 + +then2__1: ; preds = %test2__1 + %18 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint ({ double, %Qubit* }* getelementptr ({ double, %Qubit* }, { double, %Qubit* }* null, i32 1) to i64)) + %19 = bitcast %Tuple* %18 to { double, %Qubit* }* + %20 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %19, i32 0, i32 0 + %21 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %19, i32 0, i32 1 + store double %theta, double* %20, align 8 + store %Qubit* %qubit, %Qubit** %21, align 8 + call void @Microsoft__Quantum__Intrinsic__Rz__ctladj(%Array* %__controlQubits__, { double, %Qubit* }* %19) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %18, i32 -1) + br label %continue__1 + +else__1: ; preds = %test2__1 + %22 = fneg double %theta + %23 = fdiv double %22, 2.000000e+00 + call void @Microsoft__Quantum__Intrinsic____QsRef23__ApplyGlobalPhase____ctladj(%Array* %__controlQubits__, double %23) + br label %continue__1 + +continue__1: ; preds = %else__1, %then2__1, %then1__1, %then0__1 + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 -1) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Rx__ctladj(%Array* %__controlQubits__, { double, %Qubit* }* %0) { +entry: + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 1) + %1 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 0 + %theta = load double, double* %1, align 8 + %2 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 1 + %qubit = load %Qubit*, %Qubit** %2, align 8 + %3 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint ({ double, %Qubit* }* getelementptr ({ double, %Qubit* }, { double, %Qubit* }* null, i32 1) to i64)) + %4 = bitcast %Tuple* %3 to { double, %Qubit* }* + %5 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %4, i32 0, i32 0 + %6 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %4, i32 0, i32 1 + %7 = fneg double %theta + store double %7, double* %5, align 8 + store %Qubit* %qubit, %Qubit** %6, align 8 + call void @Microsoft__Quantum__Intrinsic__Rx__ctl(%Array* %__controlQubits__, { double, %Qubit* }* %4) + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 -1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %3, i32 -1) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Ry__ctladj(%Array* %__controlQubits__, { double, %Qubit* }* %0) { +entry: + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 1) + %1 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 0 + %theta = load double, double* %1, align 8 + %2 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 1 + %qubit = load %Qubit*, %Qubit** %2, align 8 + %3 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint ({ double, %Qubit* }* getelementptr ({ double, %Qubit* }, { double, %Qubit* }* null, i32 1) to i64)) + %4 = bitcast %Tuple* %3 to { double, %Qubit* }* + %5 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %4, i32 0, i32 0 + %6 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %4, i32 0, i32 1 + %7 = fneg double %theta + store double %7, double* %5, align 8 + store %Qubit* %qubit, %Qubit** %6, align 8 + call void @Microsoft__Quantum__Intrinsic__Ry__ctl(%Array* %__controlQubits__, { double, %Qubit* }* %4) + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 -1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %3, i32 -1) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Rz__ctladj(%Array* %__controlQubits__, { double, %Qubit* }* %0) { +entry: + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 1) + %1 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 0 + %theta = load double, double* %1, align 8 + %2 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 1 + %qubit = load %Qubit*, %Qubit** %2, align 8 + %3 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint ({ double, %Qubit* }* getelementptr ({ double, %Qubit* }, { double, %Qubit* }* null, i32 1) to i64)) + %4 = bitcast %Tuple* %3 to { double, %Qubit* }* + %5 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %4, i32 0, i32 0 + %6 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %4, i32 0, i32 1 + %7 = fneg double %theta + store double %7, double* %5, align 8 + store %Qubit* %qubit, %Qubit** %6, align 8 + call void @Microsoft__Quantum__Intrinsic__Rz__ctl(%Array* %__controlQubits__, { double, %Qubit* }* %4) + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 -1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %3, i32 -1) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__R1__body(double %theta, %Qubit* %qubit) { +entry: + %0 = load i2, i2* @PauliZ, align 1 + call void @Microsoft__Quantum__Intrinsic__R__body(i2 %0, double %theta, %Qubit* %qubit) + %1 = load i2, i2* @PauliI, align 1 + %2 = fneg double %theta + call void @Microsoft__Quantum__Intrinsic__R__body(i2 %1, double %2, %Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__R1__adj(double %theta, %Qubit* %qubit) { +entry: + %0 = load i2, i2* @PauliI, align 1 + %1 = fneg double %theta + call void @Microsoft__Quantum__Intrinsic__R__adj(i2 %0, double %1, %Qubit* %qubit) + %2 = load i2, i2* @PauliZ, align 1 + call void @Microsoft__Quantum__Intrinsic__R__adj(i2 %2, double %theta, %Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__R1Frac__body(i64 %numerator, i64 %power, %Qubit* %qubit) { +entry: + %0 = load i2, i2* @PauliZ, align 1 + %1 = sub i64 0, %numerator + %2 = add i64 %power, 1 + call void @Microsoft__Quantum__Intrinsic__RFrac__body(i2 %0, i64 %1, i64 %2, %Qubit* %qubit) + %3 = load i2, i2* @PauliI, align 1 + %4 = add i64 %power, 1 + call void @Microsoft__Quantum__Intrinsic__RFrac__body(i2 %3, i64 %numerator, i64 %4, %Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__RFrac__body(i2 %pauli, i64 %numerator, i64 %power, %Qubit* %qubit) { +entry: + %0 = call double @Microsoft__Quantum__Math__PI__body() + %1 = fmul double -2.000000e+00, %0 + %2 = sitofp i64 %numerator to double + %3 = fmul double %1, %2 + %4 = sitofp i64 %power to double + %5 = call double @llvm.pow.f64(double 2.000000e+00, double %4) + %angle = fdiv double %3, %5 + call void @Microsoft__Quantum__Intrinsic__R__body(i2 %pauli, double %angle, %Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__R1Frac__adj(i64 %numerator, i64 %power, %Qubit* %qubit) { +entry: + %0 = load i2, i2* @PauliI, align 1 + %1 = add i64 %power, 1 + call void @Microsoft__Quantum__Intrinsic__RFrac__adj(i2 %0, i64 %numerator, i64 %1, %Qubit* %qubit) + %2 = load i2, i2* @PauliZ, align 1 + %3 = sub i64 0, %numerator + %4 = add i64 %power, 1 + call void @Microsoft__Quantum__Intrinsic__RFrac__adj(i2 %2, i64 %3, i64 %4, %Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__RFrac__adj(i2 %pauli, i64 %numerator, i64 %power, %Qubit* %qubit) { +entry: + %0 = call double @Microsoft__Quantum__Math__PI__body() + %1 = fmul double -2.000000e+00, %0 + %2 = sitofp i64 %numerator to double + %3 = fmul double %1, %2 + %4 = sitofp i64 %power to double + %5 = call double @llvm.pow.f64(double 2.000000e+00, double %4) + %__qsVar0__angle__ = fdiv double %3, %5 + call void @Microsoft__Quantum__Intrinsic__R__adj(i2 %pauli, double %__qsVar0__angle__, %Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__R1Frac__ctl(%Array* %__controlQubits__, { i64, i64, %Qubit* }* %0) { +entry: + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 1) + %1 = getelementptr inbounds { i64, i64, %Qubit* }, { i64, i64, %Qubit* }* %0, i32 0, i32 0 + %numerator = load i64, i64* %1, align 4 + %2 = getelementptr inbounds { i64, i64, %Qubit* }, { i64, i64, %Qubit* }* %0, i32 0, i32 1 + %power = load i64, i64* %2, align 4 + %3 = getelementptr inbounds { i64, i64, %Qubit* }, { i64, i64, %Qubit* }* %0, i32 0, i32 2 + %qubit = load %Qubit*, %Qubit** %3, align 8 + %4 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint ({ i2, i64, i64, %Qubit* }* getelementptr ({ i2, i64, i64, %Qubit* }, { i2, i64, i64, %Qubit* }* null, i32 1) to i64)) + %5 = bitcast %Tuple* %4 to { i2, i64, i64, %Qubit* }* + %6 = getelementptr inbounds { i2, i64, i64, %Qubit* }, { i2, i64, i64, %Qubit* }* %5, i32 0, i32 0 + %7 = getelementptr inbounds { i2, i64, i64, %Qubit* }, { i2, i64, i64, %Qubit* }* %5, i32 0, i32 1 + %8 = getelementptr inbounds { i2, i64, i64, %Qubit* }, { i2, i64, i64, %Qubit* }* %5, i32 0, i32 2 + %9 = getelementptr inbounds { i2, i64, i64, %Qubit* }, { i2, i64, i64, %Qubit* }* %5, i32 0, i32 3 + %10 = load i2, i2* @PauliZ, align 1 + %11 = sub i64 0, %numerator + %12 = add i64 %power, 1 + store i2 %10, i2* %6, align 1 + store i64 %11, i64* %7, align 4 + store i64 %12, i64* %8, align 4 + store %Qubit* %qubit, %Qubit** %9, align 8 + call void @Microsoft__Quantum__Intrinsic__RFrac__ctl(%Array* %__controlQubits__, { i2, i64, i64, %Qubit* }* %5) + %13 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint ({ i2, i64, i64, %Qubit* }* getelementptr ({ i2, i64, i64, %Qubit* }, { i2, i64, i64, %Qubit* }* null, i32 1) to i64)) + %14 = bitcast %Tuple* %13 to { i2, i64, i64, %Qubit* }* + %15 = getelementptr inbounds { i2, i64, i64, %Qubit* }, { i2, i64, i64, %Qubit* }* %14, i32 0, i32 0 + %16 = getelementptr inbounds { i2, i64, i64, %Qubit* }, { i2, i64, i64, %Qubit* }* %14, i32 0, i32 1 + %17 = getelementptr inbounds { i2, i64, i64, %Qubit* }, { i2, i64, i64, %Qubit* }* %14, i32 0, i32 2 + %18 = getelementptr inbounds { i2, i64, i64, %Qubit* }, { i2, i64, i64, %Qubit* }* %14, i32 0, i32 3 + %19 = load i2, i2* @PauliI, align 1 + %20 = add i64 %power, 1 + store i2 %19, i2* %15, align 1 + store i64 %numerator, i64* %16, align 4 + store i64 %20, i64* %17, align 4 + store %Qubit* %qubit, %Qubit** %18, align 8 + call void @Microsoft__Quantum__Intrinsic__RFrac__ctl(%Array* %__controlQubits__, { i2, i64, i64, %Qubit* }* %14) + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 -1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %4, i32 -1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %13, i32 -1) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__RFrac__ctl(%Array* %__controlQubits__, { i2, i64, i64, %Qubit* }* %0) { +entry: + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 1) + %1 = getelementptr inbounds { i2, i64, i64, %Qubit* }, { i2, i64, i64, %Qubit* }* %0, i32 0, i32 0 + %pauli = load i2, i2* %1, align 1 + %2 = getelementptr inbounds { i2, i64, i64, %Qubit* }, { i2, i64, i64, %Qubit* }* %0, i32 0, i32 1 + %numerator = load i64, i64* %2, align 4 + %3 = getelementptr inbounds { i2, i64, i64, %Qubit* }, { i2, i64, i64, %Qubit* }* %0, i32 0, i32 2 + %power = load i64, i64* %3, align 4 + %4 = getelementptr inbounds { i2, i64, i64, %Qubit* }, { i2, i64, i64, %Qubit* }* %0, i32 0, i32 3 + %qubit = load %Qubit*, %Qubit** %4, align 8 + %5 = call double @Microsoft__Quantum__Math__PI__body() + %6 = fmul double -2.000000e+00, %5 + %7 = sitofp i64 %numerator to double + %8 = fmul double %6, %7 + %9 = sitofp i64 %power to double + %10 = call double @llvm.pow.f64(double 2.000000e+00, double %9) + %angle = fdiv double %8, %10 + %11 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint ({ i2, double, %Qubit* }* getelementptr ({ i2, double, %Qubit* }, { i2, double, %Qubit* }* null, i32 1) to i64)) + %12 = bitcast %Tuple* %11 to { i2, double, %Qubit* }* + %13 = getelementptr inbounds { i2, double, %Qubit* }, { i2, double, %Qubit* }* %12, i32 0, i32 0 + %14 = getelementptr inbounds { i2, double, %Qubit* }, { i2, double, %Qubit* }* %12, i32 0, i32 1 + %15 = getelementptr inbounds { i2, double, %Qubit* }, { i2, double, %Qubit* }* %12, i32 0, i32 2 + store i2 %pauli, i2* %13, align 1 + store double %angle, double* %14, align 8 + store %Qubit* %qubit, %Qubit** %15, align 8 + call void @Microsoft__Quantum__Intrinsic__R__ctl(%Array* %__controlQubits__, { i2, double, %Qubit* }* %12) + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 -1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %11, i32 -1) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__R1Frac__ctladj(%Array* %__controlQubits__, { i64, i64, %Qubit* }* %0) { +entry: + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 1) + %1 = getelementptr inbounds { i64, i64, %Qubit* }, { i64, i64, %Qubit* }* %0, i32 0, i32 0 + %numerator = load i64, i64* %1, align 4 + %2 = getelementptr inbounds { i64, i64, %Qubit* }, { i64, i64, %Qubit* }* %0, i32 0, i32 1 + %power = load i64, i64* %2, align 4 + %3 = getelementptr inbounds { i64, i64, %Qubit* }, { i64, i64, %Qubit* }* %0, i32 0, i32 2 + %qubit = load %Qubit*, %Qubit** %3, align 8 + %4 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint ({ i2, i64, i64, %Qubit* }* getelementptr ({ i2, i64, i64, %Qubit* }, { i2, i64, i64, %Qubit* }* null, i32 1) to i64)) + %5 = bitcast %Tuple* %4 to { i2, i64, i64, %Qubit* }* + %6 = getelementptr inbounds { i2, i64, i64, %Qubit* }, { i2, i64, i64, %Qubit* }* %5, i32 0, i32 0 + %7 = getelementptr inbounds { i2, i64, i64, %Qubit* }, { i2, i64, i64, %Qubit* }* %5, i32 0, i32 1 + %8 = getelementptr inbounds { i2, i64, i64, %Qubit* }, { i2, i64, i64, %Qubit* }* %5, i32 0, i32 2 + %9 = getelementptr inbounds { i2, i64, i64, %Qubit* }, { i2, i64, i64, %Qubit* }* %5, i32 0, i32 3 + %10 = load i2, i2* @PauliI, align 1 + %11 = add i64 %power, 1 + store i2 %10, i2* %6, align 1 + store i64 %numerator, i64* %7, align 4 + store i64 %11, i64* %8, align 4 + store %Qubit* %qubit, %Qubit** %9, align 8 + call void @Microsoft__Quantum__Intrinsic__RFrac__ctladj(%Array* %__controlQubits__, { i2, i64, i64, %Qubit* }* %5) + %12 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint ({ i2, i64, i64, %Qubit* }* getelementptr ({ i2, i64, i64, %Qubit* }, { i2, i64, i64, %Qubit* }* null, i32 1) to i64)) + %13 = bitcast %Tuple* %12 to { i2, i64, i64, %Qubit* }* + %14 = getelementptr inbounds { i2, i64, i64, %Qubit* }, { i2, i64, i64, %Qubit* }* %13, i32 0, i32 0 + %15 = getelementptr inbounds { i2, i64, i64, %Qubit* }, { i2, i64, i64, %Qubit* }* %13, i32 0, i32 1 + %16 = getelementptr inbounds { i2, i64, i64, %Qubit* }, { i2, i64, i64, %Qubit* }* %13, i32 0, i32 2 + %17 = getelementptr inbounds { i2, i64, i64, %Qubit* }, { i2, i64, i64, %Qubit* }* %13, i32 0, i32 3 + %18 = load i2, i2* @PauliZ, align 1 + %19 = sub i64 0, %numerator + %20 = add i64 %power, 1 + store i2 %18, i2* %14, align 1 + store i64 %19, i64* %15, align 4 + store i64 %20, i64* %16, align 4 + store %Qubit* %qubit, %Qubit** %17, align 8 + call void @Microsoft__Quantum__Intrinsic__RFrac__ctladj(%Array* %__controlQubits__, { i2, i64, i64, %Qubit* }* %13) + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 -1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %4, i32 -1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %12, i32 -1) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__RFrac__ctladj(%Array* %__controlQubits__, { i2, i64, i64, %Qubit* }* %0) { +entry: + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 1) + %1 = getelementptr inbounds { i2, i64, i64, %Qubit* }, { i2, i64, i64, %Qubit* }* %0, i32 0, i32 0 + %pauli = load i2, i2* %1, align 1 + %2 = getelementptr inbounds { i2, i64, i64, %Qubit* }, { i2, i64, i64, %Qubit* }* %0, i32 0, i32 1 + %numerator = load i64, i64* %2, align 4 + %3 = getelementptr inbounds { i2, i64, i64, %Qubit* }, { i2, i64, i64, %Qubit* }* %0, i32 0, i32 2 + %power = load i64, i64* %3, align 4 + %4 = getelementptr inbounds { i2, i64, i64, %Qubit* }, { i2, i64, i64, %Qubit* }* %0, i32 0, i32 3 + %qubit = load %Qubit*, %Qubit** %4, align 8 + %5 = call double @Microsoft__Quantum__Math__PI__body() + %6 = fmul double -2.000000e+00, %5 + %7 = sitofp i64 %numerator to double + %8 = fmul double %6, %7 + %9 = sitofp i64 %power to double + %10 = call double @llvm.pow.f64(double 2.000000e+00, double %9) + %__qsVar0__angle__ = fdiv double %8, %10 + %11 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint ({ i2, double, %Qubit* }* getelementptr ({ i2, double, %Qubit* }, { i2, double, %Qubit* }* null, i32 1) to i64)) + %12 = bitcast %Tuple* %11 to { i2, double, %Qubit* }* + %13 = getelementptr inbounds { i2, double, %Qubit* }, { i2, double, %Qubit* }* %12, i32 0, i32 0 + %14 = getelementptr inbounds { i2, double, %Qubit* }, { i2, double, %Qubit* }* %12, i32 0, i32 1 + %15 = getelementptr inbounds { i2, double, %Qubit* }, { i2, double, %Qubit* }* %12, i32 0, i32 2 + store i2 %pauli, i2* %13, align 1 + store double %__qsVar0__angle__, double* %14, align 8 + store %Qubit* %qubit, %Qubit** %15, align 8 + call void @Microsoft__Quantum__Intrinsic__R__ctladj(%Array* %__controlQubits__, { i2, double, %Qubit* }* %12) + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 -1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %11, i32 -1) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Reset__body(%Qubit* %qubit) { +entry: + call void @__quantum__qis__reset__body(%Qubit* %qubit) + ret void +} + +declare void @__quantum__qis__reset__body(%Qubit*) + +define internal double @Microsoft__Quantum__Math__PI__body() { +entry: + ret double 0x400921FB54442D18 +} + +; Function Attrs: nounwind readnone speculatable willreturn +declare double @llvm.pow.f64(double, double) #0 + +declare void @__quantum__qis__rx__body(double, %Qubit*) + +define internal void @Microsoft__Quantum__Intrinsic___8f3359a2b69a47ffa9fd2508e6ea5641___QsRef23__ApplyWithLessControlsA____body(%Callable* %op, { %Array*, { double, %Qubit* }* }* %0) { +entry: + call void @__quantum__rt__capture_update_alias_count(%Callable* %op, i32 1) + call void @__quantum__rt__callable_update_alias_count(%Callable* %op, i32 1) + %1 = getelementptr inbounds { %Array*, { double, %Qubit* }* }, { %Array*, { double, %Qubit* }* }* %0, i32 0, i32 0 + %controls = load %Array*, %Array** %1, align 8 + call void @__quantum__rt__array_update_alias_count(%Array* %controls, i32 1) + %2 = getelementptr inbounds { %Array*, { double, %Qubit* }* }, { %Array*, { double, %Qubit* }* }* %0, i32 0, i32 1 + %arg = load { double, %Qubit* }*, { double, %Qubit* }** %2, align 8 + %3 = bitcast { double, %Qubit* }* %arg to %Tuple* + call void @__quantum__rt__tuple_update_alias_count(%Tuple* %3, i32 1) + %numControls = call i64 @__quantum__rt__array_get_size_1d(%Array* %controls) + %numControlPairs = sdiv i64 %numControls, 2 + %temps = call %Array* @__quantum__rt__qubit_allocate_array(i64 %numControlPairs) + call void @__quantum__rt__array_update_alias_count(%Array* %temps, i32 1) + %4 = sub i64 %numControlPairs, 1 + br label %header__1 + +header__1: ; preds = %exiting__1, %entry + %__qsVar0__numPair__ = phi i64 [ 0, %entry ], [ %18, %exiting__1 ] + %5 = icmp sle i64 %__qsVar0__numPair__, %4 + br i1 %5, label %body__1, label %exit__1 + +body__1: ; preds = %header__1 + %6 = mul i64 2, %__qsVar0__numPair__ + %7 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %controls, i64 %6) + %8 = bitcast i8* %7 to %Qubit** + %9 = load %Qubit*, %Qubit** %8, align 8 + %10 = mul i64 2, %__qsVar0__numPair__ + %11 = add i64 %10, 1 + %12 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %controls, i64 %11) + %13 = bitcast i8* %12 to %Qubit** + %14 = load %Qubit*, %Qubit** %13, align 8 + %15 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %temps, i64 %__qsVar0__numPair__) + %16 = bitcast i8* %15 to %Qubit** + %17 = load %Qubit*, %Qubit** %16, align 8 + call void @Microsoft__Quantum__Intrinsic____QsRef23__PhaseCCX____body(%Qubit* %9, %Qubit* %14, %Qubit* %17) + br label %exiting__1 + +exiting__1: ; preds = %body__1 + %18 = add i64 %__qsVar0__numPair__, 1 + br label %header__1 + +exit__1: ; preds = %header__1 + %19 = srem i64 %numControls, 2 + %20 = icmp eq i64 %19, 0 + br i1 %20, label %condTrue__1, label %condFalse__1 + +condTrue__1: ; preds = %exit__1 + call void @__quantum__rt__array_update_reference_count(%Array* %temps, i32 1) + br label %condContinue__1 + +condFalse__1: ; preds = %exit__1 + %21 = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) + %22 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %21, i64 0) + %23 = bitcast i8* %22 to %Qubit** + %24 = sub i64 %numControls, 1 + %25 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %controls, i64 %24) + %26 = bitcast i8* %25 to %Qubit** + %27 = load %Qubit*, %Qubit** %26, align 8 + store %Qubit* %27, %Qubit** %23, align 8 + %28 = call %Array* @__quantum__rt__array_concatenate(%Array* %temps, %Array* %21) + call void @__quantum__rt__array_update_reference_count(%Array* %28, i32 1) + call void @__quantum__rt__array_update_reference_count(%Array* %21, i32 -1) + call void @__quantum__rt__array_update_reference_count(%Array* %28, i32 -1) + br label %condContinue__1 + +condContinue__1: ; preds = %condFalse__1, %condTrue__1 + %__qsVar1__newControls__ = phi %Array* [ %temps, %condTrue__1 ], [ %28, %condFalse__1 ] + call void @__quantum__rt__array_update_alias_count(%Array* %__qsVar1__newControls__, i32 1) + %29 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 2)) + %30 = bitcast %Tuple* %29 to { %Array*, { double, %Qubit* }* }* + %31 = getelementptr inbounds { %Array*, { double, %Qubit* }* }, { %Array*, { double, %Qubit* }* }* %30, i32 0, i32 0 + %32 = getelementptr inbounds { %Array*, { double, %Qubit* }* }, { %Array*, { double, %Qubit* }* }* %30, i32 0, i32 1 + call void @__quantum__rt__array_update_reference_count(%Array* %__qsVar1__newControls__, i32 1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %3, i32 1) + store %Array* %__qsVar1__newControls__, %Array** %31, align 8 + store { double, %Qubit* }* %arg, { double, %Qubit* }** %32, align 8 + call void @__quantum__rt__callable_invoke(%Callable* %op, %Tuple* %29, %Tuple* null) + %33 = sub i64 %numControlPairs, 1 + %34 = sub i64 %33, 0 + %35 = sdiv i64 %34, 1 + %36 = mul i64 1, %35 + %37 = add i64 0, %36 + %38 = load %Range, %Range* @EmptyRange, align 4 + %39 = insertvalue %Range %38, i64 %37, 0 + %40 = insertvalue %Range %39, i64 -1, 1 + %41 = insertvalue %Range %40, i64 0, 2 + %42 = extractvalue %Range %41, 0 + %43 = extractvalue %Range %41, 1 + %44 = extractvalue %Range %41, 2 + br label %preheader__1 + +preheader__1: ; preds = %condContinue__1 + %45 = icmp sgt i64 %43, 0 + br label %header__2 + +header__2: ; preds = %exiting__2, %preheader__1 + %__qsVar0____qsVar0__numPair____ = phi i64 [ %42, %preheader__1 ], [ %61, %exiting__2 ] + %46 = icmp sle i64 %__qsVar0____qsVar0__numPair____, %44 + %47 = icmp sge i64 %__qsVar0____qsVar0__numPair____, %44 + %48 = select i1 %45, i1 %46, i1 %47 + br i1 %48, label %body__2, label %exit__2 + +body__2: ; preds = %header__2 + %49 = mul i64 2, %__qsVar0____qsVar0__numPair____ + %50 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %controls, i64 %49) + %51 = bitcast i8* %50 to %Qubit** + %52 = load %Qubit*, %Qubit** %51, align 8 + %53 = mul i64 2, %__qsVar0____qsVar0__numPair____ + %54 = add i64 %53, 1 + %55 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %controls, i64 %54) + %56 = bitcast i8* %55 to %Qubit** + %57 = load %Qubit*, %Qubit** %56, align 8 + %58 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %temps, i64 %__qsVar0____qsVar0__numPair____) + %59 = bitcast i8* %58 to %Qubit** + %60 = load %Qubit*, %Qubit** %59, align 8 + call void @Microsoft__Quantum__Intrinsic____QsRef23__PhaseCCX____adj(%Qubit* %52, %Qubit* %57, %Qubit* %60) + br label %exiting__2 + +exiting__2: ; preds = %body__2 + %61 = add i64 %__qsVar0____qsVar0__numPair____, %43 + br label %header__2 + +exit__2: ; preds = %header__2 + call void @__quantum__rt__array_update_alias_count(%Array* %temps, i32 -1) + call void @__quantum__rt__array_update_alias_count(%Array* %__qsVar1__newControls__, i32 -1) + call void @__quantum__rt__array_update_reference_count(%Array* %__qsVar1__newControls__, i32 -1) + call void @__quantum__rt__array_update_reference_count(%Array* %__qsVar1__newControls__, i32 -1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %3, i32 -1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %29, i32 -1) + call void @__quantum__rt__qubit_release_array(%Array* %temps) + call void @__quantum__rt__capture_update_alias_count(%Callable* %op, i32 -1) + call void @__quantum__rt__callable_update_alias_count(%Callable* %op, i32 -1) + call void @__quantum__rt__array_update_alias_count(%Array* %controls, i32 -1) + call void @__quantum__rt__tuple_update_alias_count(%Tuple* %3, i32 -1) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Rx__body__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { +entry: + %0 = bitcast %Tuple* %arg-tuple to { double, %Qubit* }* + %1 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 0 + %2 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 1 + %3 = load double, double* %1, align 8 + %4 = load %Qubit*, %Qubit** %2, align 8 + call void @Microsoft__Quantum__Intrinsic__Rx__body(double %3, %Qubit* %4) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Rx__adj__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { +entry: + %0 = bitcast %Tuple* %arg-tuple to { double, %Qubit* }* + %1 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 0 + %2 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 1 + %3 = load double, double* %1, align 8 + %4 = load %Qubit*, %Qubit** %2, align 8 + call void @Microsoft__Quantum__Intrinsic__Rx__adj(double %3, %Qubit* %4) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Rx__ctl__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { +entry: + %0 = bitcast %Tuple* %arg-tuple to { %Array*, { double, %Qubit* }* }* + %1 = getelementptr inbounds { %Array*, { double, %Qubit* }* }, { %Array*, { double, %Qubit* }* }* %0, i32 0, i32 0 + %2 = getelementptr inbounds { %Array*, { double, %Qubit* }* }, { %Array*, { double, %Qubit* }* }* %0, i32 0, i32 1 + %3 = load %Array*, %Array** %1, align 8 + %4 = load { double, %Qubit* }*, { double, %Qubit* }** %2, align 8 + call void @Microsoft__Quantum__Intrinsic__Rx__ctl(%Array* %3, { double, %Qubit* }* %4) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Rx__ctladj__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { +entry: + %0 = bitcast %Tuple* %arg-tuple to { %Array*, { double, %Qubit* }* }* + %1 = getelementptr inbounds { %Array*, { double, %Qubit* }* }, { %Array*, { double, %Qubit* }* }* %0, i32 0, i32 0 + %2 = getelementptr inbounds { %Array*, { double, %Qubit* }* }, { %Array*, { double, %Qubit* }* }* %0, i32 0, i32 1 + %3 = load %Array*, %Array** %1, align 8 + %4 = load { double, %Qubit* }*, { double, %Qubit* }** %2, align 8 + call void @Microsoft__Quantum__Intrinsic__Rx__ctladj(%Array* %3, { double, %Qubit* }* %4) + ret void +} + +declare void @__quantum__qis__ry__body(double, %Qubit*) + +define internal void @Microsoft__Quantum__Intrinsic__Ry__body__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { +entry: + %0 = bitcast %Tuple* %arg-tuple to { double, %Qubit* }* + %1 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 0 + %2 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 1 + %3 = load double, double* %1, align 8 + %4 = load %Qubit*, %Qubit** %2, align 8 + call void @Microsoft__Quantum__Intrinsic__Ry__body(double %3, %Qubit* %4) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Ry__adj__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { +entry: + %0 = bitcast %Tuple* %arg-tuple to { double, %Qubit* }* + %1 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 0 + %2 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 1 + %3 = load double, double* %1, align 8 + %4 = load %Qubit*, %Qubit** %2, align 8 + call void @Microsoft__Quantum__Intrinsic__Ry__adj(double %3, %Qubit* %4) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Ry__ctl__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { +entry: + %0 = bitcast %Tuple* %arg-tuple to { %Array*, { double, %Qubit* }* }* + %1 = getelementptr inbounds { %Array*, { double, %Qubit* }* }, { %Array*, { double, %Qubit* }* }* %0, i32 0, i32 0 + %2 = getelementptr inbounds { %Array*, { double, %Qubit* }* }, { %Array*, { double, %Qubit* }* }* %0, i32 0, i32 1 + %3 = load %Array*, %Array** %1, align 8 + %4 = load { double, %Qubit* }*, { double, %Qubit* }** %2, align 8 + call void @Microsoft__Quantum__Intrinsic__Ry__ctl(%Array* %3, { double, %Qubit* }* %4) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Ry__ctladj__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { +entry: + %0 = bitcast %Tuple* %arg-tuple to { %Array*, { double, %Qubit* }* }* + %1 = getelementptr inbounds { %Array*, { double, %Qubit* }* }, { %Array*, { double, %Qubit* }* }* %0, i32 0, i32 0 + %2 = getelementptr inbounds { %Array*, { double, %Qubit* }* }, { %Array*, { double, %Qubit* }* }* %0, i32 0, i32 1 + %3 = load %Array*, %Array** %1, align 8 + %4 = load { double, %Qubit* }*, { double, %Qubit* }** %2, align 8 + call void @Microsoft__Quantum__Intrinsic__Ry__ctladj(%Array* %3, { double, %Qubit* }* %4) + ret void +} + +declare void @__quantum__qis__rz__body(double, %Qubit*) + +define internal void @Microsoft__Quantum__Intrinsic__Rz__body__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { +entry: + %0 = bitcast %Tuple* %arg-tuple to { double, %Qubit* }* + %1 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 0 + %2 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 1 + %3 = load double, double* %1, align 8 + %4 = load %Qubit*, %Qubit** %2, align 8 + call void @Microsoft__Quantum__Intrinsic__Rz__body(double %3, %Qubit* %4) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Rz__adj__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { +entry: + %0 = bitcast %Tuple* %arg-tuple to { double, %Qubit* }* + %1 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 0 + %2 = getelementptr inbounds { double, %Qubit* }, { double, %Qubit* }* %0, i32 0, i32 1 + %3 = load double, double* %1, align 8 + %4 = load %Qubit*, %Qubit** %2, align 8 + call void @Microsoft__Quantum__Intrinsic__Rz__adj(double %3, %Qubit* %4) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Rz__ctl__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { +entry: + %0 = bitcast %Tuple* %arg-tuple to { %Array*, { double, %Qubit* }* }* + %1 = getelementptr inbounds { %Array*, { double, %Qubit* }* }, { %Array*, { double, %Qubit* }* }* %0, i32 0, i32 0 + %2 = getelementptr inbounds { %Array*, { double, %Qubit* }* }, { %Array*, { double, %Qubit* }* }* %0, i32 0, i32 1 + %3 = load %Array*, %Array** %1, align 8 + %4 = load { double, %Qubit* }*, { double, %Qubit* }** %2, align 8 + call void @Microsoft__Quantum__Intrinsic__Rz__ctl(%Array* %3, { double, %Qubit* }* %4) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Rz__ctladj__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { +entry: + %0 = bitcast %Tuple* %arg-tuple to { %Array*, { double, %Qubit* }* }* + %1 = getelementptr inbounds { %Array*, { double, %Qubit* }* }, { %Array*, { double, %Qubit* }* }* %0, i32 0, i32 0 + %2 = getelementptr inbounds { %Array*, { double, %Qubit* }* }, { %Array*, { double, %Qubit* }* }* %0, i32 0, i32 1 + %3 = load %Array*, %Array** %1, align 8 + %4 = load { double, %Qubit* }*, { double, %Qubit* }** %2, align 8 + call void @Microsoft__Quantum__Intrinsic__Rz__ctladj(%Array* %3, { double, %Qubit* }* %4) + ret void +} + +declare void @__quantum__qis__s__body(%Qubit*) + +declare void @__quantum__qis__s__adj(%Qubit*) + +define internal void @Microsoft__Quantum__Intrinsic__S__ctl(%Array* %ctls, %Qubit* %qubit) { +entry: + call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i32 1) + %0 = call i64 @__quantum__rt__array_get_size_1d(%Array* %ctls) + %1 = icmp eq i64 %0, 0 + br i1 %1, label %then0__1, label %test1__1 + +then0__1: ; preds = %entry + call void @__quantum__qis__s__body(%Qubit* %qubit) + br label %continue__1 + +test1__1: ; preds = %entry + %2 = call i64 @__quantum__rt__array_get_size_1d(%Array* %ctls) + %3 = icmp eq i64 %2, 1 + br i1 %3, label %then1__1, label %else__1 + +then1__1: ; preds = %test1__1 + %4 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls, i64 0) + %5 = bitcast i8* %4 to %Qubit** + %6 = load %Qubit*, %Qubit** %5, align 8 + call void @Microsoft__Quantum__Intrinsic__T__body(%Qubit* %6) + call void @Microsoft__Quantum__Intrinsic__T__body(%Qubit* %qubit) + %7 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls, i64 0) + %8 = bitcast i8* %7 to %Qubit** + %9 = load %Qubit*, %Qubit** %8, align 8 + call void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* %9, %Qubit* %qubit) + call void @Microsoft__Quantum__Intrinsic__T__adj(%Qubit* %qubit) + %10 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls, i64 0) + %11 = bitcast i8* %10 to %Qubit** + %12 = load %Qubit*, %Qubit** %11, align 8 + call void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* %12, %Qubit* %qubit) + br label %continue__1 + +else__1: ; preds = %test1__1 + %13 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Intrinsic__S__FunctionTable, [2 x void (%Tuple*, i32)*]* null, %Tuple* null) + call void @__quantum__rt__callable_make_controlled(%Callable* %13) + %14 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 2)) + %15 = bitcast %Tuple* %14 to { %Array*, %Qubit* }* + %16 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %15, i32 0, i32 0 + %17 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %15, i32 0, i32 1 + call void @__quantum__rt__array_update_reference_count(%Array* %ctls, i32 1) + store %Array* %ctls, %Array** %16, align 8 + store %Qubit* %qubit, %Qubit** %17, align 8 + call void @Microsoft__Quantum__Intrinsic___067288bb3b0f4c3fa16d90a27710fc06___QsRef23__ApplyWithLessControlsA____body(%Callable* %13, { %Array*, %Qubit* }* %15) + call void @__quantum__rt__capture_update_reference_count(%Callable* %13, i32 -1) + call void @__quantum__rt__callable_update_reference_count(%Callable* %13, i32 -1) + call void @__quantum__rt__array_update_reference_count(%Array* %ctls, i32 -1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %14, i32 -1) + br label %continue__1 + +continue__1: ; preds = %else__1, %then1__1, %then0__1 + call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i32 -1) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__S__body__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { +entry: + %0 = bitcast %Tuple* %arg-tuple to { %Qubit* }* + %1 = getelementptr inbounds { %Qubit* }, { %Qubit* }* %0, i32 0, i32 0 + %2 = load %Qubit*, %Qubit** %1, align 8 + call void @Microsoft__Quantum__Intrinsic__S__body(%Qubit* %2) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__S__adj__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { +entry: + %0 = bitcast %Tuple* %arg-tuple to { %Qubit* }* + %1 = getelementptr inbounds { %Qubit* }, { %Qubit* }* %0, i32 0, i32 0 + %2 = load %Qubit*, %Qubit** %1, align 8 + call void @Microsoft__Quantum__Intrinsic__S__adj(%Qubit* %2) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__S__ctl__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { +entry: + %0 = bitcast %Tuple* %arg-tuple to { %Array*, %Qubit* }* + %1 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 0 + %2 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 1 + %3 = load %Array*, %Array** %1, align 8 + %4 = load %Qubit*, %Qubit** %2, align 8 + call void @Microsoft__Quantum__Intrinsic__S__ctl(%Array* %3, %Qubit* %4) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__S__ctladj__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { +entry: + %0 = bitcast %Tuple* %arg-tuple to { %Array*, %Qubit* }* + %1 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 0 + %2 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 1 + %3 = load %Array*, %Array** %1, align 8 + %4 = load %Qubit*, %Qubit** %2, align 8 + call void @Microsoft__Quantum__Intrinsic__S__ctladj(%Array* %3, %Qubit* %4) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__S__ctladj(%Array* %ctls, %Qubit* %qubit) { +entry: + call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i32 1) + %0 = call i64 @__quantum__rt__array_get_size_1d(%Array* %ctls) + %1 = icmp eq i64 %0, 0 + br i1 %1, label %then0__1, label %test1__1 + +then0__1: ; preds = %entry + call void @__quantum__qis__s__adj(%Qubit* %qubit) + br label %continue__1 + +test1__1: ; preds = %entry + %2 = call i64 @__quantum__rt__array_get_size_1d(%Array* %ctls) + %3 = icmp eq i64 %2, 1 + br i1 %3, label %then1__1, label %else__1 + +then1__1: ; preds = %test1__1 + %4 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls, i64 0) + %5 = bitcast i8* %4 to %Qubit** + %6 = load %Qubit*, %Qubit** %5, align 8 + call void @Microsoft__Quantum__Intrinsic__T__adj(%Qubit* %6) + call void @Microsoft__Quantum__Intrinsic__T__adj(%Qubit* %qubit) + %7 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls, i64 0) + %8 = bitcast i8* %7 to %Qubit** + %9 = load %Qubit*, %Qubit** %8, align 8 + call void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* %9, %Qubit* %qubit) + call void @Microsoft__Quantum__Intrinsic__T__body(%Qubit* %qubit) + %10 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls, i64 0) + %11 = bitcast i8* %10 to %Qubit** + %12 = load %Qubit*, %Qubit** %11, align 8 + call void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* %12, %Qubit* %qubit) + br label %continue__1 + +else__1: ; preds = %test1__1 + %13 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Intrinsic__S__FunctionTable, [2 x void (%Tuple*, i32)*]* null, %Tuple* null) + call void @__quantum__rt__callable_make_adjoint(%Callable* %13) + call void @__quantum__rt__callable_make_controlled(%Callable* %13) + %14 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 2)) + %15 = bitcast %Tuple* %14 to { %Array*, %Qubit* }* + %16 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %15, i32 0, i32 0 + %17 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %15, i32 0, i32 1 + call void @__quantum__rt__array_update_reference_count(%Array* %ctls, i32 1) + store %Array* %ctls, %Array** %16, align 8 + store %Qubit* %qubit, %Qubit** %17, align 8 + call void @Microsoft__Quantum__Intrinsic___067288bb3b0f4c3fa16d90a27710fc06___QsRef23__ApplyWithLessControlsA____body(%Callable* %13, { %Array*, %Qubit* }* %15) + call void @__quantum__rt__capture_update_reference_count(%Callable* %13, i32 -1) + call void @__quantum__rt__callable_update_reference_count(%Callable* %13, i32 -1) + call void @__quantum__rt__array_update_reference_count(%Array* %ctls, i32 -1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %14, i32 -1) + br label %continue__1 + +continue__1: ; preds = %else__1, %then1__1, %then0__1 + call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i32 -1) + ret void +} + +declare void @__quantum__rt__callable_make_adjoint(%Callable*) + +declare void @__quantum__qis__t__body(%Qubit*) + +declare void @__quantum__qis__t__adj(%Qubit*) + +define internal void @Microsoft__Quantum__Intrinsic__T__ctl(%Array* %ctls, %Qubit* %qubit) { +entry: + call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i32 1) + %0 = call i64 @__quantum__rt__array_get_size_1d(%Array* %ctls) + %1 = icmp eq i64 %0, 0 + br i1 %1, label %then0__1, label %test1__1 + +then0__1: ; preds = %entry + call void @__quantum__qis__t__body(%Qubit* %qubit) + br label %continue__1 + +test1__1: ; preds = %entry + %2 = call i64 @__quantum__rt__array_get_size_1d(%Array* %ctls) + %3 = icmp eq i64 %2, 1 + br i1 %3, label %then1__1, label %else__1 + +then1__1: ; preds = %test1__1 + %4 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls, i64 0) + %5 = bitcast i8* %4 to %Qubit** + %6 = load %Qubit*, %Qubit** %5, align 8 + call void @Microsoft__Quantum__Intrinsic__R1Frac__body(i64 1, i64 3, %Qubit* %6) + call void @Microsoft__Quantum__Intrinsic__R1Frac__body(i64 1, i64 3, %Qubit* %qubit) + %7 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls, i64 0) + %8 = bitcast i8* %7 to %Qubit** + %9 = load %Qubit*, %Qubit** %8, align 8 + call void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* %9, %Qubit* %qubit) + call void @Microsoft__Quantum__Intrinsic__R1Frac__adj(i64 1, i64 3, %Qubit* %qubit) + %10 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls, i64 0) + %11 = bitcast i8* %10 to %Qubit** + %12 = load %Qubit*, %Qubit** %11, align 8 + call void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* %12, %Qubit* %qubit) + br label %continue__1 + +else__1: ; preds = %test1__1 + %13 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Intrinsic__T__FunctionTable, [2 x void (%Tuple*, i32)*]* null, %Tuple* null) + call void @__quantum__rt__callable_make_controlled(%Callable* %13) + %14 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 2)) + %15 = bitcast %Tuple* %14 to { %Array*, %Qubit* }* + %16 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %15, i32 0, i32 0 + %17 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %15, i32 0, i32 1 + call void @__quantum__rt__array_update_reference_count(%Array* %ctls, i32 1) + store %Array* %ctls, %Array** %16, align 8 + store %Qubit* %qubit, %Qubit** %17, align 8 + call void @Microsoft__Quantum__Intrinsic___067288bb3b0f4c3fa16d90a27710fc06___QsRef23__ApplyWithLessControlsA____body(%Callable* %13, { %Array*, %Qubit* }* %15) + call void @__quantum__rt__capture_update_reference_count(%Callable* %13, i32 -1) + call void @__quantum__rt__callable_update_reference_count(%Callable* %13, i32 -1) + call void @__quantum__rt__array_update_reference_count(%Array* %ctls, i32 -1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %14, i32 -1) + br label %continue__1 + +continue__1: ; preds = %else__1, %then1__1, %then0__1 + call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i32 -1) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__T__body__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { +entry: + %0 = bitcast %Tuple* %arg-tuple to { %Qubit* }* + %1 = getelementptr inbounds { %Qubit* }, { %Qubit* }* %0, i32 0, i32 0 + %2 = load %Qubit*, %Qubit** %1, align 8 + call void @Microsoft__Quantum__Intrinsic__T__body(%Qubit* %2) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__T__adj__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { +entry: + %0 = bitcast %Tuple* %arg-tuple to { %Qubit* }* + %1 = getelementptr inbounds { %Qubit* }, { %Qubit* }* %0, i32 0, i32 0 + %2 = load %Qubit*, %Qubit** %1, align 8 + call void @Microsoft__Quantum__Intrinsic__T__adj(%Qubit* %2) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__T__ctl__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { +entry: + %0 = bitcast %Tuple* %arg-tuple to { %Array*, %Qubit* }* + %1 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 0 + %2 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 1 + %3 = load %Array*, %Array** %1, align 8 + %4 = load %Qubit*, %Qubit** %2, align 8 + call void @Microsoft__Quantum__Intrinsic__T__ctl(%Array* %3, %Qubit* %4) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__T__ctladj__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { +entry: + %0 = bitcast %Tuple* %arg-tuple to { %Array*, %Qubit* }* + %1 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 0 + %2 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 1 + %3 = load %Array*, %Array** %1, align 8 + %4 = load %Qubit*, %Qubit** %2, align 8 + call void @Microsoft__Quantum__Intrinsic__T__ctladj(%Array* %3, %Qubit* %4) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__T__ctladj(%Array* %ctls, %Qubit* %qubit) { +entry: + call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i32 1) + %0 = call i64 @__quantum__rt__array_get_size_1d(%Array* %ctls) + %1 = icmp eq i64 %0, 0 + br i1 %1, label %then0__1, label %test1__1 + +then0__1: ; preds = %entry + call void @__quantum__qis__t__adj(%Qubit* %qubit) + br label %continue__1 + +test1__1: ; preds = %entry + %2 = call i64 @__quantum__rt__array_get_size_1d(%Array* %ctls) + %3 = icmp eq i64 %2, 1 + br i1 %3, label %then1__1, label %else__1 + +then1__1: ; preds = %test1__1 + %4 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls, i64 0) + %5 = bitcast i8* %4 to %Qubit** + %6 = load %Qubit*, %Qubit** %5, align 8 + call void @Microsoft__Quantum__Intrinsic__R1Frac__adj(i64 1, i64 3, %Qubit* %6) + call void @Microsoft__Quantum__Intrinsic__R1Frac__adj(i64 1, i64 3, %Qubit* %qubit) + %7 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls, i64 0) + %8 = bitcast i8* %7 to %Qubit** + %9 = load %Qubit*, %Qubit** %8, align 8 + call void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* %9, %Qubit* %qubit) + call void @Microsoft__Quantum__Intrinsic__R1Frac__body(i64 1, i64 3, %Qubit* %qubit) + %10 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls, i64 0) + %11 = bitcast i8* %10 to %Qubit** + %12 = load %Qubit*, %Qubit** %11, align 8 + call void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* %12, %Qubit* %qubit) + br label %continue__1 + +else__1: ; preds = %test1__1 + %13 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Intrinsic__T__FunctionTable, [2 x void (%Tuple*, i32)*]* null, %Tuple* null) + call void @__quantum__rt__callable_make_adjoint(%Callable* %13) + call void @__quantum__rt__callable_make_controlled(%Callable* %13) + %14 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 2)) + %15 = bitcast %Tuple* %14 to { %Array*, %Qubit* }* + %16 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %15, i32 0, i32 0 + %17 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %15, i32 0, i32 1 + call void @__quantum__rt__array_update_reference_count(%Array* %ctls, i32 1) + store %Array* %ctls, %Array** %16, align 8 + store %Qubit* %qubit, %Qubit** %17, align 8 + call void @Microsoft__Quantum__Intrinsic___067288bb3b0f4c3fa16d90a27710fc06___QsRef23__ApplyWithLessControlsA____body(%Callable* %13, { %Array*, %Qubit* }* %15) + call void @__quantum__rt__capture_update_reference_count(%Callable* %13, i32 -1) + call void @__quantum__rt__callable_update_reference_count(%Callable* %13, i32 -1) + call void @__quantum__rt__array_update_reference_count(%Array* %ctls, i32 -1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %14, i32 -1) + br label %continue__1 + +continue__1: ; preds = %else__1, %then1__1, %then0__1 + call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i32 -1) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__X__adj(%Qubit* %qubit) { +entry: + call void @Microsoft__Quantum__Intrinsic__X__body(%Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__X__body__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { +entry: + %0 = bitcast %Tuple* %arg-tuple to { %Qubit* }* + %1 = getelementptr inbounds { %Qubit* }, { %Qubit* }* %0, i32 0, i32 0 + %2 = load %Qubit*, %Qubit** %1, align 8 + call void @Microsoft__Quantum__Intrinsic__X__body(%Qubit* %2) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__X__adj__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { +entry: + %0 = bitcast %Tuple* %arg-tuple to { %Qubit* }* + %1 = getelementptr inbounds { %Qubit* }, { %Qubit* }* %0, i32 0, i32 0 + %2 = load %Qubit*, %Qubit** %1, align 8 + call void @Microsoft__Quantum__Intrinsic__X__adj(%Qubit* %2) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__X__ctl__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { +entry: + %0 = bitcast %Tuple* %arg-tuple to { %Array*, %Qubit* }* + %1 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 0 + %2 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 1 + %3 = load %Array*, %Array** %1, align 8 + %4 = load %Qubit*, %Qubit** %2, align 8 + call void @Microsoft__Quantum__Intrinsic__X__ctl(%Array* %3, %Qubit* %4) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__X__ctladj__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { +entry: + %0 = bitcast %Tuple* %arg-tuple to { %Array*, %Qubit* }* + %1 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 0 + %2 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 1 + %3 = load %Array*, %Array** %1, align 8 + %4 = load %Qubit*, %Qubit** %2, align 8 + call void @Microsoft__Quantum__Intrinsic__X__ctladj(%Array* %3, %Qubit* %4) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__X__ctladj(%Array* %__controlQubits__, %Qubit* %qubit) { +entry: + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 1) + call void @Microsoft__Quantum__Intrinsic__X__ctl(%Array* %__controlQubits__, %Qubit* %qubit) + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 -1) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Z__body(%Qubit* %qubit) { +entry: + call void @__quantum__qis__z__body(%Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Z__adj(%Qubit* %qubit) { +entry: + call void @Microsoft__Quantum__Intrinsic__Z__body(%Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Z__body__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { +entry: + %0 = bitcast %Tuple* %arg-tuple to { %Qubit* }* + %1 = getelementptr inbounds { %Qubit* }, { %Qubit* }* %0, i32 0, i32 0 + %2 = load %Qubit*, %Qubit** %1, align 8 + call void @Microsoft__Quantum__Intrinsic__Z__body(%Qubit* %2) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Z__adj__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { +entry: + %0 = bitcast %Tuple* %arg-tuple to { %Qubit* }* + %1 = getelementptr inbounds { %Qubit* }, { %Qubit* }* %0, i32 0, i32 0 + %2 = load %Qubit*, %Qubit** %1, align 8 + call void @Microsoft__Quantum__Intrinsic__Z__adj(%Qubit* %2) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Z__ctl__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { +entry: + %0 = bitcast %Tuple* %arg-tuple to { %Array*, %Qubit* }* + %1 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 0 + %2 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 1 + %3 = load %Array*, %Array** %1, align 8 + %4 = load %Qubit*, %Qubit** %2, align 8 + call void @Microsoft__Quantum__Intrinsic__Z__ctl(%Array* %3, %Qubit* %4) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Z__ctladj__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) { +entry: + %0 = bitcast %Tuple* %arg-tuple to { %Array*, %Qubit* }* + %1 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 0 + %2 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 1 + %3 = load %Array*, %Array** %1, align 8 + %4 = load %Qubit*, %Qubit** %2, align 8 + call void @Microsoft__Quantum__Intrinsic__Z__ctladj(%Array* %3, %Qubit* %4) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Z__ctladj(%Array* %__controlQubits__, %Qubit* %qubit) { +entry: + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 1) + call void @Microsoft__Quantum__Intrinsic__Z__ctl(%Array* %__controlQubits__, %Qubit* %qubit) + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 -1) + ret void +} + +declare void @__quantum__rt__capture_update_alias_count(%Callable*, i32) + +declare void @__quantum__rt__callable_update_alias_count(%Callable*, i32) + +declare void @__quantum__rt__tuple_update_alias_count(%Tuple*, i32) + +declare void @__quantum__rt__qubit_release_array(%Array*) + +declare void @__quantum__rt__callable_invoke(%Callable*, %Tuple*, %Tuple*) + +define internal void @Microsoft__Quantum__Intrinsic___8f3359a2b69a47ffa9fd2508e6ea5641___QsRef23__ApplyWithLessControlsA____adj(%Callable* %op, { %Array*, { double, %Qubit* }* }* %0) { +entry: + call void @__quantum__rt__capture_update_alias_count(%Callable* %op, i32 1) + call void @__quantum__rt__callable_update_alias_count(%Callable* %op, i32 1) + %1 = getelementptr inbounds { %Array*, { double, %Qubit* }* }, { %Array*, { double, %Qubit* }* }* %0, i32 0, i32 0 + %controls = load %Array*, %Array** %1, align 8 + call void @__quantum__rt__array_update_alias_count(%Array* %controls, i32 1) + %2 = getelementptr inbounds { %Array*, { double, %Qubit* }* }, { %Array*, { double, %Qubit* }* }* %0, i32 0, i32 1 + %arg = load { double, %Qubit* }*, { double, %Qubit* }** %2, align 8 + %3 = bitcast { double, %Qubit* }* %arg to %Tuple* + call void @__quantum__rt__tuple_update_alias_count(%Tuple* %3, i32 1) + %__qsVar0__numControls__ = call i64 @__quantum__rt__array_get_size_1d(%Array* %controls) + %__qsVar1__numControlPairs__ = sdiv i64 %__qsVar0__numControls__, 2 + %__qsVar2__temps__ = call %Array* @__quantum__rt__qubit_allocate_array(i64 %__qsVar1__numControlPairs__) + call void @__quantum__rt__array_update_alias_count(%Array* %__qsVar2__temps__, i32 1) + %4 = sub i64 %__qsVar1__numControlPairs__, 1 + br label %header__1 + +header__1: ; preds = %exiting__1, %entry + %__qsVar0____qsVar3__numPair____ = phi i64 [ 0, %entry ], [ %18, %exiting__1 ] + %5 = icmp sle i64 %__qsVar0____qsVar3__numPair____, %4 + br i1 %5, label %body__1, label %exit__1 + +body__1: ; preds = %header__1 + %6 = mul i64 2, %__qsVar0____qsVar3__numPair____ + %7 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %controls, i64 %6) + %8 = bitcast i8* %7 to %Qubit** + %9 = load %Qubit*, %Qubit** %8, align 8 + %10 = mul i64 2, %__qsVar0____qsVar3__numPair____ + %11 = add i64 %10, 1 + %12 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %controls, i64 %11) + %13 = bitcast i8* %12 to %Qubit** + %14 = load %Qubit*, %Qubit** %13, align 8 + %15 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %__qsVar2__temps__, i64 %__qsVar0____qsVar3__numPair____) + %16 = bitcast i8* %15 to %Qubit** + %17 = load %Qubit*, %Qubit** %16, align 8 + call void @Microsoft__Quantum__Intrinsic____QsRef23__PhaseCCX____body(%Qubit* %9, %Qubit* %14, %Qubit* %17) + br label %exiting__1 + +exiting__1: ; preds = %body__1 + %18 = add i64 %__qsVar0____qsVar3__numPair____, 1 + br label %header__1 + +exit__1: ; preds = %header__1 + %19 = srem i64 %__qsVar0__numControls__, 2 + %20 = icmp eq i64 %19, 0 + br i1 %20, label %condTrue__1, label %condFalse__1 + +condTrue__1: ; preds = %exit__1 + call void @__quantum__rt__array_update_reference_count(%Array* %__qsVar2__temps__, i32 1) + br label %condContinue__1 + +condFalse__1: ; preds = %exit__1 + %21 = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) + %22 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %21, i64 0) + %23 = bitcast i8* %22 to %Qubit** + %24 = sub i64 %__qsVar0__numControls__, 1 + %25 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %controls, i64 %24) + %26 = bitcast i8* %25 to %Qubit** + %27 = load %Qubit*, %Qubit** %26, align 8 + store %Qubit* %27, %Qubit** %23, align 8 + %28 = call %Array* @__quantum__rt__array_concatenate(%Array* %__qsVar2__temps__, %Array* %21) + call void @__quantum__rt__array_update_reference_count(%Array* %28, i32 1) + call void @__quantum__rt__array_update_reference_count(%Array* %21, i32 -1) + call void @__quantum__rt__array_update_reference_count(%Array* %28, i32 -1) + br label %condContinue__1 + +condContinue__1: ; preds = %condFalse__1, %condTrue__1 + %__qsVar1____qsVar4__newControls____ = phi %Array* [ %__qsVar2__temps__, %condTrue__1 ], [ %28, %condFalse__1 ] + call void @__quantum__rt__array_update_alias_count(%Array* %__qsVar1____qsVar4__newControls____, i32 1) + %29 = call %Callable* @__quantum__rt__callable_copy(%Callable* %op, i1 false) + call void @__quantum__rt__capture_update_reference_count(%Callable* %29, i32 1) + call void @__quantum__rt__callable_make_adjoint(%Callable* %29) + %30 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 2)) + %31 = bitcast %Tuple* %30 to { %Array*, { double, %Qubit* }* }* + %32 = getelementptr inbounds { %Array*, { double, %Qubit* }* }, { %Array*, { double, %Qubit* }* }* %31, i32 0, i32 0 + %33 = getelementptr inbounds { %Array*, { double, %Qubit* }* }, { %Array*, { double, %Qubit* }* }* %31, i32 0, i32 1 + call void @__quantum__rt__array_update_reference_count(%Array* %__qsVar1____qsVar4__newControls____, i32 1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %3, i32 1) + store %Array* %__qsVar1____qsVar4__newControls____, %Array** %32, align 8 + store { double, %Qubit* }* %arg, { double, %Qubit* }** %33, align 8 + call void @__quantum__rt__callable_invoke(%Callable* %29, %Tuple* %30, %Tuple* null) + %34 = sub i64 %__qsVar1__numControlPairs__, 1 + %35 = sub i64 %34, 0 + %36 = sdiv i64 %35, 1 + %37 = mul i64 1, %36 + %38 = add i64 0, %37 + %39 = load %Range, %Range* @EmptyRange, align 4 + %40 = insertvalue %Range %39, i64 %38, 0 + %41 = insertvalue %Range %40, i64 -1, 1 + %42 = insertvalue %Range %41, i64 0, 2 + %43 = extractvalue %Range %42, 0 + %44 = extractvalue %Range %42, 1 + %45 = extractvalue %Range %42, 2 + br label %preheader__1 + +preheader__1: ; preds = %condContinue__1 + %46 = icmp sgt i64 %44, 0 + br label %header__2 + +header__2: ; preds = %exiting__2, %preheader__1 + %__qsVar0____qsVar0____qsVar3__numPair______ = phi i64 [ %43, %preheader__1 ], [ %62, %exiting__2 ] + %47 = icmp sle i64 %__qsVar0____qsVar0____qsVar3__numPair______, %45 + %48 = icmp sge i64 %__qsVar0____qsVar0____qsVar3__numPair______, %45 + %49 = select i1 %46, i1 %47, i1 %48 + br i1 %49, label %body__2, label %exit__2 + +body__2: ; preds = %header__2 + %50 = mul i64 2, %__qsVar0____qsVar0____qsVar3__numPair______ + %51 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %controls, i64 %50) + %52 = bitcast i8* %51 to %Qubit** + %53 = load %Qubit*, %Qubit** %52, align 8 + %54 = mul i64 2, %__qsVar0____qsVar0____qsVar3__numPair______ + %55 = add i64 %54, 1 + %56 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %controls, i64 %55) + %57 = bitcast i8* %56 to %Qubit** + %58 = load %Qubit*, %Qubit** %57, align 8 + %59 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %__qsVar2__temps__, i64 %__qsVar0____qsVar0____qsVar3__numPair______) + %60 = bitcast i8* %59 to %Qubit** + %61 = load %Qubit*, %Qubit** %60, align 8 + call void @Microsoft__Quantum__Intrinsic____QsRef23__PhaseCCX____adj(%Qubit* %53, %Qubit* %58, %Qubit* %61) + br label %exiting__2 + +exiting__2: ; preds = %body__2 + %62 = add i64 %__qsVar0____qsVar0____qsVar3__numPair______, %44 + br label %header__2 + +exit__2: ; preds = %header__2 + call void @__quantum__rt__array_update_alias_count(%Array* %__qsVar2__temps__, i32 -1) + call void @__quantum__rt__array_update_alias_count(%Array* %__qsVar1____qsVar4__newControls____, i32 -1) + call void @__quantum__rt__array_update_reference_count(%Array* %__qsVar1____qsVar4__newControls____, i32 -1) + call void @__quantum__rt__capture_update_reference_count(%Callable* %29, i32 -1) + call void @__quantum__rt__callable_update_reference_count(%Callable* %29, i32 -1) + call void @__quantum__rt__array_update_reference_count(%Array* %__qsVar1____qsVar4__newControls____, i32 -1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %3, i32 -1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %30, i32 -1) + call void @__quantum__rt__qubit_release_array(%Array* %__qsVar2__temps__) + call void @__quantum__rt__capture_update_alias_count(%Callable* %op, i32 -1) + call void @__quantum__rt__callable_update_alias_count(%Callable* %op, i32 -1) + call void @__quantum__rt__array_update_alias_count(%Array* %controls, i32 -1) + call void @__quantum__rt__tuple_update_alias_count(%Tuple* %3, i32 -1) + ret void +} + +declare %Callable* @__quantum__rt__callable_copy(%Callable*, i1) + +define internal void @Microsoft__Quantum__Intrinsic___067288bb3b0f4c3fa16d90a27710fc06___QsRef23__ApplyWithLessControlsA____adj(%Callable* %op, { %Array*, %Qubit* }* %0) { +entry: + call void @__quantum__rt__capture_update_alias_count(%Callable* %op, i32 1) + call void @__quantum__rt__callable_update_alias_count(%Callable* %op, i32 1) + %1 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 0 + %controls = load %Array*, %Array** %1, align 8 + call void @__quantum__rt__array_update_alias_count(%Array* %controls, i32 1) + %2 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 1 + %arg = load %Qubit*, %Qubit** %2, align 8 + %__qsVar0__numControls__ = call i64 @__quantum__rt__array_get_size_1d(%Array* %controls) + %__qsVar1__numControlPairs__ = sdiv i64 %__qsVar0__numControls__, 2 + %__qsVar2__temps__ = call %Array* @__quantum__rt__qubit_allocate_array(i64 %__qsVar1__numControlPairs__) + call void @__quantum__rt__array_update_alias_count(%Array* %__qsVar2__temps__, i32 1) + %3 = sub i64 %__qsVar1__numControlPairs__, 1 + br label %header__1 + +header__1: ; preds = %exiting__1, %entry + %__qsVar0____qsVar3__numPair____ = phi i64 [ 0, %entry ], [ %17, %exiting__1 ] + %4 = icmp sle i64 %__qsVar0____qsVar3__numPair____, %3 + br i1 %4, label %body__1, label %exit__1 + +body__1: ; preds = %header__1 + %5 = mul i64 2, %__qsVar0____qsVar3__numPair____ + %6 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %controls, i64 %5) + %7 = bitcast i8* %6 to %Qubit** + %8 = load %Qubit*, %Qubit** %7, align 8 + %9 = mul i64 2, %__qsVar0____qsVar3__numPair____ + %10 = add i64 %9, 1 + %11 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %controls, i64 %10) + %12 = bitcast i8* %11 to %Qubit** + %13 = load %Qubit*, %Qubit** %12, align 8 + %14 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %__qsVar2__temps__, i64 %__qsVar0____qsVar3__numPair____) + %15 = bitcast i8* %14 to %Qubit** + %16 = load %Qubit*, %Qubit** %15, align 8 + call void @Microsoft__Quantum__Intrinsic____QsRef23__PhaseCCX____body(%Qubit* %8, %Qubit* %13, %Qubit* %16) + br label %exiting__1 + +exiting__1: ; preds = %body__1 + %17 = add i64 %__qsVar0____qsVar3__numPair____, 1 + br label %header__1 + +exit__1: ; preds = %header__1 + %18 = srem i64 %__qsVar0__numControls__, 2 + %19 = icmp eq i64 %18, 0 + br i1 %19, label %condTrue__1, label %condFalse__1 + +condTrue__1: ; preds = %exit__1 + call void @__quantum__rt__array_update_reference_count(%Array* %__qsVar2__temps__, i32 1) + br label %condContinue__1 + +condFalse__1: ; preds = %exit__1 + %20 = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) + %21 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %20, i64 0) + %22 = bitcast i8* %21 to %Qubit** + %23 = sub i64 %__qsVar0__numControls__, 1 + %24 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %controls, i64 %23) + %25 = bitcast i8* %24 to %Qubit** + %26 = load %Qubit*, %Qubit** %25, align 8 + store %Qubit* %26, %Qubit** %22, align 8 + %27 = call %Array* @__quantum__rt__array_concatenate(%Array* %__qsVar2__temps__, %Array* %20) + call void @__quantum__rt__array_update_reference_count(%Array* %27, i32 1) + call void @__quantum__rt__array_update_reference_count(%Array* %20, i32 -1) + call void @__quantum__rt__array_update_reference_count(%Array* %27, i32 -1) + br label %condContinue__1 + +condContinue__1: ; preds = %condFalse__1, %condTrue__1 + %__qsVar1____qsVar4__newControls____ = phi %Array* [ %__qsVar2__temps__, %condTrue__1 ], [ %27, %condFalse__1 ] + call void @__quantum__rt__array_update_alias_count(%Array* %__qsVar1____qsVar4__newControls____, i32 1) + %28 = call %Callable* @__quantum__rt__callable_copy(%Callable* %op, i1 false) + call void @__quantum__rt__capture_update_reference_count(%Callable* %28, i32 1) + call void @__quantum__rt__callable_make_adjoint(%Callable* %28) + %29 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 2)) + %30 = bitcast %Tuple* %29 to { %Array*, %Qubit* }* + %31 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %30, i32 0, i32 0 + %32 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %30, i32 0, i32 1 + call void @__quantum__rt__array_update_reference_count(%Array* %__qsVar1____qsVar4__newControls____, i32 1) + store %Array* %__qsVar1____qsVar4__newControls____, %Array** %31, align 8 + store %Qubit* %arg, %Qubit** %32, align 8 + call void @__quantum__rt__callable_invoke(%Callable* %28, %Tuple* %29, %Tuple* null) + %33 = sub i64 %__qsVar1__numControlPairs__, 1 + %34 = sub i64 %33, 0 + %35 = sdiv i64 %34, 1 + %36 = mul i64 1, %35 + %37 = add i64 0, %36 + %38 = load %Range, %Range* @EmptyRange, align 4 + %39 = insertvalue %Range %38, i64 %37, 0 + %40 = insertvalue %Range %39, i64 -1, 1 + %41 = insertvalue %Range %40, i64 0, 2 + %42 = extractvalue %Range %41, 0 + %43 = extractvalue %Range %41, 1 + %44 = extractvalue %Range %41, 2 + br label %preheader__1 + +preheader__1: ; preds = %condContinue__1 + %45 = icmp sgt i64 %43, 0 + br label %header__2 + +header__2: ; preds = %exiting__2, %preheader__1 + %__qsVar0____qsVar0____qsVar3__numPair______ = phi i64 [ %42, %preheader__1 ], [ %61, %exiting__2 ] + %46 = icmp sle i64 %__qsVar0____qsVar0____qsVar3__numPair______, %44 + %47 = icmp sge i64 %__qsVar0____qsVar0____qsVar3__numPair______, %44 + %48 = select i1 %45, i1 %46, i1 %47 + br i1 %48, label %body__2, label %exit__2 + +body__2: ; preds = %header__2 + %49 = mul i64 2, %__qsVar0____qsVar0____qsVar3__numPair______ + %50 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %controls, i64 %49) + %51 = bitcast i8* %50 to %Qubit** + %52 = load %Qubit*, %Qubit** %51, align 8 + %53 = mul i64 2, %__qsVar0____qsVar0____qsVar3__numPair______ + %54 = add i64 %53, 1 + %55 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %controls, i64 %54) + %56 = bitcast i8* %55 to %Qubit** + %57 = load %Qubit*, %Qubit** %56, align 8 + %58 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %__qsVar2__temps__, i64 %__qsVar0____qsVar0____qsVar3__numPair______) + %59 = bitcast i8* %58 to %Qubit** + %60 = load %Qubit*, %Qubit** %59, align 8 + call void @Microsoft__Quantum__Intrinsic____QsRef23__PhaseCCX____adj(%Qubit* %52, %Qubit* %57, %Qubit* %60) + br label %exiting__2 + +exiting__2: ; preds = %body__2 + %61 = add i64 %__qsVar0____qsVar0____qsVar3__numPair______, %43 + br label %header__2 + +exit__2: ; preds = %header__2 + call void @__quantum__rt__array_update_alias_count(%Array* %__qsVar2__temps__, i32 -1) + call void @__quantum__rt__array_update_alias_count(%Array* %__qsVar1____qsVar4__newControls____, i32 -1) + call void @__quantum__rt__array_update_reference_count(%Array* %__qsVar1____qsVar4__newControls____, i32 -1) + call void @__quantum__rt__capture_update_reference_count(%Callable* %28, i32 -1) + call void @__quantum__rt__callable_update_reference_count(%Callable* %28, i32 -1) + call void @__quantum__rt__array_update_reference_count(%Array* %__qsVar1____qsVar4__newControls____, i32 -1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %29, i32 -1) + call void @__quantum__rt__qubit_release_array(%Array* %__qsVar2__temps__) + call void @__quantum__rt__capture_update_alias_count(%Callable* %op, i32 -1) + call void @__quantum__rt__callable_update_alias_count(%Callable* %op, i32 -1) + call void @__quantum__rt__array_update_alias_count(%Array* %controls, i32 -1) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic___0d8cf5dbd1bf4f63a0469c30490db51e___QsRef23__ApplyWithLessControlsA____adj(%Callable* %op, { %Array*, { %Qubit*, %Qubit* }* }* %0) { +entry: + call void @__quantum__rt__capture_update_alias_count(%Callable* %op, i32 1) + call void @__quantum__rt__callable_update_alias_count(%Callable* %op, i32 1) + %1 = getelementptr inbounds { %Array*, { %Qubit*, %Qubit* }* }, { %Array*, { %Qubit*, %Qubit* }* }* %0, i32 0, i32 0 + %controls = load %Array*, %Array** %1, align 8 + call void @__quantum__rt__array_update_alias_count(%Array* %controls, i32 1) + %2 = getelementptr inbounds { %Array*, { %Qubit*, %Qubit* }* }, { %Array*, { %Qubit*, %Qubit* }* }* %0, i32 0, i32 1 + %arg = load { %Qubit*, %Qubit* }*, { %Qubit*, %Qubit* }** %2, align 8 + %3 = bitcast { %Qubit*, %Qubit* }* %arg to %Tuple* + call void @__quantum__rt__tuple_update_alias_count(%Tuple* %3, i32 1) + %__qsVar0__numControls__ = call i64 @__quantum__rt__array_get_size_1d(%Array* %controls) + %__qsVar1__numControlPairs__ = sdiv i64 %__qsVar0__numControls__, 2 + %__qsVar2__temps__ = call %Array* @__quantum__rt__qubit_allocate_array(i64 %__qsVar1__numControlPairs__) + call void @__quantum__rt__array_update_alias_count(%Array* %__qsVar2__temps__, i32 1) + %4 = sub i64 %__qsVar1__numControlPairs__, 1 + br label %header__1 + +header__1: ; preds = %exiting__1, %entry + %__qsVar0____qsVar3__numPair____ = phi i64 [ 0, %entry ], [ %18, %exiting__1 ] + %5 = icmp sle i64 %__qsVar0____qsVar3__numPair____, %4 + br i1 %5, label %body__1, label %exit__1 + +body__1: ; preds = %header__1 + %6 = mul i64 2, %__qsVar0____qsVar3__numPair____ + %7 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %controls, i64 %6) + %8 = bitcast i8* %7 to %Qubit** + %9 = load %Qubit*, %Qubit** %8, align 8 + %10 = mul i64 2, %__qsVar0____qsVar3__numPair____ + %11 = add i64 %10, 1 + %12 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %controls, i64 %11) + %13 = bitcast i8* %12 to %Qubit** + %14 = load %Qubit*, %Qubit** %13, align 8 + %15 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %__qsVar2__temps__, i64 %__qsVar0____qsVar3__numPair____) + %16 = bitcast i8* %15 to %Qubit** + %17 = load %Qubit*, %Qubit** %16, align 8 + call void @Microsoft__Quantum__Intrinsic____QsRef23__PhaseCCX____body(%Qubit* %9, %Qubit* %14, %Qubit* %17) + br label %exiting__1 + +exiting__1: ; preds = %body__1 + %18 = add i64 %__qsVar0____qsVar3__numPair____, 1 + br label %header__1 + +exit__1: ; preds = %header__1 + %19 = srem i64 %__qsVar0__numControls__, 2 + %20 = icmp eq i64 %19, 0 + br i1 %20, label %condTrue__1, label %condFalse__1 + +condTrue__1: ; preds = %exit__1 + call void @__quantum__rt__array_update_reference_count(%Array* %__qsVar2__temps__, i32 1) + br label %condContinue__1 + +condFalse__1: ; preds = %exit__1 + %21 = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) + %22 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %21, i64 0) + %23 = bitcast i8* %22 to %Qubit** + %24 = sub i64 %__qsVar0__numControls__, 1 + %25 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %controls, i64 %24) + %26 = bitcast i8* %25 to %Qubit** + %27 = load %Qubit*, %Qubit** %26, align 8 + store %Qubit* %27, %Qubit** %23, align 8 + %28 = call %Array* @__quantum__rt__array_concatenate(%Array* %__qsVar2__temps__, %Array* %21) + call void @__quantum__rt__array_update_reference_count(%Array* %28, i32 1) + call void @__quantum__rt__array_update_reference_count(%Array* %21, i32 -1) + call void @__quantum__rt__array_update_reference_count(%Array* %28, i32 -1) + br label %condContinue__1 + +condContinue__1: ; preds = %condFalse__1, %condTrue__1 + %__qsVar1____qsVar4__newControls____ = phi %Array* [ %__qsVar2__temps__, %condTrue__1 ], [ %28, %condFalse__1 ] + call void @__quantum__rt__array_update_alias_count(%Array* %__qsVar1____qsVar4__newControls____, i32 1) + %29 = call %Callable* @__quantum__rt__callable_copy(%Callable* %op, i1 false) + call void @__quantum__rt__capture_update_reference_count(%Callable* %29, i32 1) + call void @__quantum__rt__callable_make_adjoint(%Callable* %29) + %30 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 2)) + %31 = bitcast %Tuple* %30 to { %Array*, { %Qubit*, %Qubit* }* }* + %32 = getelementptr inbounds { %Array*, { %Qubit*, %Qubit* }* }, { %Array*, { %Qubit*, %Qubit* }* }* %31, i32 0, i32 0 + %33 = getelementptr inbounds { %Array*, { %Qubit*, %Qubit* }* }, { %Array*, { %Qubit*, %Qubit* }* }* %31, i32 0, i32 1 + call void @__quantum__rt__array_update_reference_count(%Array* %__qsVar1____qsVar4__newControls____, i32 1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %3, i32 1) + store %Array* %__qsVar1____qsVar4__newControls____, %Array** %32, align 8 + store { %Qubit*, %Qubit* }* %arg, { %Qubit*, %Qubit* }** %33, align 8 + call void @__quantum__rt__callable_invoke(%Callable* %29, %Tuple* %30, %Tuple* null) + %34 = sub i64 %__qsVar1__numControlPairs__, 1 + %35 = sub i64 %34, 0 + %36 = sdiv i64 %35, 1 + %37 = mul i64 1, %36 + %38 = add i64 0, %37 + %39 = load %Range, %Range* @EmptyRange, align 4 + %40 = insertvalue %Range %39, i64 %38, 0 + %41 = insertvalue %Range %40, i64 -1, 1 + %42 = insertvalue %Range %41, i64 0, 2 + %43 = extractvalue %Range %42, 0 + %44 = extractvalue %Range %42, 1 + %45 = extractvalue %Range %42, 2 + br label %preheader__1 + +preheader__1: ; preds = %condContinue__1 + %46 = icmp sgt i64 %44, 0 + br label %header__2 + +header__2: ; preds = %exiting__2, %preheader__1 + %__qsVar0____qsVar0____qsVar3__numPair______ = phi i64 [ %43, %preheader__1 ], [ %62, %exiting__2 ] + %47 = icmp sle i64 %__qsVar0____qsVar0____qsVar3__numPair______, %45 + %48 = icmp sge i64 %__qsVar0____qsVar0____qsVar3__numPair______, %45 + %49 = select i1 %46, i1 %47, i1 %48 + br i1 %49, label %body__2, label %exit__2 + +body__2: ; preds = %header__2 + %50 = mul i64 2, %__qsVar0____qsVar0____qsVar3__numPair______ + %51 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %controls, i64 %50) + %52 = bitcast i8* %51 to %Qubit** + %53 = load %Qubit*, %Qubit** %52, align 8 + %54 = mul i64 2, %__qsVar0____qsVar0____qsVar3__numPair______ + %55 = add i64 %54, 1 + %56 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %controls, i64 %55) + %57 = bitcast i8* %56 to %Qubit** + %58 = load %Qubit*, %Qubit** %57, align 8 + %59 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %__qsVar2__temps__, i64 %__qsVar0____qsVar0____qsVar3__numPair______) + %60 = bitcast i8* %59 to %Qubit** + %61 = load %Qubit*, %Qubit** %60, align 8 + call void @Microsoft__Quantum__Intrinsic____QsRef23__PhaseCCX____adj(%Qubit* %53, %Qubit* %58, %Qubit* %61) + br label %exiting__2 + +exiting__2: ; preds = %body__2 + %62 = add i64 %__qsVar0____qsVar0____qsVar3__numPair______, %44 + br label %header__2 + +exit__2: ; preds = %header__2 + call void @__quantum__rt__array_update_alias_count(%Array* %__qsVar2__temps__, i32 -1) + call void @__quantum__rt__array_update_alias_count(%Array* %__qsVar1____qsVar4__newControls____, i32 -1) + call void @__quantum__rt__array_update_reference_count(%Array* %__qsVar1____qsVar4__newControls____, i32 -1) + call void @__quantum__rt__capture_update_reference_count(%Callable* %29, i32 -1) + call void @__quantum__rt__callable_update_reference_count(%Callable* %29, i32 -1) + call void @__quantum__rt__array_update_reference_count(%Array* %__qsVar1____qsVar4__newControls____, i32 -1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %3, i32 -1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %30, i32 -1) + call void @__quantum__rt__qubit_release_array(%Array* %__qsVar2__temps__) + call void @__quantum__rt__capture_update_alias_count(%Callable* %op, i32 -1) + call void @__quantum__rt__callable_update_alias_count(%Callable* %op, i32 -1) + call void @__quantum__rt__array_update_alias_count(%Array* %controls, i32 -1) + call void @__quantum__rt__tuple_update_alias_count(%Tuple* %3, i32 -1) + ret void +} + +declare %Result* @__quantum__qis__m__body(%Qubit*) + +define double @Microsoft__Quantum__Qir__Emission__EstimatePhaseByRandomWalk__Interop() #1 { +entry: + %0 = call double @Microsoft__Quantum__Qir__Emission__EstimatePhaseByRandomWalk__body() + ret double %0 +} + +define void @Microsoft__Quantum__Qir__Emission__EstimatePhaseByRandomWalk() #2 { +entry: + %0 = call double @Microsoft__Quantum__Qir__Emission__EstimatePhaseByRandomWalk__body() + %1 = call %String* @__quantum__rt__double_to_string(double %0) + call void @__quantum__rt__message(%String* %1) + call void @__quantum__rt__string_update_reference_count(%String* %1, i32 -1) + ret void +} + +declare void @__quantum__rt__message(%String*) + +declare %String* @__quantum__rt__double_to_string(double) + +declare void @__quantum__rt__string_update_reference_count(%String*, i32) + +attributes #0 = { nounwind readnone speculatable willreturn } +attributes #1 = { "InteropFriendly" } +attributes #2 = { "EntryPoint" } diff --git a/src/QirTools/pyqir/tests/test_api.py b/src/QirTools/pyqir/tests/test_api.py index c9780fc84c..c9537dceef 100644 --- a/src/QirTools/pyqir/tests/test_api.py +++ b/src/QirTools/pyqir/tests/test_api.py @@ -1,4 +1,5 @@ from pyqir import QirBuilder +from pyqir import module_from_bitcode import pytest def test_bell(tmpdir): @@ -127,3 +128,22 @@ def test_bernstein_vazirani_ir_string(): ir = builder.get_ir_string() assert ir.startswith("; ModuleID = 'Bernstein-Vazirani'") + +def test_parser(): + mod = module_from_bitcode("tests/randwalkphaseest.baseprofile.bc") + funcName = "Microsoft__Quantum__Qir__Emission__EstimatePhaseByRandomWalk__Interop" + func = mod.get_func_by_name(funcName) + assert(func.name == funcName) + assert(len(func.parameters) == 0) + assert(func.return_type.is_floating_point) + funcList = mod.functions + assert(len(funcList) == 1) + assert(funcList[0].name == funcName) + interop_funcs = mod.get_funcs_by_attr("InteropFriendly") + assert(len(interop_funcs) == 1) + assert(interop_funcs[0].name == funcName) + assert(interop_funcs[0].get_attribute_value("requiredQubits") == "2") + assert(interop_funcs[0].required_qubits == 2) + blocks = func.blocks + assert(len(blocks) == 3) + entry_block = func.get_block_by_name("entry") From 9f24e7f249bb1271fd03cb360f10f3b36cf1d153 Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Thu, 7 Oct 2021 22:58:24 -0700 Subject: [PATCH 02/26] Add basic block and terminator, start instruction --- Cargo.lock | 1 + src/QirTools/pyqir/Cargo.toml.template | 1 + src/QirTools/pyqir/src/parser.rs | 705 ++++++++++++- .../tests/randwalkphaseest.baseprofile.bc | Bin 2452 -> 0 bytes .../randwalkphaseest.baseprofile.ll.reference | 78 -- .../pyqir/tests/teleportchain.baseprofile.bc | Bin 0 -> 2896 bytes .../teleportchain.baseprofile.ll.reference | 111 ++ ...l.reference => teleportchain.ll.reference} | 946 ++++++++++-------- src/QirTools/pyqir/tests/test_api.py | 23 +- 9 files changed, 1303 insertions(+), 562 deletions(-) delete mode 100644 src/QirTools/pyqir/tests/randwalkphaseest.baseprofile.bc delete mode 100644 src/QirTools/pyqir/tests/randwalkphaseest.baseprofile.ll.reference create mode 100644 src/QirTools/pyqir/tests/teleportchain.baseprofile.bc create mode 100644 src/QirTools/pyqir/tests/teleportchain.baseprofile.ll.reference rename src/QirTools/pyqir/tests/{randwalkphaseest.ll.reference => teleportchain.ll.reference} (91%) diff --git a/Cargo.lock b/Cargo.lock index de8888b250..a8362dcba0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -349,6 +349,7 @@ dependencies = [ name = "pyqir" version = "0.9999.2110-alpha" dependencies = [ + "either", "env_logger", "llvm-ir", "log", diff --git a/src/QirTools/pyqir/Cargo.toml.template b/src/QirTools/pyqir/Cargo.toml.template index 6952353648..e87744ba68 100644 --- a/src/QirTools/pyqir/Cargo.toml.template +++ b/src/QirTools/pyqir/Cargo.toml.template @@ -29,6 +29,7 @@ qirlib = {path = "../qirlib"} env_logger = "0.9.0" log = "0.4.14" llvm-ir = { version = "0.8.0", features = ["llvm-11"] } +either = "1.5.3" [dependencies.pyo3] version = "0.14.2" diff --git a/src/QirTools/pyqir/src/parser.rs b/src/QirTools/pyqir/src/parser.rs index 2b36d9cba1..8900a025b1 100644 --- a/src/QirTools/pyqir/src/parser.rs +++ b/src/QirTools/pyqir/src/parser.rs @@ -20,16 +20,6 @@ pub struct QirParameter { pub(super) param: llvm_ir::function::Parameter, } -#[pyclass] -pub struct QirType { - pub(super) typeref: llvm_ir::TypeRef, -} - -#[pyclass] -pub struct QirFunctionAttribute { - pub(super) attr: llvm_ir::function::FunctionAttribute, -} - #[pyclass] pub struct QirBasicBlock { pub(super) block: llvm_ir::BasicBlock, @@ -45,6 +35,21 @@ pub struct QirTerminator { pub(super) term: llvm_ir::terminator::Terminator, } +#[pyclass] +pub struct QirOperand { + pub(super) op: llvm_ir::Operand, +} + +#[pyclass] +pub struct QirConstant { + pub(super) constantref: llvm_ir::ConstantRef, +} + +#[pyclass] +pub struct QirType { + pub(super) typeref: llvm_ir::TypeRef, +} + #[pymethods] impl QirModule { #[getter] @@ -112,15 +117,6 @@ impl QirFunction { } } - #[getter] - fn get_attributes(&self) -> Vec { - self.function - .function_attributes - .iter() - .map(|a| QirFunctionAttribute { attr: a.clone() }) - .collect() - } - #[getter] fn get_blocks(&self) -> Vec { self.function @@ -192,6 +188,557 @@ impl QirParameter { } } +#[pymethods] +impl QirBasicBlock { + #[getter] + fn get_name(&self) -> String { + name_to_string(&self.block.name) + } + + #[getter] + fn get_instructions(&self) -> Vec { + self.block + .instrs + .iter() + .map(|i| QirInstruction { instr: i.clone() }) + .collect() + } + + #[getter] + fn get_terminator(&self) -> QirTerminator { + QirTerminator { + term: self.block.term.clone(), + } + } +} + +#[pymethods] +impl QirInstruction { + #[getter] + fn get_is_add(&self) -> bool { + match self.instr { + llvm_ir::instruction::Instruction::Add(_) => true, + _ => false, + } + } + + #[getter] + fn get_is_sub(&self) -> bool { + match self.instr { + llvm_ir::instruction::Instruction::Sub(_) => true, + _ => false, + } + } + + #[getter] + fn get_is_mul(&self) -> bool { + match self.instr { + llvm_ir::instruction::Instruction::Mul(_) => true, + _ => false, + } + } + + #[getter] + fn get_is_udiv(&self) -> bool { + match self.instr { + llvm_ir::instruction::Instruction::UDiv(_) => true, + _ => false, + } + } + + #[getter] + fn get_is_sdiv(&self) -> bool { + match self.instr { + llvm_ir::instruction::Instruction::SDiv(_) => true, + _ => false, + } + } + + #[getter] + fn get_is_urem(&self) -> bool { + match self.instr { + llvm_ir::instruction::Instruction::URem(_) => true, + _ => false, + } + } + + #[getter] + fn get_is_srem(&self) -> bool { + match self.instr { + llvm_ir::instruction::Instruction::SRem(_) => true, + _ => false, + } + } + + #[getter] + fn get_is_and(&self) -> bool { + match self.instr { + llvm_ir::instruction::Instruction::And(_) => true, + _ => false, + } + } + + #[getter] + fn get_is_or(&self) -> bool { + match self.instr { + llvm_ir::instruction::Instruction::Or(_) => true, + _ => false, + } + } + + #[getter] + fn get_is_xor(&self) -> bool { + match self.instr { + llvm_ir::instruction::Instruction::Xor(_) => true, + _ => false, + } + } + + #[getter] + fn get_is_shl(&self) -> bool { + match self.instr { + llvm_ir::instruction::Instruction::Shl(_) => true, + _ => false, + } + } + + #[getter] + fn get_is_lshr(&self) -> bool { + match self.instr { + llvm_ir::instruction::Instruction::LShr(_) => true, + _ => false, + } + } + + #[getter] + fn get_is_ashr(&self) -> bool { + match self.instr { + llvm_ir::instruction::Instruction::AShr(_) => true, + _ => false, + } + } + + #[getter] + fn get_is_fadd(&self) -> bool { + match self.instr { + llvm_ir::instruction::Instruction::FAdd(_) => true, + _ => false, + } + } + + #[getter] + fn get_is_fsub(&self) -> bool { + match self.instr { + llvm_ir::instruction::Instruction::FSub(_) => true, + _ => false, + } + } + + #[getter] + fn get_is_fmul(&self) -> bool { + match self.instr { + llvm_ir::instruction::Instruction::FMul(_) => true, + _ => false, + } + } + + #[getter] + fn get_is_fdiv(&self) -> bool { + match self.instr { + llvm_ir::instruction::Instruction::FDiv(_) => true, + _ => false, + } + } + + #[getter] + fn get_is_frem(&self) -> bool { + match self.instr { + llvm_ir::instruction::Instruction::FRem(_) => true, + _ => false, + } + } + + #[getter] + fn get_is_fneg(&self) -> bool { + match self.instr { + llvm_ir::instruction::Instruction::FNeg(_) => true, + _ => false, + } + } + + #[getter] + fn get_is_extractelement(&self) -> bool { + match self.instr { + llvm_ir::instruction::Instruction::ExtractElement(_) => true, + _ => false, + } + } + + #[getter] + fn get_is_insertelement(&self) -> bool { + match self.instr { + llvm_ir::instruction::Instruction::InsertElement(_) => true, + _ => false, + } + } + + #[getter] + fn get_is_shufflevector(&self) -> bool { + match self.instr { + llvm_ir::instruction::Instruction::ShuffleVector(_) => true, + _ => false, + } + } + + #[getter] + fn get_is_extractvalue(&self) -> bool { + match self.instr { + llvm_ir::instruction::Instruction::ExtractValue(_) => true, + _ => false, + } + } + + #[getter] + fn get_is_insertvalue(&self) -> bool { + match self.instr { + llvm_ir::instruction::Instruction::InsertValue(_) => true, + _ => false, + } + } + + #[getter] + fn get_is_alloca(&self) -> bool { + match self.instr { + llvm_ir::instruction::Instruction::Alloca(_) => true, + _ => false, + } + } + + #[getter] + fn get_is_load(&self) -> bool { + match self.instr { + llvm_ir::instruction::Instruction::Load(_) => true, + _ => false, + } + } + + #[getter] + fn get_is_store(&self) -> bool { + match self.instr { + llvm_ir::instruction::Instruction::Store(_) => true, + _ => false, + } + } + + #[getter] + fn get_is_getelementptr(&self) -> bool { + match self.instr { + llvm_ir::instruction::Instruction::GetElementPtr(_) => true, + _ => false, + } + } + + #[getter] + fn get_is_trunc(&self) -> bool { + match self.instr { + llvm_ir::instruction::Instruction::Trunc(_) => true, + _ => false, + } + } + + #[getter] + fn get_is_zext(&self) -> bool { + match self.instr { + llvm_ir::instruction::Instruction::ZExt(_) => true, + _ => false, + } + } + + #[getter] + fn get_is_sext(&self) -> bool { + match self.instr { + llvm_ir::instruction::Instruction::SExt(_) => true, + _ => false, + } + } + + #[getter] + fn get_is_fptrunc(&self) -> bool { + match self.instr { + llvm_ir::instruction::Instruction::FPTrunc(_) => true, + _ => false, + } + } + + #[getter] + fn get_is_fpext(&self) -> bool { + match self.instr { + llvm_ir::instruction::Instruction::FPExt(_) => true, + _ => false, + } + } + + #[getter] + fn get_is_fptoui(&self) -> bool { + match self.instr { + llvm_ir::instruction::Instruction::FPToUI(_) => true, + _ => false, + } + } + + #[getter] + fn get_is_fptosi(&self) -> bool { + match self.instr { + llvm_ir::instruction::Instruction::FPToSI(_) => true, + _ => false, + } + } + + #[getter] + fn get_is_uitofp(&self) -> bool { + match self.instr { + llvm_ir::instruction::Instruction::UIToFP(_) => true, + _ => false, + } + } + + #[getter] + fn get_is_sitofp(&self) -> bool { + match self.instr { + llvm_ir::instruction::Instruction::SIToFP(_) => true, + _ => false, + } + } + + #[getter] + fn get_is_ptrtoint(&self) -> bool { + match self.instr { + llvm_ir::instruction::Instruction::PtrToInt(_) => true, + _ => false, + } + } + + #[getter] + fn get_is_inttoptr(&self) -> bool { + match self.instr { + llvm_ir::instruction::Instruction::IntToPtr(_) => true, + _ => false, + } + } + + #[getter] + fn get_is_bitcast(&self) -> bool { + match self.instr { + llvm_ir::instruction::Instruction::BitCast(_) => true, + _ => false, + } + } + + #[getter] + fn get_is_addrspacecast(&self) -> bool { + match self.instr { + llvm_ir::instruction::Instruction::AddrSpaceCast(_) => true, + _ => false, + } + } + + #[getter] + fn get_is_icmp(&self) -> bool { + match self.instr { + llvm_ir::instruction::Instruction::ICmp(_) => true, + _ => false, + } + } + + #[getter] + fn get_is_fcmp(&self) -> bool { + match self.instr { + llvm_ir::instruction::Instruction::FCmp(_) => true, + _ => false, + } + } + + #[getter] + fn get_is_phi(&self) -> bool { + match self.instr { + llvm_ir::instruction::Instruction::Phi(_) => true, + _ => false, + } + } + + #[getter] + fn get_is_select(&self) -> bool { + match self.instr { + llvm_ir::instruction::Instruction::Select(_) => true, + _ => false, + } + } + + #[getter] + fn get_is_call(&self) -> bool { + match self.instr { + llvm_ir::instruction::Instruction::Call(_) => true, + _ => false, + } + } +} + +#[pymethods] +impl QirTerminator { + #[getter] + fn get_is_ret(&self) -> bool { + match self.term { + llvm_ir::terminator::Terminator::Ret(_) => true, + _ => false, + } + } + + #[getter] + fn get_ret_operand(&self) -> PyResult { + match &self.term { + llvm_ir::terminator::Terminator::Ret(llvm_ir::terminator::Ret { + return_operand, + debugloc: _, + }) => match return_operand { + Some(op) => Ok(QirOperand { op: op.clone() }), + None => Err(exceptions::PyTypeError::new_err( + "Return is void and has no operand.", + )), + }, + _ => Err(exceptions::PyTypeError::new_err( + "Terminator is not return.", + )), + } + } + + #[getter] + fn get_is_br(&self) -> bool { + match self.term { + llvm_ir::terminator::Terminator::Br(_) => true, + _ => false, + } + } + + #[getter] + fn get_br_dest(&self) -> PyResult { + match &self.term { + llvm_ir::terminator::Terminator::Br(llvm_ir::terminator::Br { dest, debugloc: _ }) => { + Ok(name_to_string(&dest)) + } + _ => Err(exceptions::PyTypeError::new_err( + "Terminator is not branch.", + )), + } + } + + #[getter] + fn get_is_condbr(&self) -> bool { + match self.term { + llvm_ir::terminator::Terminator::CondBr(_) => true, + _ => false, + } + } + + #[getter] + fn get_condbr_condition(&self) -> PyResult { + match &self.term { + llvm_ir::terminator::Terminator::CondBr(llvm_ir::terminator::CondBr { + condition, + true_dest: _, + false_dest: _, + debugloc: _, + }) => Ok(QirOperand { + op: condition.clone(), + }), + _ => Err(exceptions::PyTypeError::new_err( + "Terminator is not condition branch.", + )), + } + } + + #[getter] + fn get_condbr_true_dest(&self) -> PyResult { + match &self.term { + llvm_ir::terminator::Terminator::CondBr(llvm_ir::terminator::CondBr { + condition: _, + true_dest, + false_dest: _, + debugloc: _, + }) => Ok(name_to_string(&true_dest)), + _ => Err(exceptions::PyTypeError::new_err( + "Terminator is not condition branch.", + )), + } + } + + #[getter] + fn get_condbr_false_dest(&self) -> PyResult { + match &self.term { + llvm_ir::terminator::Terminator::CondBr(llvm_ir::terminator::CondBr { + condition: _, + true_dest: _, + false_dest, + debugloc: _, + }) => Ok(name_to_string(&false_dest)), + _ => Err(exceptions::PyTypeError::new_err( + "Terminator is not condition branch.", + )), + } + } + + #[getter] + fn get_is_switch(&self) -> bool { + match self.term { + llvm_ir::terminator::Terminator::Switch(_) => true, + _ => false, + } + } + + #[getter] + fn get_switch_operand(&self) -> PyResult { + match self.term { + llvm_ir::terminator::Terminator::Switch(_) => Err(exceptions::PyTypeError::new_err( + "Switch handling not supported.", + )), + _ => Err(exceptions::PyTypeError::new_err( + "Terminator is not switch.", + )), + } + } + + #[getter] + fn get_switch_dest_values(&self) -> PyResult> { + match self.term { + llvm_ir::terminator::Terminator::Switch(_) => Err(exceptions::PyTypeError::new_err( + "Switch handling not supported.", + )), + _ => Err(exceptions::PyTypeError::new_err( + "Terminator is not switch.", + )), + } + } + + #[getter] + fn get_switch_dest_names(&self) -> PyResult> { + match self.term { + llvm_ir::terminator::Terminator::Switch(_) => Err(exceptions::PyTypeError::new_err( + "Switch handling not supported.", + )), + _ => Err(exceptions::PyTypeError::new_err( + "Terminator is not switch.", + )), + } + } + + #[getter] + fn get_is_unreachable(&self) -> bool { + match self.term { + llvm_ir::terminator::Terminator::Unreachable(_) => true, + _ => false, + } + } +} + #[pymethods] impl QirType { #[getter] @@ -201,6 +748,7 @@ impl QirType { _ => false, } } + #[getter] fn get_is_integer(&self) -> bool { match self.typeref.as_ref() { @@ -208,6 +756,15 @@ impl QirType { _ => false, } } + + #[getter] + fn get_integer_width(&self) -> PyResult { + match self.typeref.as_ref() { + llvm_ir::Type::IntegerType { bits } => Ok(bits.clone()), + _ => Err(exceptions::PyTypeError::new_err("Type is not integer.")), + } + } + #[getter] fn get_is_pointer(&self) -> bool { match self.typeref.as_ref() { @@ -218,35 +775,39 @@ impl QirType { _ => false, } } + #[getter] - fn get_is_floating_point(&self) -> bool { + fn get_pointer_type(&self) -> PyResult { match self.typeref.as_ref() { - llvm_ir::Type::FPType(_) => true, - _ => false, + llvm_ir::Type::PointerType { + pointee_type, + addr_space: _, + } => Ok(QirType { + typeref: pointee_type.clone(), + }), + _ => Err(exceptions::PyTypeError::new_err("Type is not pointer.")), } } + #[getter] - fn get_is_func(&self) -> bool { + fn get_pointer_addrspace(&self) -> PyResult { match self.typeref.as_ref() { - llvm_ir::Type::FuncType { - result_type: _, - param_types: _, - is_var_arg: _, - } => true, - _ => false, + llvm_ir::Type::PointerType { + pointee_type: _, + addr_space, + } => Ok(addr_space.clone()), + _ => Err(exceptions::PyTypeError::new_err("Type is not pointer.")), } } + #[getter] - fn get_is_vector(&self) -> bool { + fn get_is_double(&self) -> bool { match self.typeref.as_ref() { - llvm_ir::Type::VectorType { - element_type: _, - num_elements: _, - scalable: _, - } => true, + llvm_ir::Type::FPType(llvm_ir::types::FPType::Double) => true, _ => false, } } + #[getter] fn get_is_array(&self) -> bool { match self.typeref.as_ref() { @@ -257,6 +818,31 @@ impl QirType { _ => false, } } + + #[getter] + fn get_array_element_type(&self) -> PyResult { + match self.typeref.as_ref() { + llvm_ir::Type::ArrayType { + element_type, + num_elements: _, + } => Ok(QirType { + typeref: element_type.clone(), + }), + _ => Err(exceptions::PyTypeError::new_err("Type is not array.")), + } + } + + #[getter] + fn get_array_num_elements(&self) -> PyResult { + match self.typeref.as_ref() { + llvm_ir::Type::ArrayType { + element_type: _, + num_elements, + } => Ok(num_elements.clone()), + _ => Err(exceptions::PyTypeError::new_err("Type is not array.")), + } + } + #[getter] fn get_is_struct(&self) -> bool { match self.typeref.as_ref() { @@ -267,6 +853,21 @@ impl QirType { _ => false, } } + + #[getter] + fn get_struct_element_types(&self) -> PyResult> { + match self.typeref.as_ref() { + llvm_ir::Type::StructType { + element_types, + is_packed: _, + } => Ok(element_types + .iter() + .map(|t| QirType { typeref: t.clone() }) + .collect()), + _ => Err(exceptions::PyTypeError::new_err("Type is not struct.")), + } + } + #[getter] fn get_is_named_struct(&self) -> bool { match self.typeref.as_ref() { @@ -274,6 +875,40 @@ impl QirType { _ => false, } } + + #[getter] + fn get_named_struct_name(&self) -> PyResult { + match self.typeref.as_ref() { + llvm_ir::Type::NamedStructType { name } => Ok(name.clone()), + _ => Err(exceptions::PyTypeError::new_err( + "Type is not named struct.", + )), + } + } + + #[getter] + fn get_is_qubit(&self) -> bool { + self.get_is_pointer() + && self.get_pointer_type().unwrap().get_is_named_struct() + && self + .get_pointer_type() + .unwrap() + .get_named_struct_name() + .unwrap() + == "Qubit" + } + + #[getter] + fn get_is_result(&self) -> bool { + self.get_is_pointer() + && self.get_pointer_type().unwrap().get_is_named_struct() + && self + .get_pointer_type() + .unwrap() + .get_named_struct_name() + .unwrap() + == "Result" + } } fn name_to_string(name: &llvm_ir::Name) -> String { diff --git a/src/QirTools/pyqir/tests/randwalkphaseest.baseprofile.bc b/src/QirTools/pyqir/tests/randwalkphaseest.baseprofile.bc deleted file mode 100644 index 0f82b1b0666a54fde4bf5e4e241302e1dfbdbe05..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2452 zcma)7Yfu~46<(pou8q7}1R=smnw78}8dEF@w?PQ7&|(UX>@0~p#TmQO3JF6h^jL|f zJL!VttYXWJ{Fs&>WCAIjDL*>J8PC)|JPktFQHkP$lQcAOT?oRa9_%vlV>}ZQdUqji zM?+`2a3AN~d(ZjKch5bt5aYLgkOx6x2!b3^-HroC{?u~t>q{?XH!@ZM&}pO)^bwe3 zXKA1;Am@Vy_Z6M3Ns1aIn8A2X5SH!~BL!;FX$Pa&pJh3hZJERjdF6=W#jOTMq~15F zDXNvTQLN@%mNSW5%)^Pg2>xe*!4XzGU;KPb|MRh}SHp{vl~CM*2@45GR3dx-lz!E{D;U zAo_sFPQJ0zw^Wc-JSo>84X!3__;*?na%5)&F@@gNj_9u;(2Y}L?#XAU)5+b5_l%-n zQ8iie(`HdEDzXYvISdH6Q2{}6fT?f_f3gNXs$SeR#L_Xgi-BK>vB6@v3x_+CFcV|x z2-{l^_Y}i)ndD8DOybTfGSJ>+pcm0+T@L@c4_u5ZO&N9VU&~e%9cDqRfH%HC!!Vx z?&*dD1AggkNOliHA2Mi})S{kw6Zkl8P*qLeRjCB818%`24=e$)`qZt1xpXGJp+9u_gB#SbLgXS zbXg~KB!`vhVP%T%Z&J!BjdHS2HAPAO8Y7HJ!Z^V9mlNd|i1LWgbRn?^I9=^GeIhiC zC8Qs;vA!mj_JxA2aJQWeD!4Q)xc-XlJ|z2!MAI>J!7Q7{(Pa)7`i-;E|Ta2 zT~Yi-jXFL5?CiYi764FRU>XZmT?!S36Xj9Dm`YS$jvJE+5MyPk{*oVo0V+Qru!$}B z;u^Yam))C_tl+Xmooo@8Jtk2PhA!w(AU>Fr{BsUXljsv2G5@(nb$eL3BH)ozb)Wn# zQ4TI^EU{;ns7MhN5uyS_Jxx?Yqu>qafSk(SN*8l=pts34KvV(B#|YzeqW`w?+VHle z8ZMP?YgFqT} zr*H^54#r#&QNlg5?VyFD5cXgr}EV0yYHI5l{Je-OG0$@#QgGFLJ=?d^>4aA z_guNVrmKVcafJI{-51Sa)~EQlvhcvW^1LWS?ybWny0)BeT@8J+4|}x|nEY-J0*YRd zM2z*@$D2|mH9E3Sl8;H^=KW5=F&&w6#GEfZT$@jdpA*qm>_<9-gG4llB>KVNbTZPX z5912*==9)RG7{(J^%PeAX{1I2raJpvRH3jS{e6m~hsrii-BB7E#5xBF0TWK9>f>!8 zY*0R~KRX!MVkwkLU#QJ3NEt*H-_;$3VW9w00}dWv#N`eh^U@d9G$fv}=5z`g=A^T0 zpH(|{ZG9viuYD4EOOcF|)yKY$^c3?u|4~h6joP)Abp0XyH}4-1d{nDn`-667?Sxd@ z5czoZ{pSuMLTha=B)>@Qo|d9Q;pwl|`pWFD-^+d0aOBkdzUnWz-zJS7;%jm?Vn%iV znfv_sdQCT=m^Pffv|cQM{un4eQ83Dd7aUwEwAuU}lqcBHZnM!r&|HBIchGj+6|{Lh zuFV%+;DkG4$=~5<3)(2R+uKY9GtaFr(k{1)3S_QrIPCB_xpTCu#YMY3%`RKBx5ESQ zJO$@(3)pPUbg#|k@H%@k7g{%0cWUH{fjnryIYct+9=^ z+4i@$1p;ke510jlZS5cyvK0ht>3Ny*IKAyZq1->S*%~}S7wz@^7kG~Hc2^)k9na*& z>Fsd1UACat76{U9p5qyZHkAJ#ZS9+}20+s;%DHjldR-~^w}%FBy8u`phu#$kmb%>_ HNx=7SQCl+x diff --git a/src/QirTools/pyqir/tests/randwalkphaseest.baseprofile.ll.reference b/src/QirTools/pyqir/tests/randwalkphaseest.baseprofile.ll.reference deleted file mode 100644 index 2181b26f46..0000000000 --- a/src/QirTools/pyqir/tests/randwalkphaseest.baseprofile.ll.reference +++ /dev/null @@ -1,78 +0,0 @@ -; ModuleID = './randwalkphaseest.ll' -source_filename = "./randwalkphaseest.ll" - -%Result = type opaque -%Qubit = type opaque -%String = type opaque - -declare %Result* @__quantum__rt__result_get_one() local_unnamed_addr - -declare i1 @__quantum__rt__result_equal(%Result*, %Result*) local_unnamed_addr - -declare %Qubit* @__quantum__rt__qubit_allocate() local_unnamed_addr - -declare void @__quantum__rt__qubit_release(%Qubit*) local_unnamed_addr - -declare void @__quantum__rt__result_update_reference_count(%Result*, i32) local_unnamed_addr - -declare void @__quantum__qis__crz__body(double, %Qubit*, %Qubit*) local_unnamed_addr - -declare void @__quantum__qis__h__body(%Qubit*) local_unnamed_addr - -declare void @__quantum__qis__x__body(%Qubit*) local_unnamed_addr - -declare void @__quantum__qis__reset__body(%Qubit*) local_unnamed_addr - -declare void @__quantum__qis__rz__body(double, %Qubit*) local_unnamed_addr - -declare %Result* @__quantum__qis__m__body(%Qubit*) local_unnamed_addr - -define double @Microsoft__Quantum__Qir__Emission__EstimatePhaseByRandomWalk__Interop() local_unnamed_addr #0 { -entry: - tail call void @__quantum__qis__x__body(%Qubit* null) - br label %body__1.i - -body__1.i: ; preds = %body__1.i, %entry - %0 = phi i64 [ 1, %entry ], [ %11, %body__1.i ] - %sigma.03.i = phi double [ 6.065000e-01, %entry ], [ %10, %body__1.i ] - %isigma.02.i = phi double [ 0x3FFA6180F3204A49, %entry ], [ %9, %body__1.i ] - %mu.01.i = phi double [ 7.951000e-01, %entry ], [ %8, %body__1.i ] - %1 = fmul double %isigma.02.i, %mu.01.i - %2 = fsub double 1.000000e+00, %1 - %3 = fmul double %isigma.02.i, 5.000000e-01 - tail call void @__quantum__qis__h__body(%Qubit* nonnull inttoptr (i64 1 to %Qubit*)) - %4 = fmul double %2, 5.000000e-01 - tail call void @__quantum__qis__rz__body(double %4, %Qubit* nonnull inttoptr (i64 1 to %Qubit*)) - %5 = fmul double %3, 5.000000e-01 - tail call void @__quantum__qis__crz__body(double %5, %Qubit* nonnull inttoptr (i64 1 to %Qubit*), %Qubit* null) - tail call void @__quantum__qis__h__body(%Qubit* nonnull inttoptr (i64 1 to %Qubit*)) - tail call void @__quantum__qis__mz__body(%Qubit* nonnull inttoptr (i64 1 to %Qubit*), %Result* null) - tail call void @__quantum__qis__reset__body(%Qubit* nonnull inttoptr (i64 1 to %Qubit*)) - %update.i.i = fmul double %sigma.03.i, 6.065000e-01 - %6 = fneg double %update.i.i - %7 = tail call i1 @__quantum__qir__read_result(%Result* null) - %.p.i.i = select i1 %7, double %update.i.i, double %6 - %8 = fadd double %mu.01.i, %.p.i.i - %9 = fmul double %isigma.02.i, 1.257700e+00 - %10 = fmul double %sigma.03.i, 7.951000e-01 - %11 = add nuw nsw i64 %0, 1 - %12 = icmp ult i64 %0, 30 - br i1 %12, label %body__1.i, label %Microsoft__Quantum__Qir__Emission__EstimatePhaseByRandomWalk__body.1.exit - -Microsoft__Quantum__Qir__Emission__EstimatePhaseByRandomWalk__body.1.exit: ; preds = %body__1.i - %13 = fmul double %8, 2.000000e+00 - ret double %13 -} - -declare void @__quantum__rt__message(%String*) local_unnamed_addr - -declare %String* @__quantum__rt__double_to_string(double) local_unnamed_addr - -declare void @__quantum__rt__string_update_reference_count(%String*, i32) local_unnamed_addr - -declare void @__quantum__qis__mz__body(%Qubit*, %Result*) - -declare i1 @__quantum__qir__read_result(%Result*) - -attributes #0 = { "InteropFriendly" "requiredQubits"="2" } - diff --git a/src/QirTools/pyqir/tests/teleportchain.baseprofile.bc b/src/QirTools/pyqir/tests/teleportchain.baseprofile.bc new file mode 100644 index 0000000000000000000000000000000000000000..9da436f993da8bab4ced07471402fd4c74dc784c GIT binary patch literal 2896 zcmai04^R`?8Gj*RH$vQOFnU3f+{S1Rk=}(r_JRQ>Vc{-lY9r#Eb?Ai+1W7OE&l2R% zU3&=$Y#iem72BNS+(5@#&*^lq=gry9wL=KfoJI#kd$w8&2cl=u;d-{?jLy)vN$lAi zZ8yn#dB6AjzVG*a@7rXn$l+TX#QMO|MJdd`*yJgr-}_bYF^6?pH}>mFVO80N&M&5)bqO5o#GdA zNqp`5k*%UDk|rKFRFnTg@&4g{|4+Q@^Xe`R<15e9gbQdi<0O;_wn+fUfpgvk;?W|! zD1Bzf07HkE4iCCL#JKa(4g%d9Lp>pe4lvz%v@0K_1HIii;~rqTz&yCFL=~3)xIIiRI*cHJJU?6Kal=bp=veRhS z-X7v0X|#Kv|angbol>T}=J?PQr&v;j}>h@ioL$uFer-9yv=igHRfbWOqN8nZo-y!#(0qAuZbgi&2y!dpok6z~eT$EF=^3XJ?RIka zb}~+a$&HJ!`4Bd(653V5nFVaYh?U@@vRex2b%kt%lDDY#X+H63#>uj?-11L+<$kUv zz98P)h`!Z|zTC>taP%LGH|ai1n`T$@Uyk?H6}JHy)y4?{w>0`ecqFHq9E3fZlQ?8h8A zD_9|0ppg1rpE@4Z43QPEAWufhXGu)}E~CNoSuj(k1M1_+)&5*C+tS`?WRR_tkc(nXnq%0PNIhM!uXI*?0s&c^s?qqUr zjA8SQ!uwOm0wKJu65b|+|1@HD9Gg*LaQW2~^2HQ3Ys4O@$mu^TWOIYk1x`Xa^~%*h zMb+@IhN3TBCpX2(O#yNf%zB)x1RucP1rhA2>?}H;{cY*q=?s$PPC7QY z{H~5|r8$KxS%X!jGmY3CBP^|OmMyUGjuCsvcI*Va4-hz`@$wTs&2e~O+=>BTIXt{j zl_YtIfr!V@_jT7Tl88 z9{`YWa#^2sggVv=0RWUpCf?IHKurX^3O^wUL{?TPk@E@YQoyTAK-UVNLZ3c`j!KmX zBI;=*kk2NA5;4i|@%BN(F=#l9Og5#UF$l5lr;x)%7jb?hpeuq7TUVECA%YS~HNS_G zXMDHFY!oQ?$gVpnqddb{VN}aYg>+pi%oq#wIB z_d`Li=&6GBAM(bMqKCZaB`K#riYJZE=`8VLsa}<|Joa%shfpGYi5y7V$0Q&y3&V>H!43@ zR?@tmkLP56sh${>fh$km*-|(_D2Ok9vN_#e(9jz+gTIxbQ zrHg+R1t;~}d4}plpcN{`)|vkn=rb5-GFRU-Y0#6Rg!1c^>_Y^+TtxE!t{B7D_<@i8 z>q}fefX^Ghg5Pqu{cp0*B=r`X#p$5kWGiL0n@rV~Jq~-Do2J~Br#qC}>ag!~6}w+h*BgvAa#CTD#jqJDetytDUmD+xM7EG(=tPW~X2Dt&Q6KtRhx!iu!*`nJmUq bI%zg%syUT-k?KYGa#8MY+pP9C6aD)ySK`aJ literal 0 HcmV?d00001 diff --git a/src/QirTools/pyqir/tests/teleportchain.baseprofile.ll.reference b/src/QirTools/pyqir/tests/teleportchain.baseprofile.ll.reference new file mode 100644 index 0000000000..d2fec52fc4 --- /dev/null +++ b/src/QirTools/pyqir/tests/teleportchain.baseprofile.ll.reference @@ -0,0 +1,111 @@ +; ModuleID = 'qat-link' +source_filename = "qat-link" + +%Qubit = type opaque +%Result = type opaque +%Array = type opaque +%String = type opaque + +define i8 @TeleportChain__DemonstrateTeleportationUsingPresharedEntanglement__Interop() local_unnamed_addr #0 { +entry: + tail call void @__quantum__qis__h__body(%Qubit* null) + tail call void @__quantum__qis__cnot__body(%Qubit* null, %Qubit* nonnull inttoptr (i64 1 to %Qubit*)) + tail call void @__quantum__qis__h__body(%Qubit* nonnull inttoptr (i64 2 to %Qubit*)) + tail call void @__quantum__qis__cnot__body(%Qubit* nonnull inttoptr (i64 2 to %Qubit*), %Qubit* nonnull inttoptr (i64 4 to %Qubit*)) + tail call void @__quantum__qis__h__body(%Qubit* nonnull inttoptr (i64 3 to %Qubit*)) + tail call void @__quantum__qis__cnot__body(%Qubit* nonnull inttoptr (i64 3 to %Qubit*), %Qubit* nonnull inttoptr (i64 5 to %Qubit*)) + tail call void @__quantum__qis__cnot__body(%Qubit* nonnull inttoptr (i64 1 to %Qubit*), %Qubit* nonnull inttoptr (i64 2 to %Qubit*)) + tail call void @__quantum__qis__h__body(%Qubit* nonnull inttoptr (i64 1 to %Qubit*)) + tail call void @__quantum__qis__mz__body(%Qubit* nonnull inttoptr (i64 1 to %Qubit*), %Result* null) + tail call void @__quantum__qis__reset__body(%Qubit* nonnull inttoptr (i64 1 to %Qubit*)) + %0 = tail call i1 @__quantum__qir__read_result(%Result* null) + br i1 %0, label %then0__1.i.i.i, label %continue__1.i.i.i + +then0__1.i.i.i: ; preds = %entry + tail call void @__quantum__qis__z__body(%Qubit* nonnull inttoptr (i64 4 to %Qubit*)) + br label %continue__1.i.i.i + +continue__1.i.i.i: ; preds = %then0__1.i.i.i, %entry + tail call void @__quantum__qis__mz__body(%Qubit* nonnull inttoptr (i64 2 to %Qubit*), %Result* nonnull inttoptr (i64 1 to %Result*)) + tail call void @__quantum__qis__reset__body(%Qubit* nonnull inttoptr (i64 2 to %Qubit*)) + %1 = tail call i1 @__quantum__qir__read_result(%Result* nonnull inttoptr (i64 1 to %Result*)) + br i1 %1, label %then0__2.i.i.i, label %TeleportChain__TeleportQubitUsingPresharedEntanglement__body.2.exit.i + +then0__2.i.i.i: ; preds = %continue__1.i.i.i + tail call void @__quantum__qis__x__body(%Qubit* nonnull inttoptr (i64 4 to %Qubit*)) + br label %TeleportChain__TeleportQubitUsingPresharedEntanglement__body.2.exit.i + +TeleportChain__TeleportQubitUsingPresharedEntanglement__body.2.exit.i: ; preds = %then0__2.i.i.i, %continue__1.i.i.i + tail call void @__quantum__qis__cnot__body(%Qubit* nonnull inttoptr (i64 4 to %Qubit*), %Qubit* nonnull inttoptr (i64 3 to %Qubit*)) + tail call void @__quantum__qis__h__body(%Qubit* nonnull inttoptr (i64 4 to %Qubit*)) + tail call void @__quantum__qis__mz__body(%Qubit* nonnull inttoptr (i64 4 to %Qubit*), %Result* nonnull inttoptr (i64 2 to %Result*)) + tail call void @__quantum__qis__reset__body(%Qubit* nonnull inttoptr (i64 4 to %Qubit*)) + %2 = tail call i1 @__quantum__qir__read_result(%Result* nonnull inttoptr (i64 2 to %Result*)) + br i1 %2, label %then0__1.i.i1.i, label %continue__1.i.i2.i + +then0__1.i.i1.i: ; preds = %TeleportChain__TeleportQubitUsingPresharedEntanglement__body.2.exit.i + tail call void @__quantum__qis__z__body(%Qubit* nonnull inttoptr (i64 5 to %Qubit*)) + br label %continue__1.i.i2.i + +continue__1.i.i2.i: ; preds = %then0__1.i.i1.i, %TeleportChain__TeleportQubitUsingPresharedEntanglement__body.2.exit.i + tail call void @__quantum__qis__mz__body(%Qubit* nonnull inttoptr (i64 3 to %Qubit*), %Result* nonnull inttoptr (i64 3 to %Result*)) + tail call void @__quantum__qis__reset__body(%Qubit* nonnull inttoptr (i64 3 to %Qubit*)) + %3 = tail call i1 @__quantum__qir__read_result(%Result* nonnull inttoptr (i64 3 to %Result*)) + br i1 %3, label %then0__2.i.i3.i, label %TeleportChain__DemonstrateTeleportationUsingPresharedEntanglement__body.1.exit + +then0__2.i.i3.i: ; preds = %continue__1.i.i2.i + tail call void @__quantum__qis__x__body(%Qubit* nonnull inttoptr (i64 5 to %Qubit*)) + br label %TeleportChain__DemonstrateTeleportationUsingPresharedEntanglement__body.1.exit + +TeleportChain__DemonstrateTeleportationUsingPresharedEntanglement__body.1.exit: ; preds = %continue__1.i.i2.i, %then0__2.i.i3.i + tail call void @__quantum__qis__mz__body(%Qubit* null, %Result* nonnull inttoptr (i64 4 to %Result*)) + tail call void @__quantum__qis__reset__body(%Qubit* null) + tail call void @__quantum__qis__mz__body(%Qubit* nonnull inttoptr (i64 5 to %Qubit*), %Result* nonnull inttoptr (i64 5 to %Result*)) + tail call void @__quantum__qis__reset__body(%Qubit* nonnull inttoptr (i64 5 to %Qubit*)) + %4 = tail call i1 @__quantum__rt__result_equal(%Result* nonnull inttoptr (i64 4 to %Result*), %Result* nonnull inttoptr (i64 5 to %Result*)) + %5 = sext i1 %4 to i8 + ret i8 %5 +} + +declare %Qubit* @__quantum__rt__qubit_allocate() local_unnamed_addr + +declare %Array* @__quantum__rt__qubit_allocate_array(i64) local_unnamed_addr + +declare void @__quantum__rt__array_update_alias_count(%Array*, i32) local_unnamed_addr + +declare i8* @__quantum__rt__array_get_element_ptr_1d(%Array*, i64) local_unnamed_addr + +declare i1 @__quantum__rt__result_equal(%Result*, %Result*) local_unnamed_addr + +declare void @__quantum__rt__result_update_reference_count(%Result*, i32) local_unnamed_addr + +declare void @__quantum__rt__qubit_release(%Qubit*) local_unnamed_addr + +declare void @__quantum__rt__qubit_release_array(%Array*) local_unnamed_addr + +declare %Result* @__quantum__qis__m__body(%Qubit*) local_unnamed_addr + +declare void @__quantum__qis__reset__body(%Qubit*) local_unnamed_addr + +declare %Result* @__quantum__rt__result_get_one() local_unnamed_addr + +declare void @__quantum__qis__x__body(%Qubit*) local_unnamed_addr + +declare void @__quantum__qis__z__body(%Qubit*) local_unnamed_addr + +declare void @__quantum__qis__h__body(%Qubit*) local_unnamed_addr + +declare void @__quantum__qis__cnot__body(%Qubit*, %Qubit*) local_unnamed_addr + +declare %String* @__quantum__rt__bool_to_string(i1) local_unnamed_addr + +declare void @__quantum__rt__message(%String*) local_unnamed_addr + +declare void @__quantum__rt__string_update_reference_count(%String*, i32) local_unnamed_addr + +declare void @__quantum__qis__mz__body(%Qubit*, %Result*) + +declare i1 @__quantum__qir__read_result(%Result*) + +attributes #0 = { "InteropFriendly" "requiredQubits"="6" } + diff --git a/src/QirTools/pyqir/tests/randwalkphaseest.ll.reference b/src/QirTools/pyqir/tests/teleportchain.ll.reference similarity index 91% rename from src/QirTools/pyqir/tests/randwalkphaseest.ll.reference rename to src/QirTools/pyqir/tests/teleportchain.ll.reference index 8be2539f08..c4b4b52941 100644 --- a/src/QirTools/pyqir/tests/randwalkphaseest.ll.reference +++ b/src/QirTools/pyqir/tests/teleportchain.ll.reference @@ -1,11 +1,11 @@ %Range = type { i64, i64, i64 } %Tuple = type opaque -%Result = type opaque %Qubit = type opaque +%Result = type opaque %Array = type opaque -%String = type opaque %Callable = type opaque +%String = type opaque @PauliI = internal constant i2 0 @PauliX = internal constant i2 1 @@ -13,109 +13,148 @@ @PauliZ = internal constant i2 -2 @EmptyRange = internal constant %Range { i64 0, i64 1, i64 -1 } @0 = internal constant [18 x i8] c"Unsupported input\00" -@Microsoft__Quantum__Intrinsic__CNOT__FunctionTable = internal constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__CNOT__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__CNOT__adj__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__CNOT__ctl__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__CNOT__ctladj__wrapper] -@Microsoft__Quantum__Intrinsic__H__FunctionTable = internal constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__H__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__H__adj__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__H__ctl__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__H__ctladj__wrapper] -@Microsoft__Quantum__Intrinsic__Rx__FunctionTable = internal constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Rx__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Rx__adj__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Rx__ctl__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Rx__ctladj__wrapper] -@Microsoft__Quantum__Intrinsic__Ry__FunctionTable = internal constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Ry__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Ry__adj__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Ry__ctl__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Ry__ctladj__wrapper] -@Microsoft__Quantum__Intrinsic__Rz__FunctionTable = internal constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Rz__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Rz__adj__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Rz__ctl__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Rz__ctladj__wrapper] -@Microsoft__Quantum__Intrinsic__S__FunctionTable = internal constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__S__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__S__adj__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__S__ctl__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__S__ctladj__wrapper] -@Microsoft__Quantum__Intrinsic__T__FunctionTable = internal constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__T__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__T__adj__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__T__ctl__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__T__ctladj__wrapper] -@Microsoft__Quantum__Intrinsic__X__FunctionTable = internal constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__X__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__X__adj__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__X__ctl__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__X__ctladj__wrapper] -@Microsoft__Quantum__Intrinsic__Z__FunctionTable = internal constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Z__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Z__adj__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Z__ctl__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Z__ctladj__wrapper] +@1 = internal constant [18 x i8] c"Unsupported input\00" +@Microsoft__Quantum__Intrinsic__CNOT = internal constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__CNOT__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__CNOT__adj__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__CNOT__ctl__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__CNOT__ctladj__wrapper] +@Microsoft__Quantum__Intrinsic__H = internal constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__H__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__H__adj__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__H__ctl__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__H__ctladj__wrapper] +@Microsoft__Quantum__Intrinsic__Rx = internal constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Rx__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Rx__adj__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Rx__ctl__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Rx__ctladj__wrapper] +@Microsoft__Quantum__Intrinsic__Ry = internal constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Ry__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Ry__adj__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Ry__ctl__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Ry__ctladj__wrapper] +@Microsoft__Quantum__Intrinsic__Rz = internal constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Rz__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Rz__adj__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Rz__ctl__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Rz__ctladj__wrapper] +@Microsoft__Quantum__Intrinsic__S = internal constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__S__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__S__adj__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__S__ctl__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__S__ctladj__wrapper] +@Microsoft__Quantum__Intrinsic__T = internal constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__T__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__T__adj__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__T__ctl__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__T__ctladj__wrapper] +@Microsoft__Quantum__Intrinsic__X = internal constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__X__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__X__adj__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__X__ctl__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__X__ctladj__wrapper] +@Microsoft__Quantum__Intrinsic__Z = internal constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Z__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Z__adj__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Z__ctl__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* @Microsoft__Quantum__Intrinsic__Z__ctladj__wrapper] + +define internal void @TeleportChain__ApplyCorrection__body(%Qubit* %src, %Qubit* %intermediary, %Qubit* %dest) { +entry: + %0 = call %Result* @Microsoft__Quantum__Measurement__MResetZ__body(%Qubit* %src) + %1 = call %Result* @__quantum__rt__result_get_one() + %2 = call i1 @__quantum__rt__result_equal(%Result* %0, %Result* %1) + call void @__quantum__rt__result_update_reference_count(%Result* %0, i32 -1) + br i1 %2, label %then0__1, label %continue__1 -define internal double @Microsoft__Quantum__Qir__Emission__ClassicalComputeInput1__body(double %mu, double %isigma) { -entry: - %0 = fmul double %mu, %isigma - %1 = fsub double 1.000000e+00, %0 - ret double %1 -} +then0__1: ; preds = %entry + call void @Microsoft__Quantum__Intrinsic__Z__body(%Qubit* %dest) + br label %continue__1 -define internal double @Microsoft__Quantum__Qir__Emission__ClassicalComputeInput2__body(double %isigma) { -entry: - %0 = fmul double 5.000000e-01, %isigma - ret double %0 -} +continue__1: ; preds = %then0__1, %entry + %3 = call %Result* @Microsoft__Quantum__Measurement__MResetZ__body(%Qubit* %intermediary) + %4 = call %Result* @__quantum__rt__result_get_one() + %5 = call i1 @__quantum__rt__result_equal(%Result* %3, %Result* %4) + call void @__quantum__rt__result_update_reference_count(%Result* %3, i32 -1) + br i1 %5, label %then0__2, label %continue__2 -define internal double @Microsoft__Quantum__Qir__Emission__ClassicalUpdateiSigma__body(double %isigma) { -entry: - %0 = fmul double %isigma, 1.257700e+00 - ret double %0 +then0__2: ; preds = %continue__1 + call void @Microsoft__Quantum__Intrinsic__X__body(%Qubit* %dest) + br label %continue__2 + +continue__2: ; preds = %then0__2, %continue__1 + ret void } -define internal double @Microsoft__Quantum__Qir__Emission__ClassicalUpdateMu__body(double %mu, double %sigma, %Result* %res) { +define internal %Result* @Microsoft__Quantum__Measurement__MResetZ__body(%Qubit* %target) { entry: - %update = fmul double 6.065000e-01, %sigma - %0 = call %Result* @__quantum__rt__result_get_one() - %1 = call i1 @__quantum__rt__result_equal(%Result* %res, %Result* %0) - br i1 %1, label %condTrue__1, label %condFalse__1 - -condTrue__1: ; preds = %entry - %2 = fadd double %mu, %update - br label %condContinue__1 - -condFalse__1: ; preds = %entry - %3 = fsub double %mu, %update - br label %condContinue__1 - -condContinue__1: ; preds = %condFalse__1, %condTrue__1 - %4 = phi double [ %2, %condTrue__1 ], [ %3, %condFalse__1 ] - ret double %4 + %result = call %Result* @__quantum__qis__m__body(%Qubit* %target) + call void @__quantum__qis__reset__body(%Qubit* %target) + ret %Result* %result } declare %Result* @__quantum__rt__result_get_one() declare i1 @__quantum__rt__result_equal(%Result*, %Result*) -define internal double @Microsoft__Quantum__Qir__Emission__ClassicalUpdateSigma__body(double %sigma) { +declare void @__quantum__rt__result_update_reference_count(%Result*, i32) + +define internal void @Microsoft__Quantum__Intrinsic__Z__body(%Qubit* %qubit) { +entry: + call void @__quantum__qis__z__body(%Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__X__body(%Qubit* %qubit) { entry: - %0 = fmul double %sigma, 7.951000e-01 - ret double %0 + call void @__quantum__qis__x__body(%Qubit* %qubit) + ret void } -define internal double @Microsoft__Quantum__Qir__Emission__EstimatePhaseByRandomWalk__body() { +define internal i1 @TeleportChain__DemonstrateTeleportationUsingPresharedEntanglement__body() { entry: - %mu = alloca double, align 8 - store double 7.951000e-01, double* %mu, align 8 - %isigma = alloca double, align 8 - store double 0x3FFA6180F3204A49, double* %isigma, align 8 - %sigma = alloca double, align 8 - store double 6.065000e-01, double* %sigma, align 8 - %target = call %Qubit* @__quantum__rt__qubit_allocate() - %aux = call %Qubit* @__quantum__rt__qubit_allocate() - call void @Microsoft__Quantum__Qir__Emission__Prepare__body(%Qubit* %target) + %leftMessage = call %Qubit* @__quantum__rt__qubit_allocate() + %rightMessage = call %Qubit* @__quantum__rt__qubit_allocate() + %leftPreshared = call %Array* @__quantum__rt__qubit_allocate_array(i64 2) + call void @__quantum__rt__array_update_alias_count(%Array* %leftPreshared, i32 1) + %rightPreshared = call %Array* @__quantum__rt__qubit_allocate_array(i64 2) + call void @__quantum__rt__array_update_alias_count(%Array* %rightPreshared, i32 1) + call void @TeleportChain__PrepareEntangledPair__body(%Qubit* %leftMessage, %Qubit* %rightMessage) br label %header__1 header__1: ; preds = %exiting__1, %entry - %0 = phi i64 [ 1, %entry ], [ %8, %exiting__1 ] - %1 = icmp sle i64 %0, 30 - br i1 %1, label %body__1, label %exit__1 + %i = phi i64 [ 0, %entry ], [ %7, %exiting__1 ] + %0 = icmp sle i64 %i, 1 + br i1 %0, label %body__1, label %exit__1 body__1: ; preds = %header__1 - %2 = load double, double* %mu, align 8 - %3 = load double, double* %isigma, align 8 - %c1 = call double @Microsoft__Quantum__Qir__Emission__ClassicalComputeInput1__body(double %2, double %3) - %c2 = call double @Microsoft__Quantum__Qir__Emission__ClassicalComputeInput2__body(double %3) - %datum = call %Result* @Microsoft__Quantum__Qir__Emission__Iterate__body(double %c1, double %c2, %Qubit* %target, %Qubit* %aux) - %4 = load double, double* %sigma, align 8 - %5 = call double @Microsoft__Quantum__Qir__Emission__ClassicalUpdateMu__body(double %2, double %4, %Result* %datum) - store double %5, double* %mu, align 8 - %6 = call double @Microsoft__Quantum__Qir__Emission__ClassicalUpdateiSigma__body(double %3) - store double %6, double* %isigma, align 8 - %7 = call double @Microsoft__Quantum__Qir__Emission__ClassicalUpdateSigma__body(double %4) - store double %7, double* %sigma, align 8 - call void @__quantum__rt__result_update_reference_count(%Result* %datum, i32 -1) + %1 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %leftPreshared, i64 %i) + %2 = bitcast i8* %1 to %Qubit** + %3 = load %Qubit*, %Qubit** %2, align 8 + %4 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %rightPreshared, i64 %i) + %5 = bitcast i8* %4 to %Qubit** + %6 = load %Qubit*, %Qubit** %5, align 8 + call void @TeleportChain__PrepareEntangledPair__body(%Qubit* %3, %Qubit* %6) br label %exiting__1 exiting__1: ; preds = %body__1 - %8 = add i64 %0, 1 + %7 = add i64 %i, 1 br label %header__1 exit__1: ; preds = %header__1 - %9 = load double, double* %mu, align 8 - %10 = fmul double %9, 2.000000e+00 - call void @__quantum__rt__qubit_release(%Qubit* %aux) - call void @__quantum__rt__qubit_release(%Qubit* %target) - ret double %10 + %8 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %leftPreshared, i64 0) + %9 = bitcast i8* %8 to %Qubit** + %10 = load %Qubit*, %Qubit** %9, align 8 + %11 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %rightPreshared, i64 0) + %12 = bitcast i8* %11 to %Qubit** + %13 = load %Qubit*, %Qubit** %12, align 8 + call void @TeleportChain__TeleportQubitUsingPresharedEntanglement__body(%Qubit* %rightMessage, %Qubit* %10, %Qubit* %13) + br label %header__2 + +header__2: ; preds = %exiting__2, %exit__1 + %i__1 = phi i64 [ 1, %exit__1 ], [ %25, %exiting__2 ] + %14 = icmp sle i64 %i__1, 1 + br i1 %14, label %body__2, label %exit__2 + +body__2: ; preds = %header__2 + %15 = sub i64 %i__1, 1 + %16 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %rightPreshared, i64 %15) + %17 = bitcast i8* %16 to %Qubit** + %18 = load %Qubit*, %Qubit** %17, align 8 + %19 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %leftPreshared, i64 %i__1) + %20 = bitcast i8* %19 to %Qubit** + %21 = load %Qubit*, %Qubit** %20, align 8 + %22 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %rightPreshared, i64 %i__1) + %23 = bitcast i8* %22 to %Qubit** + %24 = load %Qubit*, %Qubit** %23, align 8 + call void @TeleportChain__TeleportQubitUsingPresharedEntanglement__body(%Qubit* %18, %Qubit* %21, %Qubit* %24) + br label %exiting__2 + +exiting__2: ; preds = %body__2 + %25 = add i64 %i__1, 1 + br label %header__2 + +exit__2: ; preds = %header__2 + %26 = call %Result* @Microsoft__Quantum__Measurement__MResetZ__body(%Qubit* %leftMessage) + %27 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %rightPreshared, i64 1) + %28 = bitcast i8* %27 to %Qubit** + %29 = load %Qubit*, %Qubit** %28, align 8 + %30 = call %Result* @Microsoft__Quantum__Measurement__MResetZ__body(%Qubit* %29) + %31 = call i1 @__quantum__rt__result_equal(%Result* %26, %Result* %30) + call void @__quantum__rt__array_update_alias_count(%Array* %leftPreshared, i32 -1) + call void @__quantum__rt__array_update_alias_count(%Array* %rightPreshared, i32 -1) + call void @__quantum__rt__result_update_reference_count(%Result* %26, i32 -1) + call void @__quantum__rt__result_update_reference_count(%Result* %30, i32 -1) + call void @__quantum__rt__qubit_release(%Qubit* %leftMessage) + call void @__quantum__rt__qubit_release(%Qubit* %rightMessage) + call void @__quantum__rt__qubit_release_array(%Array* %leftPreshared) + call void @__quantum__rt__qubit_release_array(%Array* %rightPreshared) + ret i1 %31 } declare %Qubit* @__quantum__rt__qubit_allocate() @@ -124,39 +163,50 @@ declare %Array* @__quantum__rt__qubit_allocate_array(i64) declare void @__quantum__rt__qubit_release(%Qubit*) -define internal void @Microsoft__Quantum__Qir__Emission__Prepare__body(%Qubit* %target) { +declare void @__quantum__rt__qubit_release_array(%Array*) + +declare void @__quantum__rt__array_update_alias_count(%Array*, i32) + +define internal void @TeleportChain__PrepareEntangledPair__body(%Qubit* %left, %Qubit* %right) { entry: - call void @Microsoft__Quantum__Intrinsic__X__body(%Qubit* %target) + call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %left) + call void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* %left, %Qubit* %right) ret void } -define internal %Result* @Microsoft__Quantum__Qir__Emission__Iterate__body(double %c1, double %c2, %Qubit* %target, %Qubit* %aux) { +declare i8* @__quantum__rt__array_get_element_ptr_1d(%Array*, i64) + +define internal void @TeleportChain__TeleportQubitUsingPresharedEntanglement__body(%Qubit* %src, %Qubit* %intermediary, %Qubit* %dest) { entry: - call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %aux) - %0 = fdiv double %c1, 2.000000e+00 - call void @Microsoft__Quantum__Intrinsic__RzPi__body(double %0, %Qubit* %aux) - %1 = fdiv double %c2, 2.000000e+00 - call void @__quantum__qis__crz__body(double %1, %Qubit* %aux, %Qubit* %target) - call void @Microsoft__Quantum__Intrinsic__H__adj(%Qubit* %aux) - %2 = call %Result* @Microsoft__Quantum__Measurement__MResetZ__body(%Qubit* %aux) - ret %Result* %2 + call void @TeleportChain__PrepareEntangledPair__adj(%Qubit* %src, %Qubit* %intermediary) + call void @TeleportChain__ApplyCorrection__body(%Qubit* %src, %Qubit* %intermediary, %Qubit* %dest) + ret void } -declare void @__quantum__rt__result_update_reference_count(%Result*, i32) - define internal void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %qubit) { entry: call void @__quantum__qis__h__body(%Qubit* %qubit) ret void } -define internal void @Microsoft__Quantum__Intrinsic__RzPi__body(double %theta, %Qubit* %qubit) { +define internal void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* %control, %Qubit* %target) { entry: - call void @Microsoft__Quantum__Intrinsic__Rz__body(double %theta, %Qubit* %qubit) + call void @__quantum__qis__cnot__body(%Qubit* %control, %Qubit* %target) + ret void +} + +define internal void @TeleportChain__PrepareEntangledPair__adj(%Qubit* %left, %Qubit* %right) { +entry: + call void @Microsoft__Quantum__Intrinsic__CNOT__adj(%Qubit* %left, %Qubit* %right) + call void @Microsoft__Quantum__Intrinsic__H__adj(%Qubit* %left) ret void } -declare void @__quantum__qis__crz__body(double, %Qubit*, %Qubit*) +define internal void @Microsoft__Quantum__Intrinsic__CNOT__adj(%Qubit* %control, %Qubit* %target) { +entry: + call void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* %control, %Qubit* %target) + ret void +} define internal void @Microsoft__Quantum__Intrinsic__H__adj(%Qubit* %qubit) { entry: @@ -164,25 +214,193 @@ entry: ret void } -define internal %Result* @Microsoft__Quantum__Measurement__MResetZ__body(%Qubit* %target) { +define internal void @TeleportChain__PrepareEntangledPair__ctl(%Array* %__controlQubits__, { %Qubit*, %Qubit* }* %0) { entry: - %result = call %Result* @__quantum__qis__m__body(%Qubit* %target) - call void @__quantum__qis__reset__body(%Qubit* %target) - ret %Result* %result + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 1) + %1 = getelementptr inbounds { %Qubit*, %Qubit* }, { %Qubit*, %Qubit* }* %0, i32 0, i32 0 + %left = load %Qubit*, %Qubit** %1, align 8 + %2 = getelementptr inbounds { %Qubit*, %Qubit* }, { %Qubit*, %Qubit* }* %0, i32 0, i32 1 + %right = load %Qubit*, %Qubit** %2, align 8 + call void @Microsoft__Quantum__Intrinsic__H__ctl(%Array* %__controlQubits__, %Qubit* %left) + %3 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 2)) + %4 = bitcast %Tuple* %3 to { %Qubit*, %Qubit* }* + %5 = getelementptr inbounds { %Qubit*, %Qubit* }, { %Qubit*, %Qubit* }* %4, i32 0, i32 0 + %6 = getelementptr inbounds { %Qubit*, %Qubit* }, { %Qubit*, %Qubit* }* %4, i32 0, i32 1 + store %Qubit* %left, %Qubit** %5, align 8 + store %Qubit* %right, %Qubit** %6, align 8 + call void @Microsoft__Quantum__Intrinsic__CNOT__ctl(%Array* %__controlQubits__, { %Qubit*, %Qubit* }* %4) + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 -1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %3, i32 -1) + ret void } -define internal void @Microsoft__Quantum__Intrinsic__X__body(%Qubit* %qubit) { +define internal void @Microsoft__Quantum__Intrinsic__H__ctl(%Array* %ctls, %Qubit* %qubit) { entry: - call void @__quantum__qis__x__body(%Qubit* %qubit) + call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i32 1) + %0 = call i64 @__quantum__rt__array_get_size_1d(%Array* %ctls) + %1 = icmp eq i64 %0, 0 + br i1 %1, label %then0__1, label %test1__1 + +then0__1: ; preds = %entry + call void @__quantum__qis__h__body(%Qubit* %qubit) + br label %continue__1 + +test1__1: ; preds = %entry + %2 = call i64 @__quantum__rt__array_get_size_1d(%Array* %ctls) + %3 = icmp eq i64 %2, 1 + br i1 %3, label %then1__1, label %else__1 + +then1__1: ; preds = %test1__1 + call void @Microsoft__Quantum__Intrinsic__S__body(%Qubit* %qubit) + call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %qubit) + call void @Microsoft__Quantum__Intrinsic__T__body(%Qubit* %qubit) + %4 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls, i64 0) + %5 = bitcast i8* %4 to %Qubit** + %6 = load %Qubit*, %Qubit** %5, align 8 + call void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* %6, %Qubit* %qubit) + call void @Microsoft__Quantum__Intrinsic__T__adj(%Qubit* %qubit) + call void @Microsoft__Quantum__Intrinsic__H__adj(%Qubit* %qubit) + call void @Microsoft__Quantum__Intrinsic__S__adj(%Qubit* %qubit) + br label %continue__1 + +else__1: ; preds = %test1__1 + %7 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Intrinsic__H, [2 x void (%Tuple*, i32)*]* null, %Tuple* null) + call void @__quantum__rt__callable_make_controlled(%Callable* %7) + %8 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 2)) + %9 = bitcast %Tuple* %8 to { %Array*, %Qubit* }* + %10 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %9, i32 0, i32 0 + %11 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %9, i32 0, i32 1 + call void @__quantum__rt__array_update_reference_count(%Array* %ctls, i32 1) + store %Array* %ctls, %Array** %10, align 8 + store %Qubit* %qubit, %Qubit** %11, align 8 + call void @Microsoft__Quantum__Intrinsic___fff485d029404f308fe7e714aec986f1___QsRef23__ApplyWithLessControlsA____body(%Callable* %7, { %Array*, %Qubit* }* %9) + call void @__quantum__rt__capture_update_reference_count(%Callable* %7, i32 -1) + call void @__quantum__rt__callable_update_reference_count(%Callable* %7, i32 -1) + call void @__quantum__rt__array_update_reference_count(%Array* %ctls, i32 -1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %8, i32 -1) + br label %continue__1 + +continue__1: ; preds = %else__1, %then1__1, %then0__1 + call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i32 -1) ret void } -define internal void @Microsoft__Quantum__Intrinsic__Rz__body(double %theta, %Qubit* %qubit) { +define internal void @Microsoft__Quantum__Intrinsic__CNOT__ctl(%Array* %ctls, { %Qubit*, %Qubit* }* %0) { entry: - call void @__quantum__qis__rz__body(double %theta, %Qubit* %qubit) + call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i32 1) + %1 = getelementptr inbounds { %Qubit*, %Qubit* }, { %Qubit*, %Qubit* }* %0, i32 0, i32 0 + %control = load %Qubit*, %Qubit** %1, align 8 + %2 = getelementptr inbounds { %Qubit*, %Qubit* }, { %Qubit*, %Qubit* }* %0, i32 0, i32 1 + %target = load %Qubit*, %Qubit** %2, align 8 + %3 = call i64 @__quantum__rt__array_get_size_1d(%Array* %ctls) + %4 = icmp eq i64 %3, 0 + br i1 %4, label %then0__1, label %test1__1 + +then0__1: ; preds = %entry + call void @__quantum__qis__cnot__body(%Qubit* %control, %Qubit* %target) + br label %continue__1 + +test1__1: ; preds = %entry + %5 = call i64 @__quantum__rt__array_get_size_1d(%Array* %ctls) + %6 = icmp eq i64 %5, 1 + br i1 %6, label %then1__1, label %else__1 + +then1__1: ; preds = %test1__1 + %7 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls, i64 0) + %8 = bitcast i8* %7 to %Qubit** + %9 = load %Qubit*, %Qubit** %8, align 8 + call void @Microsoft__Quantum__Intrinsic__CCNOT__body(%Qubit* %9, %Qubit* %control, %Qubit* %target) + br label %continue__1 + +else__1: ; preds = %test1__1 + %10 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Intrinsic__CNOT, [2 x void (%Tuple*, i32)*]* null, %Tuple* null) + call void @__quantum__rt__callable_make_controlled(%Callable* %10) + %11 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 2)) + %12 = bitcast %Tuple* %11 to { %Array*, { %Qubit*, %Qubit* }* }* + %13 = getelementptr inbounds { %Array*, { %Qubit*, %Qubit* }* }, { %Array*, { %Qubit*, %Qubit* }* }* %12, i32 0, i32 0 + %14 = getelementptr inbounds { %Array*, { %Qubit*, %Qubit* }* }, { %Array*, { %Qubit*, %Qubit* }* }* %12, i32 0, i32 1 + call void @__quantum__rt__array_update_reference_count(%Array* %ctls, i32 1) + %15 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 2)) + %16 = bitcast %Tuple* %15 to { %Qubit*, %Qubit* }* + %17 = getelementptr inbounds { %Qubit*, %Qubit* }, { %Qubit*, %Qubit* }* %16, i32 0, i32 0 + %18 = getelementptr inbounds { %Qubit*, %Qubit* }, { %Qubit*, %Qubit* }* %16, i32 0, i32 1 + store %Qubit* %control, %Qubit** %17, align 8 + store %Qubit* %target, %Qubit** %18, align 8 + store %Array* %ctls, %Array** %13, align 8 + store { %Qubit*, %Qubit* }* %16, { %Qubit*, %Qubit* }** %14, align 8 + call void @Microsoft__Quantum__Intrinsic___9befc69676a248a794d7a83b374c573e___QsRef23__ApplyWithLessControlsA____body(%Callable* %10, { %Array*, { %Qubit*, %Qubit* }* }* %12) + call void @__quantum__rt__capture_update_reference_count(%Callable* %10, i32 -1) + call void @__quantum__rt__callable_update_reference_count(%Callable* %10, i32 -1) + call void @__quantum__rt__array_update_reference_count(%Array* %ctls, i32 -1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %15, i32 -1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %11, i32 -1) + br label %continue__1 + +continue__1: ; preds = %else__1, %then1__1, %then0__1 + call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i32 -1) + ret void +} + +declare %Tuple* @__quantum__rt__tuple_create(i64) + +declare void @__quantum__rt__tuple_update_reference_count(%Tuple*, i32) + +define internal void @TeleportChain__PrepareEntangledPair__ctladj(%Array* %__controlQubits__, { %Qubit*, %Qubit* }* %0) { +entry: + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 1) + %1 = getelementptr inbounds { %Qubit*, %Qubit* }, { %Qubit*, %Qubit* }* %0, i32 0, i32 0 + %left = load %Qubit*, %Qubit** %1, align 8 + %2 = getelementptr inbounds { %Qubit*, %Qubit* }, { %Qubit*, %Qubit* }* %0, i32 0, i32 1 + %right = load %Qubit*, %Qubit** %2, align 8 + %3 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 2)) + %4 = bitcast %Tuple* %3 to { %Qubit*, %Qubit* }* + %5 = getelementptr inbounds { %Qubit*, %Qubit* }, { %Qubit*, %Qubit* }* %4, i32 0, i32 0 + %6 = getelementptr inbounds { %Qubit*, %Qubit* }, { %Qubit*, %Qubit* }* %4, i32 0, i32 1 + store %Qubit* %left, %Qubit** %5, align 8 + store %Qubit* %right, %Qubit** %6, align 8 + call void @Microsoft__Quantum__Intrinsic__CNOT__ctladj(%Array* %__controlQubits__, { %Qubit*, %Qubit* }* %4) + call void @Microsoft__Quantum__Intrinsic__H__ctladj(%Array* %__controlQubits__, %Qubit* %left) + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 -1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %3, i32 -1) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__CNOT__ctladj(%Array* %__controlQubits__, { %Qubit*, %Qubit* }* %0) { +entry: + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 1) + %1 = getelementptr inbounds { %Qubit*, %Qubit* }, { %Qubit*, %Qubit* }* %0, i32 0, i32 0 + %control = load %Qubit*, %Qubit** %1, align 8 + %2 = getelementptr inbounds { %Qubit*, %Qubit* }, { %Qubit*, %Qubit* }* %0, i32 0, i32 1 + %target = load %Qubit*, %Qubit** %2, align 8 + %3 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 2)) + %4 = bitcast %Tuple* %3 to { %Qubit*, %Qubit* }* + %5 = getelementptr inbounds { %Qubit*, %Qubit* }, { %Qubit*, %Qubit* }* %4, i32 0, i32 0 + %6 = getelementptr inbounds { %Qubit*, %Qubit* }, { %Qubit*, %Qubit* }* %4, i32 0, i32 1 + store %Qubit* %control, %Qubit** %5, align 8 + store %Qubit* %target, %Qubit** %6, align 8 + call void @Microsoft__Quantum__Intrinsic__CNOT__ctl(%Array* %__controlQubits__, { %Qubit*, %Qubit* }* %4) + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 -1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %3, i32 -1) ret void } +define internal void @Microsoft__Quantum__Intrinsic__H__ctladj(%Array* %__controlQubits__, %Qubit* %qubit) { +entry: + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 1) + call void @Microsoft__Quantum__Intrinsic__H__ctl(%Array* %__controlQubits__, %Qubit* %qubit) + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 -1) + ret void +} + +define internal double @Microsoft__Quantum__Math__PI__body() { +entry: + ret double 0x400921FB54442D18 +} + +declare %Result* @__quantum__qis__m__body(%Qubit*) + +declare void @__quantum__qis__reset__body(%Qubit*) + define internal void @Microsoft__Quantum__Intrinsic____QsRef23__ApplyControlledX____body(%Qubit* %control, %Qubit* %target) { entry: call void @__quantum__qis__cnot__body(%Qubit* %control, %Qubit* %target) @@ -256,12 +474,8 @@ continue__1: ; preds = %then0__1, %entry ret void } -declare void @__quantum__rt__array_update_alias_count(%Array*, i32) - declare i64 @__quantum__rt__array_get_size_1d(%Array*) -declare i8* @__quantum__rt__array_get_element_ptr_1d(%Array*, i64) - declare %Array* @__quantum__rt__array_slice_1d(%Array*, %Range, i1) define internal void @Microsoft__Quantum__Intrinsic__R1__ctl(%Array* %__controlQubits__, { double, %Qubit* }* %0) { @@ -298,12 +512,8 @@ entry: ret void } -declare %Tuple* @__quantum__rt__tuple_create(i64) - declare void @__quantum__rt__array_update_reference_count(%Array*, i32) -declare void @__quantum__rt__tuple_update_reference_count(%Tuple*, i32) - define internal void @Microsoft__Quantum__Intrinsic____QsRef23__ApplyGlobalPhase____ctladj(%Array* %controls, double %theta) { entry: call void @__quantum__rt__array_update_alias_count(%Array* %controls, i32 1) @@ -683,7 +893,7 @@ then5__1: ; preds = %condContinue__7 br label %continue__1 else__1: ; preds = %condContinue__7 - %33 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @0, i32 0, i32 0)) + %33 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @1, i32 0, i32 0)) call void @__quantum__rt__fail(%String* %33) unreachable @@ -707,12 +917,6 @@ entry: ret void } -define internal void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* %control, %Qubit* %target) { -entry: - call void @__quantum__qis__cnot__body(%Qubit* %control, %Qubit* %target) - ret void -} - define internal void @Microsoft__Quantum__Intrinsic__T__body(%Qubit* %qubit) { entry: call void @__quantum__qis__t__body(%Qubit* %qubit) @@ -741,12 +945,6 @@ entry: ret void } -define internal void @Microsoft__Quantum__Intrinsic__CNOT__adj(%Qubit* %control, %Qubit* %target) { -entry: - call void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* %control, %Qubit* %target) - ret void -} - define internal void @Microsoft__Quantum__Intrinsic__CCNOT__body(%Qubit* %control1, %Qubit* %control2, %Qubit* %target) { entry: call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %target) @@ -847,7 +1045,7 @@ then2__1: ; preds = %test2__1 br label %continue__1 else__1: ; preds = %test2__1 - %47 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Intrinsic__Z__FunctionTable, [2 x void (%Tuple*, i32)*]* null, %Tuple* null) + %47 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Intrinsic__Z, [2 x void (%Tuple*, i32)*]* null, %Tuple* null) call void @__quantum__rt__callable_make_controlled(%Callable* %47) %48 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 2)) %49 = bitcast %Tuple* %48 to { %Array*, %Qubit* }* @@ -856,7 +1054,7 @@ else__1: ; preds = %test2__1 call void @__quantum__rt__array_update_reference_count(%Array* %ctls, i32 1) store %Array* %ctls, %Array** %50, align 8 store %Qubit* %qubit, %Qubit** %51, align 8 - call void @Microsoft__Quantum__Intrinsic___067288bb3b0f4c3fa16d90a27710fc06___QsRef23__ApplyWithLessControlsA____body(%Callable* %47, { %Array*, %Qubit* }* %49) + call void @Microsoft__Quantum__Intrinsic___fff485d029404f308fe7e714aec986f1___QsRef23__ApplyWithLessControlsA____body(%Callable* %47, { %Array*, %Qubit* }* %49) call void @__quantum__rt__capture_update_reference_count(%Callable* %47, i32 -1) call void @__quantum__rt__callable_update_reference_count(%Callable* %47, i32 -1) call void @__quantum__rt__array_update_reference_count(%Array* %ctls, i32 -1) @@ -939,7 +1137,7 @@ then2__1: ; preds = %test2__1 br label %continue__1 else__1: ; preds = %test2__1 - %14 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Intrinsic__X__FunctionTable, [2 x void (%Tuple*, i32)*]* null, %Tuple* null) + %14 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Intrinsic__X, [2 x void (%Tuple*, i32)*]* null, %Tuple* null) call void @__quantum__rt__callable_make_controlled(%Callable* %14) %15 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 2)) %16 = bitcast %Tuple* %15 to { %Array*, %Qubit* }* @@ -948,7 +1146,7 @@ else__1: ; preds = %test2__1 call void @__quantum__rt__array_update_reference_count(%Array* %ctls, i32 1) store %Array* %ctls, %Array** %17, align 8 store %Qubit* %qubit, %Qubit** %18, align 8 - call void @Microsoft__Quantum__Intrinsic___067288bb3b0f4c3fa16d90a27710fc06___QsRef23__ApplyWithLessControlsA____body(%Callable* %14, { %Array*, %Qubit* }* %16) + call void @Microsoft__Quantum__Intrinsic___fff485d029404f308fe7e714aec986f1___QsRef23__ApplyWithLessControlsA____body(%Callable* %14, { %Array*, %Qubit* }* %16) call void @__quantum__rt__capture_update_reference_count(%Callable* %14, i32 -1) call void @__quantum__rt__callable_update_reference_count(%Callable* %14, i32 -1) call void @__quantum__rt__array_update_reference_count(%Array* %ctls, i32 -1) @@ -985,63 +1183,7 @@ entry: ret void } -define internal void @Microsoft__Quantum__Intrinsic__CNOT__ctl(%Array* %ctls, { %Qubit*, %Qubit* }* %0) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i32 1) - %1 = getelementptr inbounds { %Qubit*, %Qubit* }, { %Qubit*, %Qubit* }* %0, i32 0, i32 0 - %control = load %Qubit*, %Qubit** %1, align 8 - %2 = getelementptr inbounds { %Qubit*, %Qubit* }, { %Qubit*, %Qubit* }* %0, i32 0, i32 1 - %target = load %Qubit*, %Qubit** %2, align 8 - %3 = call i64 @__quantum__rt__array_get_size_1d(%Array* %ctls) - %4 = icmp eq i64 %3, 0 - br i1 %4, label %then0__1, label %test1__1 - -then0__1: ; preds = %entry - call void @__quantum__qis__cnot__body(%Qubit* %control, %Qubit* %target) - br label %continue__1 - -test1__1: ; preds = %entry - %5 = call i64 @__quantum__rt__array_get_size_1d(%Array* %ctls) - %6 = icmp eq i64 %5, 1 - br i1 %6, label %then1__1, label %else__1 - -then1__1: ; preds = %test1__1 - %7 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls, i64 0) - %8 = bitcast i8* %7 to %Qubit** - %9 = load %Qubit*, %Qubit** %8, align 8 - call void @Microsoft__Quantum__Intrinsic__CCNOT__body(%Qubit* %9, %Qubit* %control, %Qubit* %target) - br label %continue__1 - -else__1: ; preds = %test1__1 - %10 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Intrinsic__CNOT__FunctionTable, [2 x void (%Tuple*, i32)*]* null, %Tuple* null) - call void @__quantum__rt__callable_make_controlled(%Callable* %10) - %11 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 2)) - %12 = bitcast %Tuple* %11 to { %Array*, { %Qubit*, %Qubit* }* }* - %13 = getelementptr inbounds { %Array*, { %Qubit*, %Qubit* }* }, { %Array*, { %Qubit*, %Qubit* }* }* %12, i32 0, i32 0 - %14 = getelementptr inbounds { %Array*, { %Qubit*, %Qubit* }* }, { %Array*, { %Qubit*, %Qubit* }* }* %12, i32 0, i32 1 - call void @__quantum__rt__array_update_reference_count(%Array* %ctls, i32 1) - %15 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 2)) - %16 = bitcast %Tuple* %15 to { %Qubit*, %Qubit* }* - %17 = getelementptr inbounds { %Qubit*, %Qubit* }, { %Qubit*, %Qubit* }* %16, i32 0, i32 0 - %18 = getelementptr inbounds { %Qubit*, %Qubit* }, { %Qubit*, %Qubit* }* %16, i32 0, i32 1 - store %Qubit* %control, %Qubit** %17, align 8 - store %Qubit* %target, %Qubit** %18, align 8 - store %Array* %ctls, %Array** %13, align 8 - store { %Qubit*, %Qubit* }* %16, { %Qubit*, %Qubit* }** %14, align 8 - call void @Microsoft__Quantum__Intrinsic___0d8cf5dbd1bf4f63a0469c30490db51e___QsRef23__ApplyWithLessControlsA____body(%Callable* %10, { %Array*, { %Qubit*, %Qubit* }* }* %12) - call void @__quantum__rt__capture_update_reference_count(%Callable* %10, i32 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %10, i32 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %ctls, i32 -1) - call void @__quantum__rt__tuple_update_reference_count(%Tuple* %15, i32 -1) - call void @__quantum__rt__tuple_update_reference_count(%Tuple* %11, i32 -1) - br label %continue__1 - -continue__1: ; preds = %else__1, %then1__1, %then0__1 - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i32 -1) - ret void -} - -define internal void @Microsoft__Quantum__Intrinsic___0d8cf5dbd1bf4f63a0469c30490db51e___QsRef23__ApplyWithLessControlsA____body(%Callable* %op, { %Array*, { %Qubit*, %Qubit* }* }* %0) { +define internal void @Microsoft__Quantum__Intrinsic___9befc69676a248a794d7a83b374c573e___QsRef23__ApplyWithLessControlsA____body(%Callable* %op, { %Array*, { %Qubit*, %Qubit* }* }* %0) { entry: call void @__quantum__rt__capture_update_alias_count(%Callable* %op, i32 1) call void @__quantum__rt__callable_update_alias_count(%Callable* %op, i32 1) @@ -1232,77 +1374,7 @@ declare void @__quantum__rt__capture_update_reference_count(%Callable*, i32) declare void @__quantum__rt__callable_update_reference_count(%Callable*, i32) -define internal void @Microsoft__Quantum__Intrinsic__CNOT__ctladj(%Array* %__controlQubits__, { %Qubit*, %Qubit* }* %0) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 1) - %1 = getelementptr inbounds { %Qubit*, %Qubit* }, { %Qubit*, %Qubit* }* %0, i32 0, i32 0 - %control = load %Qubit*, %Qubit** %1, align 8 - %2 = getelementptr inbounds { %Qubit*, %Qubit* }, { %Qubit*, %Qubit* }* %0, i32 0, i32 1 - %target = load %Qubit*, %Qubit** %2, align 8 - %3 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 2)) - %4 = bitcast %Tuple* %3 to { %Qubit*, %Qubit* }* - %5 = getelementptr inbounds { %Qubit*, %Qubit* }, { %Qubit*, %Qubit* }* %4, i32 0, i32 0 - %6 = getelementptr inbounds { %Qubit*, %Qubit* }, { %Qubit*, %Qubit* }* %4, i32 0, i32 1 - store %Qubit* %control, %Qubit** %5, align 8 - store %Qubit* %target, %Qubit** %6, align 8 - call void @Microsoft__Quantum__Intrinsic__CNOT__ctl(%Array* %__controlQubits__, { %Qubit*, %Qubit* }* %4) - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 -1) - call void @__quantum__rt__tuple_update_reference_count(%Tuple* %3, i32 -1) - ret void -} - -define internal void @Microsoft__Quantum__Intrinsic__H__ctl(%Array* %ctls, %Qubit* %qubit) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i32 1) - %0 = call i64 @__quantum__rt__array_get_size_1d(%Array* %ctls) - %1 = icmp eq i64 %0, 0 - br i1 %1, label %then0__1, label %test1__1 - -then0__1: ; preds = %entry - call void @__quantum__qis__h__body(%Qubit* %qubit) - br label %continue__1 - -test1__1: ; preds = %entry - %2 = call i64 @__quantum__rt__array_get_size_1d(%Array* %ctls) - %3 = icmp eq i64 %2, 1 - br i1 %3, label %then1__1, label %else__1 - -then1__1: ; preds = %test1__1 - call void @Microsoft__Quantum__Intrinsic__S__body(%Qubit* %qubit) - call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %qubit) - call void @Microsoft__Quantum__Intrinsic__T__body(%Qubit* %qubit) - %4 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %ctls, i64 0) - %5 = bitcast i8* %4 to %Qubit** - %6 = load %Qubit*, %Qubit** %5, align 8 - call void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* %6, %Qubit* %qubit) - call void @Microsoft__Quantum__Intrinsic__T__adj(%Qubit* %qubit) - call void @Microsoft__Quantum__Intrinsic__H__adj(%Qubit* %qubit) - call void @Microsoft__Quantum__Intrinsic__S__adj(%Qubit* %qubit) - br label %continue__1 - -else__1: ; preds = %test1__1 - %7 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Intrinsic__H__FunctionTable, [2 x void (%Tuple*, i32)*]* null, %Tuple* null) - call void @__quantum__rt__callable_make_controlled(%Callable* %7) - %8 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 2)) - %9 = bitcast %Tuple* %8 to { %Array*, %Qubit* }* - %10 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %9, i32 0, i32 0 - %11 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %9, i32 0, i32 1 - call void @__quantum__rt__array_update_reference_count(%Array* %ctls, i32 1) - store %Array* %ctls, %Array** %10, align 8 - store %Qubit* %qubit, %Qubit** %11, align 8 - call void @Microsoft__Quantum__Intrinsic___067288bb3b0f4c3fa16d90a27710fc06___QsRef23__ApplyWithLessControlsA____body(%Callable* %7, { %Array*, %Qubit* }* %9) - call void @__quantum__rt__capture_update_reference_count(%Callable* %7, i32 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %7, i32 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %ctls, i32 -1) - call void @__quantum__rt__tuple_update_reference_count(%Tuple* %8, i32 -1) - br label %continue__1 - -continue__1: ; preds = %else__1, %then1__1, %then0__1 - call void @__quantum__rt__array_update_alias_count(%Array* %ctls, i32 -1) - ret void -} - -define internal void @Microsoft__Quantum__Intrinsic___067288bb3b0f4c3fa16d90a27710fc06___QsRef23__ApplyWithLessControlsA____body(%Callable* %op, { %Array*, %Qubit* }* %0) { +define internal void @Microsoft__Quantum__Intrinsic___fff485d029404f308fe7e714aec986f1___QsRef23__ApplyWithLessControlsA____body(%Callable* %op, { %Array*, %Qubit* }* %0) { entry: call void @__quantum__rt__capture_update_alias_count(%Callable* %op, i32 1) call void @__quantum__rt__callable_update_alias_count(%Callable* %op, i32 1) @@ -1476,12 +1548,10 @@ entry: ret void } -define internal void @Microsoft__Quantum__Intrinsic__H__ctladj(%Array* %__controlQubits__, %Qubit* %qubit) { +define internal %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %qubit) { entry: - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 1) - call void @Microsoft__Quantum__Intrinsic__H__ctl(%Array* %__controlQubits__, %Qubit* %qubit) - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 -1) - ret void + %0 = call %Result* @__quantum__qis__m__body(%Qubit* %qubit) + ret %Result* %0 } define internal void @Microsoft__Quantum__Intrinsic__R__body(i2 %pauli, double %theta, %Qubit* %qubit) { @@ -1534,6 +1604,12 @@ entry: ret void } +define internal void @Microsoft__Quantum__Intrinsic__Rz__body(double %theta, %Qubit* %qubit) { +entry: + call void @__quantum__qis__rz__body(double %theta, %Qubit* %qubit) + ret void +} + define internal void @Microsoft__Quantum__Intrinsic__R__adj(i2 %pauli, double %theta, %Qubit* %qubit) { entry: %0 = load i2, i2* @PauliX, align 1 @@ -1698,7 +1774,7 @@ then1__1: ; preds = %test1__1 br label %continue__1 else__1: ; preds = %test1__1 - %15 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Intrinsic__Rx__FunctionTable, [2 x void (%Tuple*, i32)*]* null, %Tuple* null) + %15 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Intrinsic__Rx, [2 x void (%Tuple*, i32)*]* null, %Tuple* null) call void @__quantum__rt__callable_make_controlled(%Callable* %15) %16 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 2)) %17 = bitcast %Tuple* %16 to { %Array*, { double, %Qubit* }* }* @@ -1713,7 +1789,7 @@ else__1: ; preds = %test1__1 store %Qubit* %qubit, %Qubit** %23, align 8 store %Array* %ctls, %Array** %18, align 8 store { double, %Qubit* }* %21, { double, %Qubit* }** %19, align 8 - call void @Microsoft__Quantum__Intrinsic___8f3359a2b69a47ffa9fd2508e6ea5641___QsRef23__ApplyWithLessControlsA____body(%Callable* %15, { %Array*, { double, %Qubit* }* }* %17) + call void @Microsoft__Quantum__Intrinsic___ad761790e5b447849d6dea7cab2a3295___QsRef23__ApplyWithLessControlsA____body(%Callable* %15, { %Array*, { double, %Qubit* }* }* %17) call void @__quantum__rt__capture_update_reference_count(%Callable* %15, i32 -1) call void @__quantum__rt__callable_update_reference_count(%Callable* %15, i32 -1) call void @__quantum__rt__array_update_reference_count(%Array* %ctls, i32 -1) @@ -1764,7 +1840,7 @@ then1__1: ; preds = %test1__1 br label %continue__1 else__1: ; preds = %test1__1 - %15 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Intrinsic__Ry__FunctionTable, [2 x void (%Tuple*, i32)*]* null, %Tuple* null) + %15 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Intrinsic__Ry, [2 x void (%Tuple*, i32)*]* null, %Tuple* null) call void @__quantum__rt__callable_make_controlled(%Callable* %15) %16 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 2)) %17 = bitcast %Tuple* %16 to { %Array*, { double, %Qubit* }* }* @@ -1779,7 +1855,7 @@ else__1: ; preds = %test1__1 store %Qubit* %qubit, %Qubit** %23, align 8 store %Array* %ctls, %Array** %18, align 8 store { double, %Qubit* }* %21, { double, %Qubit* }** %19, align 8 - call void @Microsoft__Quantum__Intrinsic___8f3359a2b69a47ffa9fd2508e6ea5641___QsRef23__ApplyWithLessControlsA____body(%Callable* %15, { %Array*, { double, %Qubit* }* }* %17) + call void @Microsoft__Quantum__Intrinsic___ad761790e5b447849d6dea7cab2a3295___QsRef23__ApplyWithLessControlsA____body(%Callable* %15, { %Array*, { double, %Qubit* }* }* %17) call void @__quantum__rt__capture_update_reference_count(%Callable* %15, i32 -1) call void @__quantum__rt__callable_update_reference_count(%Callable* %15, i32 -1) call void @__quantum__rt__array_update_reference_count(%Array* %ctls, i32 -1) @@ -1829,7 +1905,7 @@ then1__1: ; preds = %test1__1 br label %continue__1 else__1: ; preds = %test1__1 - %16 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Intrinsic__Rz__FunctionTable, [2 x void (%Tuple*, i32)*]* null, %Tuple* null) + %16 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Intrinsic__Rz, [2 x void (%Tuple*, i32)*]* null, %Tuple* null) call void @__quantum__rt__callable_make_controlled(%Callable* %16) %17 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 2)) %18 = bitcast %Tuple* %17 to { %Array*, { double, %Qubit* }* }* @@ -1844,7 +1920,7 @@ else__1: ; preds = %test1__1 store %Qubit* %qubit, %Qubit** %24, align 8 store %Array* %ctls, %Array** %19, align 8 store { double, %Qubit* }* %22, { double, %Qubit* }** %20, align 8 - call void @Microsoft__Quantum__Intrinsic___8f3359a2b69a47ffa9fd2508e6ea5641___QsRef23__ApplyWithLessControlsA____body(%Callable* %16, { %Array*, { double, %Qubit* }* }* %18) + call void @Microsoft__Quantum__Intrinsic___ad761790e5b447849d6dea7cab2a3295___QsRef23__ApplyWithLessControlsA____body(%Callable* %16, { %Array*, { double, %Qubit* }* }* %18) call void @__quantum__rt__capture_update_reference_count(%Callable* %16, i32 -1) call void @__quantum__rt__callable_update_reference_count(%Callable* %16, i32 -1) call void @__quantum__rt__array_update_reference_count(%Array* %ctls, i32 -1) @@ -2208,19 +2284,12 @@ entry: ret void } -declare void @__quantum__qis__reset__body(%Qubit*) - -define internal double @Microsoft__Quantum__Math__PI__body() { -entry: - ret double 0x400921FB54442D18 -} - ; Function Attrs: nounwind readnone speculatable willreturn declare double @llvm.pow.f64(double, double) #0 declare void @__quantum__qis__rx__body(double, %Qubit*) -define internal void @Microsoft__Quantum__Intrinsic___8f3359a2b69a47ffa9fd2508e6ea5641___QsRef23__ApplyWithLessControlsA____body(%Callable* %op, { %Array*, { double, %Qubit* }* }* %0) { +define internal void @Microsoft__Quantum__Intrinsic___ad761790e5b447849d6dea7cab2a3295___QsRef23__ApplyWithLessControlsA____body(%Callable* %op, { %Array*, { double, %Qubit* }* }* %0) { entry: call void @__quantum__rt__capture_update_alias_count(%Callable* %op, i32 1) call void @__quantum__rt__callable_update_alias_count(%Callable* %op, i32 1) @@ -2533,7 +2602,7 @@ then1__1: ; preds = %test1__1 br label %continue__1 else__1: ; preds = %test1__1 - %13 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Intrinsic__S__FunctionTable, [2 x void (%Tuple*, i32)*]* null, %Tuple* null) + %13 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Intrinsic__S, [2 x void (%Tuple*, i32)*]* null, %Tuple* null) call void @__quantum__rt__callable_make_controlled(%Callable* %13) %14 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 2)) %15 = bitcast %Tuple* %14 to { %Array*, %Qubit* }* @@ -2542,7 +2611,7 @@ else__1: ; preds = %test1__1 call void @__quantum__rt__array_update_reference_count(%Array* %ctls, i32 1) store %Array* %ctls, %Array** %16, align 8 store %Qubit* %qubit, %Qubit** %17, align 8 - call void @Microsoft__Quantum__Intrinsic___067288bb3b0f4c3fa16d90a27710fc06___QsRef23__ApplyWithLessControlsA____body(%Callable* %13, { %Array*, %Qubit* }* %15) + call void @Microsoft__Quantum__Intrinsic___fff485d029404f308fe7e714aec986f1___QsRef23__ApplyWithLessControlsA____body(%Callable* %13, { %Array*, %Qubit* }* %15) call void @__quantum__rt__capture_update_reference_count(%Callable* %13, i32 -1) call void @__quantum__rt__callable_update_reference_count(%Callable* %13, i32 -1) call void @__quantum__rt__array_update_reference_count(%Array* %ctls, i32 -1) @@ -2628,7 +2697,7 @@ then1__1: ; preds = %test1__1 br label %continue__1 else__1: ; preds = %test1__1 - %13 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Intrinsic__S__FunctionTable, [2 x void (%Tuple*, i32)*]* null, %Tuple* null) + %13 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Intrinsic__S, [2 x void (%Tuple*, i32)*]* null, %Tuple* null) call void @__quantum__rt__callable_make_adjoint(%Callable* %13) call void @__quantum__rt__callable_make_controlled(%Callable* %13) %14 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 2)) @@ -2638,7 +2707,7 @@ else__1: ; preds = %test1__1 call void @__quantum__rt__array_update_reference_count(%Array* %ctls, i32 1) store %Array* %ctls, %Array** %16, align 8 store %Qubit* %qubit, %Qubit** %17, align 8 - call void @Microsoft__Quantum__Intrinsic___067288bb3b0f4c3fa16d90a27710fc06___QsRef23__ApplyWithLessControlsA____body(%Callable* %13, { %Array*, %Qubit* }* %15) + call void @Microsoft__Quantum__Intrinsic___fff485d029404f308fe7e714aec986f1___QsRef23__ApplyWithLessControlsA____body(%Callable* %13, { %Array*, %Qubit* }* %15) call void @__quantum__rt__capture_update_reference_count(%Callable* %13, i32 -1) call void @__quantum__rt__callable_update_reference_count(%Callable* %13, i32 -1) call void @__quantum__rt__array_update_reference_count(%Array* %ctls, i32 -1) @@ -2690,7 +2759,7 @@ then1__1: ; preds = %test1__1 br label %continue__1 else__1: ; preds = %test1__1 - %13 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Intrinsic__T__FunctionTable, [2 x void (%Tuple*, i32)*]* null, %Tuple* null) + %13 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Intrinsic__T, [2 x void (%Tuple*, i32)*]* null, %Tuple* null) call void @__quantum__rt__callable_make_controlled(%Callable* %13) %14 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 2)) %15 = bitcast %Tuple* %14 to { %Array*, %Qubit* }* @@ -2699,7 +2768,7 @@ else__1: ; preds = %test1__1 call void @__quantum__rt__array_update_reference_count(%Array* %ctls, i32 1) store %Array* %ctls, %Array** %16, align 8 store %Qubit* %qubit, %Qubit** %17, align 8 - call void @Microsoft__Quantum__Intrinsic___067288bb3b0f4c3fa16d90a27710fc06___QsRef23__ApplyWithLessControlsA____body(%Callable* %13, { %Array*, %Qubit* }* %15) + call void @Microsoft__Quantum__Intrinsic___fff485d029404f308fe7e714aec986f1___QsRef23__ApplyWithLessControlsA____body(%Callable* %13, { %Array*, %Qubit* }* %15) call void @__quantum__rt__capture_update_reference_count(%Callable* %13, i32 -1) call void @__quantum__rt__callable_update_reference_count(%Callable* %13, i32 -1) call void @__quantum__rt__array_update_reference_count(%Array* %ctls, i32 -1) @@ -2785,7 +2854,7 @@ then1__1: ; preds = %test1__1 br label %continue__1 else__1: ; preds = %test1__1 - %13 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Intrinsic__T__FunctionTable, [2 x void (%Tuple*, i32)*]* null, %Tuple* null) + %13 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @Microsoft__Quantum__Intrinsic__T, [2 x void (%Tuple*, i32)*]* null, %Tuple* null) call void @__quantum__rt__callable_make_adjoint(%Callable* %13) call void @__quantum__rt__callable_make_controlled(%Callable* %13) %14 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 2)) @@ -2795,7 +2864,7 @@ else__1: ; preds = %test1__1 call void @__quantum__rt__array_update_reference_count(%Array* %ctls, i32 1) store %Array* %ctls, %Array** %16, align 8 store %Qubit* %qubit, %Qubit** %17, align 8 - call void @Microsoft__Quantum__Intrinsic___067288bb3b0f4c3fa16d90a27710fc06___QsRef23__ApplyWithLessControlsA____body(%Callable* %13, { %Array*, %Qubit* }* %15) + call void @Microsoft__Quantum__Intrinsic___fff485d029404f308fe7e714aec986f1___QsRef23__ApplyWithLessControlsA____body(%Callable* %13, { %Array*, %Qubit* }* %15) call void @__quantum__rt__capture_update_reference_count(%Callable* %13, i32 -1) call void @__quantum__rt__callable_update_reference_count(%Callable* %13, i32 -1) call void @__quantum__rt__array_update_reference_count(%Array* %ctls, i32 -1) @@ -2861,12 +2930,6 @@ entry: ret void } -define internal void @Microsoft__Quantum__Intrinsic__Z__body(%Qubit* %qubit) { -entry: - call void @__quantum__qis__z__body(%Qubit* %qubit) - ret void -} - define internal void @Microsoft__Quantum__Intrinsic__Z__adj(%Qubit* %qubit) { entry: call void @Microsoft__Quantum__Intrinsic__Z__body(%Qubit* %qubit) @@ -2925,13 +2988,152 @@ declare void @__quantum__rt__capture_update_alias_count(%Callable*, i32) declare void @__quantum__rt__callable_update_alias_count(%Callable*, i32) -declare void @__quantum__rt__tuple_update_alias_count(%Tuple*, i32) +declare void @__quantum__rt__callable_invoke(%Callable*, %Tuple*, %Tuple*) -declare void @__quantum__rt__qubit_release_array(%Array*) +define internal void @Microsoft__Quantum__Intrinsic___fff485d029404f308fe7e714aec986f1___QsRef23__ApplyWithLessControlsA____adj(%Callable* %op, { %Array*, %Qubit* }* %0) { +entry: + call void @__quantum__rt__capture_update_alias_count(%Callable* %op, i32 1) + call void @__quantum__rt__callable_update_alias_count(%Callable* %op, i32 1) + %1 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 0 + %controls = load %Array*, %Array** %1, align 8 + call void @__quantum__rt__array_update_alias_count(%Array* %controls, i32 1) + %2 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 1 + %arg = load %Qubit*, %Qubit** %2, align 8 + %__qsVar0__numControls__ = call i64 @__quantum__rt__array_get_size_1d(%Array* %controls) + %__qsVar1__numControlPairs__ = sdiv i64 %__qsVar0__numControls__, 2 + %__qsVar2__temps__ = call %Array* @__quantum__rt__qubit_allocate_array(i64 %__qsVar1__numControlPairs__) + call void @__quantum__rt__array_update_alias_count(%Array* %__qsVar2__temps__, i32 1) + %3 = sub i64 %__qsVar1__numControlPairs__, 1 + br label %header__1 -declare void @__quantum__rt__callable_invoke(%Callable*, %Tuple*, %Tuple*) +header__1: ; preds = %exiting__1, %entry + %__qsVar0____qsVar3__numPair____ = phi i64 [ 0, %entry ], [ %17, %exiting__1 ] + %4 = icmp sle i64 %__qsVar0____qsVar3__numPair____, %3 + br i1 %4, label %body__1, label %exit__1 + +body__1: ; preds = %header__1 + %5 = mul i64 2, %__qsVar0____qsVar3__numPair____ + %6 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %controls, i64 %5) + %7 = bitcast i8* %6 to %Qubit** + %8 = load %Qubit*, %Qubit** %7, align 8 + %9 = mul i64 2, %__qsVar0____qsVar3__numPair____ + %10 = add i64 %9, 1 + %11 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %controls, i64 %10) + %12 = bitcast i8* %11 to %Qubit** + %13 = load %Qubit*, %Qubit** %12, align 8 + %14 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %__qsVar2__temps__, i64 %__qsVar0____qsVar3__numPair____) + %15 = bitcast i8* %14 to %Qubit** + %16 = load %Qubit*, %Qubit** %15, align 8 + call void @Microsoft__Quantum__Intrinsic____QsRef23__PhaseCCX____body(%Qubit* %8, %Qubit* %13, %Qubit* %16) + br label %exiting__1 + +exiting__1: ; preds = %body__1 + %17 = add i64 %__qsVar0____qsVar3__numPair____, 1 + br label %header__1 + +exit__1: ; preds = %header__1 + %18 = srem i64 %__qsVar0__numControls__, 2 + %19 = icmp eq i64 %18, 0 + br i1 %19, label %condTrue__1, label %condFalse__1 + +condTrue__1: ; preds = %exit__1 + call void @__quantum__rt__array_update_reference_count(%Array* %__qsVar2__temps__, i32 1) + br label %condContinue__1 + +condFalse__1: ; preds = %exit__1 + %20 = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) + %21 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %20, i64 0) + %22 = bitcast i8* %21 to %Qubit** + %23 = sub i64 %__qsVar0__numControls__, 1 + %24 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %controls, i64 %23) + %25 = bitcast i8* %24 to %Qubit** + %26 = load %Qubit*, %Qubit** %25, align 8 + store %Qubit* %26, %Qubit** %22, align 8 + %27 = call %Array* @__quantum__rt__array_concatenate(%Array* %__qsVar2__temps__, %Array* %20) + call void @__quantum__rt__array_update_reference_count(%Array* %27, i32 1) + call void @__quantum__rt__array_update_reference_count(%Array* %20, i32 -1) + call void @__quantum__rt__array_update_reference_count(%Array* %27, i32 -1) + br label %condContinue__1 + +condContinue__1: ; preds = %condFalse__1, %condTrue__1 + %__qsVar1____qsVar4__newControls____ = phi %Array* [ %__qsVar2__temps__, %condTrue__1 ], [ %27, %condFalse__1 ] + call void @__quantum__rt__array_update_alias_count(%Array* %__qsVar1____qsVar4__newControls____, i32 1) + %28 = call %Callable* @__quantum__rt__callable_copy(%Callable* %op, i1 false) + call void @__quantum__rt__capture_update_reference_count(%Callable* %28, i32 1) + call void @__quantum__rt__callable_make_adjoint(%Callable* %28) + %29 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 2)) + %30 = bitcast %Tuple* %29 to { %Array*, %Qubit* }* + %31 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %30, i32 0, i32 0 + %32 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %30, i32 0, i32 1 + call void @__quantum__rt__array_update_reference_count(%Array* %__qsVar1____qsVar4__newControls____, i32 1) + store %Array* %__qsVar1____qsVar4__newControls____, %Array** %31, align 8 + store %Qubit* %arg, %Qubit** %32, align 8 + call void @__quantum__rt__callable_invoke(%Callable* %28, %Tuple* %29, %Tuple* null) + %33 = sub i64 %__qsVar1__numControlPairs__, 1 + %34 = sub i64 %33, 0 + %35 = sdiv i64 %34, 1 + %36 = mul i64 1, %35 + %37 = add i64 0, %36 + %38 = load %Range, %Range* @EmptyRange, align 4 + %39 = insertvalue %Range %38, i64 %37, 0 + %40 = insertvalue %Range %39, i64 -1, 1 + %41 = insertvalue %Range %40, i64 0, 2 + %42 = extractvalue %Range %41, 0 + %43 = extractvalue %Range %41, 1 + %44 = extractvalue %Range %41, 2 + br label %preheader__1 + +preheader__1: ; preds = %condContinue__1 + %45 = icmp sgt i64 %43, 0 + br label %header__2 + +header__2: ; preds = %exiting__2, %preheader__1 + %__qsVar0____qsVar0____qsVar3__numPair______ = phi i64 [ %42, %preheader__1 ], [ %61, %exiting__2 ] + %46 = icmp sle i64 %__qsVar0____qsVar0____qsVar3__numPair______, %44 + %47 = icmp sge i64 %__qsVar0____qsVar0____qsVar3__numPair______, %44 + %48 = select i1 %45, i1 %46, i1 %47 + br i1 %48, label %body__2, label %exit__2 + +body__2: ; preds = %header__2 + %49 = mul i64 2, %__qsVar0____qsVar0____qsVar3__numPair______ + %50 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %controls, i64 %49) + %51 = bitcast i8* %50 to %Qubit** + %52 = load %Qubit*, %Qubit** %51, align 8 + %53 = mul i64 2, %__qsVar0____qsVar0____qsVar3__numPair______ + %54 = add i64 %53, 1 + %55 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %controls, i64 %54) + %56 = bitcast i8* %55 to %Qubit** + %57 = load %Qubit*, %Qubit** %56, align 8 + %58 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %__qsVar2__temps__, i64 %__qsVar0____qsVar0____qsVar3__numPair______) + %59 = bitcast i8* %58 to %Qubit** + %60 = load %Qubit*, %Qubit** %59, align 8 + call void @Microsoft__Quantum__Intrinsic____QsRef23__PhaseCCX____adj(%Qubit* %52, %Qubit* %57, %Qubit* %60) + br label %exiting__2 + +exiting__2: ; preds = %body__2 + %61 = add i64 %__qsVar0____qsVar0____qsVar3__numPair______, %43 + br label %header__2 + +exit__2: ; preds = %header__2 + call void @__quantum__rt__array_update_alias_count(%Array* %__qsVar2__temps__, i32 -1) + call void @__quantum__rt__array_update_alias_count(%Array* %__qsVar1____qsVar4__newControls____, i32 -1) + call void @__quantum__rt__array_update_reference_count(%Array* %__qsVar1____qsVar4__newControls____, i32 -1) + call void @__quantum__rt__capture_update_reference_count(%Callable* %28, i32 -1) + call void @__quantum__rt__callable_update_reference_count(%Callable* %28, i32 -1) + call void @__quantum__rt__array_update_reference_count(%Array* %__qsVar1____qsVar4__newControls____, i32 -1) + call void @__quantum__rt__tuple_update_reference_count(%Tuple* %29, i32 -1) + call void @__quantum__rt__qubit_release_array(%Array* %__qsVar2__temps__) + call void @__quantum__rt__capture_update_alias_count(%Callable* %op, i32 -1) + call void @__quantum__rt__callable_update_alias_count(%Callable* %op, i32 -1) + call void @__quantum__rt__array_update_alias_count(%Array* %controls, i32 -1) + ret void +} + +declare %Callable* @__quantum__rt__callable_copy(%Callable*, i1) + +declare void @__quantum__rt__tuple_update_alias_count(%Tuple*, i32) -define internal void @Microsoft__Quantum__Intrinsic___8f3359a2b69a47ffa9fd2508e6ea5641___QsRef23__ApplyWithLessControlsA____adj(%Callable* %op, { %Array*, { double, %Qubit* }* }* %0) { +define internal void @Microsoft__Quantum__Intrinsic___ad761790e5b447849d6dea7cab2a3295___QsRef23__ApplyWithLessControlsA____adj(%Callable* %op, { %Array*, { double, %Qubit* }* }* %0) { entry: call void @__quantum__rt__capture_update_alias_count(%Callable* %op, i32 1) call void @__quantum__rt__callable_update_alias_count(%Callable* %op, i32 1) @@ -3075,148 +3277,7 @@ exit__2: ; preds = %header__2 ret void } -declare %Callable* @__quantum__rt__callable_copy(%Callable*, i1) - -define internal void @Microsoft__Quantum__Intrinsic___067288bb3b0f4c3fa16d90a27710fc06___QsRef23__ApplyWithLessControlsA____adj(%Callable* %op, { %Array*, %Qubit* }* %0) { -entry: - call void @__quantum__rt__capture_update_alias_count(%Callable* %op, i32 1) - call void @__quantum__rt__callable_update_alias_count(%Callable* %op, i32 1) - %1 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 0 - %controls = load %Array*, %Array** %1, align 8 - call void @__quantum__rt__array_update_alias_count(%Array* %controls, i32 1) - %2 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %0, i32 0, i32 1 - %arg = load %Qubit*, %Qubit** %2, align 8 - %__qsVar0__numControls__ = call i64 @__quantum__rt__array_get_size_1d(%Array* %controls) - %__qsVar1__numControlPairs__ = sdiv i64 %__qsVar0__numControls__, 2 - %__qsVar2__temps__ = call %Array* @__quantum__rt__qubit_allocate_array(i64 %__qsVar1__numControlPairs__) - call void @__quantum__rt__array_update_alias_count(%Array* %__qsVar2__temps__, i32 1) - %3 = sub i64 %__qsVar1__numControlPairs__, 1 - br label %header__1 - -header__1: ; preds = %exiting__1, %entry - %__qsVar0____qsVar3__numPair____ = phi i64 [ 0, %entry ], [ %17, %exiting__1 ] - %4 = icmp sle i64 %__qsVar0____qsVar3__numPair____, %3 - br i1 %4, label %body__1, label %exit__1 - -body__1: ; preds = %header__1 - %5 = mul i64 2, %__qsVar0____qsVar3__numPair____ - %6 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %controls, i64 %5) - %7 = bitcast i8* %6 to %Qubit** - %8 = load %Qubit*, %Qubit** %7, align 8 - %9 = mul i64 2, %__qsVar0____qsVar3__numPair____ - %10 = add i64 %9, 1 - %11 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %controls, i64 %10) - %12 = bitcast i8* %11 to %Qubit** - %13 = load %Qubit*, %Qubit** %12, align 8 - %14 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %__qsVar2__temps__, i64 %__qsVar0____qsVar3__numPair____) - %15 = bitcast i8* %14 to %Qubit** - %16 = load %Qubit*, %Qubit** %15, align 8 - call void @Microsoft__Quantum__Intrinsic____QsRef23__PhaseCCX____body(%Qubit* %8, %Qubit* %13, %Qubit* %16) - br label %exiting__1 - -exiting__1: ; preds = %body__1 - %17 = add i64 %__qsVar0____qsVar3__numPair____, 1 - br label %header__1 - -exit__1: ; preds = %header__1 - %18 = srem i64 %__qsVar0__numControls__, 2 - %19 = icmp eq i64 %18, 0 - br i1 %19, label %condTrue__1, label %condFalse__1 - -condTrue__1: ; preds = %exit__1 - call void @__quantum__rt__array_update_reference_count(%Array* %__qsVar2__temps__, i32 1) - br label %condContinue__1 - -condFalse__1: ; preds = %exit__1 - %20 = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) - %21 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %20, i64 0) - %22 = bitcast i8* %21 to %Qubit** - %23 = sub i64 %__qsVar0__numControls__, 1 - %24 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %controls, i64 %23) - %25 = bitcast i8* %24 to %Qubit** - %26 = load %Qubit*, %Qubit** %25, align 8 - store %Qubit* %26, %Qubit** %22, align 8 - %27 = call %Array* @__quantum__rt__array_concatenate(%Array* %__qsVar2__temps__, %Array* %20) - call void @__quantum__rt__array_update_reference_count(%Array* %27, i32 1) - call void @__quantum__rt__array_update_reference_count(%Array* %20, i32 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %27, i32 -1) - br label %condContinue__1 - -condContinue__1: ; preds = %condFalse__1, %condTrue__1 - %__qsVar1____qsVar4__newControls____ = phi %Array* [ %__qsVar2__temps__, %condTrue__1 ], [ %27, %condFalse__1 ] - call void @__quantum__rt__array_update_alias_count(%Array* %__qsVar1____qsVar4__newControls____, i32 1) - %28 = call %Callable* @__quantum__rt__callable_copy(%Callable* %op, i1 false) - call void @__quantum__rt__capture_update_reference_count(%Callable* %28, i32 1) - call void @__quantum__rt__callable_make_adjoint(%Callable* %28) - %29 = call %Tuple* @__quantum__rt__tuple_create(i64 mul nuw (i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64 2)) - %30 = bitcast %Tuple* %29 to { %Array*, %Qubit* }* - %31 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %30, i32 0, i32 0 - %32 = getelementptr inbounds { %Array*, %Qubit* }, { %Array*, %Qubit* }* %30, i32 0, i32 1 - call void @__quantum__rt__array_update_reference_count(%Array* %__qsVar1____qsVar4__newControls____, i32 1) - store %Array* %__qsVar1____qsVar4__newControls____, %Array** %31, align 8 - store %Qubit* %arg, %Qubit** %32, align 8 - call void @__quantum__rt__callable_invoke(%Callable* %28, %Tuple* %29, %Tuple* null) - %33 = sub i64 %__qsVar1__numControlPairs__, 1 - %34 = sub i64 %33, 0 - %35 = sdiv i64 %34, 1 - %36 = mul i64 1, %35 - %37 = add i64 0, %36 - %38 = load %Range, %Range* @EmptyRange, align 4 - %39 = insertvalue %Range %38, i64 %37, 0 - %40 = insertvalue %Range %39, i64 -1, 1 - %41 = insertvalue %Range %40, i64 0, 2 - %42 = extractvalue %Range %41, 0 - %43 = extractvalue %Range %41, 1 - %44 = extractvalue %Range %41, 2 - br label %preheader__1 - -preheader__1: ; preds = %condContinue__1 - %45 = icmp sgt i64 %43, 0 - br label %header__2 - -header__2: ; preds = %exiting__2, %preheader__1 - %__qsVar0____qsVar0____qsVar3__numPair______ = phi i64 [ %42, %preheader__1 ], [ %61, %exiting__2 ] - %46 = icmp sle i64 %__qsVar0____qsVar0____qsVar3__numPair______, %44 - %47 = icmp sge i64 %__qsVar0____qsVar0____qsVar3__numPair______, %44 - %48 = select i1 %45, i1 %46, i1 %47 - br i1 %48, label %body__2, label %exit__2 - -body__2: ; preds = %header__2 - %49 = mul i64 2, %__qsVar0____qsVar0____qsVar3__numPair______ - %50 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %controls, i64 %49) - %51 = bitcast i8* %50 to %Qubit** - %52 = load %Qubit*, %Qubit** %51, align 8 - %53 = mul i64 2, %__qsVar0____qsVar0____qsVar3__numPair______ - %54 = add i64 %53, 1 - %55 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %controls, i64 %54) - %56 = bitcast i8* %55 to %Qubit** - %57 = load %Qubit*, %Qubit** %56, align 8 - %58 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %__qsVar2__temps__, i64 %__qsVar0____qsVar0____qsVar3__numPair______) - %59 = bitcast i8* %58 to %Qubit** - %60 = load %Qubit*, %Qubit** %59, align 8 - call void @Microsoft__Quantum__Intrinsic____QsRef23__PhaseCCX____adj(%Qubit* %52, %Qubit* %57, %Qubit* %60) - br label %exiting__2 - -exiting__2: ; preds = %body__2 - %61 = add i64 %__qsVar0____qsVar0____qsVar3__numPair______, %43 - br label %header__2 - -exit__2: ; preds = %header__2 - call void @__quantum__rt__array_update_alias_count(%Array* %__qsVar2__temps__, i32 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %__qsVar1____qsVar4__newControls____, i32 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %__qsVar1____qsVar4__newControls____, i32 -1) - call void @__quantum__rt__capture_update_reference_count(%Callable* %28, i32 -1) - call void @__quantum__rt__callable_update_reference_count(%Callable* %28, i32 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %__qsVar1____qsVar4__newControls____, i32 -1) - call void @__quantum__rt__tuple_update_reference_count(%Tuple* %29, i32 -1) - call void @__quantum__rt__qubit_release_array(%Array* %__qsVar2__temps__) - call void @__quantum__rt__capture_update_alias_count(%Callable* %op, i32 -1) - call void @__quantum__rt__callable_update_alias_count(%Callable* %op, i32 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %controls, i32 -1) - ret void -} - -define internal void @Microsoft__Quantum__Intrinsic___0d8cf5dbd1bf4f63a0469c30490db51e___QsRef23__ApplyWithLessControlsA____adj(%Callable* %op, { %Array*, { %Qubit*, %Qubit* }* }* %0) { +define internal void @Microsoft__Quantum__Intrinsic___9befc69676a248a794d7a83b374c573e___QsRef23__ApplyWithLessControlsA____adj(%Callable* %op, { %Array*, { %Qubit*, %Qubit* }* }* %0) { entry: call void @__quantum__rt__capture_update_alias_count(%Callable* %op, i32 1) call void @__quantum__rt__callable_update_alias_count(%Callable* %op, i32 1) @@ -3360,18 +3421,17 @@ exit__2: ; preds = %header__2 ret void } -declare %Result* @__quantum__qis__m__body(%Qubit*) - -define double @Microsoft__Quantum__Qir__Emission__EstimatePhaseByRandomWalk__Interop() #1 { +define i8 @TeleportChain__DemonstrateTeleportationUsingPresharedEntanglement__Interop() #1 { entry: - %0 = call double @Microsoft__Quantum__Qir__Emission__EstimatePhaseByRandomWalk__body() - ret double %0 + %0 = call i1 @TeleportChain__DemonstrateTeleportationUsingPresharedEntanglement__body() + %1 = sext i1 %0 to i8 + ret i8 %1 } -define void @Microsoft__Quantum__Qir__Emission__EstimatePhaseByRandomWalk() #2 { +define void @TeleportChain__DemonstrateTeleportationUsingPresharedEntanglement() #2 { entry: - %0 = call double @Microsoft__Quantum__Qir__Emission__EstimatePhaseByRandomWalk__body() - %1 = call %String* @__quantum__rt__double_to_string(double %0) + %0 = call i1 @TeleportChain__DemonstrateTeleportationUsingPresharedEntanglement__body() + %1 = call %String* @__quantum__rt__bool_to_string(i1 %0) call void @__quantum__rt__message(%String* %1) call void @__quantum__rt__string_update_reference_count(%String* %1, i32 -1) ret void @@ -3379,7 +3439,7 @@ entry: declare void @__quantum__rt__message(%String*) -declare %String* @__quantum__rt__double_to_string(double) +declare %String* @__quantum__rt__bool_to_string(i1) declare void @__quantum__rt__string_update_reference_count(%String*, i32) diff --git a/src/QirTools/pyqir/tests/test_api.py b/src/QirTools/pyqir/tests/test_api.py index c9537dceef..992099a655 100644 --- a/src/QirTools/pyqir/tests/test_api.py +++ b/src/QirTools/pyqir/tests/test_api.py @@ -130,20 +130,31 @@ def test_bernstein_vazirani_ir_string(): assert ir.startswith("; ModuleID = 'Bernstein-Vazirani'") def test_parser(): - mod = module_from_bitcode("tests/randwalkphaseest.baseprofile.bc") - funcName = "Microsoft__Quantum__Qir__Emission__EstimatePhaseByRandomWalk__Interop" + mod = module_from_bitcode("tests/teleportchain.baseprofile.bc") + funcName = "TeleportChain__DemonstrateTeleportationUsingPresharedEntanglement__Interop" func = mod.get_func_by_name(funcName) assert(func.name == funcName) assert(len(func.parameters) == 0) - assert(func.return_type.is_floating_point) + assert(func.return_type.is_integer) funcList = mod.functions assert(len(funcList) == 1) assert(funcList[0].name == funcName) interop_funcs = mod.get_funcs_by_attr("InteropFriendly") assert(len(interop_funcs) == 1) assert(interop_funcs[0].name == funcName) - assert(interop_funcs[0].get_attribute_value("requiredQubits") == "2") - assert(interop_funcs[0].required_qubits == 2) + assert(interop_funcs[0].get_attribute_value("requiredQubits") == "6") + assert(interop_funcs[0].required_qubits == 6) blocks = func.blocks - assert(len(blocks) == 3) + assert(len(blocks) == 9) + assert(blocks[0].name == "entry") entry_block = func.get_block_by_name("entry") + assert(entry_block.name == "entry") + assert(entry_block.terminator.is_condbr) + assert(not entry_block.terminator.is_ret) + assert(entry_block.terminator.condbr_true_dest == "then0__1.i.i.i") + assert(entry_block.terminator.condbr_false_dest == "continue__1.i.i.i") + assert(blocks[1].terminator.is_br) + assert(blocks[1].terminator.br_dest == "continue__1.i.i.i") + assert(blocks[8].terminator.is_ret) + assert(len(entry_block.instructions) == 11) + assert(entry_block.instructions[0].is_call) From 6401952a013ca016c0fab1023e881646537d5cf3 Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Fri, 8 Oct 2021 10:17:07 -0700 Subject: [PATCH 03/26] beginning basic qir/qrt/qis call support --- src/QirTools/pyqir/src/parser.rs | 40 ++++++++++++++++++++++++++++ src/QirTools/pyqir/tests/test_api.py | 3 +++ 2 files changed, 43 insertions(+) diff --git a/src/QirTools/pyqir/src/parser.rs b/src/QirTools/pyqir/src/parser.rs index 8900a025b1..02a7defa81 100644 --- a/src/QirTools/pyqir/src/parser.rs +++ b/src/QirTools/pyqir/src/parser.rs @@ -581,6 +581,46 @@ impl QirInstruction { _ => false, } } + + #[getter] + fn get_call_func_name(&self) -> PyResult { + match &self.instr { + llvm_ir::instruction::Instruction::Call(call) => match call.function.clone().right() { + Some(llvm_ir::operand::Operand::ConstantOperand(cref)) => match cref.as_ref() { + llvm_ir::constant::Constant::GlobalReference { name, ty: _ } => { + Ok(name_to_string(&name)) + } + _ => Err(exceptions::PyTypeError::new_err("Unhandled operand type in call.")), + }, + _ => Err(exceptions::PyTypeError::new_err("Unhandled call type.")), + }, + _ => Err(exceptions::PyTypeError::new_err("Instruction is not call.")), + } + } + + #[getter] + fn get_is_qis_call(&self) -> bool { + match self.get_call_func_name() { + Ok(name) => name.starts_with("__quantum__qis__"), + _ => false, + } + } + + #[getter] + fn get_is_qrt_call(&self) -> bool { + match self.get_call_func_name() { + Ok(name) => name.starts_with("__quantum__rt__"), + _ => false, + } + } + + #[getter] + fn get_is_qir_call(&self) -> bool { + match self.get_call_func_name() { + Ok(name) => name.starts_with("__quantum__qir__"), + _ => false, + } + } } #[pymethods] diff --git a/src/QirTools/pyqir/tests/test_api.py b/src/QirTools/pyqir/tests/test_api.py index 992099a655..14585a01a1 100644 --- a/src/QirTools/pyqir/tests/test_api.py +++ b/src/QirTools/pyqir/tests/test_api.py @@ -158,3 +158,6 @@ def test_parser(): assert(blocks[8].terminator.is_ret) assert(len(entry_block.instructions) == 11) assert(entry_block.instructions[0].is_call) + assert(entry_block.instructions[0].call_func_name == "__quantum__qis__h__body") + assert(entry_block.instructions[0].is_qis_call) + assert(entry_block.instructions[10].is_qir_call) From 029ea1162d3368f29e8f11612e142a50fc93973b Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Fri, 8 Oct 2021 21:58:46 -0700 Subject: [PATCH 04/26] ongoing progress --- src/QirTools/pyqir/src/parser.rs | 412 ++++++++++++++++++++++----- src/QirTools/pyqir/tests/test_api.py | 17 ++ 2 files changed, 362 insertions(+), 67 deletions(-) diff --git a/src/QirTools/pyqir/src/parser.rs b/src/QirTools/pyqir/src/parser.rs index 02a7defa81..ac4642d8a7 100644 --- a/src/QirTools/pyqir/src/parser.rs +++ b/src/QirTools/pyqir/src/parser.rs @@ -4,6 +4,7 @@ use pyo3::exceptions; use pyo3::prelude::*; use llvm_ir; +use llvm_ir::types::Typed; #[pyclass] pub struct QirModule { @@ -13,6 +14,7 @@ pub struct QirModule { #[pyclass] pub struct QirFunction { pub(super) function: llvm_ir::Function, + pub(super) types: llvm_ir::types::Types, } #[pyclass] @@ -23,26 +25,31 @@ pub struct QirParameter { #[pyclass] pub struct QirBasicBlock { pub(super) block: llvm_ir::BasicBlock, + pub(super) types: llvm_ir::types::Types, } #[pyclass] pub struct QirInstruction { pub(super) instr: llvm_ir::instruction::Instruction, + pub(super) types: llvm_ir::types::Types, } #[pyclass] pub struct QirTerminator { pub(super) term: llvm_ir::terminator::Terminator, + pub(super) types: llvm_ir::types::Types, } #[pyclass] pub struct QirOperand { pub(super) op: llvm_ir::Operand, + pub(super) types: llvm_ir::types::Types, } #[pyclass] pub struct QirConstant { pub(super) constantref: llvm_ir::ConstantRef, + pub(super) types: llvm_ir::types::Types, } #[pyclass] @@ -59,6 +66,7 @@ impl QirModule { .iter() .map(|f| QirFunction { function: f.clone(), + types: self.module.types.clone(), }) .collect() } @@ -67,6 +75,7 @@ impl QirModule { match self.module.get_func_by_name(&name) { Some(f) => Ok(QirFunction { function: f.clone(), + types: self.module.types.clone(), }), None => Err(exceptions::PyTypeError::new_err(format!( "Function with name '{}' not found", @@ -89,6 +98,7 @@ impl QirModule { }) .map(|f| QirFunction { function: f.clone(), + types: self.module.types.clone(), }) .collect() } @@ -122,7 +132,10 @@ impl QirFunction { self.function .basic_blocks .iter() - .map(|b| QirBasicBlock { block: b.clone() }) + .map(|b| QirBasicBlock { + block: b.clone(), + types: self.types.clone(), + }) .collect() } @@ -164,13 +177,38 @@ impl QirFunction { .function .get_bb_by_name(&llvm_ir::Name::from(name.clone())) { - Some(b) => Ok(QirBasicBlock { block: b.clone() }), + Some(b) => Ok(QirBasicBlock { + block: b.clone(), + types: self.types.clone(), + }), None => Err(exceptions::PyTypeError::new_err(format!( "Block with name '{}' not found", name ))), } } + + fn get_instruction_by_output_name(&self, name: String) -> PyResult { + for block in &self.function.basic_blocks { + for instr in &block.instrs { + match instr.try_get_result() { + Some(resname) => { + if name_to_string(resname) == name { + return Ok(QirInstruction { + instr: instr.clone(), + types: self.types.clone(), + }); + } + } + None => continue, + } + } + } + Err(exceptions::PyTypeError::new_err(format!( + "Instruction with result name '{}' not found", + name + ))) + } } #[pymethods] @@ -200,7 +238,10 @@ impl QirBasicBlock { self.block .instrs .iter() - .map(|i| QirInstruction { instr: i.clone() }) + .map(|i| QirInstruction { + instr: i.clone(), + types: self.types.clone(), + }) .collect() } @@ -208,6 +249,7 @@ impl QirBasicBlock { fn get_terminator(&self) -> QirTerminator { QirTerminator { term: self.block.term.clone(), + types: self.types.clone(), } } } @@ -217,7 +259,7 @@ impl QirInstruction { #[getter] fn get_is_add(&self) -> bool { match self.instr { - llvm_ir::instruction::Instruction::Add(_) => true, + llvm_ir::Instruction::Add(_) => true, _ => false, } } @@ -225,7 +267,7 @@ impl QirInstruction { #[getter] fn get_is_sub(&self) -> bool { match self.instr { - llvm_ir::instruction::Instruction::Sub(_) => true, + llvm_ir::Instruction::Sub(_) => true, _ => false, } } @@ -233,7 +275,7 @@ impl QirInstruction { #[getter] fn get_is_mul(&self) -> bool { match self.instr { - llvm_ir::instruction::Instruction::Mul(_) => true, + llvm_ir::Instruction::Mul(_) => true, _ => false, } } @@ -241,7 +283,7 @@ impl QirInstruction { #[getter] fn get_is_udiv(&self) -> bool { match self.instr { - llvm_ir::instruction::Instruction::UDiv(_) => true, + llvm_ir::Instruction::UDiv(_) => true, _ => false, } } @@ -249,7 +291,7 @@ impl QirInstruction { #[getter] fn get_is_sdiv(&self) -> bool { match self.instr { - llvm_ir::instruction::Instruction::SDiv(_) => true, + llvm_ir::Instruction::SDiv(_) => true, _ => false, } } @@ -257,7 +299,7 @@ impl QirInstruction { #[getter] fn get_is_urem(&self) -> bool { match self.instr { - llvm_ir::instruction::Instruction::URem(_) => true, + llvm_ir::Instruction::URem(_) => true, _ => false, } } @@ -265,7 +307,7 @@ impl QirInstruction { #[getter] fn get_is_srem(&self) -> bool { match self.instr { - llvm_ir::instruction::Instruction::SRem(_) => true, + llvm_ir::Instruction::SRem(_) => true, _ => false, } } @@ -273,7 +315,7 @@ impl QirInstruction { #[getter] fn get_is_and(&self) -> bool { match self.instr { - llvm_ir::instruction::Instruction::And(_) => true, + llvm_ir::Instruction::And(_) => true, _ => false, } } @@ -281,7 +323,7 @@ impl QirInstruction { #[getter] fn get_is_or(&self) -> bool { match self.instr { - llvm_ir::instruction::Instruction::Or(_) => true, + llvm_ir::Instruction::Or(_) => true, _ => false, } } @@ -289,7 +331,7 @@ impl QirInstruction { #[getter] fn get_is_xor(&self) -> bool { match self.instr { - llvm_ir::instruction::Instruction::Xor(_) => true, + llvm_ir::Instruction::Xor(_) => true, _ => false, } } @@ -297,7 +339,7 @@ impl QirInstruction { #[getter] fn get_is_shl(&self) -> bool { match self.instr { - llvm_ir::instruction::Instruction::Shl(_) => true, + llvm_ir::Instruction::Shl(_) => true, _ => false, } } @@ -305,7 +347,7 @@ impl QirInstruction { #[getter] fn get_is_lshr(&self) -> bool { match self.instr { - llvm_ir::instruction::Instruction::LShr(_) => true, + llvm_ir::Instruction::LShr(_) => true, _ => false, } } @@ -313,7 +355,7 @@ impl QirInstruction { #[getter] fn get_is_ashr(&self) -> bool { match self.instr { - llvm_ir::instruction::Instruction::AShr(_) => true, + llvm_ir::Instruction::AShr(_) => true, _ => false, } } @@ -321,7 +363,7 @@ impl QirInstruction { #[getter] fn get_is_fadd(&self) -> bool { match self.instr { - llvm_ir::instruction::Instruction::FAdd(_) => true, + llvm_ir::Instruction::FAdd(_) => true, _ => false, } } @@ -329,7 +371,7 @@ impl QirInstruction { #[getter] fn get_is_fsub(&self) -> bool { match self.instr { - llvm_ir::instruction::Instruction::FSub(_) => true, + llvm_ir::Instruction::FSub(_) => true, _ => false, } } @@ -337,7 +379,7 @@ impl QirInstruction { #[getter] fn get_is_fmul(&self) -> bool { match self.instr { - llvm_ir::instruction::Instruction::FMul(_) => true, + llvm_ir::Instruction::FMul(_) => true, _ => false, } } @@ -345,7 +387,7 @@ impl QirInstruction { #[getter] fn get_is_fdiv(&self) -> bool { match self.instr { - llvm_ir::instruction::Instruction::FDiv(_) => true, + llvm_ir::Instruction::FDiv(_) => true, _ => false, } } @@ -353,7 +395,7 @@ impl QirInstruction { #[getter] fn get_is_frem(&self) -> bool { match self.instr { - llvm_ir::instruction::Instruction::FRem(_) => true, + llvm_ir::Instruction::FRem(_) => true, _ => false, } } @@ -361,7 +403,7 @@ impl QirInstruction { #[getter] fn get_is_fneg(&self) -> bool { match self.instr { - llvm_ir::instruction::Instruction::FNeg(_) => true, + llvm_ir::Instruction::FNeg(_) => true, _ => false, } } @@ -369,7 +411,7 @@ impl QirInstruction { #[getter] fn get_is_extractelement(&self) -> bool { match self.instr { - llvm_ir::instruction::Instruction::ExtractElement(_) => true, + llvm_ir::Instruction::ExtractElement(_) => true, _ => false, } } @@ -377,7 +419,7 @@ impl QirInstruction { #[getter] fn get_is_insertelement(&self) -> bool { match self.instr { - llvm_ir::instruction::Instruction::InsertElement(_) => true, + llvm_ir::Instruction::InsertElement(_) => true, _ => false, } } @@ -385,7 +427,7 @@ impl QirInstruction { #[getter] fn get_is_shufflevector(&self) -> bool { match self.instr { - llvm_ir::instruction::Instruction::ShuffleVector(_) => true, + llvm_ir::Instruction::ShuffleVector(_) => true, _ => false, } } @@ -393,7 +435,7 @@ impl QirInstruction { #[getter] fn get_is_extractvalue(&self) -> bool { match self.instr { - llvm_ir::instruction::Instruction::ExtractValue(_) => true, + llvm_ir::Instruction::ExtractValue(_) => true, _ => false, } } @@ -401,7 +443,7 @@ impl QirInstruction { #[getter] fn get_is_insertvalue(&self) -> bool { match self.instr { - llvm_ir::instruction::Instruction::InsertValue(_) => true, + llvm_ir::Instruction::InsertValue(_) => true, _ => false, } } @@ -409,7 +451,7 @@ impl QirInstruction { #[getter] fn get_is_alloca(&self) -> bool { match self.instr { - llvm_ir::instruction::Instruction::Alloca(_) => true, + llvm_ir::Instruction::Alloca(_) => true, _ => false, } } @@ -417,7 +459,7 @@ impl QirInstruction { #[getter] fn get_is_load(&self) -> bool { match self.instr { - llvm_ir::instruction::Instruction::Load(_) => true, + llvm_ir::Instruction::Load(_) => true, _ => false, } } @@ -425,7 +467,7 @@ impl QirInstruction { #[getter] fn get_is_store(&self) -> bool { match self.instr { - llvm_ir::instruction::Instruction::Store(_) => true, + llvm_ir::Instruction::Store(_) => true, _ => false, } } @@ -433,7 +475,7 @@ impl QirInstruction { #[getter] fn get_is_getelementptr(&self) -> bool { match self.instr { - llvm_ir::instruction::Instruction::GetElementPtr(_) => true, + llvm_ir::Instruction::GetElementPtr(_) => true, _ => false, } } @@ -441,7 +483,7 @@ impl QirInstruction { #[getter] fn get_is_trunc(&self) -> bool { match self.instr { - llvm_ir::instruction::Instruction::Trunc(_) => true, + llvm_ir::Instruction::Trunc(_) => true, _ => false, } } @@ -449,7 +491,7 @@ impl QirInstruction { #[getter] fn get_is_zext(&self) -> bool { match self.instr { - llvm_ir::instruction::Instruction::ZExt(_) => true, + llvm_ir::Instruction::ZExt(_) => true, _ => false, } } @@ -457,7 +499,7 @@ impl QirInstruction { #[getter] fn get_is_sext(&self) -> bool { match self.instr { - llvm_ir::instruction::Instruction::SExt(_) => true, + llvm_ir::Instruction::SExt(_) => true, _ => false, } } @@ -465,7 +507,7 @@ impl QirInstruction { #[getter] fn get_is_fptrunc(&self) -> bool { match self.instr { - llvm_ir::instruction::Instruction::FPTrunc(_) => true, + llvm_ir::Instruction::FPTrunc(_) => true, _ => false, } } @@ -473,7 +515,7 @@ impl QirInstruction { #[getter] fn get_is_fpext(&self) -> bool { match self.instr { - llvm_ir::instruction::Instruction::FPExt(_) => true, + llvm_ir::Instruction::FPExt(_) => true, _ => false, } } @@ -481,7 +523,7 @@ impl QirInstruction { #[getter] fn get_is_fptoui(&self) -> bool { match self.instr { - llvm_ir::instruction::Instruction::FPToUI(_) => true, + llvm_ir::Instruction::FPToUI(_) => true, _ => false, } } @@ -489,7 +531,7 @@ impl QirInstruction { #[getter] fn get_is_fptosi(&self) -> bool { match self.instr { - llvm_ir::instruction::Instruction::FPToSI(_) => true, + llvm_ir::Instruction::FPToSI(_) => true, _ => false, } } @@ -497,7 +539,7 @@ impl QirInstruction { #[getter] fn get_is_uitofp(&self) -> bool { match self.instr { - llvm_ir::instruction::Instruction::UIToFP(_) => true, + llvm_ir::Instruction::UIToFP(_) => true, _ => false, } } @@ -505,7 +547,7 @@ impl QirInstruction { #[getter] fn get_is_sitofp(&self) -> bool { match self.instr { - llvm_ir::instruction::Instruction::SIToFP(_) => true, + llvm_ir::Instruction::SIToFP(_) => true, _ => false, } } @@ -513,7 +555,7 @@ impl QirInstruction { #[getter] fn get_is_ptrtoint(&self) -> bool { match self.instr { - llvm_ir::instruction::Instruction::PtrToInt(_) => true, + llvm_ir::Instruction::PtrToInt(_) => true, _ => false, } } @@ -521,7 +563,7 @@ impl QirInstruction { #[getter] fn get_is_inttoptr(&self) -> bool { match self.instr { - llvm_ir::instruction::Instruction::IntToPtr(_) => true, + llvm_ir::Instruction::IntToPtr(_) => true, _ => false, } } @@ -529,7 +571,7 @@ impl QirInstruction { #[getter] fn get_is_bitcast(&self) -> bool { match self.instr { - llvm_ir::instruction::Instruction::BitCast(_) => true, + llvm_ir::Instruction::BitCast(_) => true, _ => false, } } @@ -537,7 +579,7 @@ impl QirInstruction { #[getter] fn get_is_addrspacecast(&self) -> bool { match self.instr { - llvm_ir::instruction::Instruction::AddrSpaceCast(_) => true, + llvm_ir::Instruction::AddrSpaceCast(_) => true, _ => false, } } @@ -545,7 +587,7 @@ impl QirInstruction { #[getter] fn get_is_icmp(&self) -> bool { match self.instr { - llvm_ir::instruction::Instruction::ICmp(_) => true, + llvm_ir::Instruction::ICmp(_) => true, _ => false, } } @@ -553,7 +595,7 @@ impl QirInstruction { #[getter] fn get_is_fcmp(&self) -> bool { match self.instr { - llvm_ir::instruction::Instruction::FCmp(_) => true, + llvm_ir::Instruction::FCmp(_) => true, _ => false, } } @@ -561,7 +603,7 @@ impl QirInstruction { #[getter] fn get_is_phi(&self) -> bool { match self.instr { - llvm_ir::instruction::Instruction::Phi(_) => true, + llvm_ir::Instruction::Phi(_) => true, _ => false, } } @@ -569,7 +611,7 @@ impl QirInstruction { #[getter] fn get_is_select(&self) -> bool { match self.instr { - llvm_ir::instruction::Instruction::Select(_) => true, + llvm_ir::Instruction::Select(_) => true, _ => false, } } @@ -577,7 +619,7 @@ impl QirInstruction { #[getter] fn get_is_call(&self) -> bool { match self.instr { - llvm_ir::instruction::Instruction::Call(_) => true, + llvm_ir::Instruction::Call(_) => true, _ => false, } } @@ -585,12 +627,14 @@ impl QirInstruction { #[getter] fn get_call_func_name(&self) -> PyResult { match &self.instr { - llvm_ir::instruction::Instruction::Call(call) => match call.function.clone().right() { + llvm_ir::Instruction::Call(call) => match call.function.clone().right() { Some(llvm_ir::operand::Operand::ConstantOperand(cref)) => match cref.as_ref() { llvm_ir::constant::Constant::GlobalReference { name, ty: _ } => { Ok(name_to_string(&name)) } - _ => Err(exceptions::PyTypeError::new_err("Unhandled operand type in call.")), + _ => Err(exceptions::PyTypeError::new_err( + "Unhandled operand type in call.", + )), }, _ => Err(exceptions::PyTypeError::new_err("Unhandled call type.")), }, @@ -598,6 +642,21 @@ impl QirInstruction { } } + #[getter] + fn get_call_func_params(&self) -> PyResult> { + match &self.instr { + llvm_ir::Instruction::Call(call) => Ok(call + .arguments + .iter() + .map(|o| QirOperand { + op: o.0.clone(), + types: self.types.clone(), + }) + .collect()), + _ => Err(exceptions::PyTypeError::new_err("Instruction is not call.")), + } + } + #[getter] fn get_is_qis_call(&self) -> bool { match self.get_call_func_name() { @@ -621,6 +680,24 @@ impl QirInstruction { _ => false, } } + + #[getter] + fn get_has_output(&self) -> bool { + match self.instr.try_get_result() { + Some(_) => true, + None => false, + } + } + + #[getter] + fn get_output_name(&self) -> PyResult { + match self.instr.try_get_result() { + Some(name) => Ok(name_to_string(name)), + None => Err(exceptions::PyTypeError::new_err( + "Instruction has no output.", + )), + } + } } #[pymethods] @@ -628,7 +705,7 @@ impl QirTerminator { #[getter] fn get_is_ret(&self) -> bool { match self.term { - llvm_ir::terminator::Terminator::Ret(_) => true, + llvm_ir::Terminator::Ret(_) => true, _ => false, } } @@ -636,11 +713,14 @@ impl QirTerminator { #[getter] fn get_ret_operand(&self) -> PyResult { match &self.term { - llvm_ir::terminator::Terminator::Ret(llvm_ir::terminator::Ret { + llvm_ir::Terminator::Ret(llvm_ir::terminator::Ret { return_operand, debugloc: _, }) => match return_operand { - Some(op) => Ok(QirOperand { op: op.clone() }), + Some(op) => Ok(QirOperand { + op: op.clone(), + types: self.types.clone(), + }), None => Err(exceptions::PyTypeError::new_err( "Return is void and has no operand.", )), @@ -654,7 +734,7 @@ impl QirTerminator { #[getter] fn get_is_br(&self) -> bool { match self.term { - llvm_ir::terminator::Terminator::Br(_) => true, + llvm_ir::Terminator::Br(_) => true, _ => false, } } @@ -662,7 +742,7 @@ impl QirTerminator { #[getter] fn get_br_dest(&self) -> PyResult { match &self.term { - llvm_ir::terminator::Terminator::Br(llvm_ir::terminator::Br { dest, debugloc: _ }) => { + llvm_ir::Terminator::Br(llvm_ir::terminator::Br { dest, debugloc: _ }) => { Ok(name_to_string(&dest)) } _ => Err(exceptions::PyTypeError::new_err( @@ -674,7 +754,7 @@ impl QirTerminator { #[getter] fn get_is_condbr(&self) -> bool { match self.term { - llvm_ir::terminator::Terminator::CondBr(_) => true, + llvm_ir::Terminator::CondBr(_) => true, _ => false, } } @@ -682,13 +762,14 @@ impl QirTerminator { #[getter] fn get_condbr_condition(&self) -> PyResult { match &self.term { - llvm_ir::terminator::Terminator::CondBr(llvm_ir::terminator::CondBr { + llvm_ir::Terminator::CondBr(llvm_ir::terminator::CondBr { condition, true_dest: _, false_dest: _, debugloc: _, }) => Ok(QirOperand { op: condition.clone(), + types: self.types.clone(), }), _ => Err(exceptions::PyTypeError::new_err( "Terminator is not condition branch.", @@ -699,7 +780,7 @@ impl QirTerminator { #[getter] fn get_condbr_true_dest(&self) -> PyResult { match &self.term { - llvm_ir::terminator::Terminator::CondBr(llvm_ir::terminator::CondBr { + llvm_ir::Terminator::CondBr(llvm_ir::terminator::CondBr { condition: _, true_dest, false_dest: _, @@ -714,7 +795,7 @@ impl QirTerminator { #[getter] fn get_condbr_false_dest(&self) -> PyResult { match &self.term { - llvm_ir::terminator::Terminator::CondBr(llvm_ir::terminator::CondBr { + llvm_ir::Terminator::CondBr(llvm_ir::terminator::CondBr { condition: _, true_dest: _, false_dest, @@ -729,7 +810,7 @@ impl QirTerminator { #[getter] fn get_is_switch(&self) -> bool { match self.term { - llvm_ir::terminator::Terminator::Switch(_) => true, + llvm_ir::Terminator::Switch(_) => true, _ => false, } } @@ -737,7 +818,7 @@ impl QirTerminator { #[getter] fn get_switch_operand(&self) -> PyResult { match self.term { - llvm_ir::terminator::Terminator::Switch(_) => Err(exceptions::PyTypeError::new_err( + llvm_ir::Terminator::Switch(_) => Err(exceptions::PyTypeError::new_err( "Switch handling not supported.", )), _ => Err(exceptions::PyTypeError::new_err( @@ -749,7 +830,7 @@ impl QirTerminator { #[getter] fn get_switch_dest_values(&self) -> PyResult> { match self.term { - llvm_ir::terminator::Terminator::Switch(_) => Err(exceptions::PyTypeError::new_err( + llvm_ir::Terminator::Switch(_) => Err(exceptions::PyTypeError::new_err( "Switch handling not supported.", )), _ => Err(exceptions::PyTypeError::new_err( @@ -761,7 +842,7 @@ impl QirTerminator { #[getter] fn get_switch_dest_names(&self) -> PyResult> { match self.term { - llvm_ir::terminator::Terminator::Switch(_) => Err(exceptions::PyTypeError::new_err( + llvm_ir::Terminator::Switch(_) => Err(exceptions::PyTypeError::new_err( "Switch handling not supported.", )), _ => Err(exceptions::PyTypeError::new_err( @@ -773,12 +854,209 @@ impl QirTerminator { #[getter] fn get_is_unreachable(&self) -> bool { match self.term { - llvm_ir::terminator::Terminator::Unreachable(_) => true, + llvm_ir::Terminator::Unreachable(_) => true, _ => false, } } } +#[pymethods] +impl QirOperand { + #[getter] + fn get_is_local(&self) -> bool { + match self.op { + llvm_ir::Operand::LocalOperand { name: _, ty: _ } => true, + _ => false, + } + } + + #[getter] + fn get_local_name(&self) -> PyResult { + match &self.op { + llvm_ir::Operand::LocalOperand { name, ty: _ } => Ok(name_to_string(&name)), + _ => Err(exceptions::PyTypeError::new_err("Operand is not local.")), + } + } + + #[getter] + fn get_local_type(&self) -> PyResult { + match &self.op { + llvm_ir::Operand::LocalOperand { name: _, ty } => Ok(QirType { + typeref: ty.clone(), + }), + _ => Err(exceptions::PyTypeError::new_err("Operand is not local.")), + } + } + + #[getter] + fn get_is_constant(&self) -> bool { + match self.op { + llvm_ir::Operand::ConstantOperand(_) => true, + _ => false, + } + } + + #[getter] + fn get_constant(&self) -> PyResult { + match &self.op { + llvm_ir::Operand::ConstantOperand(cref) => Ok(QirConstant { + constantref: cref.clone(), + types: self.types.clone(), + }), + _ => Err(exceptions::PyTypeError::new_err("Operand is not constant.")), + } + } +} + +#[pymethods] +impl QirConstant { + #[getter] + fn get_is_int(&self) -> bool { + match self.constantref.as_ref() { + llvm_ir::Constant::Int { bits: _, value: _ } => true, + _ => false, + } + } + + #[getter] + fn get_int_value(&self) -> PyResult { + match self.constantref.as_ref() { + llvm_ir::Constant::Int { bits: _, value } => Ok(value.clone() as i64), + _ => Err(exceptions::PyTypeError::new_err("Constant is not int.")), + } + } + + #[getter] + fn get_int_width(&self) -> PyResult { + match &self.constantref.as_ref() { + llvm_ir::Constant::Int { bits, value: _ } => Ok(bits.clone()), + _ => Err(exceptions::PyTypeError::new_err("Constant is not int.")), + } + } + + #[getter] + fn get_is_float(&self) -> bool { + match self.constantref.as_ref() { + llvm_ir::Constant::Float(_) => true, + _ => false, + } + } + + #[getter] + fn get_is_null(&self) -> bool { + match self.constantref.as_ref() { + llvm_ir::Constant::Null(_) => true, + _ => false, + } + } + + #[getter] + fn get_is_agregate_zero(&self) -> bool { + match self.constantref.as_ref() { + llvm_ir::Constant::AggregateZero(_) => true, + _ => false, + } + } + + #[getter] + fn get_is_array(&self) -> bool { + match self.constantref.as_ref() { + llvm_ir::Constant::Array { + element_type: _, + elements: _, + } => true, + _ => false, + } + } + + #[getter] + fn get_is_vector(&self) -> bool { + match self.constantref.as_ref() { + llvm_ir::Constant::Vector(_) => true, + _ => false, + } + } + + #[getter] + fn get_is_undef(&self) -> bool { + match self.constantref.as_ref() { + llvm_ir::Constant::Undef(_) => true, + _ => false, + } + } + + #[getter] + fn get_is_global_reference(&self) -> bool { + match self.constantref.as_ref() { + llvm_ir::Constant::GlobalReference { name: _, ty: _ } => true, + _ => false, + } + } + + #[getter] + fn get_type(&self) -> QirType { + QirType { + typeref: self.constantref.get_type(&self.types), + } + } + + #[getter] + fn get_is_qubit(&self) -> bool { + self.get_type().get_is_qubit() + } + + #[getter] + fn get_qubit_static_id(&self) -> PyResult { + if !self.get_is_qubit() { + Err(exceptions::PyTypeError::new_err("Constant is not qubit.")) + } else { + match &self.constantref.as_ref() { + llvm_ir::Constant::Null(_) => Ok(0), + llvm_ir::Constant::IntToPtr(llvm_ir::constant::IntToPtr { + operand, + to_type: _, + }) => match operand.as_ref() { + llvm_ir::Constant::Int { bits: 64, value } => Ok(value.clone()), + _ => Err(exceptions::PyTypeError::new_err( + "Qubit is not recognized constant.", + )), + }, + _ => Err(exceptions::PyTypeError::new_err( + "Qubit is not recognized constant.", + )), + } + } + } + + #[getter] + fn get_is_result(&self) -> bool { + self.get_type().get_is_result() + } + + #[getter] + fn get_result_static_id(&self) -> PyResult { + if !self.get_is_result() { + Err(exceptions::PyTypeError::new_err("Constant is not result.")) + } else { + match &self.constantref.as_ref() { + llvm_ir::Constant::Null(_) => Ok(0), + llvm_ir::Constant::IntToPtr(llvm_ir::constant::IntToPtr { + operand, + to_type: _, + }) => match operand.as_ref() { + llvm_ir::Constant::Int { bits: 64, value } => Ok(value.clone()), + _ => Err(exceptions::PyTypeError::new_err( + "Result is not recognized constant.", + )), + }, + _ => Err(exceptions::PyTypeError::new_err( + "Result is not recognized constant.", + )), + } + } + } +} + #[pymethods] impl QirType { #[getter] @@ -953,7 +1231,7 @@ impl QirType { fn name_to_string(name: &llvm_ir::Name) -> String { match name { - llvm_ir::name::Name::Name(n) => n.to_string(), - llvm_ir::name::Name::Number(n) => n.to_string(), + llvm_ir::Name::Name(n) => n.to_string(), + llvm_ir::Name::Number(n) => n.to_string(), } } diff --git a/src/QirTools/pyqir/tests/test_api.py b/src/QirTools/pyqir/tests/test_api.py index 14585a01a1..725fb8893f 100644 --- a/src/QirTools/pyqir/tests/test_api.py +++ b/src/QirTools/pyqir/tests/test_api.py @@ -160,4 +160,21 @@ def test_parser(): assert(entry_block.instructions[0].is_call) assert(entry_block.instructions[0].call_func_name == "__quantum__qis__h__body") assert(entry_block.instructions[0].is_qis_call) + paramList = entry_block.instructions[0].call_func_params + assert(len(paramList) == 1) + assert(paramList[0].is_constant) + assert(paramList[0].constant.is_qubit) + assert(paramList[0].constant.qubit_static_id == 0) + assert(entry_block.instructions[8].is_qis_call) + assert(entry_block.instructions[8].call_func_name == "__quantum__qis__mz__body") + assert(entry_block.instructions[8].call_func_params[0].constant.qubit_static_id == 1) + assert(entry_block.instructions[8].call_func_params[1].constant.result_static_id == 0) + branch_cond = entry_block.terminator.condbr_condition + assert(branch_cond.local_name == "0") assert(entry_block.instructions[10].is_qir_call) + assert(entry_block.instructions[10].call_func_name == "__quantum__qir__read_result") + assert(entry_block.instructions[10].call_func_params[0].constant.result_static_id == 0) + assert(entry_block.instructions[10].has_output) + assert(entry_block.instructions[10].output_name == "0") + source_instr = func.get_instruction_by_output_name(branch_cond.local_name) + assert(source_instr.call_func_params[0].constant.result_static_id == 0) \ No newline at end of file From 23749e9f0c3dd6bd6de9a4c2648d0e19b5a70e22 Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Sat, 9 Oct 2021 13:10:37 -0700 Subject: [PATCH 05/26] Add getters for float, arithmetic op targets --- src/QirTools/pyqir/src/parser.rs | 330 +++++++++++++++++++++++++++++++ 1 file changed, 330 insertions(+) diff --git a/src/QirTools/pyqir/src/parser.rs b/src/QirTools/pyqir/src/parser.rs index ac4642d8a7..a346adeb8a 100644 --- a/src/QirTools/pyqir/src/parser.rs +++ b/src/QirTools/pyqir/src/parser.rs @@ -264,6 +264,23 @@ impl QirInstruction { } } + #[getter] + fn get_add_targets(&self) -> PyResult> { + match &self.instr { + llvm_ir::Instruction::Add(instr) => Ok(vec![ + QirOperand { + op: instr.operand0.clone(), + types: self.types.clone(), + }, + QirOperand { + op: instr.operand1.clone(), + types: self.types.clone(), + }, + ]), + _ => Err(exceptions::PyTypeError::new_err("Instruction is not add.")), + } + } + #[getter] fn get_is_sub(&self) -> bool { match self.instr { @@ -272,6 +289,23 @@ impl QirInstruction { } } + #[getter] + fn get_sub_targets(&self) -> PyResult> { + match &self.instr { + llvm_ir::Instruction::Sub(instr) => Ok(vec![ + QirOperand { + op: instr.operand0.clone(), + types: self.types.clone(), + }, + QirOperand { + op: instr.operand1.clone(), + types: self.types.clone(), + }, + ]), + _ => Err(exceptions::PyTypeError::new_err("Instruction is not sub.")), + } + } + #[getter] fn get_is_mul(&self) -> bool { match self.instr { @@ -280,6 +314,23 @@ impl QirInstruction { } } + #[getter] + fn get_mul_targets(&self) -> PyResult> { + match &self.instr { + llvm_ir::Instruction::Mul(instr) => Ok(vec![ + QirOperand { + op: instr.operand0.clone(), + types: self.types.clone(), + }, + QirOperand { + op: instr.operand1.clone(), + types: self.types.clone(), + }, + ]), + _ => Err(exceptions::PyTypeError::new_err("Instruction is not mul.")), + } + } + #[getter] fn get_is_udiv(&self) -> bool { match self.instr { @@ -288,6 +339,23 @@ impl QirInstruction { } } + #[getter] + fn get_udiv_targets(&self) -> PyResult> { + match &self.instr { + llvm_ir::Instruction::UDiv(instr) => Ok(vec![ + QirOperand { + op: instr.operand0.clone(), + types: self.types.clone(), + }, + QirOperand { + op: instr.operand1.clone(), + types: self.types.clone(), + }, + ]), + _ => Err(exceptions::PyTypeError::new_err("Instruction is not udiv.")), + } + } + #[getter] fn get_is_sdiv(&self) -> bool { match self.instr { @@ -296,6 +364,23 @@ impl QirInstruction { } } + #[getter] + fn get_sdiv_targets(&self) -> PyResult> { + match &self.instr { + llvm_ir::Instruction::SDiv(instr) => Ok(vec![ + QirOperand { + op: instr.operand0.clone(), + types: self.types.clone(), + }, + QirOperand { + op: instr.operand1.clone(), + types: self.types.clone(), + }, + ]), + _ => Err(exceptions::PyTypeError::new_err("Instruction is not sdiv.")), + } + } + #[getter] fn get_is_urem(&self) -> bool { match self.instr { @@ -304,6 +389,23 @@ impl QirInstruction { } } + #[getter] + fn get_urem_targets(&self) -> PyResult> { + match &self.instr { + llvm_ir::Instruction::URem(instr) => Ok(vec![ + QirOperand { + op: instr.operand0.clone(), + types: self.types.clone(), + }, + QirOperand { + op: instr.operand1.clone(), + types: self.types.clone(), + }, + ]), + _ => Err(exceptions::PyTypeError::new_err("Instruction is not urem.")), + } + } + #[getter] fn get_is_srem(&self) -> bool { match self.instr { @@ -312,6 +414,23 @@ impl QirInstruction { } } + #[getter] + fn get_srem_targets(&self) -> PyResult> { + match &self.instr { + llvm_ir::Instruction::SRem(instr) => Ok(vec![ + QirOperand { + op: instr.operand0.clone(), + types: self.types.clone(), + }, + QirOperand { + op: instr.operand1.clone(), + types: self.types.clone(), + }, + ]), + _ => Err(exceptions::PyTypeError::new_err("Instruction is not srem.")), + } + } + #[getter] fn get_is_and(&self) -> bool { match self.instr { @@ -320,6 +439,23 @@ impl QirInstruction { } } + #[getter] + fn get_and_targets(&self) -> PyResult> { + match &self.instr { + llvm_ir::Instruction::And(instr) => Ok(vec![ + QirOperand { + op: instr.operand0.clone(), + types: self.types.clone(), + }, + QirOperand { + op: instr.operand1.clone(), + types: self.types.clone(), + }, + ]), + _ => Err(exceptions::PyTypeError::new_err("Instruction is not and.")), + } + } + #[getter] fn get_is_or(&self) -> bool { match self.instr { @@ -328,6 +464,23 @@ impl QirInstruction { } } + #[getter] + fn get_or_targets(&self) -> PyResult> { + match &self.instr { + llvm_ir::Instruction::Or(instr) => Ok(vec![ + QirOperand { + op: instr.operand0.clone(), + types: self.types.clone(), + }, + QirOperand { + op: instr.operand1.clone(), + types: self.types.clone(), + }, + ]), + _ => Err(exceptions::PyTypeError::new_err("Instruction is not or.")), + } + } + #[getter] fn get_is_xor(&self) -> bool { match self.instr { @@ -336,6 +489,23 @@ impl QirInstruction { } } + #[getter] + fn get_xor_targets(&self) -> PyResult> { + match &self.instr { + llvm_ir::Instruction::Xor(instr) => Ok(vec![ + QirOperand { + op: instr.operand0.clone(), + types: self.types.clone(), + }, + QirOperand { + op: instr.operand1.clone(), + types: self.types.clone(), + }, + ]), + _ => Err(exceptions::PyTypeError::new_err("Instruction is not xor.")), + } + } + #[getter] fn get_is_shl(&self) -> bool { match self.instr { @@ -344,6 +514,23 @@ impl QirInstruction { } } + #[getter] + fn get_shl_targets(&self) -> PyResult> { + match &self.instr { + llvm_ir::Instruction::Shl(instr) => Ok(vec![ + QirOperand { + op: instr.operand0.clone(), + types: self.types.clone(), + }, + QirOperand { + op: instr.operand1.clone(), + types: self.types.clone(), + }, + ]), + _ => Err(exceptions::PyTypeError::new_err("Instruction is not shl.")), + } + } + #[getter] fn get_is_lshr(&self) -> bool { match self.instr { @@ -352,6 +539,23 @@ impl QirInstruction { } } + #[getter] + fn get_lshr_targets(&self) -> PyResult> { + match &self.instr { + llvm_ir::Instruction::LShr(instr) => Ok(vec![ + QirOperand { + op: instr.operand0.clone(), + types: self.types.clone(), + }, + QirOperand { + op: instr.operand1.clone(), + types: self.types.clone(), + }, + ]), + _ => Err(exceptions::PyTypeError::new_err("Instruction is not lshr.")), + } + } + #[getter] fn get_is_ashr(&self) -> bool { match self.instr { @@ -360,6 +564,23 @@ impl QirInstruction { } } + #[getter] + fn get_ashr_targets(&self) -> PyResult> { + match &self.instr { + llvm_ir::Instruction::AShr(instr) => Ok(vec![ + QirOperand { + op: instr.operand0.clone(), + types: self.types.clone(), + }, + QirOperand { + op: instr.operand1.clone(), + types: self.types.clone(), + }, + ]), + _ => Err(exceptions::PyTypeError::new_err("Instruction is not ashr.")), + } + } + #[getter] fn get_is_fadd(&self) -> bool { match self.instr { @@ -368,6 +589,23 @@ impl QirInstruction { } } + #[getter] + fn get_fadd_targets(&self) -> PyResult> { + match &self.instr { + llvm_ir::Instruction::FAdd(instr) => Ok(vec![ + QirOperand { + op: instr.operand0.clone(), + types: self.types.clone(), + }, + QirOperand { + op: instr.operand1.clone(), + types: self.types.clone(), + }, + ]), + _ => Err(exceptions::PyTypeError::new_err("Instruction is not fadd.")), + } + } + #[getter] fn get_is_fsub(&self) -> bool { match self.instr { @@ -376,6 +614,23 @@ impl QirInstruction { } } + #[getter] + fn get_fsub_targets(&self) -> PyResult> { + match &self.instr { + llvm_ir::Instruction::FSub(instr) => Ok(vec![ + QirOperand { + op: instr.operand0.clone(), + types: self.types.clone(), + }, + QirOperand { + op: instr.operand1.clone(), + types: self.types.clone(), + }, + ]), + _ => Err(exceptions::PyTypeError::new_err("Instruction is not fsub.")), + } + } + #[getter] fn get_is_fmul(&self) -> bool { match self.instr { @@ -384,6 +639,23 @@ impl QirInstruction { } } + #[getter] + fn get_fmul_targets(&self) -> PyResult> { + match &self.instr { + llvm_ir::Instruction::FMul(instr) => Ok(vec![ + QirOperand { + op: instr.operand0.clone(), + types: self.types.clone(), + }, + QirOperand { + op: instr.operand1.clone(), + types: self.types.clone(), + }, + ]), + _ => Err(exceptions::PyTypeError::new_err("Instruction is not fmul.")), + } + } + #[getter] fn get_is_fdiv(&self) -> bool { match self.instr { @@ -392,6 +664,23 @@ impl QirInstruction { } } + #[getter] + fn get_fdiv_targets(&self) -> PyResult> { + match &self.instr { + llvm_ir::Instruction::FDiv(instr) => Ok(vec![ + QirOperand { + op: instr.operand0.clone(), + types: self.types.clone(), + }, + QirOperand { + op: instr.operand1.clone(), + types: self.types.clone(), + }, + ]), + _ => Err(exceptions::PyTypeError::new_err("Instruction is not fdiv.")), + } + } + #[getter] fn get_is_frem(&self) -> bool { match self.instr { @@ -400,6 +689,23 @@ impl QirInstruction { } } + #[getter] + fn get_frem_targets(&self) -> PyResult> { + match &self.instr { + llvm_ir::Instruction::FRem(instr) => Ok(vec![ + QirOperand { + op: instr.operand0.clone(), + types: self.types.clone(), + }, + QirOperand { + op: instr.operand1.clone(), + types: self.types.clone(), + }, + ]), + _ => Err(exceptions::PyTypeError::new_err("Instruction is not frem.")), + } + } + #[getter] fn get_is_fneg(&self) -> bool { match self.instr { @@ -408,6 +714,17 @@ impl QirInstruction { } } + #[getter] + fn get_fneg_targets(&self) -> PyResult> { + match &self.instr { + llvm_ir::Instruction::FNeg(instr) => Ok(vec![QirOperand { + op: instr.operand.clone(), + types: self.types.clone(), + }]), + _ => Err(exceptions::PyTypeError::new_err("Instruction is not fneg.")), + } + } + #[getter] fn get_is_extractelement(&self) -> bool { match self.instr { @@ -942,6 +1259,19 @@ impl QirConstant { } } + #[getter] + fn get_float_double_value(&self) -> PyResult { + match &self.constantref.as_ref() { + llvm_ir::Constant::Float(f) => match f { + llvm_ir::constant::Float::Double(d) => Ok(d.clone()), + _ => Err(exceptions::PyTypeError::new_err( + "Constant is not float double.", + )), + }, + _ => Err(exceptions::PyTypeError::new_err("Constant is not float.")), + } + } + #[getter] fn get_is_null(&self) -> bool { match self.constantref.as_ref() { From e8de45343a538b692eead3811454fb3e7083d5d9 Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Sun, 10 Oct 2021 00:53:22 -0700 Subject: [PATCH 06/26] Macro cleanup, initial phi node support --- src/QirTools/pyqir/src/parser.rs | 717 ++++++++----------------------- 1 file changed, 180 insertions(+), 537 deletions(-) diff --git a/src/QirTools/pyqir/src/parser.rs b/src/QirTools/pyqir/src/parser.rs index a346adeb8a..458db2b91f 100644 --- a/src/QirTools/pyqir/src/parser.rs +++ b/src/QirTools/pyqir/src/parser.rs @@ -254,464 +254,212 @@ impl QirBasicBlock { } } +macro_rules! instr_targets { + ($qir_instr:ident, $instr_pat:pat, $match:ident, $name:literal) => { + match &$qir_instr.instr { + $instr_pat => Ok(vec![ + QirOperand { + op: $match.operand0.clone(), + types: $qir_instr.types.clone(), + }, + QirOperand { + op: $match.operand1.clone(), + types: $qir_instr.types.clone(), + }, + ]), + _ => Err(exceptions::PyTypeError::new_err(format!( + "Instruction is not {}.", + $name + ))), + } + }; +} + #[pymethods] impl QirInstruction { #[getter] fn get_is_add(&self) -> bool { - match self.instr { - llvm_ir::Instruction::Add(_) => true, - _ => false, - } + matches!(self.instr, llvm_ir::Instruction::Add(_)) } #[getter] fn get_add_targets(&self) -> PyResult> { - match &self.instr { - llvm_ir::Instruction::Add(instr) => Ok(vec![ - QirOperand { - op: instr.operand0.clone(), - types: self.types.clone(), - }, - QirOperand { - op: instr.operand1.clone(), - types: self.types.clone(), - }, - ]), - _ => Err(exceptions::PyTypeError::new_err("Instruction is not add.")), - } + instr_targets!(self, llvm_ir::Instruction::Add(instr), instr, "add") } #[getter] fn get_is_sub(&self) -> bool { - match self.instr { - llvm_ir::Instruction::Sub(_) => true, - _ => false, - } + matches!(self.instr, llvm_ir::Instruction::Sub(_)) } #[getter] fn get_sub_targets(&self) -> PyResult> { - match &self.instr { - llvm_ir::Instruction::Sub(instr) => Ok(vec![ - QirOperand { - op: instr.operand0.clone(), - types: self.types.clone(), - }, - QirOperand { - op: instr.operand1.clone(), - types: self.types.clone(), - }, - ]), - _ => Err(exceptions::PyTypeError::new_err("Instruction is not sub.")), - } + instr_targets!(self, llvm_ir::Instruction::Sub(instr), instr, "sub") } #[getter] fn get_is_mul(&self) -> bool { - match self.instr { - llvm_ir::Instruction::Mul(_) => true, - _ => false, - } + matches!(self.instr, llvm_ir::Instruction::Mul(_)) } #[getter] fn get_mul_targets(&self) -> PyResult> { - match &self.instr { - llvm_ir::Instruction::Mul(instr) => Ok(vec![ - QirOperand { - op: instr.operand0.clone(), - types: self.types.clone(), - }, - QirOperand { - op: instr.operand1.clone(), - types: self.types.clone(), - }, - ]), - _ => Err(exceptions::PyTypeError::new_err("Instruction is not mul.")), - } + instr_targets!(self, llvm_ir::Instruction::Mul(instr), instr, "mul") } #[getter] fn get_is_udiv(&self) -> bool { - match self.instr { - llvm_ir::Instruction::UDiv(_) => true, - _ => false, - } + matches!(self.instr, llvm_ir::Instruction::UDiv(_)) } #[getter] fn get_udiv_targets(&self) -> PyResult> { - match &self.instr { - llvm_ir::Instruction::UDiv(instr) => Ok(vec![ - QirOperand { - op: instr.operand0.clone(), - types: self.types.clone(), - }, - QirOperand { - op: instr.operand1.clone(), - types: self.types.clone(), - }, - ]), - _ => Err(exceptions::PyTypeError::new_err("Instruction is not udiv.")), - } + instr_targets!(self, llvm_ir::Instruction::UDiv(instr), instr, "udiv") } #[getter] fn get_is_sdiv(&self) -> bool { - match self.instr { - llvm_ir::Instruction::SDiv(_) => true, - _ => false, - } + matches!(self.instr, llvm_ir::Instruction::SDiv(_)) } #[getter] fn get_sdiv_targets(&self) -> PyResult> { - match &self.instr { - llvm_ir::Instruction::SDiv(instr) => Ok(vec![ - QirOperand { - op: instr.operand0.clone(), - types: self.types.clone(), - }, - QirOperand { - op: instr.operand1.clone(), - types: self.types.clone(), - }, - ]), - _ => Err(exceptions::PyTypeError::new_err("Instruction is not sdiv.")), - } + instr_targets!(self, llvm_ir::Instruction::SDiv(instr), instr, "sdiv") } #[getter] fn get_is_urem(&self) -> bool { - match self.instr { - llvm_ir::Instruction::URem(_) => true, - _ => false, - } + matches!(self.instr, llvm_ir::Instruction::URem(_)) } #[getter] fn get_urem_targets(&self) -> PyResult> { - match &self.instr { - llvm_ir::Instruction::URem(instr) => Ok(vec![ - QirOperand { - op: instr.operand0.clone(), - types: self.types.clone(), - }, - QirOperand { - op: instr.operand1.clone(), - types: self.types.clone(), - }, - ]), - _ => Err(exceptions::PyTypeError::new_err("Instruction is not urem.")), - } + instr_targets!(self, llvm_ir::Instruction::URem(instr), instr, "urem") } #[getter] fn get_is_srem(&self) -> bool { - match self.instr { - llvm_ir::Instruction::SRem(_) => true, - _ => false, - } + matches!(self.instr, llvm_ir::Instruction::SRem(_)) } #[getter] fn get_srem_targets(&self) -> PyResult> { - match &self.instr { - llvm_ir::Instruction::SRem(instr) => Ok(vec![ - QirOperand { - op: instr.operand0.clone(), - types: self.types.clone(), - }, - QirOperand { - op: instr.operand1.clone(), - types: self.types.clone(), - }, - ]), - _ => Err(exceptions::PyTypeError::new_err("Instruction is not srem.")), - } + instr_targets!(self, llvm_ir::Instruction::SRem(instr), instr, "srem") } #[getter] fn get_is_and(&self) -> bool { - match self.instr { - llvm_ir::Instruction::And(_) => true, - _ => false, - } + matches!(self.instr, llvm_ir::Instruction::And(_)) } #[getter] fn get_and_targets(&self) -> PyResult> { - match &self.instr { - llvm_ir::Instruction::And(instr) => Ok(vec![ - QirOperand { - op: instr.operand0.clone(), - types: self.types.clone(), - }, - QirOperand { - op: instr.operand1.clone(), - types: self.types.clone(), - }, - ]), - _ => Err(exceptions::PyTypeError::new_err("Instruction is not and.")), - } + instr_targets!(self, llvm_ir::Instruction::And(instr), instr, "and") } #[getter] fn get_is_or(&self) -> bool { - match self.instr { - llvm_ir::Instruction::Or(_) => true, - _ => false, - } + matches!(self.instr, llvm_ir::Instruction::Or(_)) } #[getter] fn get_or_targets(&self) -> PyResult> { - match &self.instr { - llvm_ir::Instruction::Or(instr) => Ok(vec![ - QirOperand { - op: instr.operand0.clone(), - types: self.types.clone(), - }, - QirOperand { - op: instr.operand1.clone(), - types: self.types.clone(), - }, - ]), - _ => Err(exceptions::PyTypeError::new_err("Instruction is not or.")), - } + instr_targets!(self, llvm_ir::Instruction::Or(instr), instr, "or") } #[getter] fn get_is_xor(&self) -> bool { - match self.instr { - llvm_ir::Instruction::Xor(_) => true, - _ => false, - } + matches!(self.instr, llvm_ir::Instruction::Xor(_)) } #[getter] fn get_xor_targets(&self) -> PyResult> { - match &self.instr { - llvm_ir::Instruction::Xor(instr) => Ok(vec![ - QirOperand { - op: instr.operand0.clone(), - types: self.types.clone(), - }, - QirOperand { - op: instr.operand1.clone(), - types: self.types.clone(), - }, - ]), - _ => Err(exceptions::PyTypeError::new_err("Instruction is not xor.")), - } + instr_targets!(self, llvm_ir::Instruction::Xor(instr), instr, "xor") } #[getter] fn get_is_shl(&self) -> bool { - match self.instr { - llvm_ir::Instruction::Shl(_) => true, - _ => false, - } + matches!(self.instr, llvm_ir::Instruction::Shl(_)) } #[getter] fn get_shl_targets(&self) -> PyResult> { - match &self.instr { - llvm_ir::Instruction::Shl(instr) => Ok(vec![ - QirOperand { - op: instr.operand0.clone(), - types: self.types.clone(), - }, - QirOperand { - op: instr.operand1.clone(), - types: self.types.clone(), - }, - ]), - _ => Err(exceptions::PyTypeError::new_err("Instruction is not shl.")), - } + instr_targets!(self, llvm_ir::Instruction::Shl(instr), instr, "shl") } #[getter] fn get_is_lshr(&self) -> bool { - match self.instr { - llvm_ir::Instruction::LShr(_) => true, - _ => false, - } + matches!(self.instr, llvm_ir::Instruction::LShr(_)) } #[getter] fn get_lshr_targets(&self) -> PyResult> { - match &self.instr { - llvm_ir::Instruction::LShr(instr) => Ok(vec![ - QirOperand { - op: instr.operand0.clone(), - types: self.types.clone(), - }, - QirOperand { - op: instr.operand1.clone(), - types: self.types.clone(), - }, - ]), - _ => Err(exceptions::PyTypeError::new_err("Instruction is not lshr.")), - } + instr_targets!(self, llvm_ir::Instruction::LShr(instr), instr, "lshr") } #[getter] fn get_is_ashr(&self) -> bool { - match self.instr { - llvm_ir::Instruction::AShr(_) => true, - _ => false, - } + matches!(self.instr, llvm_ir::Instruction::AShr(_)) } #[getter] fn get_ashr_targets(&self) -> PyResult> { - match &self.instr { - llvm_ir::Instruction::AShr(instr) => Ok(vec![ - QirOperand { - op: instr.operand0.clone(), - types: self.types.clone(), - }, - QirOperand { - op: instr.operand1.clone(), - types: self.types.clone(), - }, - ]), - _ => Err(exceptions::PyTypeError::new_err("Instruction is not ashr.")), - } + instr_targets!(self, llvm_ir::Instruction::AShr(instr), instr, "ashr") } #[getter] fn get_is_fadd(&self) -> bool { - match self.instr { - llvm_ir::Instruction::FAdd(_) => true, - _ => false, - } + matches!(self.instr, llvm_ir::Instruction::FAdd(_)) } #[getter] fn get_fadd_targets(&self) -> PyResult> { - match &self.instr { - llvm_ir::Instruction::FAdd(instr) => Ok(vec![ - QirOperand { - op: instr.operand0.clone(), - types: self.types.clone(), - }, - QirOperand { - op: instr.operand1.clone(), - types: self.types.clone(), - }, - ]), - _ => Err(exceptions::PyTypeError::new_err("Instruction is not fadd.")), - } + instr_targets!(self, llvm_ir::Instruction::FAdd(instr), instr, "fadd") } #[getter] fn get_is_fsub(&self) -> bool { - match self.instr { - llvm_ir::Instruction::FSub(_) => true, - _ => false, - } + matches!(self.instr, llvm_ir::Instruction::FSub(_)) } #[getter] fn get_fsub_targets(&self) -> PyResult> { - match &self.instr { - llvm_ir::Instruction::FSub(instr) => Ok(vec![ - QirOperand { - op: instr.operand0.clone(), - types: self.types.clone(), - }, - QirOperand { - op: instr.operand1.clone(), - types: self.types.clone(), - }, - ]), - _ => Err(exceptions::PyTypeError::new_err("Instruction is not fsub.")), - } + instr_targets!(self, llvm_ir::Instruction::FSub(instr), instr, "fsub") } #[getter] fn get_is_fmul(&self) -> bool { - match self.instr { - llvm_ir::Instruction::FMul(_) => true, - _ => false, - } + matches!(self.instr, llvm_ir::Instruction::FMul(_)) } #[getter] fn get_fmul_targets(&self) -> PyResult> { - match &self.instr { - llvm_ir::Instruction::FMul(instr) => Ok(vec![ - QirOperand { - op: instr.operand0.clone(), - types: self.types.clone(), - }, - QirOperand { - op: instr.operand1.clone(), - types: self.types.clone(), - }, - ]), - _ => Err(exceptions::PyTypeError::new_err("Instruction is not fmul.")), - } + instr_targets!(self, llvm_ir::Instruction::FMul(instr), instr, "fmul") } #[getter] fn get_is_fdiv(&self) -> bool { - match self.instr { - llvm_ir::Instruction::FDiv(_) => true, - _ => false, - } + matches!(self.instr, llvm_ir::Instruction::FDiv(_)) } #[getter] fn get_fdiv_targets(&self) -> PyResult> { - match &self.instr { - llvm_ir::Instruction::FDiv(instr) => Ok(vec![ - QirOperand { - op: instr.operand0.clone(), - types: self.types.clone(), - }, - QirOperand { - op: instr.operand1.clone(), - types: self.types.clone(), - }, - ]), - _ => Err(exceptions::PyTypeError::new_err("Instruction is not fdiv.")), - } + instr_targets!(self, llvm_ir::Instruction::FDiv(instr), instr, "fdiv") } #[getter] fn get_is_frem(&self) -> bool { - match self.instr { - llvm_ir::Instruction::FRem(_) => true, - _ => false, - } + matches!(self.instr, llvm_ir::Instruction::FRem(_)) } #[getter] fn get_frem_targets(&self) -> PyResult> { - match &self.instr { - llvm_ir::Instruction::FRem(instr) => Ok(vec![ - QirOperand { - op: instr.operand0.clone(), - types: self.types.clone(), - }, - QirOperand { - op: instr.operand1.clone(), - types: self.types.clone(), - }, - ]), - _ => Err(exceptions::PyTypeError::new_err("Instruction is not frem.")), - } + instr_targets!(self, llvm_ir::Instruction::FRem(instr), instr, "frem") } #[getter] fn get_is_fneg(&self) -> bool { - match self.instr { - llvm_ir::Instruction::FNeg(_) => true, - _ => false, - } + matches!(self.instr, llvm_ir::Instruction::FNeg(_)) } #[getter] @@ -727,218 +475,185 @@ impl QirInstruction { #[getter] fn get_is_extractelement(&self) -> bool { - match self.instr { - llvm_ir::Instruction::ExtractElement(_) => true, - _ => false, - } + matches!(self.instr, llvm_ir::Instruction::ExtractElement(_)) } #[getter] fn get_is_insertelement(&self) -> bool { - match self.instr { - llvm_ir::Instruction::InsertElement(_) => true, - _ => false, - } + matches!(self.instr, llvm_ir::Instruction::InsertElement(_)) } #[getter] fn get_is_shufflevector(&self) -> bool { - match self.instr { - llvm_ir::Instruction::ShuffleVector(_) => true, - _ => false, - } + matches!(self.instr, llvm_ir::Instruction::ShuffleVector(_)) } #[getter] fn get_is_extractvalue(&self) -> bool { - match self.instr { - llvm_ir::Instruction::ExtractValue(_) => true, - _ => false, - } + matches!(self.instr, llvm_ir::Instruction::ExtractValue(_)) } #[getter] fn get_is_insertvalue(&self) -> bool { - match self.instr { - llvm_ir::Instruction::InsertValue(_) => true, - _ => false, - } + matches!(self.instr, llvm_ir::Instruction::InsertValue(_)) } #[getter] fn get_is_alloca(&self) -> bool { - match self.instr { - llvm_ir::Instruction::Alloca(_) => true, - _ => false, - } + matches!(self.instr, llvm_ir::Instruction::Alloca(_)) } #[getter] fn get_is_load(&self) -> bool { - match self.instr { - llvm_ir::Instruction::Load(_) => true, - _ => false, - } + matches!(self.instr, llvm_ir::Instruction::Load(_)) } #[getter] fn get_is_store(&self) -> bool { - match self.instr { - llvm_ir::Instruction::Store(_) => true, - _ => false, - } + matches!(self.instr, llvm_ir::Instruction::Store(_)) } #[getter] fn get_is_getelementptr(&self) -> bool { - match self.instr { - llvm_ir::Instruction::GetElementPtr(_) => true, - _ => false, - } + matches!(self.instr, llvm_ir::Instruction::GetElementPtr(_)) } #[getter] fn get_is_trunc(&self) -> bool { - match self.instr { - llvm_ir::Instruction::Trunc(_) => true, - _ => false, - } + matches!(self.instr, llvm_ir::Instruction::Trunc(_)) } #[getter] fn get_is_zext(&self) -> bool { - match self.instr { - llvm_ir::Instruction::ZExt(_) => true, - _ => false, - } + matches!(self.instr, llvm_ir::Instruction::ZExt(_)) } #[getter] fn get_is_sext(&self) -> bool { - match self.instr { - llvm_ir::Instruction::SExt(_) => true, - _ => false, - } + matches!(self.instr, llvm_ir::Instruction::SExt(_)) } #[getter] fn get_is_fptrunc(&self) -> bool { - match self.instr { - llvm_ir::Instruction::FPTrunc(_) => true, - _ => false, - } + matches!(self.instr, llvm_ir::Instruction::FPTrunc(_)) } #[getter] fn get_is_fpext(&self) -> bool { - match self.instr { - llvm_ir::Instruction::FPExt(_) => true, - _ => false, - } + matches!(self.instr, llvm_ir::Instruction::FPExt(_)) } #[getter] fn get_is_fptoui(&self) -> bool { - match self.instr { - llvm_ir::Instruction::FPToUI(_) => true, - _ => false, - } + matches!(self.instr, llvm_ir::Instruction::FPToUI(_)) } #[getter] fn get_is_fptosi(&self) -> bool { - match self.instr { - llvm_ir::Instruction::FPToSI(_) => true, - _ => false, - } + matches!(self.instr, llvm_ir::Instruction::FPToSI(_)) } #[getter] fn get_is_uitofp(&self) -> bool { - match self.instr { - llvm_ir::Instruction::UIToFP(_) => true, - _ => false, - } + matches!(self.instr, llvm_ir::Instruction::UIToFP(_)) } #[getter] fn get_is_sitofp(&self) -> bool { - match self.instr { - llvm_ir::Instruction::SIToFP(_) => true, - _ => false, - } + matches!(self.instr, llvm_ir::Instruction::SIToFP(_)) } #[getter] fn get_is_ptrtoint(&self) -> bool { - match self.instr { - llvm_ir::Instruction::PtrToInt(_) => true, - _ => false, - } + matches!(self.instr, llvm_ir::Instruction::PtrToInt(_)) } #[getter] fn get_is_inttoptr(&self) -> bool { - match self.instr { - llvm_ir::Instruction::IntToPtr(_) => true, - _ => false, - } + matches!(self.instr, llvm_ir::Instruction::IntToPtr(_)) } #[getter] fn get_is_bitcast(&self) -> bool { - match self.instr { - llvm_ir::Instruction::BitCast(_) => true, - _ => false, - } + matches!(self.instr, llvm_ir::Instruction::BitCast(_)) } #[getter] fn get_is_addrspacecast(&self) -> bool { - match self.instr { - llvm_ir::Instruction::AddrSpaceCast(_) => true, - _ => false, - } + matches!(self.instr, llvm_ir::Instruction::AddrSpaceCast(_)) } #[getter] fn get_is_icmp(&self) -> bool { - match self.instr { - llvm_ir::Instruction::ICmp(_) => true, - _ => false, - } + matches!(self.instr, llvm_ir::Instruction::ICmp(_)) + } + + #[getter] + fn get_icmp_targets(&self) -> PyResult> { + instr_targets!(self, llvm_ir::Instruction::ICmp(instr), instr, "icmp") } #[getter] fn get_is_fcmp(&self) -> bool { - match self.instr { - llvm_ir::Instruction::FCmp(_) => true, - _ => false, - } + matches!(self.instr, llvm_ir::Instruction::FCmp(_)) + } + + #[getter] + fn get_fcmp_targets(&self) -> PyResult> { + instr_targets!(self, llvm_ir::Instruction::FCmp(instr), instr, "fcmp") } #[getter] fn get_is_phi(&self) -> bool { - match self.instr { - llvm_ir::Instruction::Phi(_) => true, - _ => false, + matches!(self.instr, llvm_ir::Instruction::Phi(_)) + } + + #[getter] + fn get_phi_incoming_values(&self) -> PyResult> { + match &self.instr { + llvm_ir::Instruction::Phi(llvm_ir::instruction::Phi { + incoming_values, + dest: _, + to_type: _, + debugloc: _, + }) => Ok(incoming_values + .iter() + .map(|(op, name)| { + ( + QirOperand { + op: op.clone(), + types: self.types.clone(), + }, + name_to_string(name), + ) + }) + .collect()), + _ => Err(exceptions::PyTypeError::new_err("Instruction is not phi.")), + } + } + + fn get_phi_incoming_value_for_name(&self, name: String) -> PyResult { + match self + .get_phi_incoming_values()? + .into_iter() + .find(|phi_pair| phi_pair.1 == name) + { + Some((op, _)) => Ok(op), + None => Err(exceptions::PyTypeError::new_err(format!( + "Phi instruction has no incoming value for block named '{}'", + name + ))), } } #[getter] fn get_is_select(&self) -> bool { - match self.instr { - llvm_ir::Instruction::Select(_) => true, - _ => false, - } + matches!(self.instr, llvm_ir::Instruction::Select(_)) } #[getter] fn get_is_call(&self) -> bool { - match self.instr { - llvm_ir::Instruction::Call(_) => true, - _ => false, - } + matches!(self.instr, llvm_ir::Instruction::Call(_)) } #[getter] @@ -1021,10 +736,7 @@ impl QirInstruction { impl QirTerminator { #[getter] fn get_is_ret(&self) -> bool { - match self.term { - llvm_ir::Terminator::Ret(_) => true, - _ => false, - } + matches!(self.term, llvm_ir::Terminator::Ret(_)) } #[getter] @@ -1050,10 +762,7 @@ impl QirTerminator { #[getter] fn get_is_br(&self) -> bool { - match self.term { - llvm_ir::Terminator::Br(_) => true, - _ => false, - } + matches!(self.term, llvm_ir::Terminator::Br(_)) } #[getter] @@ -1070,10 +779,7 @@ impl QirTerminator { #[getter] fn get_is_condbr(&self) -> bool { - match self.term { - llvm_ir::Terminator::CondBr(_) => true, - _ => false, - } + matches!(self.term, llvm_ir::Terminator::CondBr(_)) } #[getter] @@ -1126,54 +832,12 @@ impl QirTerminator { #[getter] fn get_is_switch(&self) -> bool { - match self.term { - llvm_ir::Terminator::Switch(_) => true, - _ => false, - } - } - - #[getter] - fn get_switch_operand(&self) -> PyResult { - match self.term { - llvm_ir::Terminator::Switch(_) => Err(exceptions::PyTypeError::new_err( - "Switch handling not supported.", - )), - _ => Err(exceptions::PyTypeError::new_err( - "Terminator is not switch.", - )), - } - } - - #[getter] - fn get_switch_dest_values(&self) -> PyResult> { - match self.term { - llvm_ir::Terminator::Switch(_) => Err(exceptions::PyTypeError::new_err( - "Switch handling not supported.", - )), - _ => Err(exceptions::PyTypeError::new_err( - "Terminator is not switch.", - )), - } - } - - #[getter] - fn get_switch_dest_names(&self) -> PyResult> { - match self.term { - llvm_ir::Terminator::Switch(_) => Err(exceptions::PyTypeError::new_err( - "Switch handling not supported.", - )), - _ => Err(exceptions::PyTypeError::new_err( - "Terminator is not switch.", - )), - } + matches!(self.term, llvm_ir::Terminator::Switch(_)) } #[getter] fn get_is_unreachable(&self) -> bool { - match self.term { - llvm_ir::Terminator::Unreachable(_) => true, - _ => false, - } + matches!(self.term, llvm_ir::Terminator::Unreachable(_)) } } @@ -1181,10 +845,7 @@ impl QirTerminator { impl QirOperand { #[getter] fn get_is_local(&self) -> bool { - match self.op { - llvm_ir::Operand::LocalOperand { name: _, ty: _ } => true, - _ => false, - } + matches!(self.op, llvm_ir::Operand::LocalOperand { name: _, ty: _ }) } #[getter] @@ -1207,10 +868,7 @@ impl QirOperand { #[getter] fn get_is_constant(&self) -> bool { - match self.op { - llvm_ir::Operand::ConstantOperand(_) => true, - _ => false, - } + matches!(self.op, llvm_ir::Operand::ConstantOperand(_)) } #[getter] @@ -1229,10 +887,10 @@ impl QirOperand { impl QirConstant { #[getter] fn get_is_int(&self) -> bool { - match self.constantref.as_ref() { - llvm_ir::Constant::Int { bits: _, value: _ } => true, - _ => false, - } + matches!( + self.constantref.as_ref(), + llvm_ir::Constant::Int { bits: _, value: _ } + ) } #[getter] @@ -1253,10 +911,7 @@ impl QirConstant { #[getter] fn get_is_float(&self) -> bool { - match self.constantref.as_ref() { - llvm_ir::Constant::Float(_) => true, - _ => false, - } + matches!(self.constantref.as_ref(), llvm_ir::Constant::Float(_)) } #[getter] @@ -1274,45 +929,36 @@ impl QirConstant { #[getter] fn get_is_null(&self) -> bool { - match self.constantref.as_ref() { - llvm_ir::Constant::Null(_) => true, - _ => false, - } + matches!(self.constantref.as_ref(), llvm_ir::Constant::Null(_)) } #[getter] fn get_is_agregate_zero(&self) -> bool { - match self.constantref.as_ref() { - llvm_ir::Constant::AggregateZero(_) => true, - _ => false, - } + matches!( + self.constantref.as_ref(), + llvm_ir::Constant::AggregateZero(_) + ) } #[getter] fn get_is_array(&self) -> bool { - match self.constantref.as_ref() { + matches!( + self.constantref.as_ref(), llvm_ir::Constant::Array { element_type: _, elements: _, - } => true, - _ => false, - } + } + ) } #[getter] fn get_is_vector(&self) -> bool { - match self.constantref.as_ref() { - llvm_ir::Constant::Vector(_) => true, - _ => false, - } + matches!(self.constantref.as_ref(), llvm_ir::Constant::Vector(_)) } #[getter] fn get_is_undef(&self) -> bool { - match self.constantref.as_ref() { - llvm_ir::Constant::Undef(_) => true, - _ => false, - } + matches!(self.constantref.as_ref(), llvm_ir::Constant::Undef(_)) } #[getter] @@ -1391,18 +1037,15 @@ impl QirConstant { impl QirType { #[getter] fn get_is_void(&self) -> bool { - match self.typeref.as_ref() { - llvm_ir::Type::VoidType => true, - _ => false, - } + matches!(self.typeref.as_ref(), llvm_ir::Type::VoidType) } #[getter] fn get_is_integer(&self) -> bool { - match self.typeref.as_ref() { - llvm_ir::Type::IntegerType { bits: _ } => true, - _ => false, - } + matches!( + self.typeref.as_ref(), + llvm_ir::Type::IntegerType { bits: _ } + ) } #[getter] @@ -1415,13 +1058,13 @@ impl QirType { #[getter] fn get_is_pointer(&self) -> bool { - match self.typeref.as_ref() { + matches!( + self.typeref.as_ref(), llvm_ir::Type::PointerType { pointee_type: _, addr_space: _, - } => true, - _ => false, - } + } + ) } #[getter] @@ -1450,21 +1093,21 @@ impl QirType { #[getter] fn get_is_double(&self) -> bool { - match self.typeref.as_ref() { - llvm_ir::Type::FPType(llvm_ir::types::FPType::Double) => true, - _ => false, - } + matches!( + self.typeref.as_ref(), + llvm_ir::Type::FPType(llvm_ir::types::FPType::Double) + ) } #[getter] fn get_is_array(&self) -> bool { - match self.typeref.as_ref() { + matches!( + self.typeref.as_ref(), llvm_ir::Type::ArrayType { element_type: _, num_elements: _, - } => true, - _ => false, - } + } + ) } #[getter] @@ -1493,13 +1136,13 @@ impl QirType { #[getter] fn get_is_struct(&self) -> bool { - match self.typeref.as_ref() { + matches!( + self.typeref.as_ref(), llvm_ir::Type::StructType { element_types: _, is_packed: _, - } => true, - _ => false, - } + } + ) } #[getter] @@ -1518,10 +1161,10 @@ impl QirType { #[getter] fn get_is_named_struct(&self) -> bool { - match self.typeref.as_ref() { - llvm_ir::Type::NamedStructType { name: _ } => true, - _ => false, - } + matches!( + self.typeref.as_ref(), + llvm_ir::Type::NamedStructType { name: _ } + ) } #[getter] From c1f8c2112469d5e9e1f23c71c269e6372bfeb768 Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Sun, 10 Oct 2021 12:50:54 -0700 Subject: [PATCH 07/26] Phi node helper methods --- src/QirTools/pyqir/src/parser.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/QirTools/pyqir/src/parser.rs b/src/QirTools/pyqir/src/parser.rs index 458db2b91f..5d4a18e0c3 100644 --- a/src/QirTools/pyqir/src/parser.rs +++ b/src/QirTools/pyqir/src/parser.rs @@ -245,6 +245,28 @@ impl QirBasicBlock { .collect() } + #[getter] + fn get_phi_nodes(&self) -> Vec { + self.get_instructions() + .into_iter() + .filter(|i| i.get_is_phi()) + .collect() + } + + fn get_phi_pairs_by_source_name(&self, name: String) -> Vec<(String, QirOperand)> { + self.get_phi_nodes() + .iter() + .map(|i| { + ( + i.get_output_name().unwrap(), + i.get_phi_incoming_value_for_name(name.clone()), + ) + }) + .filter(|phi_pair| phi_pair.1.is_ok()) + .map(|phi_pair| (phi_pair.0, phi_pair.1.unwrap())) + .collect() + } + #[getter] fn get_terminator(&self) -> QirTerminator { QirTerminator { From b1694b3267c2ae5019f645d8b3343f404f5d9315 Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Mon, 11 Oct 2021 14:39:05 -0700 Subject: [PATCH 08/26] Add TODO comment --- src/QirTools/pyqir/src/parser.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/QirTools/pyqir/src/parser.rs b/src/QirTools/pyqir/src/parser.rs index 5d4a18e0c3..a9c6ee0b95 100644 --- a/src/QirTools/pyqir/src/parser.rs +++ b/src/QirTools/pyqir/src/parser.rs @@ -1,5 +1,14 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. + +// TODO(swernli): The initial version of the parser exposes a subset of the llvm_ir crate API into +// python directly, along with some extensions that provide QIR specific support (such as `get_qubit_static_id`). +// Eventually this should be split up similar to how QIR emission functionality works; these wrappers will +// remain here and provide the pyclass-compatible implementation, the QIR specific extensions will be implemented +// as traits and extended onto the llvm_ir types as part of the qirlib such that they can be conveniently used +// from within rust, and wrappers for each class and function will be added to __init__.py so that the +// parser API can have full python doc comments for usability. + use pyo3::exceptions; use pyo3::prelude::*; From 678adf07f5e2ce5fcee403c922282b274e8282c6 Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Tue, 12 Oct 2021 16:24:33 -0700 Subject: [PATCH 09/26] Fixing error types --- Cargo.lock | 2 +- src/QirTools/pyqir/Cargo.toml.template | 1 - src/QirTools/pyqir/src/parser.rs | 16 ++++++++-------- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a8362dcba0..aee2ffb271 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -349,7 +349,6 @@ dependencies = [ name = "pyqir" version = "0.9999.2110-alpha" dependencies = [ - "either", "env_logger", "llvm-ir", "log", @@ -366,6 +365,7 @@ dependencies = [ "cty", "inkwell", "libloading", + "llvm-ir", "llvm-sys", "log", "rand", diff --git a/src/QirTools/pyqir/Cargo.toml.template b/src/QirTools/pyqir/Cargo.toml.template index e87744ba68..6952353648 100644 --- a/src/QirTools/pyqir/Cargo.toml.template +++ b/src/QirTools/pyqir/Cargo.toml.template @@ -29,7 +29,6 @@ qirlib = {path = "../qirlib"} env_logger = "0.9.0" log = "0.4.14" llvm-ir = { version = "0.8.0", features = ["llvm-11"] } -either = "1.5.3" [dependencies.pyo3] version = "0.14.2" diff --git a/src/QirTools/pyqir/src/parser.rs b/src/QirTools/pyqir/src/parser.rs index a9c6ee0b95..dd8a8c58cb 100644 --- a/src/QirTools/pyqir/src/parser.rs +++ b/src/QirTools/pyqir/src/parser.rs @@ -6,7 +6,7 @@ // Eventually this should be split up similar to how QIR emission functionality works; these wrappers will // remain here and provide the pyclass-compatible implementation, the QIR specific extensions will be implemented // as traits and extended onto the llvm_ir types as part of the qirlib such that they can be conveniently used -// from within rust, and wrappers for each class and function will be added to __init__.py so that the +// from within rust, and wrappers for each class and function will be added to __init__.py so that the // parser API can have full python doc comments for usability. use pyo3::exceptions; @@ -86,7 +86,7 @@ impl QirModule { function: f.clone(), types: self.module.types.clone(), }), - None => Err(exceptions::PyTypeError::new_err(format!( + None => Err(exceptions::PyLookupError::new_err(format!( "Function with name '{}' not found", name ))), @@ -175,7 +175,7 @@ impl QirFunction { _ => continue, } } - Err(exceptions::PyTypeError::new_err(format!( + Err(exceptions::PyLookupError::new_err(format!( "Attribute with name '{}' not found", attr_name ))) @@ -190,7 +190,7 @@ impl QirFunction { block: b.clone(), types: self.types.clone(), }), - None => Err(exceptions::PyTypeError::new_err(format!( + None => Err(exceptions::PyLookupError::new_err(format!( "Block with name '{}' not found", name ))), @@ -213,7 +213,7 @@ impl QirFunction { } } } - Err(exceptions::PyTypeError::new_err(format!( + Err(exceptions::PyLookupError::new_err(format!( "Instruction with result name '{}' not found", name ))) @@ -670,7 +670,7 @@ impl QirInstruction { .find(|phi_pair| phi_pair.1 == name) { Some((op, _)) => Ok(op), - None => Err(exceptions::PyTypeError::new_err(format!( + None => Err(exceptions::PyLookupError::new_err(format!( "Phi instruction has no incoming value for block named '{}'", name ))), @@ -695,11 +695,11 @@ impl QirInstruction { llvm_ir::constant::Constant::GlobalReference { name, ty: _ } => { Ok(name_to_string(&name)) } - _ => Err(exceptions::PyTypeError::new_err( + _ => Err(exceptions::PyNotImplementedError::new_err( "Unhandled operand type in call.", )), }, - _ => Err(exceptions::PyTypeError::new_err("Unhandled call type.")), + _ => Err(exceptions::PyNotImplementedError::new_err("Unhandled call type.")), }, _ => Err(exceptions::PyTypeError::new_err("Instruction is not call.")), } From 1d1a334cf592f2799e6eaf34155afb9f20314d13 Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Tue, 12 Oct 2021 16:43:20 -0700 Subject: [PATCH 10/26] Fix formatting, error use --- src/QirTools/pyqir/src/python.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/QirTools/pyqir/src/python.rs b/src/QirTools/pyqir/src/python.rs index f89ff2c117..458e0d1733 100644 --- a/src/QirTools/pyqir/src/python.rs +++ b/src/QirTools/pyqir/src/python.rs @@ -4,7 +4,7 @@ use log; use pyo3::PyErr; -use pyo3::{exceptions::PyOSError, prelude::*}; +use pyo3::{exceptions::PyOSError, exceptions::PyRuntimeError, prelude::*}; use qirlib::interop::{ ClassicalRegister, Controlled, Instruction, Measured, QuantumRegister, Rotated, SemanticModel, Single, @@ -16,11 +16,12 @@ use crate::parser::QirModule; fn pyqir(_py: Python<'_>, m: &PyModule) -> PyResult<()> { m.add_class::()?; - #[pyfn(m)] #[pyo3(name = "module_from_bitcode")] + #[pyfn(m)] + #[pyo3(name = "module_from_bitcode")] fn module_from_bitcode_py(_py: Python, bc_path: String) -> PyResult { match llvm_ir::Module::from_bc_path(&bc_path) { Ok(m) => Ok(QirModule { module: m }), - Err(s) => Err(exceptions::PyTypeError::new_err(s)), + Err(s) => Err(PyRuntimeError::new_err(s)), } } From d0828e4bb3de7ba6b1e1e7b32033c9f42ab18e62 Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Sun, 17 Oct 2021 22:54:39 -0700 Subject: [PATCH 11/26] Split Rust parsing utilities into qirlib --- src/QirTools/pyqir/src/parser.rs | 734 +++++++++------------------ src/QirTools/qirlib/Cargo.toml | 1 + src/QirTools/qirlib/src/lib.rs | 1 + src/QirTools/qirlib/src/parse/mod.rs | 307 +++++++++++ 4 files changed, 562 insertions(+), 481 deletions(-) create mode 100644 src/QirTools/qirlib/src/parse/mod.rs diff --git a/src/QirTools/pyqir/src/parser.rs b/src/QirTools/pyqir/src/parser.rs index dd8a8c58cb..39972e95a6 100644 --- a/src/QirTools/pyqir/src/parser.rs +++ b/src/QirTools/pyqir/src/parser.rs @@ -9,11 +9,11 @@ // from within rust, and wrappers for each class and function will be added to __init__.py so that the // parser API can have full python doc comments for usability. -use pyo3::exceptions; -use pyo3::prelude::*; - use llvm_ir; use llvm_ir::types::Typed; +use pyo3::prelude::*; +use qirlib::parse::*; +use std::convert::TryFrom; #[pyclass] pub struct QirModule { @@ -66,6 +66,15 @@ pub struct QirType { pub(super) typeref: llvm_ir::TypeRef, } +macro_rules! match_contents { + ($target:expr, $pattern:pat, $property:expr) => { + match $target { + $pattern => Some($property), + _ => None, + } + }; +} + #[pymethods] impl QirModule { #[getter] @@ -80,33 +89,44 @@ impl QirModule { .collect() } - fn get_func_by_name(&self, name: String) -> PyResult { + fn get_func_by_name(&self, name: String) -> Option { match self.module.get_func_by_name(&name) { - Some(f) => Ok(QirFunction { + Some(f) => Some(QirFunction { function: f.clone(), types: self.module.types.clone(), }), - None => Err(exceptions::PyLookupError::new_err(format!( - "Function with name '{}' not found", - name - ))), + None => None, } } fn get_funcs_by_attr(&self, attr: String) -> Vec { self.module - .functions + .get_func_by_attr_name(&attr) .iter() - .filter(|f| { - f.function_attributes.contains( - &llvm_ir::function::FunctionAttribute::StringAttribute { - kind: attr.clone(), - value: "".to_string(), - }, - ) + .map(|f| QirFunction { + function: (*f).clone(), + types: self.module.types.clone(), + }) + .collect() + } + + fn get_entrypoint_funcs(&self) -> Vec { + self.module + .get_entrypoint_funcs() + .iter() + .map(|f| QirFunction { + function: (*f).clone(), + types: self.module.types.clone(), }) + .collect() + } + + fn get_interop_funcs(&self) -> Vec { + self.module + .get_interop_funcs() + .iter() .map(|f| QirFunction { - function: f.clone(), + function: (*f).clone(), types: self.module.types.clone(), }) .collect() @@ -149,74 +169,34 @@ impl QirFunction { } #[getter] - fn get_required_qubits(&self) -> i64 { - match self.get_attribute_value("requiredQubits".to_string()) { - Ok(s) => s.parse().unwrap(), - Err(_) => 0, - } + fn get_required_qubits(&self) -> PyResult> { + Ok(self.function.get_required_qubits()?) } #[getter] - fn get_required_results(&self) -> i64 { - match self.get_attribute_value("requiredResults".to_string()) { - Ok(s) => s.parse().unwrap(), - Err(_) => 0, - } + fn get_required_results(&self) -> PyResult> { + Ok(self.function.get_required_results()?) } - fn get_attribute_value(&self, attr_name: String) -> PyResult { - for attr in &self.function.function_attributes { - match attr { - llvm_ir::function::FunctionAttribute::StringAttribute { kind, value } => { - if kind.to_string() == attr_name { - return Ok(value.to_string()); - } - } - _ => continue, - } - } - Err(exceptions::PyLookupError::new_err(format!( - "Attribute with name '{}' not found", - attr_name - ))) - } - - fn get_block_by_name(&self, name: String) -> PyResult { - match self - .function - .get_bb_by_name(&llvm_ir::Name::from(name.clone())) - { - Some(b) => Ok(QirBasicBlock { - block: b.clone(), - types: self.types.clone(), - }), - None => Err(exceptions::PyLookupError::new_err(format!( - "Block with name '{}' not found", - name - ))), - } + fn get_attribute_value(&self, attr_name: String) -> Option { + self.function.get_attribute_value(&attr_name) } - fn get_instruction_by_output_name(&self, name: String) -> PyResult { - for block in &self.function.basic_blocks { - for instr in &block.instrs { - match instr.try_get_result() { - Some(resname) => { - if name_to_string(resname) == name { - return Ok(QirInstruction { - instr: instr.clone(), - types: self.types.clone(), - }); - } - } - None => continue, - } - } - } - Err(exceptions::PyLookupError::new_err(format!( - "Instruction with result name '{}' not found", - name - ))) + fn get_block_by_name(&self, name: String) -> Option { + Some(QirBasicBlock { + block: self + .function + .get_bb_by_name(&llvm_ir::Name::from(name.clone()))? + .clone(), + types: self.types.clone(), + }) + } + + fn get_instruction_by_output_name(&self, name: String) -> Option { + Some(QirInstruction { + instr: self.function.get_instruction_by_output_name(&name)?.clone(), + types: self.types.clone(), + }) } } @@ -224,7 +204,7 @@ impl QirFunction { impl QirParameter { #[getter] fn get_name(&self) -> String { - name_to_string(&self.param.name) + self.param.name.get_string() } #[getter] @@ -239,7 +219,7 @@ impl QirParameter { impl QirBasicBlock { #[getter] fn get_name(&self) -> String { - name_to_string(&self.block.name) + self.block.name.get_string() } #[getter] @@ -256,23 +236,29 @@ impl QirBasicBlock { #[getter] fn get_phi_nodes(&self) -> Vec { - self.get_instructions() - .into_iter() - .filter(|i| i.get_is_phi()) + self.block + .get_phi_nodes() + .iter() + .map(|phi| QirInstruction { + instr: llvm_ir::Instruction::from(phi.clone()), + types: self.types.clone(), + }) .collect() } fn get_phi_pairs_by_source_name(&self, name: String) -> Vec<(String, QirOperand)> { - self.get_phi_nodes() + self.block + .get_phi_pairs_by_source_name(&name) .iter() - .map(|i| { + .map(|(n, op)| { ( - i.get_output_name().unwrap(), - i.get_phi_incoming_value_for_name(name.clone()), + n.get_string(), + QirOperand { + op: op.clone(), + types: self.types.clone(), + }, ) }) - .filter(|phi_pair| phi_pair.1.is_ok()) - .map(|phi_pair| (phi_pair.0, phi_pair.1.unwrap())) .collect() } @@ -285,37 +271,23 @@ impl QirBasicBlock { } } -macro_rules! instr_targets { - ($qir_instr:ident, $instr_pat:pat, $match:ident, $name:literal) => { - match &$qir_instr.instr { - $instr_pat => Ok(vec![ - QirOperand { - op: $match.operand0.clone(), - types: $qir_instr.types.clone(), - }, - QirOperand { - op: $match.operand1.clone(), - types: $qir_instr.types.clone(), - }, - ]), - _ => Err(exceptions::PyTypeError::new_err(format!( - "Instruction is not {}.", - $name - ))), - } - }; -} - #[pymethods] impl QirInstruction { #[getter] - fn get_is_add(&self) -> bool { - matches!(self.instr, llvm_ir::Instruction::Add(_)) + fn get_target_operands(&self) -> Vec { + self.instr + .get_target_operands() + .iter() + .map(|op| QirOperand { + op: op.clone(), + types: self.types.clone(), + }) + .collect() } #[getter] - fn get_add_targets(&self) -> PyResult> { - instr_targets!(self, llvm_ir::Instruction::Add(instr), instr, "add") + fn get_is_add(&self) -> bool { + matches!(self.instr, llvm_ir::Instruction::Add(_)) } #[getter] @@ -323,187 +295,91 @@ impl QirInstruction { matches!(self.instr, llvm_ir::Instruction::Sub(_)) } - #[getter] - fn get_sub_targets(&self) -> PyResult> { - instr_targets!(self, llvm_ir::Instruction::Sub(instr), instr, "sub") - } - #[getter] fn get_is_mul(&self) -> bool { matches!(self.instr, llvm_ir::Instruction::Mul(_)) } - #[getter] - fn get_mul_targets(&self) -> PyResult> { - instr_targets!(self, llvm_ir::Instruction::Mul(instr), instr, "mul") - } - #[getter] fn get_is_udiv(&self) -> bool { matches!(self.instr, llvm_ir::Instruction::UDiv(_)) } - #[getter] - fn get_udiv_targets(&self) -> PyResult> { - instr_targets!(self, llvm_ir::Instruction::UDiv(instr), instr, "udiv") - } - #[getter] fn get_is_sdiv(&self) -> bool { matches!(self.instr, llvm_ir::Instruction::SDiv(_)) } - #[getter] - fn get_sdiv_targets(&self) -> PyResult> { - instr_targets!(self, llvm_ir::Instruction::SDiv(instr), instr, "sdiv") - } - #[getter] fn get_is_urem(&self) -> bool { matches!(self.instr, llvm_ir::Instruction::URem(_)) } - #[getter] - fn get_urem_targets(&self) -> PyResult> { - instr_targets!(self, llvm_ir::Instruction::URem(instr), instr, "urem") - } - #[getter] fn get_is_srem(&self) -> bool { matches!(self.instr, llvm_ir::Instruction::SRem(_)) } - #[getter] - fn get_srem_targets(&self) -> PyResult> { - instr_targets!(self, llvm_ir::Instruction::SRem(instr), instr, "srem") - } - #[getter] fn get_is_and(&self) -> bool { matches!(self.instr, llvm_ir::Instruction::And(_)) } - #[getter] - fn get_and_targets(&self) -> PyResult> { - instr_targets!(self, llvm_ir::Instruction::And(instr), instr, "and") - } - #[getter] fn get_is_or(&self) -> bool { matches!(self.instr, llvm_ir::Instruction::Or(_)) } - #[getter] - fn get_or_targets(&self) -> PyResult> { - instr_targets!(self, llvm_ir::Instruction::Or(instr), instr, "or") - } - #[getter] fn get_is_xor(&self) -> bool { matches!(self.instr, llvm_ir::Instruction::Xor(_)) } - #[getter] - fn get_xor_targets(&self) -> PyResult> { - instr_targets!(self, llvm_ir::Instruction::Xor(instr), instr, "xor") - } - #[getter] fn get_is_shl(&self) -> bool { matches!(self.instr, llvm_ir::Instruction::Shl(_)) } - #[getter] - fn get_shl_targets(&self) -> PyResult> { - instr_targets!(self, llvm_ir::Instruction::Shl(instr), instr, "shl") - } - #[getter] fn get_is_lshr(&self) -> bool { matches!(self.instr, llvm_ir::Instruction::LShr(_)) } - #[getter] - fn get_lshr_targets(&self) -> PyResult> { - instr_targets!(self, llvm_ir::Instruction::LShr(instr), instr, "lshr") - } - #[getter] fn get_is_ashr(&self) -> bool { matches!(self.instr, llvm_ir::Instruction::AShr(_)) } - #[getter] - fn get_ashr_targets(&self) -> PyResult> { - instr_targets!(self, llvm_ir::Instruction::AShr(instr), instr, "ashr") - } - #[getter] fn get_is_fadd(&self) -> bool { matches!(self.instr, llvm_ir::Instruction::FAdd(_)) } - #[getter] - fn get_fadd_targets(&self) -> PyResult> { - instr_targets!(self, llvm_ir::Instruction::FAdd(instr), instr, "fadd") - } - #[getter] fn get_is_fsub(&self) -> bool { matches!(self.instr, llvm_ir::Instruction::FSub(_)) } - #[getter] - fn get_fsub_targets(&self) -> PyResult> { - instr_targets!(self, llvm_ir::Instruction::FSub(instr), instr, "fsub") - } - #[getter] fn get_is_fmul(&self) -> bool { matches!(self.instr, llvm_ir::Instruction::FMul(_)) } - #[getter] - fn get_fmul_targets(&self) -> PyResult> { - instr_targets!(self, llvm_ir::Instruction::FMul(instr), instr, "fmul") - } - #[getter] fn get_is_fdiv(&self) -> bool { matches!(self.instr, llvm_ir::Instruction::FDiv(_)) } - #[getter] - fn get_fdiv_targets(&self) -> PyResult> { - instr_targets!(self, llvm_ir::Instruction::FDiv(instr), instr, "fdiv") - } - #[getter] fn get_is_frem(&self) -> bool { matches!(self.instr, llvm_ir::Instruction::FRem(_)) } - #[getter] - fn get_frem_targets(&self) -> PyResult> { - instr_targets!(self, llvm_ir::Instruction::FRem(instr), instr, "frem") - } - #[getter] fn get_is_fneg(&self) -> bool { matches!(self.instr, llvm_ir::Instruction::FNeg(_)) } - #[getter] - fn get_fneg_targets(&self) -> PyResult> { - match &self.instr { - llvm_ir::Instruction::FNeg(instr) => Ok(vec![QirOperand { - op: instr.operand.clone(), - types: self.types.clone(), - }]), - _ => Err(exceptions::PyTypeError::new_err("Instruction is not fneg.")), - } - } - #[getter] fn get_is_extractelement(&self) -> bool { matches!(self.instr, llvm_ir::Instruction::ExtractElement(_)) @@ -619,35 +495,22 @@ impl QirInstruction { matches!(self.instr, llvm_ir::Instruction::ICmp(_)) } - #[getter] - fn get_icmp_targets(&self) -> PyResult> { - instr_targets!(self, llvm_ir::Instruction::ICmp(instr), instr, "icmp") - } - #[getter] fn get_is_fcmp(&self) -> bool { matches!(self.instr, llvm_ir::Instruction::FCmp(_)) } - #[getter] - fn get_fcmp_targets(&self) -> PyResult> { - instr_targets!(self, llvm_ir::Instruction::FCmp(instr), instr, "fcmp") - } - #[getter] fn get_is_phi(&self) -> bool { matches!(self.instr, llvm_ir::Instruction::Phi(_)) } #[getter] - fn get_phi_incoming_values(&self) -> PyResult> { - match &self.instr { - llvm_ir::Instruction::Phi(llvm_ir::instruction::Phi { - incoming_values, - dest: _, - to_type: _, - debugloc: _, - }) => Ok(incoming_values + fn get_phi_incoming_values(&self) -> Option> { + Some( + llvm_ir::instruction::Phi::try_from(self.instr.clone()) + .ok()? + .incoming_values .iter() .map(|(op, name)| { ( @@ -655,26 +518,20 @@ impl QirInstruction { op: op.clone(), types: self.types.clone(), }, - name_to_string(name), + name.get_string(), ) }) - .collect()), - _ => Err(exceptions::PyTypeError::new_err("Instruction is not phi.")), - } + .collect(), + ) } - fn get_phi_incoming_value_for_name(&self, name: String) -> PyResult { - match self - .get_phi_incoming_values()? - .into_iter() - .find(|phi_pair| phi_pair.1 == name) - { - Some((op, _)) => Ok(op), - None => Err(exceptions::PyLookupError::new_err(format!( - "Phi instruction has no incoming value for block named '{}'", - name - ))), - } + fn get_phi_incoming_value_for_name(&self, name: String) -> Option { + Some(QirOperand { + op: llvm_ir::instruction::Phi::try_from(self.instr.clone()) + .ok()? + .get_incoming_value_for_name(&name)?, + types: self.types.clone(), + }) } #[getter] @@ -688,60 +545,43 @@ impl QirInstruction { } #[getter] - fn get_call_func_name(&self) -> PyResult { - match &self.instr { - llvm_ir::Instruction::Call(call) => match call.function.clone().right() { - Some(llvm_ir::operand::Operand::ConstantOperand(cref)) => match cref.as_ref() { - llvm_ir::constant::Constant::GlobalReference { name, ty: _ } => { - Ok(name_to_string(&name)) - } - _ => Err(exceptions::PyNotImplementedError::new_err( - "Unhandled operand type in call.", - )), - }, - _ => Err(exceptions::PyNotImplementedError::new_err("Unhandled call type.")), - }, - _ => Err(exceptions::PyTypeError::new_err("Instruction is not call.")), - } + fn get_call_func_name(&self) -> Option { + Some( + llvm_ir::instruction::Call::try_from(self.instr.clone()) + .ok()? + .get_func_name()? + .get_string(), + ) } #[getter] - fn get_call_func_params(&self) -> PyResult> { - match &self.instr { - llvm_ir::Instruction::Call(call) => Ok(call + fn get_call_func_params(&self) -> Option> { + Some( + llvm_ir::instruction::Call::try_from(self.instr.clone()) + .ok()? .arguments .iter() .map(|o| QirOperand { op: o.0.clone(), types: self.types.clone(), }) - .collect()), - _ => Err(exceptions::PyTypeError::new_err("Instruction is not call.")), - } + .collect(), + ) } #[getter] fn get_is_qis_call(&self) -> bool { - match self.get_call_func_name() { - Ok(name) => name.starts_with("__quantum__qis__"), - _ => false, - } + llvm_ir::instruction::Call::try_from(self.instr.clone()).map_or(false, |c| c.is_qis()) } #[getter] fn get_is_qrt_call(&self) -> bool { - match self.get_call_func_name() { - Ok(name) => name.starts_with("__quantum__rt__"), - _ => false, - } + llvm_ir::instruction::Call::try_from(self.instr.clone()).map_or(false, |c| c.is_qrt()) } #[getter] fn get_is_qir_call(&self) -> bool { - match self.get_call_func_name() { - Ok(name) => name.starts_with("__quantum__qir__"), - _ => false, - } + llvm_ir::instruction::Call::try_from(self.instr.clone()).map_or(false, |c| c.is_qir()) } #[getter] @@ -753,13 +593,8 @@ impl QirInstruction { } #[getter] - fn get_output_name(&self) -> PyResult { - match self.instr.try_get_result() { - Some(name) => Ok(name_to_string(name)), - None => Err(exceptions::PyTypeError::new_err( - "Instruction has no output.", - )), - } + fn get_output_name(&self) -> Option { + Some(self.instr.try_get_result()?.get_string()) } } @@ -771,24 +606,18 @@ impl QirTerminator { } #[getter] - fn get_ret_operand(&self) -> PyResult { - match &self.term { + fn get_ret_operand(&self) -> Option { + match_contents!( + &self.term, llvm_ir::Terminator::Ret(llvm_ir::terminator::Ret { return_operand, debugloc: _, - }) => match return_operand { - Some(op) => Ok(QirOperand { - op: op.clone(), - types: self.types.clone(), - }), - None => Err(exceptions::PyTypeError::new_err( - "Return is void and has no operand.", - )), - }, - _ => Err(exceptions::PyTypeError::new_err( - "Terminator is not return.", - )), - } + }), + QirOperand { + op: return_operand.as_ref()?.clone(), + types: self.types.clone(), + } + ) } #[getter] @@ -797,15 +626,12 @@ impl QirTerminator { } #[getter] - fn get_br_dest(&self) -> PyResult { - match &self.term { - llvm_ir::Terminator::Br(llvm_ir::terminator::Br { dest, debugloc: _ }) => { - Ok(name_to_string(&dest)) - } - _ => Err(exceptions::PyTypeError::new_err( - "Terminator is not branch.", - )), - } + fn get_br_dest(&self) -> Option { + match_contents!( + &self.term, + llvm_ir::Terminator::Br(llvm_ir::terminator::Br { dest, debugloc: _ }), + dest.get_string() + ) } #[getter] @@ -814,51 +640,48 @@ impl QirTerminator { } #[getter] - fn get_condbr_condition(&self) -> PyResult { - match &self.term { + fn get_condbr_condition(&self) -> Option { + match_contents!( + &self.term, llvm_ir::Terminator::CondBr(llvm_ir::terminator::CondBr { condition, true_dest: _, false_dest: _, debugloc: _, - }) => Ok(QirOperand { + }), + QirOperand { op: condition.clone(), types: self.types.clone(), - }), - _ => Err(exceptions::PyTypeError::new_err( - "Terminator is not condition branch.", - )), - } + } + ) } #[getter] - fn get_condbr_true_dest(&self) -> PyResult { - match &self.term { + fn get_condbr_true_dest(&self) -> Option { + match_contents!( + &self.term, llvm_ir::Terminator::CondBr(llvm_ir::terminator::CondBr { condition: _, true_dest, false_dest: _, debugloc: _, - }) => Ok(name_to_string(&true_dest)), - _ => Err(exceptions::PyTypeError::new_err( - "Terminator is not condition branch.", - )), - } + }), + true_dest.get_string() + ) } #[getter] - fn get_condbr_false_dest(&self) -> PyResult { - match &self.term { + fn get_condbr_false_dest(&self) -> Option { + match_contents!( + &self.term, llvm_ir::Terminator::CondBr(llvm_ir::terminator::CondBr { condition: _, true_dest: _, false_dest, debugloc: _, - }) => Ok(name_to_string(&false_dest)), - _ => Err(exceptions::PyTypeError::new_err( - "Terminator is not condition branch.", - )), - } + }), + false_dest.get_string() + ) } #[getter] @@ -880,21 +703,23 @@ impl QirOperand { } #[getter] - fn get_local_name(&self) -> PyResult { - match &self.op { - llvm_ir::Operand::LocalOperand { name, ty: _ } => Ok(name_to_string(&name)), - _ => Err(exceptions::PyTypeError::new_err("Operand is not local.")), - } + fn get_local_name(&self) -> Option { + match_contents!( + &self.op, + llvm_ir::Operand::LocalOperand { name, ty: _ }, + name.get_string() + ) } #[getter] - fn get_local_type(&self) -> PyResult { - match &self.op { - llvm_ir::Operand::LocalOperand { name: _, ty } => Ok(QirType { + fn get_local_type(&self) -> Option { + match_contents!( + &self.op, + llvm_ir::Operand::LocalOperand { name: _, ty }, + QirType { typeref: ty.clone(), - }), - _ => Err(exceptions::PyTypeError::new_err("Operand is not local.")), - } + } + ) } #[getter] @@ -903,14 +728,15 @@ impl QirOperand { } #[getter] - fn get_constant(&self) -> PyResult { - match &self.op { - llvm_ir::Operand::ConstantOperand(cref) => Ok(QirConstant { + fn get_constant(&self) -> Option { + match_contents!( + &self.op, + llvm_ir::Operand::ConstantOperand(cref), + QirConstant { constantref: cref.clone(), types: self.types.clone(), - }), - _ => Err(exceptions::PyTypeError::new_err("Operand is not constant.")), - } + } + ) } } @@ -925,19 +751,21 @@ impl QirConstant { } #[getter] - fn get_int_value(&self) -> PyResult { - match self.constantref.as_ref() { - llvm_ir::Constant::Int { bits: _, value } => Ok(value.clone() as i64), - _ => Err(exceptions::PyTypeError::new_err("Constant is not int.")), - } + fn get_int_value(&self) -> Option { + match_contents!( + self.constantref.as_ref(), + llvm_ir::Constant::Int { bits: _, value }, + value.clone() as i64 + ) } #[getter] - fn get_int_width(&self) -> PyResult { - match &self.constantref.as_ref() { - llvm_ir::Constant::Int { bits, value: _ } => Ok(bits.clone()), - _ => Err(exceptions::PyTypeError::new_err("Constant is not int.")), - } + fn get_int_width(&self) -> Option { + match_contents!( + &self.constantref.as_ref(), + llvm_ir::Constant::Int { bits, value: _ }, + bits.clone() + ) } #[getter] @@ -946,16 +774,12 @@ impl QirConstant { } #[getter] - fn get_float_double_value(&self) -> PyResult { - match &self.constantref.as_ref() { - llvm_ir::Constant::Float(f) => match f { - llvm_ir::constant::Float::Double(d) => Ok(d.clone()), - _ => Err(exceptions::PyTypeError::new_err( - "Constant is not float double.", - )), - }, - _ => Err(exceptions::PyTypeError::new_err("Constant is not float.")), - } + fn get_float_double_value(&self) -> Option { + match_contents!( + &self.constantref.as_ref(), + llvm_ir::Constant::Float(llvm_ir::constant::Float::Double(d)), + d.clone() + ) } #[getter] @@ -964,7 +788,7 @@ impl QirConstant { } #[getter] - fn get_is_agregate_zero(&self) -> bool { + fn get_is_aggregate_zero(&self) -> bool { matches!( self.constantref.as_ref(), llvm_ir::Constant::AggregateZero(_) @@ -994,10 +818,10 @@ impl QirConstant { #[getter] fn get_is_global_reference(&self) -> bool { - match self.constantref.as_ref() { - llvm_ir::Constant::GlobalReference { name: _, ty: _ } => true, - _ => false, - } + matches!( + self.constantref.as_ref(), + llvm_ir::Constant::GlobalReference { name: _, ty: _ } + ) } #[getter] @@ -1013,26 +837,8 @@ impl QirConstant { } #[getter] - fn get_qubit_static_id(&self) -> PyResult { - if !self.get_is_qubit() { - Err(exceptions::PyTypeError::new_err("Constant is not qubit.")) - } else { - match &self.constantref.as_ref() { - llvm_ir::Constant::Null(_) => Ok(0), - llvm_ir::Constant::IntToPtr(llvm_ir::constant::IntToPtr { - operand, - to_type: _, - }) => match operand.as_ref() { - llvm_ir::Constant::Int { bits: 64, value } => Ok(value.clone()), - _ => Err(exceptions::PyTypeError::new_err( - "Qubit is not recognized constant.", - )), - }, - _ => Err(exceptions::PyTypeError::new_err( - "Qubit is not recognized constant.", - )), - } - } + fn get_qubit_static_id(&self) -> Option { + self.constantref.qubit_id() } #[getter] @@ -1041,26 +847,8 @@ impl QirConstant { } #[getter] - fn get_result_static_id(&self) -> PyResult { - if !self.get_is_result() { - Err(exceptions::PyTypeError::new_err("Constant is not result.")) - } else { - match &self.constantref.as_ref() { - llvm_ir::Constant::Null(_) => Ok(0), - llvm_ir::Constant::IntToPtr(llvm_ir::constant::IntToPtr { - operand, - to_type: _, - }) => match operand.as_ref() { - llvm_ir::Constant::Int { bits: 64, value } => Ok(value.clone()), - _ => Err(exceptions::PyTypeError::new_err( - "Result is not recognized constant.", - )), - }, - _ => Err(exceptions::PyTypeError::new_err( - "Result is not recognized constant.", - )), - } - } + fn get_result_static_id(&self) -> Option { + self.constantref.result_id() } } @@ -1080,11 +868,12 @@ impl QirType { } #[getter] - fn get_integer_width(&self) -> PyResult { - match self.typeref.as_ref() { - llvm_ir::Type::IntegerType { bits } => Ok(bits.clone()), - _ => Err(exceptions::PyTypeError::new_err("Type is not integer.")), - } + fn get_integer_width(&self) -> Option { + match_contents!( + self.typeref.as_ref(), + llvm_ir::Type::IntegerType { bits }, + bits.clone() + ) } #[getter] @@ -1099,27 +888,29 @@ impl QirType { } #[getter] - fn get_pointer_type(&self) -> PyResult { - match self.typeref.as_ref() { + fn get_pointer_type(&self) -> Option { + match_contents!( + self.typeref.as_ref(), llvm_ir::Type::PointerType { pointee_type, - addr_space: _, - } => Ok(QirType { - typeref: pointee_type.clone(), - }), - _ => Err(exceptions::PyTypeError::new_err("Type is not pointer.")), - } + addr_space: _ + }, + QirType { + typeref: pointee_type.clone() + } + ) } #[getter] - fn get_pointer_addrspace(&self) -> PyResult { - match self.typeref.as_ref() { + fn get_pointer_addrspace(&self) -> Option { + match_contents!( + self.typeref.as_ref(), llvm_ir::Type::PointerType { pointee_type: _, - addr_space, - } => Ok(addr_space.clone()), - _ => Err(exceptions::PyTypeError::new_err("Type is not pointer.")), - } + addr_space + }, + addr_space.clone() + ) } #[getter] @@ -1142,27 +933,29 @@ impl QirType { } #[getter] - fn get_array_element_type(&self) -> PyResult { - match self.typeref.as_ref() { + fn get_array_element_type(&self) -> Option { + match_contents!( + self.typeref.as_ref(), llvm_ir::Type::ArrayType { element_type, num_elements: _, - } => Ok(QirType { - typeref: element_type.clone(), - }), - _ => Err(exceptions::PyTypeError::new_err("Type is not array.")), - } + }, + QirType { + typeref: element_type.clone() + } + ) } #[getter] - fn get_array_num_elements(&self) -> PyResult { - match self.typeref.as_ref() { + fn get_array_num_elements(&self) -> Option { + match_contents!( + self.typeref.as_ref(), llvm_ir::Type::ArrayType { element_type: _, num_elements, - } => Ok(num_elements.clone()), - _ => Err(exceptions::PyTypeError::new_err("Type is not array.")), - } + }, + num_elements.clone() + ) } #[getter] @@ -1177,17 +970,18 @@ impl QirType { } #[getter] - fn get_struct_element_types(&self) -> PyResult> { - match self.typeref.as_ref() { + fn get_struct_element_types(&self) -> Option> { + match_contents!( + self.typeref.as_ref(), llvm_ir::Type::StructType { element_types, - is_packed: _, - } => Ok(element_types + is_packed: _ + }, + element_types .iter() .map(|t| QirType { typeref: t.clone() }) - .collect()), - _ => Err(exceptions::PyTypeError::new_err("Type is not struct.")), - } + .collect() + ) } #[getter] @@ -1199,43 +993,21 @@ impl QirType { } #[getter] - fn get_named_struct_name(&self) -> PyResult { - match self.typeref.as_ref() { - llvm_ir::Type::NamedStructType { name } => Ok(name.clone()), - _ => Err(exceptions::PyTypeError::new_err( - "Type is not named struct.", - )), - } + fn get_named_struct_name(&self) -> Option { + match_contents!( + self.typeref.as_ref(), + llvm_ir::Type::NamedStructType { name }, + name.clone() + ) } #[getter] fn get_is_qubit(&self) -> bool { - self.get_is_pointer() - && self.get_pointer_type().unwrap().get_is_named_struct() - && self - .get_pointer_type() - .unwrap() - .get_named_struct_name() - .unwrap() - == "Qubit" + self.typeref.is_qubit() } #[getter] fn get_is_result(&self) -> bool { - self.get_is_pointer() - && self.get_pointer_type().unwrap().get_is_named_struct() - && self - .get_pointer_type() - .unwrap() - .get_named_struct_name() - .unwrap() - == "Result" - } -} - -fn name_to_string(name: &llvm_ir::Name) -> String { - match name { - llvm_ir::Name::Name(n) => n.to_string(), - llvm_ir::Name::Number(n) => n.to_string(), + self.typeref.is_result() } } diff --git a/src/QirTools/qirlib/Cargo.toml b/src/QirTools/qirlib/Cargo.toml index 796d679a98..74a0d45947 100644 --- a/src/QirTools/qirlib/Cargo.toml +++ b/src/QirTools/qirlib/Cargo.toml @@ -11,6 +11,7 @@ log = "0.4.14" libloading = "0.7.0" cty="0.2.1" rand="0.8.4" +llvm-ir = { version = "0.8.0", features = ["llvm-11"] } [dev-dependencies] serial_test = "0.5.1" diff --git a/src/QirTools/qirlib/src/lib.rs b/src/QirTools/qirlib/src/lib.rs index 9e994b6a3a..e7b407fead 100644 --- a/src/QirTools/qirlib/src/lib.rs +++ b/src/QirTools/qirlib/src/lib.rs @@ -8,5 +8,6 @@ pub mod emit; pub mod interop; +pub mod parse; mod jit; diff --git a/src/QirTools/qirlib/src/parse/mod.rs b/src/QirTools/qirlib/src/parse/mod.rs new file mode 100644 index 0000000000..a3e5fe3cb4 --- /dev/null +++ b/src/QirTools/qirlib/src/parse/mod.rs @@ -0,0 +1,307 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +use std::convert::TryFrom; +use std::num::ParseIntError; + +use llvm_ir; + +// This module introdues extensions to the existing types exposed by llvm_ir to bring in some +// convenience functions as well as QIR-specific utilities. + +pub trait ModuleExt { + fn get_func_by_attr_name(&self, name: &str) -> Vec<&llvm_ir::Function>; + fn get_entrypoint_funcs(&self) -> Vec<&llvm_ir::Function>; + fn get_interop_funcs(&self) -> Vec<&llvm_ir::Function>; +} + +impl ModuleExt for llvm_ir::Module { + fn get_func_by_attr_name(&self, name: &str) -> Vec<&llvm_ir::Function> { + self.functions + .iter() + .filter(|f| { + f.function_attributes.contains( + &llvm_ir::function::FunctionAttribute::StringAttribute { + kind: name.to_string(), + value: String::new(), + }, + ) + }) + .collect() + } + + fn get_entrypoint_funcs(&self) -> Vec<&llvm_ir::Function> { + self.get_func_by_attr_name("EntryPoint") + } + + fn get_interop_funcs(&self) -> Vec<&llvm_ir::Function> { + self.get_func_by_attr_name("InteropFriendly") + } +} + +pub trait FunctionExt { + fn get_attribute_value(&self, name: &str) -> Option; + fn get_required_qubits(&self) -> Result, ParseIntError>; + fn get_required_results(&self) -> Result, ParseIntError>; + fn get_instruction_by_output_name(&self, name: &str) -> Option<&llvm_ir::Instruction>; +} + +impl FunctionExt for llvm_ir::Function { + fn get_attribute_value(&self, name: &str) -> Option { + for attr in &self.function_attributes { + match attr { + llvm_ir::function::FunctionAttribute::StringAttribute { kind, value } => { + if kind.to_string().eq(name) { + return Some(value.to_string()); + } + } + _ => continue, + } + } + None + } + + fn get_required_qubits(&self) -> Result, ParseIntError> { + match self.get_attribute_value("requiredQubits") { + Some(s) => Ok(Some(s.parse()?)), + None => Ok(None), + } + } + + fn get_required_results(&self) -> Result, ParseIntError> { + match self.get_attribute_value("requiredResults") { + Some(s) => Ok(Some(s.parse()?)), + None => Ok(None), + } + } + + fn get_instruction_by_output_name(&self, name: &str) -> Option<&llvm_ir::Instruction> { + for block in &self.basic_blocks { + for instr in &block.instrs { + match instr.try_get_result() { + Some(resname) => { + if resname.get_string().eq(name) { + return Some(instr); + } + } + None => continue, + } + } + } + None + } +} + +pub trait BasicBlockExt { + fn get_phi_nodes(&self) -> Vec; + fn get_phi_pairs_by_source_name(&self, name: &str) -> Vec<(llvm_ir::Name, llvm_ir::Operand)>; +} + +impl BasicBlockExt for llvm_ir::BasicBlock { + fn get_phi_nodes(&self) -> Vec { + self.instrs + .iter() + .filter_map(|i| llvm_ir::instruction::Phi::try_from(i.clone()).ok()) + .collect() + } + + fn get_phi_pairs_by_source_name(&self, name: &str) -> Vec<(llvm_ir::Name, llvm_ir::Operand)> { + self.get_phi_nodes() + .iter() + .filter_map(|phi| Some((phi.dest.clone(), phi.get_incoming_value_for_name(name)?))) + .collect() + } +} + +pub trait IntructionExt { + fn get_target_operands(&self) -> Vec; +} + +impl IntructionExt for llvm_ir::Instruction { + fn get_target_operands(&self) -> Vec { + match &self { + llvm_ir::Instruction::Add(instr) => { + vec![instr.operand0.clone(), instr.operand1.clone()] + } + llvm_ir::Instruction::Sub(instr) => { + vec![instr.operand0.clone(), instr.operand1.clone()] + } + llvm_ir::Instruction::Mul(instr) => { + vec![instr.operand0.clone(), instr.operand1.clone()] + } + llvm_ir::Instruction::UDiv(instr) => { + vec![instr.operand0.clone(), instr.operand1.clone()] + } + llvm_ir::Instruction::SDiv(instr) => { + vec![instr.operand0.clone(), instr.operand1.clone()] + } + llvm_ir::Instruction::URem(instr) => { + vec![instr.operand0.clone(), instr.operand1.clone()] + } + llvm_ir::Instruction::SRem(instr) => { + vec![instr.operand0.clone(), instr.operand1.clone()] + } + llvm_ir::Instruction::And(instr) => { + vec![instr.operand0.clone(), instr.operand1.clone()] + } + llvm_ir::Instruction::Or(instr) => vec![instr.operand0.clone(), instr.operand1.clone()], + llvm_ir::Instruction::Xor(instr) => { + vec![instr.operand0.clone(), instr.operand1.clone()] + } + llvm_ir::Instruction::Shl(instr) => { + vec![instr.operand0.clone(), instr.operand1.clone()] + } + llvm_ir::Instruction::LShr(instr) => { + vec![instr.operand0.clone(), instr.operand1.clone()] + } + llvm_ir::Instruction::AShr(instr) => { + vec![instr.operand0.clone(), instr.operand1.clone()] + } + llvm_ir::Instruction::FAdd(instr) => { + vec![instr.operand0.clone(), instr.operand1.clone()] + } + llvm_ir::Instruction::FSub(instr) => { + vec![instr.operand0.clone(), instr.operand1.clone()] + } + llvm_ir::Instruction::FMul(instr) => { + vec![instr.operand0.clone(), instr.operand1.clone()] + } + llvm_ir::Instruction::FDiv(instr) => { + vec![instr.operand0.clone(), instr.operand1.clone()] + } + llvm_ir::Instruction::FRem(instr) => { + vec![instr.operand0.clone(), instr.operand1.clone()] + } + llvm_ir::Instruction::FNeg(instr) => vec![instr.operand.clone()], + llvm_ir::Instruction::ICmp(instr) => { + vec![instr.operand0.clone(), instr.operand1.clone()] + } + llvm_ir::Instruction::FCmp(instr) => { + vec![instr.operand0.clone(), instr.operand1.clone()] + } + _ => vec![], + } + } +} + +pub trait CallExt { + fn get_func_name(&self) -> Option; + fn is_qis(&self) -> bool; + fn is_qrt(&self) -> bool; + fn is_qir(&self) -> bool; +} + +impl CallExt for llvm_ir::instruction::Call { + fn get_func_name(&self) -> Option { + match self.function.clone().right()? { + llvm_ir::Operand::ConstantOperand(c) => match c.as_ref() { + llvm_ir::constant::Constant::GlobalReference { name, ty: _ } => Some(name.clone()), + _ => None, + }, + _ => None, + } + } + + fn is_qis(&self) -> bool { + self.get_func_name() + .map_or(false, |n| n.get_string().starts_with("__quantum__qis__")) + } + fn is_qrt(&self) -> bool { + self.get_func_name() + .map_or(false, |n| n.get_string().starts_with("__quantum__qrt__")) + } + fn is_qir(&self) -> bool { + self.get_func_name() + .map_or(false, |n| n.get_string().starts_with("__quantum__qir__")) + } +} + +pub trait PhiExt { + fn get_incoming_value_for_name(&self, name: &str) -> Option; +} + +impl PhiExt for llvm_ir::instruction::Phi { + fn get_incoming_value_for_name(&self, name: &str) -> Option { + self.incoming_values.iter().find_map(|(op, block_name)| { + match block_name.get_string().eq(name) { + true => Some(op.clone()), + false => None, + } + }) + } +} + +pub trait TypeExt { + fn is_qubit(&self) -> bool; + fn is_result(&self) -> bool; +} + +impl TypeExt for llvm_ir::Type { + fn is_qubit(&self) -> bool { + match self { + llvm_ir::Type::PointerType { + pointee_type, + addr_space: _, + } => pointee_type.as_ref().is_qubit(), + llvm_ir::Type::NamedStructType { name } => name == "Qubit", + _ => false, + } + } + + fn is_result(&self) -> bool { + match self { + llvm_ir::Type::PointerType { + pointee_type, + addr_space: _, + } => pointee_type.as_ref().is_result(), + llvm_ir::Type::NamedStructType { name } => name == "Result", + _ => false, + } + } +} + +pub trait ConstantExt { + fn qubit_id(&self) -> Option; + fn result_id(&self) -> Option; +} + +macro_rules! constant_id { + ($name:ident, $check_func:path) => { + fn $name(&self) -> Option { + match &self { + llvm_ir::Constant::Null(t) => { + if $check_func(t.as_ref()) { + Some(0) + } else { + None + } + } + llvm_ir::Constant::IntToPtr(llvm_ir::constant::IntToPtr { operand, to_type }) => { + match ($check_func(to_type.as_ref()), operand.as_ref()) { + (true, llvm_ir::Constant::Int { bits: 64, value }) => Some(value.clone()), + _ => None, + } + } + _ => None, + } + } + }; +} + +impl ConstantExt for llvm_ir::Constant { + constant_id!(qubit_id, TypeExt::is_qubit); + constant_id!(result_id, TypeExt::is_result); +} + +pub trait NameExt { + fn get_string(&self) -> String; +} + +impl NameExt for llvm_ir::Name { + fn get_string(&self) -> String { + match &self { + llvm_ir::Name::Name(n) => n.to_string(), + llvm_ir::Name::Number(n) => n.to_string(), + } + } +} From 11515ca19d3b2f91c2f42afc54df9981cf070153 Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Sun, 17 Oct 2021 22:56:57 -0700 Subject: [PATCH 12/26] Fix gitignore from PR feedback --- src/QirTools/pyqir/.gitignore | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/QirTools/pyqir/.gitignore b/src/QirTools/pyqir/.gitignore index c8c07a73b5..e16cd69a70 100644 --- a/src/QirTools/pyqir/.gitignore +++ b/src/QirTools/pyqir/.gitignore @@ -155,7 +155,4 @@ Cargo.lock *.pdb # We inject version numbers into Cargo.toml, so don't want them stored in repo. -Cargo.toml - -# Ignore the IR files generated during testing -*.ll \ No newline at end of file +Cargo.toml \ No newline at end of file From f27020e5f915b80c209b90134128fb62ac414889 Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Mon, 18 Oct 2021 21:24:31 -0700 Subject: [PATCH 13/26] Updating Python API (more doc comments later) --- src/QirTools/pyqir/pyqir/__init__.py | 604 +++++++++++++++++++++++++++ src/QirTools/pyqir/src/parser.rs | 144 +++---- src/QirTools/pyqir/src/python.rs | 15 +- src/QirTools/pyqir/tests/test_api.py | 39 +- 4 files changed, 726 insertions(+), 76 deletions(-) diff --git a/src/QirTools/pyqir/pyqir/__init__.py b/src/QirTools/pyqir/pyqir/__init__.py index ad6489b41e..18fbf7ddaa 100644 --- a/src/QirTools/pyqir/pyqir/__init__.py +++ b/src/QirTools/pyqir/pyqir/__init__.py @@ -251,3 +251,607 @@ def test_logging(): [2021-09-15T16:55:46Z INFO pyqir::python] h => qr0 """ self.pyqir.enable_logging() + +class QirModule: + """ + The QirModule object parses a QIR program from bitcode into an in-memory + representation for iterating over the program structure. It contains all the + functions and global definitions from the program. + + :param bitcode_path: the path to the bitcode file for the QIR program + :type bitcode_path: string + """ + + def __init__(self, bitcode_path: str): + self.module = module_from_bitcode(bitcode_path) + + def from_pyqir_module(self, module: PyQirModule): + self.module = module + + @property + def functions(self): + """ + Gets all the functions defined in this module. + :return: a list of functions in the module + :rtype: list[QirFunction] + """ + return list(map(QirFunction, self.module.functions)) + + + def get_func_by_name(self, name: str): + """ + Gets the function with the given name, or None if no matching function is found. + + :param name: the name of the function to get + :type name: string + :return: the function matchign the name, or None if not found + :rtype: QirFunction or None + """ + return QirFunction(self.module.get_func_by_name(name)) + + def get_funcs_by_attr(self, attr: str): + """ + Gets any functions that have an attribute whose name matches the provided string. + + :param attr: the attribute to use when looking for functions + :type attr: string + :return: a list of functions + :rtype: list[QirFunction] + """ + return list(map(QirFunction, self.module.get_funcs_by_attr(attr))) + + @property + def entrypoint_funcs(self): + """ + Gets any functions with the "EntryPoint" attribute. + :return: a list of functions + :rtype: list[QirFunction] + """ + return list(map(QirFunction, self.module.get_entrypoint_funcs())) + + @property + def interop_funcs(self): + """ + Gets any functions with the "InteropFriendly" attribute. + :return: a list of functions + :rtype: list[QirFunction] + """ + return list(map(QirFunction, self.module.get_interop_funcs())) + +class QirFunction: + """ + The QirFunction object represents a single function in the QIR program. It + is made up of one or more blocks that represent function execution flow. + + :param func: the function object from the underlying representation + :param type: PyQirFunction + """ + def __init__(self, func: PyQirFunction): + self.func = func + + @property + def name(self): + """ + Gets the string name for this function. + :return: the string name of the function + :rtype: str + """ + return self.func.name + + @property + def parameters(self): + """ + Gets the list of parameters used when calling this function. + :return: the list of parameters + :rtype: list[QirParameter] + """ + return list(map(QirParameter, self.func.parameters)) + + @property + def return_type(self): + """ + Gets the return type for this function. + :return: the type of the function + :rtype: QirType + """ + return QirType(self.func.return_type) + + @property + def blocks(self): + """ + Gets all the basic blocks for this function. + :return: a list of all basic blocks + :rtype: list[QirBlock] + """ + return list(map(QirBlock, self.func.blocks)) + + @property + def required_qubits(self): + """ + Gets the number of qubits needed to execute this function based on the + "RequiredQubits" attribute, or None if that attribute is not present. + :return: the number of qubits needed or None + :rtype: int or None + """ + return self.func.required_qubits + + @property + def required_results(self): + """ + Gets the number of result bits needed to execute this function based on the + "RequiredResults" attribute, or None if that attribute is not present. + :return: the number of results needed or None + :rtype: int or None + """ + return self.func.required_results + + def get_attribute_value(self, name: str): + """ + Gets the string value of the given attribute key name, or None if that attribute + is missing or has no defined value. + :param name: the name of the attribute to look for + :type name: str + :return: the value of the attribute or None + :rtype: str + """ + return self.func.get_attribute_value(name) + + def get_block_by_name(self, name: str): + """ + Gets the block with the given name, or None if no block with that name is found. + :param name: the name of the block to look for + :type name: str + :return: the QirBlock with that name or None + :rtype: QirBlock + """ + if (b := self.func.get_block_by_name(name)) is not None: + return QirBlock(b) + return None + + def get_instruction_by_output_name(self, name: str): + """ + Gets the instruction anywhere in the function where the variable with a given name + is set. Since LLVM requires any variable is defined by only one instruction, this is + guaranteed to be no more than one instruction. This will return None if no such instruction + can be found. + :param name: the name of the variable to search for + :type name: str + :return: the QirInstruction that defines that variable or None + :rtype: QirInstruction + """ + if (instr := self.func.get_instruction_by_output_name(name)) is not None: + return QirInstruction(instr) + return None + +class QirParameter: + """ + The QirParameter object describes a parameter in a function definition or declaration. It + includes a type and a name, where the name is used in the function body as a variable. + :param param: the the parameter object from the underlying representation + :type param: PyQirParameter + """ + def __init__(self, param: PyQirParameter): + self.param = param + + @property + def name(self): + """ + Gets the name of this parameter, used as the variable identifier within the body of the + function. + :return: the name of the parameter + :rtype: str + """ + return self.param.name + + @property + def type(self): + """ + Gets the type of this parameter as represented in the QIR. + :return: the QIR type for this parameter + :rtype: QirType + """ + return QirType(self.param.type) + +class QirBlock: + """ + The QirBlock object represents a basic block within a function body. Each basic block is + comprised of a list of instructions executed in sequence and single, special final instruction + called a terminator that indicates where execution should jump at the end of the block. + :param block: the basic block object from the underlying representation + :type block: PyQirBasicBlock + """ + def __init__(self, block: PyQirBasicBlock): + self.block = block + + @property + def name(self): + """ + Gets the identifying name for this block. This is unique within a given function and acts + as a label for any branches that transfer execution to this block. + :return: the name for this block + :rtype: str + """ + return self.block.name + + @property + def instructions(self): + """ + Gets the list of instructions that make up this block. The list is ordered; instructions are + executed from first to last unconditionally. This list does not include the special + terminator instruction (see QirBlock.terminator). + :return: the list of instructions for the block + :rtype: list[QirInstruction] + """ + return list(map(QirInstruction, self.block.instructions)) + + @property + def terminator(self): + """ + Gets the terminator instruction for this block. Every block has exactly one terminator + and it is the last intruction in the block. + :return: the terminator for this block + :rtype: QirTerminator + """ + return QirTerminator(self.block.terminator) + + @property + def phi_nodes(self): + """ + Gets any phi nodes defined for this block. Phi nodes are a special instruction that defines + variables based on which block transfered execution to this block. A block may have any number + of phi nodes, but they are always the first instructions in any given block. A block with no + phi nodes will return an empty list. + :return: the phi nodes, if any, for this block. + :rtype: list[QirInstruction] + """ + return list(map(QirInstruction, self.block.phi_nodes)) + + def get_phi_pairs_by_source_name(self, name: str): + """ + Gets the variable name, variable value pairs for any phi nodes in this block that correspond + to the given name. If the name doesn't match a block that can branch to this block or if + this block doesn't include any phi nodes, the list will be empty. + :return: the list of name-value pairs for the given source block name + :rtype: list[(str, QirOperand)] + """ + return list(map(lambda p: (p[0], QirOperand(p[1])) ,self.get_phi_pairs_by_source_name(name))) + +class QirInstruction: + def __new__(cls, instr: PyQirInstruction): + if instr.is_qis_call: + return super().__new__(QirQisCallInstr) + elif instr.is_qrt_call: + return super().__new__(QirQrtCallInstr) + elif instr.is_qir_call: + return super().__new__(QirQirCallInstr) + elif instr.is_call: + return super().__new__(QirCallInstr) + elif instr.is_add: + return super().__new__(QirAddInstr) + elif instr.is_sub: + return super().__new__(QirSubInstr) + elif instr.is_mul: + return super().__new__(QirMulInstr) + elif instr.is_udiv: + return super().__new__(QirUDivInstr) + elif instr.is_sdiv: + return super().__new__(QirSDivInstr) + elif instr.is_urem: + return super().__new__(QirURemInstr) + elif instr.is_srem: + return super().__new__(QirSRemInstr) + elif instr.is_and: + return super().__new__(QirAndInstr) + elif instr.is_or: + return super().__new__(QirOrInstr) + elif instr.is_xor: + return super().__new__(QirXorInstr) + elif instr.is_shl: + return super().__new__(QirShlInstr) + elif instr.is_lshr: + return super().__new__(QirLShrInstr) + elif instr.is_ashr: + return super().__new__(QirAShrInstr) + elif instr.is_fadd: + return super().__new__(QirFAddInstr) + elif instr.is_fsub: + return super().__new__(QirFSubInstr) + elif instr.is_fmul: + return super().__new__(QirFMulInstr) + elif instr.is_fdiv: + return super().__new__(QirFDivInstr) + elif instr.is_frem: + return super().__new__(QirFRemInstr) + elif instr.is_fneg: + return super().__new__(QirFNegInstr) + elif instr.is_icmp: + return super().__new__(QirICmpInstr) + elif instr.is_fcmp: + return super().__new__(QirFCmpInstr) + else: + return super().__new__(cls) + + def __init__(self, instr: PyQirInstruction): + self.instr = instr + + @property + def output_name(self): + return self.instr.output_name + +class QirOpInstr(QirInstruction): + @property + def target_operands(self): + return list(map(QirOperand, self.target_operands)) + +class QirAddInstr(QirOpInstr): + pass + +class QirSubInstr(QirOpInstr): + pass + +class QirMulInstr(QirOpInstr): + pass + +class QirUDivInstr(QirOpInstr): + pass + +class QirSDivInstr(QirOpInstr): + pass + +class QirURemInstr(QirOpInstr): + pass + +class QirSRemInstr(QirOpInstr): + pass + +class QirAndInstr(QirOpInstr): + pass + +class QirOrInstr(QirOpInstr): + pass + +class QirXorInstr(QirOpInstr): + pass + +class QirShlInstr(QirOpInstr): + pass + +class QirLShrInstr(QirOpInstr): + pass + +class QirAShrInstr(QirOpInstr): + pass + +class QirFAddInstr(QirOpInstr): + pass + +class QirFSubInstr(QirOpInstr): + pass + +class QirFMulInstr(QirOpInstr): + pass + +class QirFDivInstr(QirOpInstr): + pass + +class QirFRemInstr(QirOpInstr): + pass + +class QirFNegInstr(QirOpInstr): + pass + +class QirICmpInstr(QirOpInstr): + pass + +class QirFCmpInstr(QirOpInstr): + pass + +class QirPhiInstr(QirInstruction): + @property + def incoming_values(self): + return list(map(lambda p: (QirOperand(p[0]), p[1]), self.instr.phi_incoming_values)) + + def get_incoming_values_for_name(self, name: str): + return list(map(QirOperand, self.instr.get_phi_incoming_values_for_name(name))) + +class QirCallInstr(QirInstruction): + @property + def func_name(self): + return self.instr.call_func_name + + @property + def func_args(self): + return list(map(QirOperand, self.instr.call_func_params)) + +class QirQisCallInstr(QirCallInstr): + pass + +class QirQrtCallInstr(QirCallInstr): + pass + +class QirQirCallInstr(QirCallInstr): + pass + +class QirTerminator: + def __new__(cls, term: PyQirTerminator): + if term.is_ret: + return super().__new__(QirRetTerminator) + elif term.is_br: + return super().__new__(QirBrTerminator) + elif term.is_condbr: + return super().__new__(QirCondBrTerminator) + elif term.is_switch: + return super().__new__(QirSwitchTerminator) + elif term.is_unreachable: + return super().__new__(QirUnreachableTerminator) + else: + return super().__new__(cls) + + def __init__(self, term: PyQirTerminator) -> None: + self.term = term + +class QirRetTerminator(QirTerminator): + @property + def operand(self): + return QirOperand(self.term.ret_operand) + +class QirBrTerminator(QirTerminator): + @property + def dest(self): + return self.term.br_dest + +class QirCondBrTerminator(QirTerminator): + @property + def condition(self): + return QirOperand(self.term.condbr_condition) + + @property + def true_dest(self): + return self.term.condbr_true_dest + + @property + def false_dest(self): + return self.term.condbr_false_dest + +class QirSwitchTerminator(QirTerminator): + pass + +class QirUnreachableTerminator(QirTerminator): + pass + +class QirOperand: + def __new__(cls, op: PyQirOperand): + if op.is_local: + return super().__new__(QirLocalOperand) + elif op.is_constant: + return QirConstant(op.constant) + else: + return super().__new__(cls) + + def __init__(self, op: PyQirOperand): + self.op = op + +class QirLocalOperand(QirOperand): + @property + def name(self): + return self.op.local_name + + @property + def type(self): + return QirType(self.op.local_type) + +class QirConstant: + def __new__(cls, const: PyQirConstant): + if const.is_qubit: + return super().__new__(QirQubitConstant) + elif const.is_result: + return super().__new__(QirResultConstant) + elif const.is_int: + return super().__new__(QirIntConstant) + elif const.is_float: + return super().__new__(QirDoubleConstant) + elif const.is_null: + return super().__new__(QirNullConstant) + else: + return super().__new__(cls) + + def __init__(self, const: PyQirConstant): + self.const = const + +class QirIntConstant(QirConstant): + @property + def value(self): + return self.const.int_value + + @property + def width(self): + return self.const.int_width + +class QirDoubleConstant(QirConstant): + @property + def value(self): + return self.const.float_double_value + +class QirNullConstant(QirConstant): + pass + +class QirQubitConstant(QirConstant): + @property + def id(self): + return self.const.qubit_static_id + +class QirResultConstant(QirConstant): + @property + def id(self): + return self.const.result_static_id + +class QirType: + def __new__(cls, ty: PyQirType): + if ty.is_qubit: + return super().__new__(QirQubitType) + elif ty.is_result: + return super().__new__(QirResultType) + elif ty.is_void: + return super().__new__(QirVoidType) + elif ty.is_integer: + return super().__new__(QirIntegerType) + elif ty.is_pointer: + return super().__new__(QirPointerType) + elif ty.is_double: + return super().__new__(QirDoubleType) + elif ty.is_array: + return super().__new__(QirArrayType) + elif ty.is_struct: + return super().__new__(QirStructType) + elif ty.is_named_struct: + return super().__new__(QirNamedStruct) + else: + return super().__new__(cls) + + def __init__(self, ty: PyQirType): + self.ty = ty + +class QirVoidType(QirType): + pass + +class QirIntegerType(QirType): + @property + def width(self): + return self.ty.integer_width + +class QirPointerType(QirType): + @property + def type(self): + return QirType(self.ty.pointer_type) + + @property + def addrspace(self): + return self.ty.pointer_addrspace + +class QirDoubleType(QirType): + pass + +class QirArrayType(QirType): + @property + def element_types(self): + return list(map(QirType, self.ty.array_element_type)) + + @property + def element_count(self): + return self.ty.array_num_elements + +class QirStructType(QirType): + @property + def struct_element_types(self): + return list(map(QirType, self.ty.struct_element_types)) + +class QirNamedStruct(QirType): + @property + def name(self): + return self.ty.named_struct_name + +class QirQubitType(QirPointerType): + pass + +class QirResultType(QirPointerType): + pass diff --git a/src/QirTools/pyqir/src/parser.rs b/src/QirTools/pyqir/src/parser.rs index 39972e95a6..bdc115075a 100644 --- a/src/QirTools/pyqir/src/parser.rs +++ b/src/QirTools/pyqir/src/parser.rs @@ -16,53 +16,53 @@ use qirlib::parse::*; use std::convert::TryFrom; #[pyclass] -pub struct QirModule { +pub struct PyQirModule { pub(super) module: llvm_ir::Module, } #[pyclass] -pub struct QirFunction { +pub struct PyQirFunction { pub(super) function: llvm_ir::Function, pub(super) types: llvm_ir::types::Types, } #[pyclass] -pub struct QirParameter { +pub struct PyQirParameter { pub(super) param: llvm_ir::function::Parameter, } #[pyclass] -pub struct QirBasicBlock { +pub struct PyQirBasicBlock { pub(super) block: llvm_ir::BasicBlock, pub(super) types: llvm_ir::types::Types, } #[pyclass] -pub struct QirInstruction { +pub struct PyQirInstruction { pub(super) instr: llvm_ir::instruction::Instruction, pub(super) types: llvm_ir::types::Types, } #[pyclass] -pub struct QirTerminator { +pub struct PyQirTerminator { pub(super) term: llvm_ir::terminator::Terminator, pub(super) types: llvm_ir::types::Types, } #[pyclass] -pub struct QirOperand { +pub struct PyQirOperand { pub(super) op: llvm_ir::Operand, pub(super) types: llvm_ir::types::Types, } #[pyclass] -pub struct QirConstant { +pub struct PyQirConstant { pub(super) constantref: llvm_ir::ConstantRef, pub(super) types: llvm_ir::types::Types, } #[pyclass] -pub struct QirType { +pub struct PyQirType { pub(super) typeref: llvm_ir::TypeRef, } @@ -76,22 +76,22 @@ macro_rules! match_contents { } #[pymethods] -impl QirModule { +impl PyQirModule { #[getter] - fn get_functions(&self) -> Vec { + fn get_functions(&self) -> Vec { self.module .functions .iter() - .map(|f| QirFunction { + .map(|f| PyQirFunction { function: f.clone(), types: self.module.types.clone(), }) .collect() } - fn get_func_by_name(&self, name: String) -> Option { + fn get_func_by_name(&self, name: String) -> Option { match self.module.get_func_by_name(&name) { - Some(f) => Some(QirFunction { + Some(f) => Some(PyQirFunction { function: f.clone(), types: self.module.types.clone(), }), @@ -99,33 +99,33 @@ impl QirModule { } } - fn get_funcs_by_attr(&self, attr: String) -> Vec { + fn get_funcs_by_attr(&self, attr: String) -> Vec { self.module .get_func_by_attr_name(&attr) .iter() - .map(|f| QirFunction { + .map(|f| PyQirFunction { function: (*f).clone(), types: self.module.types.clone(), }) .collect() } - fn get_entrypoint_funcs(&self) -> Vec { + fn get_entrypoint_funcs(&self) -> Vec { self.module .get_entrypoint_funcs() .iter() - .map(|f| QirFunction { + .map(|f| PyQirFunction { function: (*f).clone(), types: self.module.types.clone(), }) .collect() } - fn get_interop_funcs(&self) -> Vec { + fn get_interop_funcs(&self) -> Vec { self.module .get_interop_funcs() .iter() - .map(|f| QirFunction { + .map(|f| PyQirFunction { function: (*f).clone(), types: self.module.types.clone(), }) @@ -134,34 +134,34 @@ impl QirModule { } #[pymethods] -impl QirFunction { +impl PyQirFunction { #[getter] fn get_name(&self) -> String { self.function.name.clone() } #[getter] - fn get_parameters(&self) -> Vec { + fn get_parameters(&self) -> Vec { self.function .parameters .iter() - .map(|p| QirParameter { param: p.clone() }) + .map(|p| PyQirParameter { param: p.clone() }) .collect() } #[getter] - fn get_return_type(&self) -> QirType { - QirType { + fn get_return_type(&self) -> PyQirType { + PyQirType { typeref: self.function.return_type.clone(), } } #[getter] - fn get_blocks(&self) -> Vec { + fn get_blocks(&self) -> Vec { self.function .basic_blocks .iter() - .map(|b| QirBasicBlock { + .map(|b| PyQirBasicBlock { block: b.clone(), types: self.types.clone(), }) @@ -182,8 +182,8 @@ impl QirFunction { self.function.get_attribute_value(&attr_name) } - fn get_block_by_name(&self, name: String) -> Option { - Some(QirBasicBlock { + fn get_block_by_name(&self, name: String) -> Option { + Some(PyQirBasicBlock { block: self .function .get_bb_by_name(&llvm_ir::Name::from(name.clone()))? @@ -192,8 +192,8 @@ impl QirFunction { }) } - fn get_instruction_by_output_name(&self, name: String) -> Option { - Some(QirInstruction { + fn get_instruction_by_output_name(&self, name: String) -> Option { + Some(PyQirInstruction { instr: self.function.get_instruction_by_output_name(&name)?.clone(), types: self.types.clone(), }) @@ -201,33 +201,33 @@ impl QirFunction { } #[pymethods] -impl QirParameter { +impl PyQirParameter { #[getter] fn get_name(&self) -> String { self.param.name.get_string() } #[getter] - fn get_type(&self) -> QirType { - QirType { + fn get_type(&self) -> PyQirType { + PyQirType { typeref: self.param.ty.clone(), } } } #[pymethods] -impl QirBasicBlock { +impl PyQirBasicBlock { #[getter] fn get_name(&self) -> String { self.block.name.get_string() } #[getter] - fn get_instructions(&self) -> Vec { + fn get_instructions(&self) -> Vec { self.block .instrs .iter() - .map(|i| QirInstruction { + .map(|i| PyQirInstruction { instr: i.clone(), types: self.types.clone(), }) @@ -235,25 +235,25 @@ impl QirBasicBlock { } #[getter] - fn get_phi_nodes(&self) -> Vec { + fn get_phi_nodes(&self) -> Vec { self.block .get_phi_nodes() .iter() - .map(|phi| QirInstruction { + .map(|phi| PyQirInstruction { instr: llvm_ir::Instruction::from(phi.clone()), types: self.types.clone(), }) .collect() } - fn get_phi_pairs_by_source_name(&self, name: String) -> Vec<(String, QirOperand)> { + fn get_phi_pairs_by_source_name(&self, name: String) -> Vec<(String, PyQirOperand)> { self.block .get_phi_pairs_by_source_name(&name) .iter() .map(|(n, op)| { ( n.get_string(), - QirOperand { + PyQirOperand { op: op.clone(), types: self.types.clone(), }, @@ -263,8 +263,8 @@ impl QirBasicBlock { } #[getter] - fn get_terminator(&self) -> QirTerminator { - QirTerminator { + fn get_terminator(&self) -> PyQirTerminator { + PyQirTerminator { term: self.block.term.clone(), types: self.types.clone(), } @@ -272,13 +272,13 @@ impl QirBasicBlock { } #[pymethods] -impl QirInstruction { +impl PyQirInstruction { #[getter] - fn get_target_operands(&self) -> Vec { + fn get_target_operands(&self) -> Vec { self.instr .get_target_operands() .iter() - .map(|op| QirOperand { + .map(|op| PyQirOperand { op: op.clone(), types: self.types.clone(), }) @@ -506,7 +506,7 @@ impl QirInstruction { } #[getter] - fn get_phi_incoming_values(&self) -> Option> { + fn get_phi_incoming_values(&self) -> Option> { Some( llvm_ir::instruction::Phi::try_from(self.instr.clone()) .ok()? @@ -514,7 +514,7 @@ impl QirInstruction { .iter() .map(|(op, name)| { ( - QirOperand { + PyQirOperand { op: op.clone(), types: self.types.clone(), }, @@ -525,8 +525,8 @@ impl QirInstruction { ) } - fn get_phi_incoming_value_for_name(&self, name: String) -> Option { - Some(QirOperand { + fn get_phi_incoming_value_for_name(&self, name: String) -> Option { + Some(PyQirOperand { op: llvm_ir::instruction::Phi::try_from(self.instr.clone()) .ok()? .get_incoming_value_for_name(&name)?, @@ -555,13 +555,13 @@ impl QirInstruction { } #[getter] - fn get_call_func_params(&self) -> Option> { + fn get_call_func_params(&self) -> Option> { Some( llvm_ir::instruction::Call::try_from(self.instr.clone()) .ok()? .arguments .iter() - .map(|o| QirOperand { + .map(|o| PyQirOperand { op: o.0.clone(), types: self.types.clone(), }) @@ -599,21 +599,21 @@ impl QirInstruction { } #[pymethods] -impl QirTerminator { +impl PyQirTerminator { #[getter] fn get_is_ret(&self) -> bool { matches!(self.term, llvm_ir::Terminator::Ret(_)) } #[getter] - fn get_ret_operand(&self) -> Option { + fn get_ret_operand(&self) -> Option { match_contents!( &self.term, llvm_ir::Terminator::Ret(llvm_ir::terminator::Ret { return_operand, debugloc: _, }), - QirOperand { + PyQirOperand { op: return_operand.as_ref()?.clone(), types: self.types.clone(), } @@ -640,7 +640,7 @@ impl QirTerminator { } #[getter] - fn get_condbr_condition(&self) -> Option { + fn get_condbr_condition(&self) -> Option { match_contents!( &self.term, llvm_ir::Terminator::CondBr(llvm_ir::terminator::CondBr { @@ -649,7 +649,7 @@ impl QirTerminator { false_dest: _, debugloc: _, }), - QirOperand { + PyQirOperand { op: condition.clone(), types: self.types.clone(), } @@ -696,7 +696,7 @@ impl QirTerminator { } #[pymethods] -impl QirOperand { +impl PyQirOperand { #[getter] fn get_is_local(&self) -> bool { matches!(self.op, llvm_ir::Operand::LocalOperand { name: _, ty: _ }) @@ -712,11 +712,11 @@ impl QirOperand { } #[getter] - fn get_local_type(&self) -> Option { + fn get_local_type(&self) -> Option { match_contents!( &self.op, llvm_ir::Operand::LocalOperand { name: _, ty }, - QirType { + PyQirType { typeref: ty.clone(), } ) @@ -728,11 +728,11 @@ impl QirOperand { } #[getter] - fn get_constant(&self) -> Option { + fn get_constant(&self) -> Option { match_contents!( &self.op, llvm_ir::Operand::ConstantOperand(cref), - QirConstant { + PyQirConstant { constantref: cref.clone(), types: self.types.clone(), } @@ -741,7 +741,7 @@ impl QirOperand { } #[pymethods] -impl QirConstant { +impl PyQirConstant { #[getter] fn get_is_int(&self) -> bool { matches!( @@ -825,8 +825,8 @@ impl QirConstant { } #[getter] - fn get_type(&self) -> QirType { - QirType { + fn get_type(&self) -> PyQirType { + PyQirType { typeref: self.constantref.get_type(&self.types), } } @@ -853,7 +853,7 @@ impl QirConstant { } #[pymethods] -impl QirType { +impl PyQirType { #[getter] fn get_is_void(&self) -> bool { matches!(self.typeref.as_ref(), llvm_ir::Type::VoidType) @@ -888,14 +888,14 @@ impl QirType { } #[getter] - fn get_pointer_type(&self) -> Option { + fn get_pointer_type(&self) -> Option { match_contents!( self.typeref.as_ref(), llvm_ir::Type::PointerType { pointee_type, addr_space: _ }, - QirType { + PyQirType { typeref: pointee_type.clone() } ) @@ -933,14 +933,14 @@ impl QirType { } #[getter] - fn get_array_element_type(&self) -> Option { + fn get_array_element_type(&self) -> Option { match_contents!( self.typeref.as_ref(), llvm_ir::Type::ArrayType { element_type, num_elements: _, }, - QirType { + PyQirType { typeref: element_type.clone() } ) @@ -970,7 +970,7 @@ impl QirType { } #[getter] - fn get_struct_element_types(&self) -> Option> { + fn get_struct_element_types(&self) -> Option> { match_contents!( self.typeref.as_ref(), llvm_ir::Type::StructType { @@ -979,7 +979,7 @@ impl QirType { }, element_types .iter() - .map(|t| QirType { typeref: t.clone() }) + .map(|t| PyQirType { typeref: t.clone() }) .collect() ) } diff --git a/src/QirTools/pyqir/src/python.rs b/src/QirTools/pyqir/src/python.rs index 458e0d1733..d230ccb41b 100644 --- a/src/QirTools/pyqir/src/python.rs +++ b/src/QirTools/pyqir/src/python.rs @@ -10,17 +10,26 @@ use qirlib::interop::{ Single, }; -use crate::parser::QirModule; +use crate::parser::*; #[pymodule] fn pyqir(_py: Python<'_>, m: &PyModule) -> PyResult<()> { m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; #[pyfn(m)] #[pyo3(name = "module_from_bitcode")] - fn module_from_bitcode_py(_py: Python, bc_path: String) -> PyResult { + fn module_from_bitcode_py(_py: Python, bc_path: String) -> PyResult { match llvm_ir::Module::from_bc_path(&bc_path) { - Ok(m) => Ok(QirModule { module: m }), + Ok(m) => Ok(PyQirModule { module: m }), Err(s) => Err(PyRuntimeError::new_err(s)), } } diff --git a/src/QirTools/pyqir/tests/test_api.py b/src/QirTools/pyqir/tests/test_api.py index 725fb8893f..36935de5c1 100644 --- a/src/QirTools/pyqir/tests/test_api.py +++ b/src/QirTools/pyqir/tests/test_api.py @@ -1,4 +1,4 @@ -from pyqir import QirBuilder +from pyqir import * from pyqir import module_from_bitcode import pytest @@ -129,6 +129,43 @@ def test_bernstein_vazirani_ir_string(): ir = builder.get_ir_string() assert ir.startswith("; ModuleID = 'Bernstein-Vazirani'") +def test_parser_pythonic(): + mod = QirModule("tests/teleportchain.baseprofile.bc") + func_name = "TeleportChain__DemonstrateTeleportationUsingPresharedEntanglement__Interop" + func = mod.get_func_by_name(func_name) + assert(func.name == func_name) + func_list = mod.functions + assert(len(func_list) == 1) + assert(func_list[0].name == func_name) + interop_funcs = mod.get_funcs_by_attr("InteropFriendly") + assert(len(interop_funcs) == 1) + assert(len(mod.interop_funcs) == 1) + assert(mod.interop_funcs[0].name == interop_funcs[0].name) + assert(len(mod.entrypoint_funcs) == 0) + blocks = func.blocks + assert(len(blocks) == 9) + assert(blocks[0].name == "entry") + term = blocks[0].terminator + assert(isinstance(term, QirTerminator)) + assert(isinstance(term, QirCondBrTerminator)) + assert(term.true_dest == "then0__1.i.i.i") + assert(term.false_dest == "continue__1.i.i.i") + assert(term.condition.name == "0") + assert(blocks[1].terminator.dest == "continue__1.i.i.i") + assert(blocks[8].terminator.operand.type.width == 8) + block = func.get_block_by_name("then0__2.i.i3.i") + assert(isinstance(block.instructions[0], QirQisCallInstr)) + assert(isinstance(block.instructions[0].func_args[0], QirQubitConstant)) + assert(block.instructions[0].func_args[0].id == 5) + block = func.get_block_by_name("continue__1.i.i2.i") + var_name = block.terminator.condition.name + instr = func.get_instruction_by_output_name(var_name) + assert(isinstance(instr, QirQirCallInstr)) + assert(instr.output_name == var_name) + assert(instr.func_name == "__quantum__qir__read_result") + assert(instr.func_args[0].id == 3) + + def test_parser(): mod = module_from_bitcode("tests/teleportchain.baseprofile.bc") funcName = "TeleportChain__DemonstrateTeleportationUsingPresharedEntanglement__Interop" From c3fa99fde7eaa10d009851ca0aa10694833f210c Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Mon, 18 Oct 2021 21:27:41 -0700 Subject: [PATCH 14/26] fix test variable names --- src/QirTools/pyqir/tests/test_api.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/QirTools/pyqir/tests/test_api.py b/src/QirTools/pyqir/tests/test_api.py index 36935de5c1..e96b7a8773 100644 --- a/src/QirTools/pyqir/tests/test_api.py +++ b/src/QirTools/pyqir/tests/test_api.py @@ -168,17 +168,17 @@ def test_parser_pythonic(): def test_parser(): mod = module_from_bitcode("tests/teleportchain.baseprofile.bc") - funcName = "TeleportChain__DemonstrateTeleportationUsingPresharedEntanglement__Interop" - func = mod.get_func_by_name(funcName) - assert(func.name == funcName) + func_name = "TeleportChain__DemonstrateTeleportationUsingPresharedEntanglement__Interop" + func = mod.get_func_by_name(func_name) + assert(func.name == func_name) assert(len(func.parameters) == 0) assert(func.return_type.is_integer) - funcList = mod.functions - assert(len(funcList) == 1) - assert(funcList[0].name == funcName) + func_list = mod.functions + assert(len(func_list) == 1) + assert(func_list[0].name == func_name) interop_funcs = mod.get_funcs_by_attr("InteropFriendly") assert(len(interop_funcs) == 1) - assert(interop_funcs[0].name == funcName) + assert(interop_funcs[0].name == func_name) assert(interop_funcs[0].get_attribute_value("requiredQubits") == "6") assert(interop_funcs[0].required_qubits == 6) blocks = func.blocks @@ -197,11 +197,11 @@ def test_parser(): assert(entry_block.instructions[0].is_call) assert(entry_block.instructions[0].call_func_name == "__quantum__qis__h__body") assert(entry_block.instructions[0].is_qis_call) - paramList = entry_block.instructions[0].call_func_params - assert(len(paramList) == 1) - assert(paramList[0].is_constant) - assert(paramList[0].constant.is_qubit) - assert(paramList[0].constant.qubit_static_id == 0) + param_list = entry_block.instructions[0].call_func_params + assert(len(param_list) == 1) + assert(param_list[0].is_constant) + assert(param_list[0].constant.is_qubit) + assert(param_list[0].constant.qubit_static_id == 0) assert(entry_block.instructions[8].is_qis_call) assert(entry_block.instructions[8].call_func_name == "__quantum__qis__mz__body") assert(entry_block.instructions[8].call_func_params[0].constant.qubit_static_id == 1) From 5530f876973d02d2d132e83d31c59cd0baa92dcb Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Mon, 18 Oct 2021 21:54:06 -0700 Subject: [PATCH 15/26] Add type getter for QirInstruction --- src/QirTools/pyqir/pyqir/__init__.py | 9 +++++++++ src/QirTools/pyqir/src/parser.rs | 7 +++++++ src/QirTools/pyqir/tests/test_api.py | 2 ++ 3 files changed, 18 insertions(+) diff --git a/src/QirTools/pyqir/pyqir/__init__.py b/src/QirTools/pyqir/pyqir/__init__.py index 18fbf7ddaa..a5f45dd486 100644 --- a/src/QirTools/pyqir/pyqir/__init__.py +++ b/src/QirTools/pyqir/pyqir/__init__.py @@ -578,6 +578,11 @@ def __init__(self, instr: PyQirInstruction): def output_name(self): return self.instr.output_name + @property + def type(self): + return QirType(self.instr.type) + + class QirOpInstr(QirInstruction): @property def target_operands(self): @@ -758,6 +763,10 @@ def __new__(cls, const: PyQirConstant): def __init__(self, const: PyQirConstant): self.const = const + @property + def type(self): + return QirType(self.const.type) + class QirIntConstant(QirConstant): @property def value(self): diff --git a/src/QirTools/pyqir/src/parser.rs b/src/QirTools/pyqir/src/parser.rs index bdc115075a..1cad1c1a13 100644 --- a/src/QirTools/pyqir/src/parser.rs +++ b/src/QirTools/pyqir/src/parser.rs @@ -285,6 +285,13 @@ impl PyQirInstruction { .collect() } + #[getter] + fn get_type(&self) -> Option { + Some(PyQirType { + typeref: self.instr.get_type(&self.types), + }) + } + #[getter] fn get_is_add(&self) -> bool { matches!(self.instr, llvm_ir::Instruction::Add(_)) diff --git a/src/QirTools/pyqir/tests/test_api.py b/src/QirTools/pyqir/tests/test_api.py index e96b7a8773..77228915f2 100644 --- a/src/QirTools/pyqir/tests/test_api.py +++ b/src/QirTools/pyqir/tests/test_api.py @@ -164,6 +164,8 @@ def test_parser_pythonic(): assert(instr.output_name == var_name) assert(instr.func_name == "__quantum__qir__read_result") assert(instr.func_args[0].id == 3) + assert(isinstance(instr.type, QirIntegerType)) + assert(instr.type.width == 1) def test_parser(): From 8103815c18de4ad522a5dba731cfbf5bc1f55620 Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Mon, 18 Oct 2021 22:22:12 -0700 Subject: [PATCH 16/26] Fix "is not None" pattern --- src/QirTools/pyqir/bell_measure.ll | 502 +++++++++++++++++++ src/QirTools/pyqir/bell_no_measure.ll | 474 ++++++++++++++++++ src/QirTools/pyqir/bernstein_vazirani.ll | 569 ++++++++++++++++++++++ src/QirTools/pyqir/build.ps1 | 4 +- src/QirTools/pyqir/pyqir/__init__.py | 7 +- src/QirTools/pyqir/pytest.ll | 582 +++++++++++++++++++++++ 6 files changed, 2133 insertions(+), 5 deletions(-) create mode 100644 src/QirTools/pyqir/bell_measure.ll create mode 100644 src/QirTools/pyqir/bell_no_measure.ll create mode 100644 src/QirTools/pyqir/bernstein_vazirani.ll create mode 100644 src/QirTools/pyqir/pytest.ll diff --git a/src/QirTools/pyqir/bell_measure.ll b/src/QirTools/pyqir/bell_measure.ll new file mode 100644 index 0000000000..002e6be9e4 --- /dev/null +++ b/src/QirTools/pyqir/bell_measure.ll @@ -0,0 +1,502 @@ +; ModuleID = 'Bell circuit' +source_filename = "C:\\Users\\iadavis\\dev\\qsharp-compiler\\src\\QirTools\\pyqir\\qirlib\\src\\emit\\qir\\module.ll" + +%Range = type { i64, i64, i64 } +%Array = type opaque +%Qubit = type opaque +%Result = type opaque +%String = type opaque + +@PauliI = internal constant i2 0 +@PauliX = internal constant i2 1 +@PauliY = internal constant i2 -1 +@PauliZ = internal constant i2 -2 +@EmptyRange = internal constant %Range { i64 0, i64 1, i64 -1 } +@0 = internal constant [3 x i8] c", \00" +@1 = internal constant [2 x i8] c"[\00" +@2 = internal constant [3 x i8] c", \00" +@3 = internal constant [2 x i8] c"[\00" +@4 = internal constant [2 x i8] c"]\00" +@5 = internal constant [2 x i8] c"]\00" + +define internal %Array* @QuantumApplication__Run__body() { +entry: + %qr0 = call %Qubit* @__quantum__rt__qubit_allocate() + %qr1 = call %Qubit* @__quantum__rt__qubit_allocate() + %results = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) + %qc = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 2) + %qc_0_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qc, i64 0) + %qc_result_0 = bitcast i8* %qc_0_raw to %Result** + %zero_0 = call %Result* @__quantum__rt__result_get_zero() + call void @__quantum__rt__result_update_reference_count(%Result* %zero_0, i32 1) + store %Result* %zero_0, %Result** %qc_result_0, align 8 + %qc_1_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qc, i64 1) + %qc_result_1 = bitcast i8* %qc_1_raw to %Result** + %zero_1 = call %Result* @__quantum__rt__result_get_zero() + call void @__quantum__rt__result_update_reference_count(%Result* %zero_1, i32 1) + store %Result* %zero_1, %Result** %qc_result_1, align 8 + %results_result_tmp_0_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %results, i64 0) + %results_result_tmp_result_0 = bitcast i8* %results_result_tmp_0_raw to %Array** + store %Array* %qc, %Array** %results_result_tmp_result_0, align 8 + call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %qr0) + %__controlQubits__ = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) + %__controlQubits__0_result_tmp_0_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %__controlQubits__, i64 0) + %__controlQubits__0_result_tmp_result_0 = bitcast i8* %__controlQubits__0_result_tmp_0_raw to %Qubit** + store %Qubit* %qr0, %Qubit** %__controlQubits__0_result_tmp_result_0, align 8 + call void @Microsoft__Quantum__Intrinsic__X__ctl(%Array* %__controlQubits__, %Qubit* %qr1) + call void @__quantum__rt__array_update_reference_count(%Array* %__controlQubits__, i32 -1) + %measurement = call %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %qr0) + %qc0_0_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qc, i64 0) + %qc0_result_0 = bitcast i8* %qc0_0_raw to %Result** + %existing_value = load %Result*, %Result** %qc0_result_0, align 8 + call void @__quantum__rt__result_update_reference_count(%Result* %existing_value, i32 -1) + call void @__quantum__rt__result_update_reference_count(%Result* %measurement, i32 1) + store %Result* %measurement, %Result** %qc0_result_0, align 8 + %measurement1 = call %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %qr1) + %qc1_1_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qc, i64 1) + %qc1_result_1 = bitcast i8* %qc1_1_raw to %Result** + %existing_value2 = load %Result*, %Result** %qc1_result_1, align 8 + call void @__quantum__rt__result_update_reference_count(%Result* %existing_value2, i32 -1) + call void @__quantum__rt__result_update_reference_count(%Result* %measurement1, i32 1) + store %Result* %measurement1, %Result** %qc1_result_1, align 8 + call void @__quantum__rt__qubit_release(%Qubit* %qr0) + call void @__quantum__rt__qubit_release(%Qubit* %qr1) + ret %Array* %results +} + +declare %Qubit* @__quantum__rt__qubit_allocate() + +declare void @__quantum__rt__qubit_release(%Qubit*) + +declare %Array* @__quantum__rt__array_create_1d(i32, i64) + +declare i8* @__quantum__rt__array_get_element_ptr_1d(%Array*, i64) + +declare %Result* @__quantum__rt__result_get_zero() + +declare void @__quantum__rt__result_update_reference_count(%Result*, i32) + +declare void @__quantum__rt__array_update_alias_count(%Array*, i32) + +declare i64 @__quantum__rt__array_get_size_1d(%Array*) + +declare void @__quantum__rt__array_update_reference_count(%Array*, i32) + +declare void @__quantum__qis__x__body(%Qubit*) + +declare void @__quantum__qis__x__ctl(%Array*, %Qubit*) + +declare void @__quantum__qis__y__body(%Qubit*) + +declare void @__quantum__qis__z__body(%Qubit*) + +declare void @__quantum__qis__z__ctl(%Array*, %Qubit*) + +declare void @__quantum__qis__h__body(%Qubit*) + +define internal %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %qubit) { +entry: + %bases = call %Array* @__quantum__rt__array_create_1d(i32 1, i64 1) + %0 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %bases, i64 0) + %1 = bitcast i8* %0 to i2* + %2 = load i2, i2* @PauliZ, align 1 + store i2 %2, i2* %1, align 1 + call void @__quantum__rt__array_update_alias_count(%Array* %bases, i32 1) + %qubits = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) + %3 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qubits, i64 0) + %4 = bitcast i8* %3 to %Qubit** + store %Qubit* %qubit, %Qubit** %4, align 8 + call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i32 1) + %5 = call %Result* @__quantum__qis__measure__body(%Array* %bases, %Array* %qubits) + call void @__quantum__rt__array_update_alias_count(%Array* %bases, i32 -1) + call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i32 -1) + call void @__quantum__rt__array_update_reference_count(%Array* %bases, i32 -1) + call void @__quantum__rt__array_update_reference_count(%Array* %qubits, i32 -1) + ret %Result* %5 +} + +define internal void @Microsoft__Quantum__Intrinsic__Reset__body(%Qubit* %qubit) { +entry: + %0 = call %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %qubit) + %1 = call %Result* @__quantum__rt__result_get_one() + %2 = call i1 @__quantum__rt__result_equal(%Result* %0, %Result* %1) + call void @__quantum__rt__result_update_reference_count(%Result* %0, i32 -1) + br i1 %2, label %then0__1, label %continue__1 + +then0__1: ; preds = %entry + call void @__quantum__qis__x__body(%Qubit* %qubit) + br label %continue__1 + +continue__1: ; preds = %then0__1, %entry + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Rx__body(double %theta, %Qubit* %qubit) { +entry: + %pauli = load i2, i2* @PauliX, align 1 + call void @__quantum__qis__r__body(i2 %pauli, double %theta, %Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Ry__body(double %theta, %Qubit* %qubit) { +entry: + %pauli = load i2, i2* @PauliY, align 1 + call void @__quantum__qis__r__body(i2 %pauli, double %theta, %Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Rz__body(double %theta, %Qubit* %qubit) { +entry: + %pauli = load i2, i2* @PauliZ, align 1 + call void @__quantum__qis__r__body(i2 %pauli, double %theta, %Qubit* %qubit) + ret void +} + +declare void @__quantum__qis__s__body(%Qubit*) + +declare void @__quantum__qis__s__adj(%Qubit*) + +declare void @__quantum__qis__t__body(%Qubit*) + +declare void @__quantum__qis__t__adj(%Qubit*) + +define internal void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %qubit) { +entry: + call void @__quantum__qis__h__body(%Qubit* %qubit) + ret void +} + +declare %Result* @__quantum__qis__measure__body(%Array*, %Array*) + +declare void @__quantum__qis__r__body(i2, double, %Qubit*) + +declare %Result* @__quantum__rt__result_get_one() + +declare i1 @__quantum__rt__result_equal(%Result*, %Result*) + +define internal void @Microsoft__Quantum__Intrinsic__S__body(%Qubit* %qubit) { +entry: + call void @__quantum__qis__s__body(%Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__S__adj(%Qubit* %qubit) { +entry: + call void @__quantum__qis__s__adj(%Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__T__body(%Qubit* %qubit) { +entry: + call void @__quantum__qis__t__body(%Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__T__adj(%Qubit* %qubit) { +entry: + call void @__quantum__qis__t__adj(%Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__X__body(%Qubit* %qubit) { +entry: + call void @__quantum__qis__x__body(%Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__X__ctl(%Array* %__controlQubits__, %Qubit* %qubit) { +entry: + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 1) + call void @__quantum__qis__x__ctl(%Array* %__controlQubits__, %Qubit* %qubit) + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 -1) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Y__body(%Qubit* %qubit) { +entry: + call void @__quantum__qis__y__body(%Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Z__body(%Qubit* %qubit) { +entry: + call void @__quantum__qis__z__body(%Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Z__ctl(%Array* %__controlQubits__, %Qubit* %qubit) { +entry: + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 1) + call void @__quantum__qis__z__ctl(%Array* %__controlQubits__, %Qubit* %qubit) + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 -1) + ret void +} + +define { i64, i8* }* @QuantumApplication__Run__Interop() #0 { +entry: + %0 = call %Array* @QuantumApplication__Run__body() + %1 = call i64 @__quantum__rt__array_get_size_1d(%Array* %0) + %2 = mul i64 %1, 8 + %3 = call i8* @__quantum__rt__memory_allocate(i64 %2) + %4 = ptrtoint i8* %3 to i64 + %5 = sub i64 %1, 1 + br label %header__1 + +header__1: ; preds = %exiting__1, %entry + %6 = phi i64 [ 0, %entry ], [ %19, %exiting__1 ] + %7 = icmp sle i64 %6, %5 + br i1 %7, label %body__1, label %exit__1 + +body__1: ; preds = %header__1 + %8 = mul i64 %6, 8 + %9 = add i64 %4, %8 + %10 = inttoptr i64 %9 to { i64, i8* }** + %11 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %0, i64 %6) + %12 = bitcast i8* %11 to %Array** + %13 = load %Array*, %Array** %12, align 8 + %14 = call i64 @__quantum__rt__array_get_size_1d(%Array* %13) + %15 = mul i64 %14, 1 + %16 = call i8* @__quantum__rt__memory_allocate(i64 %15) + %17 = ptrtoint i8* %16 to i64 + %18 = sub i64 %14, 1 + br label %header__2 + +exiting__1: ; preds = %exit__2 + %19 = add i64 %6, 1 + br label %header__1 + +exit__1: ; preds = %header__1 + %20 = call i8* @__quantum__rt__memory_allocate(i64 ptrtoint ({ i64, i8* }* getelementptr ({ i64, i8* }, { i64, i8* }* null, i32 1) to i64)) + %21 = bitcast i8* %20 to { i64, i8* }* + %22 = getelementptr { i64, i8* }, { i64, i8* }* %21, i64 0, i32 0 + store i64 %1, i64* %22, align 4 + %23 = getelementptr { i64, i8* }, { i64, i8* }* %21, i64 0, i32 1 + store i8* %3, i8** %23, align 8 + %24 = sub i64 %1, 1 + br label %header__3 + +header__2: ; preds = %exiting__2, %body__1 + %25 = phi i64 [ 0, %body__1 ], [ %36, %exiting__2 ] + %26 = icmp sle i64 %25, %18 + br i1 %26, label %body__2, label %exit__2 + +body__2: ; preds = %header__2 + %27 = mul i64 %25, 1 + %28 = add i64 %17, %27 + %29 = inttoptr i64 %28 to i8* + %30 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %13, i64 %25) + %31 = bitcast i8* %30 to %Result** + %32 = load %Result*, %Result** %31, align 8 + %33 = call %Result* @__quantum__rt__result_get_zero() + %34 = call i1 @__quantum__rt__result_equal(%Result* %32, %Result* %33) + %35 = select i1 %34, i8 0, i8 -1 + store i8 %35, i8* %29, align 1 + br label %exiting__2 + +exiting__2: ; preds = %body__2 + %36 = add i64 %25, 1 + br label %header__2 + +exit__2: ; preds = %header__2 + %37 = call i8* @__quantum__rt__memory_allocate(i64 ptrtoint ({ i64, i8* }* getelementptr ({ i64, i8* }, { i64, i8* }* null, i32 1) to i64)) + %38 = bitcast i8* %37 to { i64, i8* }* + %39 = getelementptr { i64, i8* }, { i64, i8* }* %38, i64 0, i32 0 + store i64 %14, i64* %39, align 4 + %40 = getelementptr { i64, i8* }, { i64, i8* }* %38, i64 0, i32 1 + store i8* %16, i8** %40, align 8 + store { i64, i8* }* %38, { i64, i8* }** %10, align 8 + br label %exiting__1 + +header__3: ; preds = %exiting__3, %exit__1 + %41 = phi i64 [ 0, %exit__1 ], [ %48, %exiting__3 ] + %42 = icmp sle i64 %41, %24 + br i1 %42, label %body__3, label %exit__3 + +body__3: ; preds = %header__3 + %43 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %0, i64 %41) + %44 = bitcast i8* %43 to %Array** + %45 = load %Array*, %Array** %44, align 8 + %46 = call i64 @__quantum__rt__array_get_size_1d(%Array* %45) + %47 = sub i64 %46, 1 + br label %header__4 + +exiting__3: ; preds = %exit__4 + %48 = add i64 %41, 1 + br label %header__3 + +exit__3: ; preds = %header__3 + call void @__quantum__rt__array_update_reference_count(%Array* %0, i32 -1) + ret { i64, i8* }* %21 + +header__4: ; preds = %exiting__4, %body__3 + %49 = phi i64 [ 0, %body__3 ], [ %54, %exiting__4 ] + %50 = icmp sle i64 %49, %47 + br i1 %50, label %body__4, label %exit__4 + +body__4: ; preds = %header__4 + %51 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %45, i64 %49) + %52 = bitcast i8* %51 to %Result** + %53 = load %Result*, %Result** %52, align 8 + call void @__quantum__rt__result_update_reference_count(%Result* %53, i32 -1) + br label %exiting__4 + +exiting__4: ; preds = %body__4 + %54 = add i64 %49, 1 + br label %header__4 + +exit__4: ; preds = %header__4 + call void @__quantum__rt__array_update_reference_count(%Array* %45, i32 -1) + br label %exiting__3 +} + +declare i8* @__quantum__rt__memory_allocate(i64) + +define void @QuantumApplication__Run() #1 { +entry: + %0 = call %Array* @QuantumApplication__Run__body() + %1 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @0, i32 0, i32 0)) + %2 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @1, i32 0, i32 0)) + call void @__quantum__rt__string_update_reference_count(%String* %2, i32 1) + %3 = call i64 @__quantum__rt__array_get_size_1d(%Array* %0) + %4 = sub i64 %3, 1 + br label %header__1 + +header__1: ; preds = %exiting__1, %entry + %5 = phi %String* [ %2, %entry ], [ %36, %exiting__1 ] + %6 = phi i64 [ 0, %entry ], [ %18, %exiting__1 ] + %7 = icmp sle i64 %6, %4 + br i1 %7, label %body__1, label %exit__1 + +body__1: ; preds = %header__1 + %8 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %0, i64 %6) + %9 = bitcast i8* %8 to %Array** + %10 = load %Array*, %Array** %9, align 8 + %11 = icmp ne %String* %5, %2 + br i1 %11, label %condTrue__1, label %condContinue__1 + +condTrue__1: ; preds = %body__1 + %12 = call %String* @__quantum__rt__string_concatenate(%String* %5, %String* %1) + call void @__quantum__rt__string_update_reference_count(%String* %5, i32 -1) + br label %condContinue__1 + +condContinue__1: ; preds = %condTrue__1, %body__1 + %13 = phi %String* [ %12, %condTrue__1 ], [ %5, %body__1 ] + %14 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @2, i32 0, i32 0)) + %15 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @3, i32 0, i32 0)) + call void @__quantum__rt__string_update_reference_count(%String* %15, i32 1) + %16 = call i64 @__quantum__rt__array_get_size_1d(%Array* %10) + %17 = sub i64 %16, 1 + br label %header__2 + +exiting__1: ; preds = %exit__2 + %18 = add i64 %6, 1 + br label %header__1 + +exit__1: ; preds = %header__1 + %19 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @5, i32 0, i32 0)) + %20 = call %String* @__quantum__rt__string_concatenate(%String* %5, %String* %19) + call void @__quantum__rt__string_update_reference_count(%String* %5, i32 -1) + call void @__quantum__rt__string_update_reference_count(%String* %19, i32 -1) + call void @__quantum__rt__string_update_reference_count(%String* %1, i32 -1) + call void @__quantum__rt__string_update_reference_count(%String* %2, i32 -1) + call void @__quantum__rt__message(%String* %20) + %21 = sub i64 %3, 1 + br label %header__3 + +header__2: ; preds = %exiting__2, %condContinue__1 + %22 = phi %String* [ %15, %condContinue__1 ], [ %32, %exiting__2 ] + %23 = phi i64 [ 0, %condContinue__1 ], [ %33, %exiting__2 ] + %24 = icmp sle i64 %23, %17 + br i1 %24, label %body__2, label %exit__2 + +body__2: ; preds = %header__2 + %25 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %10, i64 %23) + %26 = bitcast i8* %25 to %Result** + %27 = load %Result*, %Result** %26, align 8 + %28 = icmp ne %String* %22, %15 + br i1 %28, label %condTrue__2, label %condContinue__2 + +condTrue__2: ; preds = %body__2 + %29 = call %String* @__quantum__rt__string_concatenate(%String* %22, %String* %14) + call void @__quantum__rt__string_update_reference_count(%String* %22, i32 -1) + br label %condContinue__2 + +condContinue__2: ; preds = %condTrue__2, %body__2 + %30 = phi %String* [ %29, %condTrue__2 ], [ %22, %body__2 ] + %31 = call %String* @__quantum__rt__result_to_string(%Result* %27) + %32 = call %String* @__quantum__rt__string_concatenate(%String* %30, %String* %31) + call void @__quantum__rt__string_update_reference_count(%String* %30, i32 -1) + call void @__quantum__rt__string_update_reference_count(%String* %31, i32 -1) + br label %exiting__2 + +exiting__2: ; preds = %condContinue__2 + %33 = add i64 %23, 1 + br label %header__2 + +exit__2: ; preds = %header__2 + %34 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @4, i32 0, i32 0)) + %35 = call %String* @__quantum__rt__string_concatenate(%String* %22, %String* %34) + call void @__quantum__rt__string_update_reference_count(%String* %22, i32 -1) + call void @__quantum__rt__string_update_reference_count(%String* %34, i32 -1) + call void @__quantum__rt__string_update_reference_count(%String* %14, i32 -1) + call void @__quantum__rt__string_update_reference_count(%String* %15, i32 -1) + %36 = call %String* @__quantum__rt__string_concatenate(%String* %13, %String* %35) + call void @__quantum__rt__string_update_reference_count(%String* %13, i32 -1) + call void @__quantum__rt__string_update_reference_count(%String* %35, i32 -1) + br label %exiting__1 + +header__3: ; preds = %exiting__3, %exit__1 + %37 = phi i64 [ 0, %exit__1 ], [ %44, %exiting__3 ] + %38 = icmp sle i64 %37, %21 + br i1 %38, label %body__3, label %exit__3 + +body__3: ; preds = %header__3 + %39 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %0, i64 %37) + %40 = bitcast i8* %39 to %Array** + %41 = load %Array*, %Array** %40, align 8 + %42 = call i64 @__quantum__rt__array_get_size_1d(%Array* %41) + %43 = sub i64 %42, 1 + br label %header__4 + +exiting__3: ; preds = %exit__4 + %44 = add i64 %37, 1 + br label %header__3 + +exit__3: ; preds = %header__3 + call void @__quantum__rt__array_update_reference_count(%Array* %0, i32 -1) + call void @__quantum__rt__string_update_reference_count(%String* %20, i32 -1) + ret void + +header__4: ; preds = %exiting__4, %body__3 + %45 = phi i64 [ 0, %body__3 ], [ %50, %exiting__4 ] + %46 = icmp sle i64 %45, %43 + br i1 %46, label %body__4, label %exit__4 + +body__4: ; preds = %header__4 + %47 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %41, i64 %45) + %48 = bitcast i8* %47 to %Result** + %49 = load %Result*, %Result** %48, align 8 + call void @__quantum__rt__result_update_reference_count(%Result* %49, i32 -1) + br label %exiting__4 + +exiting__4: ; preds = %body__4 + %50 = add i64 %45, 1 + br label %header__4 + +exit__4: ; preds = %header__4 + call void @__quantum__rt__array_update_reference_count(%Array* %41, i32 -1) + br label %exiting__3 +} + +declare void @__quantum__rt__message(%String*) + +declare %String* @__quantum__rt__string_create(i8*) + +declare void @__quantum__rt__string_update_reference_count(%String*, i32) + +declare %String* @__quantum__rt__string_concatenate(%String*, %String*) + +declare %String* @__quantum__rt__result_to_string(%Result*) + +attributes #0 = { "InteropFriendly" } +attributes #1 = { "EntryPoint" } diff --git a/src/QirTools/pyqir/bell_no_measure.ll b/src/QirTools/pyqir/bell_no_measure.ll new file mode 100644 index 0000000000..a1a26909a8 --- /dev/null +++ b/src/QirTools/pyqir/bell_no_measure.ll @@ -0,0 +1,474 @@ +; ModuleID = 'Bell circuit' +source_filename = "C:\\Users\\iadavis\\dev\\qsharp-compiler\\src\\QirTools\\pyqir\\qirlib\\src\\emit\\qir\\module.ll" + +%Range = type { i64, i64, i64 } +%Array = type opaque +%Qubit = type opaque +%Result = type opaque +%String = type opaque + +@PauliI = internal constant i2 0 +@PauliX = internal constant i2 1 +@PauliY = internal constant i2 -1 +@PauliZ = internal constant i2 -2 +@EmptyRange = internal constant %Range { i64 0, i64 1, i64 -1 } +@0 = internal constant [3 x i8] c", \00" +@1 = internal constant [2 x i8] c"[\00" +@2 = internal constant [3 x i8] c", \00" +@3 = internal constant [2 x i8] c"[\00" +@4 = internal constant [2 x i8] c"]\00" +@5 = internal constant [2 x i8] c"]\00" + +define internal %Array* @QuantumApplication__Run__body() { +entry: + %qr0 = call %Qubit* @__quantum__rt__qubit_allocate() + %qr1 = call %Qubit* @__quantum__rt__qubit_allocate() + %results = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 0) + call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %qr0) + %__controlQubits__ = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) + %__controlQubits__0_result_tmp_0_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %__controlQubits__, i64 0) + %__controlQubits__0_result_tmp_result_0 = bitcast i8* %__controlQubits__0_result_tmp_0_raw to %Qubit** + store %Qubit* %qr0, %Qubit** %__controlQubits__0_result_tmp_result_0, align 8 + call void @Microsoft__Quantum__Intrinsic__X__ctl(%Array* %__controlQubits__, %Qubit* %qr1) + call void @__quantum__rt__array_update_reference_count(%Array* %__controlQubits__, i32 -1) + call void @__quantum__rt__qubit_release(%Qubit* %qr0) + call void @__quantum__rt__qubit_release(%Qubit* %qr1) + ret %Array* %results +} + +declare %Qubit* @__quantum__rt__qubit_allocate() + +declare void @__quantum__rt__qubit_release(%Qubit*) + +declare %Array* @__quantum__rt__array_create_1d(i32, i64) + +declare i8* @__quantum__rt__array_get_element_ptr_1d(%Array*, i64) + +declare %Result* @__quantum__rt__result_get_zero() + +declare void @__quantum__rt__result_update_reference_count(%Result*, i32) + +declare void @__quantum__rt__array_update_alias_count(%Array*, i32) + +declare i64 @__quantum__rt__array_get_size_1d(%Array*) + +declare void @__quantum__rt__array_update_reference_count(%Array*, i32) + +declare void @__quantum__qis__x__body(%Qubit*) + +declare void @__quantum__qis__x__ctl(%Array*, %Qubit*) + +declare void @__quantum__qis__y__body(%Qubit*) + +declare void @__quantum__qis__z__body(%Qubit*) + +declare void @__quantum__qis__z__ctl(%Array*, %Qubit*) + +declare void @__quantum__qis__h__body(%Qubit*) + +define internal %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %qubit) { +entry: + %bases = call %Array* @__quantum__rt__array_create_1d(i32 1, i64 1) + %0 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %bases, i64 0) + %1 = bitcast i8* %0 to i2* + %2 = load i2, i2* @PauliZ, align 1 + store i2 %2, i2* %1, align 1 + call void @__quantum__rt__array_update_alias_count(%Array* %bases, i32 1) + %qubits = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) + %3 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qubits, i64 0) + %4 = bitcast i8* %3 to %Qubit** + store %Qubit* %qubit, %Qubit** %4, align 8 + call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i32 1) + %5 = call %Result* @__quantum__qis__measure__body(%Array* %bases, %Array* %qubits) + call void @__quantum__rt__array_update_alias_count(%Array* %bases, i32 -1) + call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i32 -1) + call void @__quantum__rt__array_update_reference_count(%Array* %bases, i32 -1) + call void @__quantum__rt__array_update_reference_count(%Array* %qubits, i32 -1) + ret %Result* %5 +} + +define internal void @Microsoft__Quantum__Intrinsic__Reset__body(%Qubit* %qubit) { +entry: + %0 = call %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %qubit) + %1 = call %Result* @__quantum__rt__result_get_one() + %2 = call i1 @__quantum__rt__result_equal(%Result* %0, %Result* %1) + call void @__quantum__rt__result_update_reference_count(%Result* %0, i32 -1) + br i1 %2, label %then0__1, label %continue__1 + +then0__1: ; preds = %entry + call void @__quantum__qis__x__body(%Qubit* %qubit) + br label %continue__1 + +continue__1: ; preds = %then0__1, %entry + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Rx__body(double %theta, %Qubit* %qubit) { +entry: + %pauli = load i2, i2* @PauliX, align 1 + call void @__quantum__qis__r__body(i2 %pauli, double %theta, %Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Ry__body(double %theta, %Qubit* %qubit) { +entry: + %pauli = load i2, i2* @PauliY, align 1 + call void @__quantum__qis__r__body(i2 %pauli, double %theta, %Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Rz__body(double %theta, %Qubit* %qubit) { +entry: + %pauli = load i2, i2* @PauliZ, align 1 + call void @__quantum__qis__r__body(i2 %pauli, double %theta, %Qubit* %qubit) + ret void +} + +declare void @__quantum__qis__s__body(%Qubit*) + +declare void @__quantum__qis__s__adj(%Qubit*) + +declare void @__quantum__qis__t__body(%Qubit*) + +declare void @__quantum__qis__t__adj(%Qubit*) + +define internal void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %qubit) { +entry: + call void @__quantum__qis__h__body(%Qubit* %qubit) + ret void +} + +declare %Result* @__quantum__qis__measure__body(%Array*, %Array*) + +declare void @__quantum__qis__r__body(i2, double, %Qubit*) + +declare %Result* @__quantum__rt__result_get_one() + +declare i1 @__quantum__rt__result_equal(%Result*, %Result*) + +define internal void @Microsoft__Quantum__Intrinsic__S__body(%Qubit* %qubit) { +entry: + call void @__quantum__qis__s__body(%Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__S__adj(%Qubit* %qubit) { +entry: + call void @__quantum__qis__s__adj(%Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__T__body(%Qubit* %qubit) { +entry: + call void @__quantum__qis__t__body(%Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__T__adj(%Qubit* %qubit) { +entry: + call void @__quantum__qis__t__adj(%Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__X__body(%Qubit* %qubit) { +entry: + call void @__quantum__qis__x__body(%Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__X__ctl(%Array* %__controlQubits__, %Qubit* %qubit) { +entry: + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 1) + call void @__quantum__qis__x__ctl(%Array* %__controlQubits__, %Qubit* %qubit) + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 -1) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Y__body(%Qubit* %qubit) { +entry: + call void @__quantum__qis__y__body(%Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Z__body(%Qubit* %qubit) { +entry: + call void @__quantum__qis__z__body(%Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Z__ctl(%Array* %__controlQubits__, %Qubit* %qubit) { +entry: + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 1) + call void @__quantum__qis__z__ctl(%Array* %__controlQubits__, %Qubit* %qubit) + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 -1) + ret void +} + +define { i64, i8* }* @QuantumApplication__Run__Interop() #0 { +entry: + %0 = call %Array* @QuantumApplication__Run__body() + %1 = call i64 @__quantum__rt__array_get_size_1d(%Array* %0) + %2 = mul i64 %1, 8 + %3 = call i8* @__quantum__rt__memory_allocate(i64 %2) + %4 = ptrtoint i8* %3 to i64 + %5 = sub i64 %1, 1 + br label %header__1 + +header__1: ; preds = %exiting__1, %entry + %6 = phi i64 [ 0, %entry ], [ %19, %exiting__1 ] + %7 = icmp sle i64 %6, %5 + br i1 %7, label %body__1, label %exit__1 + +body__1: ; preds = %header__1 + %8 = mul i64 %6, 8 + %9 = add i64 %4, %8 + %10 = inttoptr i64 %9 to { i64, i8* }** + %11 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %0, i64 %6) + %12 = bitcast i8* %11 to %Array** + %13 = load %Array*, %Array** %12, align 8 + %14 = call i64 @__quantum__rt__array_get_size_1d(%Array* %13) + %15 = mul i64 %14, 1 + %16 = call i8* @__quantum__rt__memory_allocate(i64 %15) + %17 = ptrtoint i8* %16 to i64 + %18 = sub i64 %14, 1 + br label %header__2 + +exiting__1: ; preds = %exit__2 + %19 = add i64 %6, 1 + br label %header__1 + +exit__1: ; preds = %header__1 + %20 = call i8* @__quantum__rt__memory_allocate(i64 ptrtoint ({ i64, i8* }* getelementptr ({ i64, i8* }, { i64, i8* }* null, i32 1) to i64)) + %21 = bitcast i8* %20 to { i64, i8* }* + %22 = getelementptr { i64, i8* }, { i64, i8* }* %21, i64 0, i32 0 + store i64 %1, i64* %22, align 4 + %23 = getelementptr { i64, i8* }, { i64, i8* }* %21, i64 0, i32 1 + store i8* %3, i8** %23, align 8 + %24 = sub i64 %1, 1 + br label %header__3 + +header__2: ; preds = %exiting__2, %body__1 + %25 = phi i64 [ 0, %body__1 ], [ %36, %exiting__2 ] + %26 = icmp sle i64 %25, %18 + br i1 %26, label %body__2, label %exit__2 + +body__2: ; preds = %header__2 + %27 = mul i64 %25, 1 + %28 = add i64 %17, %27 + %29 = inttoptr i64 %28 to i8* + %30 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %13, i64 %25) + %31 = bitcast i8* %30 to %Result** + %32 = load %Result*, %Result** %31, align 8 + %33 = call %Result* @__quantum__rt__result_get_zero() + %34 = call i1 @__quantum__rt__result_equal(%Result* %32, %Result* %33) + %35 = select i1 %34, i8 0, i8 -1 + store i8 %35, i8* %29, align 1 + br label %exiting__2 + +exiting__2: ; preds = %body__2 + %36 = add i64 %25, 1 + br label %header__2 + +exit__2: ; preds = %header__2 + %37 = call i8* @__quantum__rt__memory_allocate(i64 ptrtoint ({ i64, i8* }* getelementptr ({ i64, i8* }, { i64, i8* }* null, i32 1) to i64)) + %38 = bitcast i8* %37 to { i64, i8* }* + %39 = getelementptr { i64, i8* }, { i64, i8* }* %38, i64 0, i32 0 + store i64 %14, i64* %39, align 4 + %40 = getelementptr { i64, i8* }, { i64, i8* }* %38, i64 0, i32 1 + store i8* %16, i8** %40, align 8 + store { i64, i8* }* %38, { i64, i8* }** %10, align 8 + br label %exiting__1 + +header__3: ; preds = %exiting__3, %exit__1 + %41 = phi i64 [ 0, %exit__1 ], [ %48, %exiting__3 ] + %42 = icmp sle i64 %41, %24 + br i1 %42, label %body__3, label %exit__3 + +body__3: ; preds = %header__3 + %43 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %0, i64 %41) + %44 = bitcast i8* %43 to %Array** + %45 = load %Array*, %Array** %44, align 8 + %46 = call i64 @__quantum__rt__array_get_size_1d(%Array* %45) + %47 = sub i64 %46, 1 + br label %header__4 + +exiting__3: ; preds = %exit__4 + %48 = add i64 %41, 1 + br label %header__3 + +exit__3: ; preds = %header__3 + call void @__quantum__rt__array_update_reference_count(%Array* %0, i32 -1) + ret { i64, i8* }* %21 + +header__4: ; preds = %exiting__4, %body__3 + %49 = phi i64 [ 0, %body__3 ], [ %54, %exiting__4 ] + %50 = icmp sle i64 %49, %47 + br i1 %50, label %body__4, label %exit__4 + +body__4: ; preds = %header__4 + %51 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %45, i64 %49) + %52 = bitcast i8* %51 to %Result** + %53 = load %Result*, %Result** %52, align 8 + call void @__quantum__rt__result_update_reference_count(%Result* %53, i32 -1) + br label %exiting__4 + +exiting__4: ; preds = %body__4 + %54 = add i64 %49, 1 + br label %header__4 + +exit__4: ; preds = %header__4 + call void @__quantum__rt__array_update_reference_count(%Array* %45, i32 -1) + br label %exiting__3 +} + +declare i8* @__quantum__rt__memory_allocate(i64) + +define void @QuantumApplication__Run() #1 { +entry: + %0 = call %Array* @QuantumApplication__Run__body() + %1 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @0, i32 0, i32 0)) + %2 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @1, i32 0, i32 0)) + call void @__quantum__rt__string_update_reference_count(%String* %2, i32 1) + %3 = call i64 @__quantum__rt__array_get_size_1d(%Array* %0) + %4 = sub i64 %3, 1 + br label %header__1 + +header__1: ; preds = %exiting__1, %entry + %5 = phi %String* [ %2, %entry ], [ %36, %exiting__1 ] + %6 = phi i64 [ 0, %entry ], [ %18, %exiting__1 ] + %7 = icmp sle i64 %6, %4 + br i1 %7, label %body__1, label %exit__1 + +body__1: ; preds = %header__1 + %8 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %0, i64 %6) + %9 = bitcast i8* %8 to %Array** + %10 = load %Array*, %Array** %9, align 8 + %11 = icmp ne %String* %5, %2 + br i1 %11, label %condTrue__1, label %condContinue__1 + +condTrue__1: ; preds = %body__1 + %12 = call %String* @__quantum__rt__string_concatenate(%String* %5, %String* %1) + call void @__quantum__rt__string_update_reference_count(%String* %5, i32 -1) + br label %condContinue__1 + +condContinue__1: ; preds = %condTrue__1, %body__1 + %13 = phi %String* [ %12, %condTrue__1 ], [ %5, %body__1 ] + %14 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @2, i32 0, i32 0)) + %15 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @3, i32 0, i32 0)) + call void @__quantum__rt__string_update_reference_count(%String* %15, i32 1) + %16 = call i64 @__quantum__rt__array_get_size_1d(%Array* %10) + %17 = sub i64 %16, 1 + br label %header__2 + +exiting__1: ; preds = %exit__2 + %18 = add i64 %6, 1 + br label %header__1 + +exit__1: ; preds = %header__1 + %19 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @5, i32 0, i32 0)) + %20 = call %String* @__quantum__rt__string_concatenate(%String* %5, %String* %19) + call void @__quantum__rt__string_update_reference_count(%String* %5, i32 -1) + call void @__quantum__rt__string_update_reference_count(%String* %19, i32 -1) + call void @__quantum__rt__string_update_reference_count(%String* %1, i32 -1) + call void @__quantum__rt__string_update_reference_count(%String* %2, i32 -1) + call void @__quantum__rt__message(%String* %20) + %21 = sub i64 %3, 1 + br label %header__3 + +header__2: ; preds = %exiting__2, %condContinue__1 + %22 = phi %String* [ %15, %condContinue__1 ], [ %32, %exiting__2 ] + %23 = phi i64 [ 0, %condContinue__1 ], [ %33, %exiting__2 ] + %24 = icmp sle i64 %23, %17 + br i1 %24, label %body__2, label %exit__2 + +body__2: ; preds = %header__2 + %25 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %10, i64 %23) + %26 = bitcast i8* %25 to %Result** + %27 = load %Result*, %Result** %26, align 8 + %28 = icmp ne %String* %22, %15 + br i1 %28, label %condTrue__2, label %condContinue__2 + +condTrue__2: ; preds = %body__2 + %29 = call %String* @__quantum__rt__string_concatenate(%String* %22, %String* %14) + call void @__quantum__rt__string_update_reference_count(%String* %22, i32 -1) + br label %condContinue__2 + +condContinue__2: ; preds = %condTrue__2, %body__2 + %30 = phi %String* [ %29, %condTrue__2 ], [ %22, %body__2 ] + %31 = call %String* @__quantum__rt__result_to_string(%Result* %27) + %32 = call %String* @__quantum__rt__string_concatenate(%String* %30, %String* %31) + call void @__quantum__rt__string_update_reference_count(%String* %30, i32 -1) + call void @__quantum__rt__string_update_reference_count(%String* %31, i32 -1) + br label %exiting__2 + +exiting__2: ; preds = %condContinue__2 + %33 = add i64 %23, 1 + br label %header__2 + +exit__2: ; preds = %header__2 + %34 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @4, i32 0, i32 0)) + %35 = call %String* @__quantum__rt__string_concatenate(%String* %22, %String* %34) + call void @__quantum__rt__string_update_reference_count(%String* %22, i32 -1) + call void @__quantum__rt__string_update_reference_count(%String* %34, i32 -1) + call void @__quantum__rt__string_update_reference_count(%String* %14, i32 -1) + call void @__quantum__rt__string_update_reference_count(%String* %15, i32 -1) + %36 = call %String* @__quantum__rt__string_concatenate(%String* %13, %String* %35) + call void @__quantum__rt__string_update_reference_count(%String* %13, i32 -1) + call void @__quantum__rt__string_update_reference_count(%String* %35, i32 -1) + br label %exiting__1 + +header__3: ; preds = %exiting__3, %exit__1 + %37 = phi i64 [ 0, %exit__1 ], [ %44, %exiting__3 ] + %38 = icmp sle i64 %37, %21 + br i1 %38, label %body__3, label %exit__3 + +body__3: ; preds = %header__3 + %39 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %0, i64 %37) + %40 = bitcast i8* %39 to %Array** + %41 = load %Array*, %Array** %40, align 8 + %42 = call i64 @__quantum__rt__array_get_size_1d(%Array* %41) + %43 = sub i64 %42, 1 + br label %header__4 + +exiting__3: ; preds = %exit__4 + %44 = add i64 %37, 1 + br label %header__3 + +exit__3: ; preds = %header__3 + call void @__quantum__rt__array_update_reference_count(%Array* %0, i32 -1) + call void @__quantum__rt__string_update_reference_count(%String* %20, i32 -1) + ret void + +header__4: ; preds = %exiting__4, %body__3 + %45 = phi i64 [ 0, %body__3 ], [ %50, %exiting__4 ] + %46 = icmp sle i64 %45, %43 + br i1 %46, label %body__4, label %exit__4 + +body__4: ; preds = %header__4 + %47 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %41, i64 %45) + %48 = bitcast i8* %47 to %Result** + %49 = load %Result*, %Result** %48, align 8 + call void @__quantum__rt__result_update_reference_count(%Result* %49, i32 -1) + br label %exiting__4 + +exiting__4: ; preds = %body__4 + %50 = add i64 %45, 1 + br label %header__4 + +exit__4: ; preds = %header__4 + call void @__quantum__rt__array_update_reference_count(%Array* %41, i32 -1) + br label %exiting__3 +} + +declare void @__quantum__rt__message(%String*) + +declare %String* @__quantum__rt__string_create(i8*) + +declare void @__quantum__rt__string_update_reference_count(%String*, i32) + +declare %String* @__quantum__rt__string_concatenate(%String*, %String*) + +declare %String* @__quantum__rt__result_to_string(%Result*) + +attributes #0 = { "InteropFriendly" } +attributes #1 = { "EntryPoint" } diff --git a/src/QirTools/pyqir/bernstein_vazirani.ll b/src/QirTools/pyqir/bernstein_vazirani.ll new file mode 100644 index 0000000000..64fe28567a --- /dev/null +++ b/src/QirTools/pyqir/bernstein_vazirani.ll @@ -0,0 +1,569 @@ +; ModuleID = 'Bernstein-Vazirani' +source_filename = "C:\\Users\\iadavis\\dev\\qsharp-compiler\\src\\QirTools\\pyqir\\qirlib\\src\\emit\\qir\\module.ll" + +%Range = type { i64, i64, i64 } +%Array = type opaque +%Qubit = type opaque +%Result = type opaque +%String = type opaque + +@PauliI = internal constant i2 0 +@PauliX = internal constant i2 1 +@PauliY = internal constant i2 -1 +@PauliZ = internal constant i2 -2 +@EmptyRange = internal constant %Range { i64 0, i64 1, i64 -1 } +@0 = internal constant [3 x i8] c", \00" +@1 = internal constant [2 x i8] c"[\00" +@2 = internal constant [3 x i8] c", \00" +@3 = internal constant [2 x i8] c"[\00" +@4 = internal constant [2 x i8] c"]\00" +@5 = internal constant [2 x i8] c"]\00" + +define internal %Array* @QuantumApplication__Run__body() { +entry: + %input0 = call %Qubit* @__quantum__rt__qubit_allocate() + %input1 = call %Qubit* @__quantum__rt__qubit_allocate() + %input2 = call %Qubit* @__quantum__rt__qubit_allocate() + %input3 = call %Qubit* @__quantum__rt__qubit_allocate() + %input4 = call %Qubit* @__quantum__rt__qubit_allocate() + %target0 = call %Qubit* @__quantum__rt__qubit_allocate() + %results = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) + %output = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 5) + %output_0_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %output, i64 0) + %output_result_0 = bitcast i8* %output_0_raw to %Result** + %zero_0 = call %Result* @__quantum__rt__result_get_zero() + call void @__quantum__rt__result_update_reference_count(%Result* %zero_0, i32 1) + store %Result* %zero_0, %Result** %output_result_0, align 8 + %output_1_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %output, i64 1) + %output_result_1 = bitcast i8* %output_1_raw to %Result** + %zero_1 = call %Result* @__quantum__rt__result_get_zero() + call void @__quantum__rt__result_update_reference_count(%Result* %zero_1, i32 1) + store %Result* %zero_1, %Result** %output_result_1, align 8 + %output_2_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %output, i64 2) + %output_result_2 = bitcast i8* %output_2_raw to %Result** + %zero_2 = call %Result* @__quantum__rt__result_get_zero() + call void @__quantum__rt__result_update_reference_count(%Result* %zero_2, i32 1) + store %Result* %zero_2, %Result** %output_result_2, align 8 + %output_3_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %output, i64 3) + %output_result_3 = bitcast i8* %output_3_raw to %Result** + %zero_3 = call %Result* @__quantum__rt__result_get_zero() + call void @__quantum__rt__result_update_reference_count(%Result* %zero_3, i32 1) + store %Result* %zero_3, %Result** %output_result_3, align 8 + %output_4_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %output, i64 4) + %output_result_4 = bitcast i8* %output_4_raw to %Result** + %zero_4 = call %Result* @__quantum__rt__result_get_zero() + call void @__quantum__rt__result_update_reference_count(%Result* %zero_4, i32 1) + store %Result* %zero_4, %Result** %output_result_4, align 8 + %results_result_tmp_0_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %results, i64 0) + %results_result_tmp_result_0 = bitcast i8* %results_result_tmp_0_raw to %Array** + store %Array* %output, %Array** %results_result_tmp_result_0, align 8 + call void @Microsoft__Quantum__Intrinsic__X__body(%Qubit* %target0) + call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %input0) + call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %input1) + call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %input2) + call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %input3) + call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %input4) + call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %target0) + %__controlQubits__ = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) + %__controlQubits__0_result_tmp_0_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %__controlQubits__, i64 0) + %__controlQubits__0_result_tmp_result_0 = bitcast i8* %__controlQubits__0_result_tmp_0_raw to %Qubit** + store %Qubit* %input1, %Qubit** %__controlQubits__0_result_tmp_result_0, align 8 + call void @Microsoft__Quantum__Intrinsic__X__ctl(%Array* %__controlQubits__, %Qubit* %target0) + call void @__quantum__rt__array_update_reference_count(%Array* %__controlQubits__, i32 -1) + %__controlQubits__1 = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) + %__controlQubits__0_result_tmp_0_raw2 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %__controlQubits__1, i64 0) + %__controlQubits__0_result_tmp_result_03 = bitcast i8* %__controlQubits__0_result_tmp_0_raw2 to %Qubit** + store %Qubit* %input3, %Qubit** %__controlQubits__0_result_tmp_result_03, align 8 + call void @Microsoft__Quantum__Intrinsic__X__ctl(%Array* %__controlQubits__1, %Qubit* %target0) + call void @__quantum__rt__array_update_reference_count(%Array* %__controlQubits__1, i32 -1) + %__controlQubits__4 = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) + %__controlQubits__0_result_tmp_0_raw5 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %__controlQubits__4, i64 0) + %__controlQubits__0_result_tmp_result_06 = bitcast i8* %__controlQubits__0_result_tmp_0_raw5 to %Qubit** + store %Qubit* %input4, %Qubit** %__controlQubits__0_result_tmp_result_06, align 8 + call void @Microsoft__Quantum__Intrinsic__X__ctl(%Array* %__controlQubits__4, %Qubit* %target0) + call void @__quantum__rt__array_update_reference_count(%Array* %__controlQubits__4, i32 -1) + call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %input0) + call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %input1) + call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %input2) + call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %input3) + call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %input4) + %measurement = call %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %input0) + %output0_0_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %output, i64 0) + %output0_result_0 = bitcast i8* %output0_0_raw to %Result** + %existing_value = load %Result*, %Result** %output0_result_0, align 8 + call void @__quantum__rt__result_update_reference_count(%Result* %existing_value, i32 -1) + call void @__quantum__rt__result_update_reference_count(%Result* %measurement, i32 1) + store %Result* %measurement, %Result** %output0_result_0, align 8 + %measurement7 = call %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %input1) + %output1_1_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %output, i64 1) + %output1_result_1 = bitcast i8* %output1_1_raw to %Result** + %existing_value8 = load %Result*, %Result** %output1_result_1, align 8 + call void @__quantum__rt__result_update_reference_count(%Result* %existing_value8, i32 -1) + call void @__quantum__rt__result_update_reference_count(%Result* %measurement7, i32 1) + store %Result* %measurement7, %Result** %output1_result_1, align 8 + %measurement9 = call %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %input2) + %output2_2_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %output, i64 2) + %output2_result_2 = bitcast i8* %output2_2_raw to %Result** + %existing_value10 = load %Result*, %Result** %output2_result_2, align 8 + call void @__quantum__rt__result_update_reference_count(%Result* %existing_value10, i32 -1) + call void @__quantum__rt__result_update_reference_count(%Result* %measurement9, i32 1) + store %Result* %measurement9, %Result** %output2_result_2, align 8 + %measurement11 = call %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %input3) + %output3_3_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %output, i64 3) + %output3_result_3 = bitcast i8* %output3_3_raw to %Result** + %existing_value12 = load %Result*, %Result** %output3_result_3, align 8 + call void @__quantum__rt__result_update_reference_count(%Result* %existing_value12, i32 -1) + call void @__quantum__rt__result_update_reference_count(%Result* %measurement11, i32 1) + store %Result* %measurement11, %Result** %output3_result_3, align 8 + %measurement13 = call %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %input4) + %output4_4_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %output, i64 4) + %output4_result_4 = bitcast i8* %output4_4_raw to %Result** + %existing_value14 = load %Result*, %Result** %output4_result_4, align 8 + call void @__quantum__rt__result_update_reference_count(%Result* %existing_value14, i32 -1) + call void @__quantum__rt__result_update_reference_count(%Result* %measurement13, i32 1) + store %Result* %measurement13, %Result** %output4_result_4, align 8 + call void @__quantum__rt__qubit_release(%Qubit* %input0) + call void @__quantum__rt__qubit_release(%Qubit* %input3) + call void @__quantum__rt__qubit_release(%Qubit* %target0) + call void @__quantum__rt__qubit_release(%Qubit* %input2) + call void @__quantum__rt__qubit_release(%Qubit* %input1) + call void @__quantum__rt__qubit_release(%Qubit* %input4) + ret %Array* %results +} + +declare %Qubit* @__quantum__rt__qubit_allocate() + +declare void @__quantum__rt__qubit_release(%Qubit*) + +declare %Array* @__quantum__rt__array_create_1d(i32, i64) + +declare i8* @__quantum__rt__array_get_element_ptr_1d(%Array*, i64) + +declare %Result* @__quantum__rt__result_get_zero() + +declare void @__quantum__rt__result_update_reference_count(%Result*, i32) + +declare void @__quantum__rt__array_update_alias_count(%Array*, i32) + +declare i64 @__quantum__rt__array_get_size_1d(%Array*) + +declare void @__quantum__rt__array_update_reference_count(%Array*, i32) + +declare void @__quantum__qis__x__body(%Qubit*) + +declare void @__quantum__qis__x__ctl(%Array*, %Qubit*) + +declare void @__quantum__qis__y__body(%Qubit*) + +declare void @__quantum__qis__z__body(%Qubit*) + +declare void @__quantum__qis__z__ctl(%Array*, %Qubit*) + +declare void @__quantum__qis__h__body(%Qubit*) + +define internal %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %qubit) { +entry: + %bases = call %Array* @__quantum__rt__array_create_1d(i32 1, i64 1) + %0 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %bases, i64 0) + %1 = bitcast i8* %0 to i2* + %2 = load i2, i2* @PauliZ, align 1 + store i2 %2, i2* %1, align 1 + call void @__quantum__rt__array_update_alias_count(%Array* %bases, i32 1) + %qubits = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) + %3 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qubits, i64 0) + %4 = bitcast i8* %3 to %Qubit** + store %Qubit* %qubit, %Qubit** %4, align 8 + call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i32 1) + %5 = call %Result* @__quantum__qis__measure__body(%Array* %bases, %Array* %qubits) + call void @__quantum__rt__array_update_alias_count(%Array* %bases, i32 -1) + call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i32 -1) + call void @__quantum__rt__array_update_reference_count(%Array* %bases, i32 -1) + call void @__quantum__rt__array_update_reference_count(%Array* %qubits, i32 -1) + ret %Result* %5 +} + +define internal void @Microsoft__Quantum__Intrinsic__Reset__body(%Qubit* %qubit) { +entry: + %0 = call %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %qubit) + %1 = call %Result* @__quantum__rt__result_get_one() + %2 = call i1 @__quantum__rt__result_equal(%Result* %0, %Result* %1) + call void @__quantum__rt__result_update_reference_count(%Result* %0, i32 -1) + br i1 %2, label %then0__1, label %continue__1 + +then0__1: ; preds = %entry + call void @__quantum__qis__x__body(%Qubit* %qubit) + br label %continue__1 + +continue__1: ; preds = %then0__1, %entry + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Rx__body(double %theta, %Qubit* %qubit) { +entry: + %pauli = load i2, i2* @PauliX, align 1 + call void @__quantum__qis__r__body(i2 %pauli, double %theta, %Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Ry__body(double %theta, %Qubit* %qubit) { +entry: + %pauli = load i2, i2* @PauliY, align 1 + call void @__quantum__qis__r__body(i2 %pauli, double %theta, %Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Rz__body(double %theta, %Qubit* %qubit) { +entry: + %pauli = load i2, i2* @PauliZ, align 1 + call void @__quantum__qis__r__body(i2 %pauli, double %theta, %Qubit* %qubit) + ret void +} + +declare void @__quantum__qis__s__body(%Qubit*) + +declare void @__quantum__qis__s__adj(%Qubit*) + +declare void @__quantum__qis__t__body(%Qubit*) + +declare void @__quantum__qis__t__adj(%Qubit*) + +define internal void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %qubit) { +entry: + call void @__quantum__qis__h__body(%Qubit* %qubit) + ret void +} + +declare %Result* @__quantum__qis__measure__body(%Array*, %Array*) + +declare void @__quantum__qis__r__body(i2, double, %Qubit*) + +declare %Result* @__quantum__rt__result_get_one() + +declare i1 @__quantum__rt__result_equal(%Result*, %Result*) + +define internal void @Microsoft__Quantum__Intrinsic__S__body(%Qubit* %qubit) { +entry: + call void @__quantum__qis__s__body(%Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__S__adj(%Qubit* %qubit) { +entry: + call void @__quantum__qis__s__adj(%Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__T__body(%Qubit* %qubit) { +entry: + call void @__quantum__qis__t__body(%Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__T__adj(%Qubit* %qubit) { +entry: + call void @__quantum__qis__t__adj(%Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__X__body(%Qubit* %qubit) { +entry: + call void @__quantum__qis__x__body(%Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__X__ctl(%Array* %__controlQubits__, %Qubit* %qubit) { +entry: + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 1) + call void @__quantum__qis__x__ctl(%Array* %__controlQubits__, %Qubit* %qubit) + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 -1) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Y__body(%Qubit* %qubit) { +entry: + call void @__quantum__qis__y__body(%Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Z__body(%Qubit* %qubit) { +entry: + call void @__quantum__qis__z__body(%Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Z__ctl(%Array* %__controlQubits__, %Qubit* %qubit) { +entry: + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 1) + call void @__quantum__qis__z__ctl(%Array* %__controlQubits__, %Qubit* %qubit) + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 -1) + ret void +} + +define { i64, i8* }* @QuantumApplication__Run__Interop() #0 { +entry: + %0 = call %Array* @QuantumApplication__Run__body() + %1 = call i64 @__quantum__rt__array_get_size_1d(%Array* %0) + %2 = mul i64 %1, 8 + %3 = call i8* @__quantum__rt__memory_allocate(i64 %2) + %4 = ptrtoint i8* %3 to i64 + %5 = sub i64 %1, 1 + br label %header__1 + +header__1: ; preds = %exiting__1, %entry + %6 = phi i64 [ 0, %entry ], [ %19, %exiting__1 ] + %7 = icmp sle i64 %6, %5 + br i1 %7, label %body__1, label %exit__1 + +body__1: ; preds = %header__1 + %8 = mul i64 %6, 8 + %9 = add i64 %4, %8 + %10 = inttoptr i64 %9 to { i64, i8* }** + %11 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %0, i64 %6) + %12 = bitcast i8* %11 to %Array** + %13 = load %Array*, %Array** %12, align 8 + %14 = call i64 @__quantum__rt__array_get_size_1d(%Array* %13) + %15 = mul i64 %14, 1 + %16 = call i8* @__quantum__rt__memory_allocate(i64 %15) + %17 = ptrtoint i8* %16 to i64 + %18 = sub i64 %14, 1 + br label %header__2 + +exiting__1: ; preds = %exit__2 + %19 = add i64 %6, 1 + br label %header__1 + +exit__1: ; preds = %header__1 + %20 = call i8* @__quantum__rt__memory_allocate(i64 ptrtoint ({ i64, i8* }* getelementptr ({ i64, i8* }, { i64, i8* }* null, i32 1) to i64)) + %21 = bitcast i8* %20 to { i64, i8* }* + %22 = getelementptr { i64, i8* }, { i64, i8* }* %21, i64 0, i32 0 + store i64 %1, i64* %22, align 4 + %23 = getelementptr { i64, i8* }, { i64, i8* }* %21, i64 0, i32 1 + store i8* %3, i8** %23, align 8 + %24 = sub i64 %1, 1 + br label %header__3 + +header__2: ; preds = %exiting__2, %body__1 + %25 = phi i64 [ 0, %body__1 ], [ %36, %exiting__2 ] + %26 = icmp sle i64 %25, %18 + br i1 %26, label %body__2, label %exit__2 + +body__2: ; preds = %header__2 + %27 = mul i64 %25, 1 + %28 = add i64 %17, %27 + %29 = inttoptr i64 %28 to i8* + %30 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %13, i64 %25) + %31 = bitcast i8* %30 to %Result** + %32 = load %Result*, %Result** %31, align 8 + %33 = call %Result* @__quantum__rt__result_get_zero() + %34 = call i1 @__quantum__rt__result_equal(%Result* %32, %Result* %33) + %35 = select i1 %34, i8 0, i8 -1 + store i8 %35, i8* %29, align 1 + br label %exiting__2 + +exiting__2: ; preds = %body__2 + %36 = add i64 %25, 1 + br label %header__2 + +exit__2: ; preds = %header__2 + %37 = call i8* @__quantum__rt__memory_allocate(i64 ptrtoint ({ i64, i8* }* getelementptr ({ i64, i8* }, { i64, i8* }* null, i32 1) to i64)) + %38 = bitcast i8* %37 to { i64, i8* }* + %39 = getelementptr { i64, i8* }, { i64, i8* }* %38, i64 0, i32 0 + store i64 %14, i64* %39, align 4 + %40 = getelementptr { i64, i8* }, { i64, i8* }* %38, i64 0, i32 1 + store i8* %16, i8** %40, align 8 + store { i64, i8* }* %38, { i64, i8* }** %10, align 8 + br label %exiting__1 + +header__3: ; preds = %exiting__3, %exit__1 + %41 = phi i64 [ 0, %exit__1 ], [ %48, %exiting__3 ] + %42 = icmp sle i64 %41, %24 + br i1 %42, label %body__3, label %exit__3 + +body__3: ; preds = %header__3 + %43 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %0, i64 %41) + %44 = bitcast i8* %43 to %Array** + %45 = load %Array*, %Array** %44, align 8 + %46 = call i64 @__quantum__rt__array_get_size_1d(%Array* %45) + %47 = sub i64 %46, 1 + br label %header__4 + +exiting__3: ; preds = %exit__4 + %48 = add i64 %41, 1 + br label %header__3 + +exit__3: ; preds = %header__3 + call void @__quantum__rt__array_update_reference_count(%Array* %0, i32 -1) + ret { i64, i8* }* %21 + +header__4: ; preds = %exiting__4, %body__3 + %49 = phi i64 [ 0, %body__3 ], [ %54, %exiting__4 ] + %50 = icmp sle i64 %49, %47 + br i1 %50, label %body__4, label %exit__4 + +body__4: ; preds = %header__4 + %51 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %45, i64 %49) + %52 = bitcast i8* %51 to %Result** + %53 = load %Result*, %Result** %52, align 8 + call void @__quantum__rt__result_update_reference_count(%Result* %53, i32 -1) + br label %exiting__4 + +exiting__4: ; preds = %body__4 + %54 = add i64 %49, 1 + br label %header__4 + +exit__4: ; preds = %header__4 + call void @__quantum__rt__array_update_reference_count(%Array* %45, i32 -1) + br label %exiting__3 +} + +declare i8* @__quantum__rt__memory_allocate(i64) + +define void @QuantumApplication__Run() #1 { +entry: + %0 = call %Array* @QuantumApplication__Run__body() + %1 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @0, i32 0, i32 0)) + %2 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @1, i32 0, i32 0)) + call void @__quantum__rt__string_update_reference_count(%String* %2, i32 1) + %3 = call i64 @__quantum__rt__array_get_size_1d(%Array* %0) + %4 = sub i64 %3, 1 + br label %header__1 + +header__1: ; preds = %exiting__1, %entry + %5 = phi %String* [ %2, %entry ], [ %36, %exiting__1 ] + %6 = phi i64 [ 0, %entry ], [ %18, %exiting__1 ] + %7 = icmp sle i64 %6, %4 + br i1 %7, label %body__1, label %exit__1 + +body__1: ; preds = %header__1 + %8 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %0, i64 %6) + %9 = bitcast i8* %8 to %Array** + %10 = load %Array*, %Array** %9, align 8 + %11 = icmp ne %String* %5, %2 + br i1 %11, label %condTrue__1, label %condContinue__1 + +condTrue__1: ; preds = %body__1 + %12 = call %String* @__quantum__rt__string_concatenate(%String* %5, %String* %1) + call void @__quantum__rt__string_update_reference_count(%String* %5, i32 -1) + br label %condContinue__1 + +condContinue__1: ; preds = %condTrue__1, %body__1 + %13 = phi %String* [ %12, %condTrue__1 ], [ %5, %body__1 ] + %14 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @2, i32 0, i32 0)) + %15 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @3, i32 0, i32 0)) + call void @__quantum__rt__string_update_reference_count(%String* %15, i32 1) + %16 = call i64 @__quantum__rt__array_get_size_1d(%Array* %10) + %17 = sub i64 %16, 1 + br label %header__2 + +exiting__1: ; preds = %exit__2 + %18 = add i64 %6, 1 + br label %header__1 + +exit__1: ; preds = %header__1 + %19 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @5, i32 0, i32 0)) + %20 = call %String* @__quantum__rt__string_concatenate(%String* %5, %String* %19) + call void @__quantum__rt__string_update_reference_count(%String* %5, i32 -1) + call void @__quantum__rt__string_update_reference_count(%String* %19, i32 -1) + call void @__quantum__rt__string_update_reference_count(%String* %1, i32 -1) + call void @__quantum__rt__string_update_reference_count(%String* %2, i32 -1) + call void @__quantum__rt__message(%String* %20) + %21 = sub i64 %3, 1 + br label %header__3 + +header__2: ; preds = %exiting__2, %condContinue__1 + %22 = phi %String* [ %15, %condContinue__1 ], [ %32, %exiting__2 ] + %23 = phi i64 [ 0, %condContinue__1 ], [ %33, %exiting__2 ] + %24 = icmp sle i64 %23, %17 + br i1 %24, label %body__2, label %exit__2 + +body__2: ; preds = %header__2 + %25 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %10, i64 %23) + %26 = bitcast i8* %25 to %Result** + %27 = load %Result*, %Result** %26, align 8 + %28 = icmp ne %String* %22, %15 + br i1 %28, label %condTrue__2, label %condContinue__2 + +condTrue__2: ; preds = %body__2 + %29 = call %String* @__quantum__rt__string_concatenate(%String* %22, %String* %14) + call void @__quantum__rt__string_update_reference_count(%String* %22, i32 -1) + br label %condContinue__2 + +condContinue__2: ; preds = %condTrue__2, %body__2 + %30 = phi %String* [ %29, %condTrue__2 ], [ %22, %body__2 ] + %31 = call %String* @__quantum__rt__result_to_string(%Result* %27) + %32 = call %String* @__quantum__rt__string_concatenate(%String* %30, %String* %31) + call void @__quantum__rt__string_update_reference_count(%String* %30, i32 -1) + call void @__quantum__rt__string_update_reference_count(%String* %31, i32 -1) + br label %exiting__2 + +exiting__2: ; preds = %condContinue__2 + %33 = add i64 %23, 1 + br label %header__2 + +exit__2: ; preds = %header__2 + %34 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @4, i32 0, i32 0)) + %35 = call %String* @__quantum__rt__string_concatenate(%String* %22, %String* %34) + call void @__quantum__rt__string_update_reference_count(%String* %22, i32 -1) + call void @__quantum__rt__string_update_reference_count(%String* %34, i32 -1) + call void @__quantum__rt__string_update_reference_count(%String* %14, i32 -1) + call void @__quantum__rt__string_update_reference_count(%String* %15, i32 -1) + %36 = call %String* @__quantum__rt__string_concatenate(%String* %13, %String* %35) + call void @__quantum__rt__string_update_reference_count(%String* %13, i32 -1) + call void @__quantum__rt__string_update_reference_count(%String* %35, i32 -1) + br label %exiting__1 + +header__3: ; preds = %exiting__3, %exit__1 + %37 = phi i64 [ 0, %exit__1 ], [ %44, %exiting__3 ] + %38 = icmp sle i64 %37, %21 + br i1 %38, label %body__3, label %exit__3 + +body__3: ; preds = %header__3 + %39 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %0, i64 %37) + %40 = bitcast i8* %39 to %Array** + %41 = load %Array*, %Array** %40, align 8 + %42 = call i64 @__quantum__rt__array_get_size_1d(%Array* %41) + %43 = sub i64 %42, 1 + br label %header__4 + +exiting__3: ; preds = %exit__4 + %44 = add i64 %37, 1 + br label %header__3 + +exit__3: ; preds = %header__3 + call void @__quantum__rt__array_update_reference_count(%Array* %0, i32 -1) + call void @__quantum__rt__string_update_reference_count(%String* %20, i32 -1) + ret void + +header__4: ; preds = %exiting__4, %body__3 + %45 = phi i64 [ 0, %body__3 ], [ %50, %exiting__4 ] + %46 = icmp sle i64 %45, %43 + br i1 %46, label %body__4, label %exit__4 + +body__4: ; preds = %header__4 + %47 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %41, i64 %45) + %48 = bitcast i8* %47 to %Result** + %49 = load %Result*, %Result** %48, align 8 + call void @__quantum__rt__result_update_reference_count(%Result* %49, i32 -1) + br label %exiting__4 + +exiting__4: ; preds = %body__4 + %50 = add i64 %45, 1 + br label %header__4 + +exit__4: ; preds = %header__4 + call void @__quantum__rt__array_update_reference_count(%Array* %41, i32 -1) + br label %exiting__3 +} + +declare void @__quantum__rt__message(%String*) + +declare %String* @__quantum__rt__string_create(i8*) + +declare void @__quantum__rt__string_update_reference_count(%String*, i32) + +declare %String* @__quantum__rt__string_concatenate(%String*, %String*) + +declare %String* @__quantum__rt__result_to_string(%Result*) + +attributes #0 = { "InteropFriendly" } +attributes #1 = { "EntryPoint" } diff --git a/src/QirTools/pyqir/build.ps1 b/src/QirTools/pyqir/build.ps1 index 6fc2d2e98f..d1478b4e1e 100644 --- a/src/QirTools/pyqir/build.ps1 +++ b/src/QirTools/pyqir/build.ps1 @@ -1,6 +1,8 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. +. (Join-Path $PSScriptRoot .. .. .. build "utils.ps1") + if (!(Test-Path function:\Get-RepoRoot)) { # git revparse uses cwd. E2E builds use a different # working dir, so we pin it to out repo (submodule in E2E) @@ -11,8 +13,6 @@ if (!(Test-Path function:\Get-RepoRoot)) { } } -. (Join-Path (Get-RepoRoot) build "utils.ps1") - function Use-ExternalLlvmInstallation { Write-Vso "Using LLVM installation specified by AQ_LLVM_EXTERNAL_DIR" Assert (Test-Path $env:AQ_LLVM_EXTERNAL_DIR) "AQ_LLVM_EXTERNAL_DIR folder does not exist" diff --git a/src/QirTools/pyqir/pyqir/__init__.py b/src/QirTools/pyqir/pyqir/__init__.py index a5f45dd486..ff2f556384 100644 --- a/src/QirTools/pyqir/pyqir/__init__.py +++ b/src/QirTools/pyqir/pyqir/__init__.py @@ -404,7 +404,8 @@ def get_block_by_name(self, name: str): :return: the QirBlock with that name or None :rtype: QirBlock """ - if (b := self.func.get_block_by_name(name)) is not None: + b = self.func.get_block_by_name(name) + if b is not None: return QirBlock(b) return None @@ -419,7 +420,8 @@ def get_instruction_by_output_name(self, name: str): :return: the QirInstruction that defines that variable or None :rtype: QirInstruction """ - if (instr := self.func.get_instruction_by_output_name(name)) is not None: + instr = self.func.get_instruction_by_output_name(name) + if instr is not None: return QirInstruction(instr) return None @@ -582,7 +584,6 @@ def output_name(self): def type(self): return QirType(self.instr.type) - class QirOpInstr(QirInstruction): @property def target_operands(self): diff --git a/src/QirTools/pyqir/pytest.ll b/src/QirTools/pyqir/pytest.ll new file mode 100644 index 0000000000..707c6bf431 --- /dev/null +++ b/src/QirTools/pyqir/pytest.ll @@ -0,0 +1,582 @@ +; ModuleID = 'sample' +source_filename = "C:\\Users\\iadavis\\dev\\qsharp-compiler\\src\\QirTools\\pyqir\\qirlib\\src\\emit\\qir\\module.ll" + +%Range = type { i64, i64, i64 } +%Array = type opaque +%Qubit = type opaque +%Result = type opaque +%String = type opaque + +@PauliI = internal constant i2 0 +@PauliX = internal constant i2 1 +@PauliY = internal constant i2 -1 +@PauliZ = internal constant i2 -2 +@EmptyRange = internal constant %Range { i64 0, i64 1, i64 -1 } +@0 = internal constant [3 x i8] c", \00" +@1 = internal constant [2 x i8] c"[\00" +@2 = internal constant [3 x i8] c", \00" +@3 = internal constant [2 x i8] c"[\00" +@4 = internal constant [2 x i8] c"]\00" +@5 = internal constant [2 x i8] c"]\00" + +define internal %Array* @QuantumApplication__Run__body() { +entry: + %q0 = call %Qubit* @__quantum__rt__qubit_allocate() + %q1 = call %Qubit* @__quantum__rt__qubit_allocate() + %q2 = call %Qubit* @__quantum__rt__qubit_allocate() + %q3 = call %Qubit* @__quantum__rt__qubit_allocate() + %control0 = call %Qubit* @__quantum__rt__qubit_allocate() + %results = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 3) + %c = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 4) + %c_0_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %c, i64 0) + %c_result_0 = bitcast i8* %c_0_raw to %Result** + %zero_0 = call %Result* @__quantum__rt__result_get_zero() + call void @__quantum__rt__result_update_reference_count(%Result* %zero_0, i32 1) + store %Result* %zero_0, %Result** %c_result_0, align 8 + %c_1_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %c, i64 1) + %c_result_1 = bitcast i8* %c_1_raw to %Result** + %zero_1 = call %Result* @__quantum__rt__result_get_zero() + call void @__quantum__rt__result_update_reference_count(%Result* %zero_1, i32 1) + store %Result* %zero_1, %Result** %c_result_1, align 8 + %c_2_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %c, i64 2) + %c_result_2 = bitcast i8* %c_2_raw to %Result** + %zero_2 = call %Result* @__quantum__rt__result_get_zero() + call void @__quantum__rt__result_update_reference_count(%Result* %zero_2, i32 1) + store %Result* %zero_2, %Result** %c_result_2, align 8 + %c_3_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %c, i64 3) + %c_result_3 = bitcast i8* %c_3_raw to %Result** + %zero_3 = call %Result* @__quantum__rt__result_get_zero() + call void @__quantum__rt__result_update_reference_count(%Result* %zero_3, i32 1) + store %Result* %zero_3, %Result** %c_result_3, align 8 + %i = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 3) + %i_0_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %i, i64 0) + %i_result_0 = bitcast i8* %i_0_raw to %Result** + %zero_01 = call %Result* @__quantum__rt__result_get_zero() + call void @__quantum__rt__result_update_reference_count(%Result* %zero_01, i32 1) + store %Result* %zero_01, %Result** %i_result_0, align 8 + %i_1_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %i, i64 1) + %i_result_1 = bitcast i8* %i_1_raw to %Result** + %zero_12 = call %Result* @__quantum__rt__result_get_zero() + call void @__quantum__rt__result_update_reference_count(%Result* %zero_12, i32 1) + store %Result* %zero_12, %Result** %i_result_1, align 8 + %i_2_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %i, i64 2) + %i_result_2 = bitcast i8* %i_2_raw to %Result** + %zero_23 = call %Result* @__quantum__rt__result_get_zero() + call void @__quantum__rt__result_update_reference_count(%Result* %zero_23, i32 1) + store %Result* %zero_23, %Result** %i_result_2, align 8 + %j = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 2) + %j_0_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %j, i64 0) + %j_result_0 = bitcast i8* %j_0_raw to %Result** + %zero_04 = call %Result* @__quantum__rt__result_get_zero() + call void @__quantum__rt__result_update_reference_count(%Result* %zero_04, i32 1) + store %Result* %zero_04, %Result** %j_result_0, align 8 + %j_1_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %j, i64 1) + %j_result_1 = bitcast i8* %j_1_raw to %Result** + %zero_15 = call %Result* @__quantum__rt__result_get_zero() + call void @__quantum__rt__result_update_reference_count(%Result* %zero_15, i32 1) + store %Result* %zero_15, %Result** %j_result_1, align 8 + %results_result_tmp_0_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %results, i64 0) + %results_result_tmp_result_0 = bitcast i8* %results_result_tmp_0_raw to %Array** + store %Array* %c, %Array** %results_result_tmp_result_0, align 8 + %results_result_tmp_1_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %results, i64 1) + %results_result_tmp_result_1 = bitcast i8* %results_result_tmp_1_raw to %Array** + store %Array* %i, %Array** %results_result_tmp_result_1, align 8 + %results_result_tmp_2_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %results, i64 2) + %results_result_tmp_result_2 = bitcast i8* %results_result_tmp_2_raw to %Array** + store %Array* %j, %Array** %results_result_tmp_result_2, align 8 + %__controlQubits__ = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) + %__controlQubits__0_result_tmp_0_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %__controlQubits__, i64 0) + %__controlQubits__0_result_tmp_result_0 = bitcast i8* %__controlQubits__0_result_tmp_0_raw to %Qubit** + store %Qubit* %q0, %Qubit** %__controlQubits__0_result_tmp_result_0, align 8 + call void @Microsoft__Quantum__Intrinsic__X__ctl(%Array* %__controlQubits__, %Qubit* %control0) + call void @__quantum__rt__array_update_reference_count(%Array* %__controlQubits__, i32 -1) + %__controlQubits__6 = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) + %__controlQubits__0_result_tmp_0_raw7 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %__controlQubits__6, i64 0) + %__controlQubits__0_result_tmp_result_08 = bitcast i8* %__controlQubits__0_result_tmp_0_raw7 to %Qubit** + store %Qubit* %q1, %Qubit** %__controlQubits__0_result_tmp_result_08, align 8 + call void @Microsoft__Quantum__Intrinsic__Z__ctl(%Array* %__controlQubits__6, %Qubit* %control0) + call void @__quantum__rt__array_update_reference_count(%Array* %__controlQubits__6, i32 -1) + call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %q0) + call void @Microsoft__Quantum__Intrinsic__Reset__body(%Qubit* %q0) + call void @Microsoft__Quantum__Intrinsic__Rx__body(double 1.500000e+01, %Qubit* %q1) + call void @Microsoft__Quantum__Intrinsic__Ry__body(double 1.600000e+01, %Qubit* %q2) + call void @Microsoft__Quantum__Intrinsic__Rz__body(double 1.700000e+01, %Qubit* %q3) + call void @Microsoft__Quantum__Intrinsic__S__body(%Qubit* %q0) + call void @Microsoft__Quantum__Intrinsic__S__adj(%Qubit* %q1) + call void @Microsoft__Quantum__Intrinsic__T__body(%Qubit* %q2) + call void @Microsoft__Quantum__Intrinsic__T__adj(%Qubit* %q3) + call void @Microsoft__Quantum__Intrinsic__X__body(%Qubit* %q0) + call void @Microsoft__Quantum__Intrinsic__Y__body(%Qubit* %q1) + call void @Microsoft__Quantum__Intrinsic__Z__body(%Qubit* %q2) + %measurement = call %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %q0) + %c0_0_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %c, i64 0) + %c0_result_0 = bitcast i8* %c0_0_raw to %Result** + %existing_value = load %Result*, %Result** %c0_result_0, align 8 + call void @__quantum__rt__result_update_reference_count(%Result* %existing_value, i32 -1) + call void @__quantum__rt__result_update_reference_count(%Result* %measurement, i32 1) + store %Result* %measurement, %Result** %c0_result_0, align 8 + %measurement9 = call %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %q1) + %c1_1_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %c, i64 1) + %c1_result_1 = bitcast i8* %c1_1_raw to %Result** + %existing_value10 = load %Result*, %Result** %c1_result_1, align 8 + call void @__quantum__rt__result_update_reference_count(%Result* %existing_value10, i32 -1) + call void @__quantum__rt__result_update_reference_count(%Result* %measurement9, i32 1) + store %Result* %measurement9, %Result** %c1_result_1, align 8 + %measurement11 = call %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %q2) + %c2_2_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %c, i64 2) + %c2_result_2 = bitcast i8* %c2_2_raw to %Result** + %existing_value12 = load %Result*, %Result** %c2_result_2, align 8 + call void @__quantum__rt__result_update_reference_count(%Result* %existing_value12, i32 -1) + call void @__quantum__rt__result_update_reference_count(%Result* %measurement11, i32 1) + store %Result* %measurement11, %Result** %c2_result_2, align 8 + %measurement13 = call %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %q3) + %c3_3_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %c, i64 3) + %c3_result_3 = bitcast i8* %c3_3_raw to %Result** + %existing_value14 = load %Result*, %Result** %c3_result_3, align 8 + call void @__quantum__rt__result_update_reference_count(%Result* %existing_value14, i32 -1) + call void @__quantum__rt__result_update_reference_count(%Result* %measurement13, i32 1) + store %Result* %measurement13, %Result** %c3_result_3, align 8 + call void @__quantum__rt__qubit_release(%Qubit* %q1) + call void @__quantum__rt__qubit_release(%Qubit* %q2) + call void @__quantum__rt__qubit_release(%Qubit* %q3) + call void @__quantum__rt__qubit_release(%Qubit* %control0) + call void @__quantum__rt__qubit_release(%Qubit* %q0) + ret %Array* %results +} + +declare %Qubit* @__quantum__rt__qubit_allocate() + +declare void @__quantum__rt__qubit_release(%Qubit*) + +declare %Array* @__quantum__rt__array_create_1d(i32, i64) + +declare i8* @__quantum__rt__array_get_element_ptr_1d(%Array*, i64) + +declare %Result* @__quantum__rt__result_get_zero() + +declare void @__quantum__rt__result_update_reference_count(%Result*, i32) + +declare void @__quantum__rt__array_update_alias_count(%Array*, i32) + +declare i64 @__quantum__rt__array_get_size_1d(%Array*) + +declare void @__quantum__rt__array_update_reference_count(%Array*, i32) + +declare void @__quantum__qis__x__body(%Qubit*) + +declare void @__quantum__qis__x__ctl(%Array*, %Qubit*) + +declare void @__quantum__qis__y__body(%Qubit*) + +declare void @__quantum__qis__z__body(%Qubit*) + +declare void @__quantum__qis__z__ctl(%Array*, %Qubit*) + +declare void @__quantum__qis__h__body(%Qubit*) + +define internal %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %qubit) { +entry: + %bases = call %Array* @__quantum__rt__array_create_1d(i32 1, i64 1) + %0 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %bases, i64 0) + %1 = bitcast i8* %0 to i2* + %2 = load i2, i2* @PauliZ, align 1 + store i2 %2, i2* %1, align 1 + call void @__quantum__rt__array_update_alias_count(%Array* %bases, i32 1) + %qubits = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) + %3 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qubits, i64 0) + %4 = bitcast i8* %3 to %Qubit** + store %Qubit* %qubit, %Qubit** %4, align 8 + call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i32 1) + %5 = call %Result* @__quantum__qis__measure__body(%Array* %bases, %Array* %qubits) + call void @__quantum__rt__array_update_alias_count(%Array* %bases, i32 -1) + call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i32 -1) + call void @__quantum__rt__array_update_reference_count(%Array* %bases, i32 -1) + call void @__quantum__rt__array_update_reference_count(%Array* %qubits, i32 -1) + ret %Result* %5 +} + +define internal void @Microsoft__Quantum__Intrinsic__Reset__body(%Qubit* %qubit) { +entry: + %0 = call %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %qubit) + %1 = call %Result* @__quantum__rt__result_get_one() + %2 = call i1 @__quantum__rt__result_equal(%Result* %0, %Result* %1) + call void @__quantum__rt__result_update_reference_count(%Result* %0, i32 -1) + br i1 %2, label %then0__1, label %continue__1 + +then0__1: ; preds = %entry + call void @__quantum__qis__x__body(%Qubit* %qubit) + br label %continue__1 + +continue__1: ; preds = %then0__1, %entry + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Rx__body(double %theta, %Qubit* %qubit) { +entry: + %pauli = load i2, i2* @PauliX, align 1 + call void @__quantum__qis__r__body(i2 %pauli, double %theta, %Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Ry__body(double %theta, %Qubit* %qubit) { +entry: + %pauli = load i2, i2* @PauliY, align 1 + call void @__quantum__qis__r__body(i2 %pauli, double %theta, %Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Rz__body(double %theta, %Qubit* %qubit) { +entry: + %pauli = load i2, i2* @PauliZ, align 1 + call void @__quantum__qis__r__body(i2 %pauli, double %theta, %Qubit* %qubit) + ret void +} + +declare void @__quantum__qis__s__body(%Qubit*) + +declare void @__quantum__qis__s__adj(%Qubit*) + +declare void @__quantum__qis__t__body(%Qubit*) + +declare void @__quantum__qis__t__adj(%Qubit*) + +define internal void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %qubit) { +entry: + call void @__quantum__qis__h__body(%Qubit* %qubit) + ret void +} + +declare %Result* @__quantum__qis__measure__body(%Array*, %Array*) + +declare void @__quantum__qis__r__body(i2, double, %Qubit*) + +declare %Result* @__quantum__rt__result_get_one() + +declare i1 @__quantum__rt__result_equal(%Result*, %Result*) + +define internal void @Microsoft__Quantum__Intrinsic__S__body(%Qubit* %qubit) { +entry: + call void @__quantum__qis__s__body(%Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__S__adj(%Qubit* %qubit) { +entry: + call void @__quantum__qis__s__adj(%Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__T__body(%Qubit* %qubit) { +entry: + call void @__quantum__qis__t__body(%Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__T__adj(%Qubit* %qubit) { +entry: + call void @__quantum__qis__t__adj(%Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__X__body(%Qubit* %qubit) { +entry: + call void @__quantum__qis__x__body(%Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__X__ctl(%Array* %__controlQubits__, %Qubit* %qubit) { +entry: + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 1) + call void @__quantum__qis__x__ctl(%Array* %__controlQubits__, %Qubit* %qubit) + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 -1) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Y__body(%Qubit* %qubit) { +entry: + call void @__quantum__qis__y__body(%Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Z__body(%Qubit* %qubit) { +entry: + call void @__quantum__qis__z__body(%Qubit* %qubit) + ret void +} + +define internal void @Microsoft__Quantum__Intrinsic__Z__ctl(%Array* %__controlQubits__, %Qubit* %qubit) { +entry: + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 1) + call void @__quantum__qis__z__ctl(%Array* %__controlQubits__, %Qubit* %qubit) + call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 -1) + ret void +} + +define { i64, i8* }* @QuantumApplication__Run__Interop() #0 { +entry: + %0 = call %Array* @QuantumApplication__Run__body() + %1 = call i64 @__quantum__rt__array_get_size_1d(%Array* %0) + %2 = mul i64 %1, 8 + %3 = call i8* @__quantum__rt__memory_allocate(i64 %2) + %4 = ptrtoint i8* %3 to i64 + %5 = sub i64 %1, 1 + br label %header__1 + +header__1: ; preds = %exiting__1, %entry + %6 = phi i64 [ 0, %entry ], [ %19, %exiting__1 ] + %7 = icmp sle i64 %6, %5 + br i1 %7, label %body__1, label %exit__1 + +body__1: ; preds = %header__1 + %8 = mul i64 %6, 8 + %9 = add i64 %4, %8 + %10 = inttoptr i64 %9 to { i64, i8* }** + %11 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %0, i64 %6) + %12 = bitcast i8* %11 to %Array** + %13 = load %Array*, %Array** %12, align 8 + %14 = call i64 @__quantum__rt__array_get_size_1d(%Array* %13) + %15 = mul i64 %14, 1 + %16 = call i8* @__quantum__rt__memory_allocate(i64 %15) + %17 = ptrtoint i8* %16 to i64 + %18 = sub i64 %14, 1 + br label %header__2 + +exiting__1: ; preds = %exit__2 + %19 = add i64 %6, 1 + br label %header__1 + +exit__1: ; preds = %header__1 + %20 = call i8* @__quantum__rt__memory_allocate(i64 ptrtoint ({ i64, i8* }* getelementptr ({ i64, i8* }, { i64, i8* }* null, i32 1) to i64)) + %21 = bitcast i8* %20 to { i64, i8* }* + %22 = getelementptr { i64, i8* }, { i64, i8* }* %21, i64 0, i32 0 + store i64 %1, i64* %22, align 4 + %23 = getelementptr { i64, i8* }, { i64, i8* }* %21, i64 0, i32 1 + store i8* %3, i8** %23, align 8 + %24 = sub i64 %1, 1 + br label %header__3 + +header__2: ; preds = %exiting__2, %body__1 + %25 = phi i64 [ 0, %body__1 ], [ %36, %exiting__2 ] + %26 = icmp sle i64 %25, %18 + br i1 %26, label %body__2, label %exit__2 + +body__2: ; preds = %header__2 + %27 = mul i64 %25, 1 + %28 = add i64 %17, %27 + %29 = inttoptr i64 %28 to i8* + %30 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %13, i64 %25) + %31 = bitcast i8* %30 to %Result** + %32 = load %Result*, %Result** %31, align 8 + %33 = call %Result* @__quantum__rt__result_get_zero() + %34 = call i1 @__quantum__rt__result_equal(%Result* %32, %Result* %33) + %35 = select i1 %34, i8 0, i8 -1 + store i8 %35, i8* %29, align 1 + br label %exiting__2 + +exiting__2: ; preds = %body__2 + %36 = add i64 %25, 1 + br label %header__2 + +exit__2: ; preds = %header__2 + %37 = call i8* @__quantum__rt__memory_allocate(i64 ptrtoint ({ i64, i8* }* getelementptr ({ i64, i8* }, { i64, i8* }* null, i32 1) to i64)) + %38 = bitcast i8* %37 to { i64, i8* }* + %39 = getelementptr { i64, i8* }, { i64, i8* }* %38, i64 0, i32 0 + store i64 %14, i64* %39, align 4 + %40 = getelementptr { i64, i8* }, { i64, i8* }* %38, i64 0, i32 1 + store i8* %16, i8** %40, align 8 + store { i64, i8* }* %38, { i64, i8* }** %10, align 8 + br label %exiting__1 + +header__3: ; preds = %exiting__3, %exit__1 + %41 = phi i64 [ 0, %exit__1 ], [ %48, %exiting__3 ] + %42 = icmp sle i64 %41, %24 + br i1 %42, label %body__3, label %exit__3 + +body__3: ; preds = %header__3 + %43 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %0, i64 %41) + %44 = bitcast i8* %43 to %Array** + %45 = load %Array*, %Array** %44, align 8 + %46 = call i64 @__quantum__rt__array_get_size_1d(%Array* %45) + %47 = sub i64 %46, 1 + br label %header__4 + +exiting__3: ; preds = %exit__4 + %48 = add i64 %41, 1 + br label %header__3 + +exit__3: ; preds = %header__3 + call void @__quantum__rt__array_update_reference_count(%Array* %0, i32 -1) + ret { i64, i8* }* %21 + +header__4: ; preds = %exiting__4, %body__3 + %49 = phi i64 [ 0, %body__3 ], [ %54, %exiting__4 ] + %50 = icmp sle i64 %49, %47 + br i1 %50, label %body__4, label %exit__4 + +body__4: ; preds = %header__4 + %51 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %45, i64 %49) + %52 = bitcast i8* %51 to %Result** + %53 = load %Result*, %Result** %52, align 8 + call void @__quantum__rt__result_update_reference_count(%Result* %53, i32 -1) + br label %exiting__4 + +exiting__4: ; preds = %body__4 + %54 = add i64 %49, 1 + br label %header__4 + +exit__4: ; preds = %header__4 + call void @__quantum__rt__array_update_reference_count(%Array* %45, i32 -1) + br label %exiting__3 +} + +declare i8* @__quantum__rt__memory_allocate(i64) + +define void @QuantumApplication__Run() #1 { +entry: + %0 = call %Array* @QuantumApplication__Run__body() + %1 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @0, i32 0, i32 0)) + %2 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @1, i32 0, i32 0)) + call void @__quantum__rt__string_update_reference_count(%String* %2, i32 1) + %3 = call i64 @__quantum__rt__array_get_size_1d(%Array* %0) + %4 = sub i64 %3, 1 + br label %header__1 + +header__1: ; preds = %exiting__1, %entry + %5 = phi %String* [ %2, %entry ], [ %36, %exiting__1 ] + %6 = phi i64 [ 0, %entry ], [ %18, %exiting__1 ] + %7 = icmp sle i64 %6, %4 + br i1 %7, label %body__1, label %exit__1 + +body__1: ; preds = %header__1 + %8 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %0, i64 %6) + %9 = bitcast i8* %8 to %Array** + %10 = load %Array*, %Array** %9, align 8 + %11 = icmp ne %String* %5, %2 + br i1 %11, label %condTrue__1, label %condContinue__1 + +condTrue__1: ; preds = %body__1 + %12 = call %String* @__quantum__rt__string_concatenate(%String* %5, %String* %1) + call void @__quantum__rt__string_update_reference_count(%String* %5, i32 -1) + br label %condContinue__1 + +condContinue__1: ; preds = %condTrue__1, %body__1 + %13 = phi %String* [ %12, %condTrue__1 ], [ %5, %body__1 ] + %14 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @2, i32 0, i32 0)) + %15 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @3, i32 0, i32 0)) + call void @__quantum__rt__string_update_reference_count(%String* %15, i32 1) + %16 = call i64 @__quantum__rt__array_get_size_1d(%Array* %10) + %17 = sub i64 %16, 1 + br label %header__2 + +exiting__1: ; preds = %exit__2 + %18 = add i64 %6, 1 + br label %header__1 + +exit__1: ; preds = %header__1 + %19 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @5, i32 0, i32 0)) + %20 = call %String* @__quantum__rt__string_concatenate(%String* %5, %String* %19) + call void @__quantum__rt__string_update_reference_count(%String* %5, i32 -1) + call void @__quantum__rt__string_update_reference_count(%String* %19, i32 -1) + call void @__quantum__rt__string_update_reference_count(%String* %1, i32 -1) + call void @__quantum__rt__string_update_reference_count(%String* %2, i32 -1) + call void @__quantum__rt__message(%String* %20) + %21 = sub i64 %3, 1 + br label %header__3 + +header__2: ; preds = %exiting__2, %condContinue__1 + %22 = phi %String* [ %15, %condContinue__1 ], [ %32, %exiting__2 ] + %23 = phi i64 [ 0, %condContinue__1 ], [ %33, %exiting__2 ] + %24 = icmp sle i64 %23, %17 + br i1 %24, label %body__2, label %exit__2 + +body__2: ; preds = %header__2 + %25 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %10, i64 %23) + %26 = bitcast i8* %25 to %Result** + %27 = load %Result*, %Result** %26, align 8 + %28 = icmp ne %String* %22, %15 + br i1 %28, label %condTrue__2, label %condContinue__2 + +condTrue__2: ; preds = %body__2 + %29 = call %String* @__quantum__rt__string_concatenate(%String* %22, %String* %14) + call void @__quantum__rt__string_update_reference_count(%String* %22, i32 -1) + br label %condContinue__2 + +condContinue__2: ; preds = %condTrue__2, %body__2 + %30 = phi %String* [ %29, %condTrue__2 ], [ %22, %body__2 ] + %31 = call %String* @__quantum__rt__result_to_string(%Result* %27) + %32 = call %String* @__quantum__rt__string_concatenate(%String* %30, %String* %31) + call void @__quantum__rt__string_update_reference_count(%String* %30, i32 -1) + call void @__quantum__rt__string_update_reference_count(%String* %31, i32 -1) + br label %exiting__2 + +exiting__2: ; preds = %condContinue__2 + %33 = add i64 %23, 1 + br label %header__2 + +exit__2: ; preds = %header__2 + %34 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @4, i32 0, i32 0)) + %35 = call %String* @__quantum__rt__string_concatenate(%String* %22, %String* %34) + call void @__quantum__rt__string_update_reference_count(%String* %22, i32 -1) + call void @__quantum__rt__string_update_reference_count(%String* %34, i32 -1) + call void @__quantum__rt__string_update_reference_count(%String* %14, i32 -1) + call void @__quantum__rt__string_update_reference_count(%String* %15, i32 -1) + %36 = call %String* @__quantum__rt__string_concatenate(%String* %13, %String* %35) + call void @__quantum__rt__string_update_reference_count(%String* %13, i32 -1) + call void @__quantum__rt__string_update_reference_count(%String* %35, i32 -1) + br label %exiting__1 + +header__3: ; preds = %exiting__3, %exit__1 + %37 = phi i64 [ 0, %exit__1 ], [ %44, %exiting__3 ] + %38 = icmp sle i64 %37, %21 + br i1 %38, label %body__3, label %exit__3 + +body__3: ; preds = %header__3 + %39 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %0, i64 %37) + %40 = bitcast i8* %39 to %Array** + %41 = load %Array*, %Array** %40, align 8 + %42 = call i64 @__quantum__rt__array_get_size_1d(%Array* %41) + %43 = sub i64 %42, 1 + br label %header__4 + +exiting__3: ; preds = %exit__4 + %44 = add i64 %37, 1 + br label %header__3 + +exit__3: ; preds = %header__3 + call void @__quantum__rt__array_update_reference_count(%Array* %0, i32 -1) + call void @__quantum__rt__string_update_reference_count(%String* %20, i32 -1) + ret void + +header__4: ; preds = %exiting__4, %body__3 + %45 = phi i64 [ 0, %body__3 ], [ %50, %exiting__4 ] + %46 = icmp sle i64 %45, %43 + br i1 %46, label %body__4, label %exit__4 + +body__4: ; preds = %header__4 + %47 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %41, i64 %45) + %48 = bitcast i8* %47 to %Result** + %49 = load %Result*, %Result** %48, align 8 + call void @__quantum__rt__result_update_reference_count(%Result* %49, i32 -1) + br label %exiting__4 + +exiting__4: ; preds = %body__4 + %50 = add i64 %45, 1 + br label %header__4 + +exit__4: ; preds = %header__4 + call void @__quantum__rt__array_update_reference_count(%Array* %41, i32 -1) + br label %exiting__3 +} + +declare void @__quantum__rt__message(%String*) + +declare %String* @__quantum__rt__string_create(i8*) + +declare void @__quantum__rt__string_update_reference_count(%String*, i32) + +declare %String* @__quantum__rt__string_concatenate(%String*, %String*) + +declare %String* @__quantum__rt__result_to_string(%Result*) + +attributes #0 = { "InteropFriendly" } +attributes #1 = { "EntryPoint" } From ab6739465a7f97b299921832672ae8f6b4ee7360 Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Mon, 18 Oct 2021 23:18:07 -0700 Subject: [PATCH 17/26] fix bug in QirOpInstr --- src/QirTools/pyqir/pyqir/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/QirTools/pyqir/pyqir/__init__.py b/src/QirTools/pyqir/pyqir/__init__.py index ff2f556384..2bc3310f9b 100644 --- a/src/QirTools/pyqir/pyqir/__init__.py +++ b/src/QirTools/pyqir/pyqir/__init__.py @@ -587,7 +587,7 @@ def type(self): class QirOpInstr(QirInstruction): @property def target_operands(self): - return list(map(QirOperand, self.target_operands)) + return list(map(QirOperand, self.instr.target_operands)) class QirAddInstr(QirOpInstr): pass From 3c3812d03929700ef1151af0e75fb6ec0f672947 Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Tue, 19 Oct 2021 01:24:02 -0700 Subject: [PATCH 18/26] Add predicate for comparisons --- src/QirTools/pyqir/pyqir/__init__.py | 8 ++++++-- src/QirTools/pyqir/src/parser.rs | 20 ++++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/QirTools/pyqir/pyqir/__init__.py b/src/QirTools/pyqir/pyqir/__init__.py index 2bc3310f9b..d388336dc3 100644 --- a/src/QirTools/pyqir/pyqir/__init__.py +++ b/src/QirTools/pyqir/pyqir/__init__.py @@ -647,10 +647,14 @@ class QirFNegInstr(QirOpInstr): pass class QirICmpInstr(QirOpInstr): - pass + @property + def predicate(self): + return self.instr.icmp_predicate class QirFCmpInstr(QirOpInstr): - pass + @property + def predicate(self): + return self.instr.fcmp_predicate class QirPhiInstr(QirInstruction): @property diff --git a/src/QirTools/pyqir/src/parser.rs b/src/QirTools/pyqir/src/parser.rs index 1cad1c1a13..e3bd72ec53 100644 --- a/src/QirTools/pyqir/src/parser.rs +++ b/src/QirTools/pyqir/src/parser.rs @@ -502,11 +502,31 @@ impl PyQirInstruction { matches!(self.instr, llvm_ir::Instruction::ICmp(_)) } + #[getter] + fn get_icmp_predicate(&self) -> Option { + Some( + llvm_ir::instruction::ICmp::try_from(self.instr.clone()) + .ok()? + .predicate + .to_string(), + ) + } + #[getter] fn get_is_fcmp(&self) -> bool { matches!(self.instr, llvm_ir::Instruction::FCmp(_)) } + #[getter] + fn get_fcmp_predicate(&self) -> Option { + Some( + llvm_ir::instruction::FCmp::try_from(self.instr.clone()) + .ok()? + .predicate + .to_string(), + ) + } + #[getter] fn get_is_phi(&self) -> bool { matches!(self.instr, llvm_ir::Instruction::Phi(_)) From 4599ba315bb9e16ef7b4bf8c5315620ca513d58a Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Tue, 19 Oct 2021 01:49:53 -0700 Subject: [PATCH 19/26] Add missing phi subclass handling --- src/QirTools/pyqir/pyqir/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/QirTools/pyqir/pyqir/__init__.py b/src/QirTools/pyqir/pyqir/__init__.py index d388336dc3..669d2706dd 100644 --- a/src/QirTools/pyqir/pyqir/__init__.py +++ b/src/QirTools/pyqir/pyqir/__init__.py @@ -570,6 +570,8 @@ def __new__(cls, instr: PyQirInstruction): return super().__new__(QirICmpInstr) elif instr.is_fcmp: return super().__new__(QirFCmpInstr) + elif instr.is_phi: + return super().__new__(QirPhiInstr) else: return super().__new__(cls) From f43dd91bc2fddb28fc11e50abac78edb3e2174fd Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Tue, 19 Oct 2021 09:49:38 -0700 Subject: [PATCH 20/26] Fix recursion bug in QirBlock --- src/QirTools/pyqir/pyqir/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/QirTools/pyqir/pyqir/__init__.py b/src/QirTools/pyqir/pyqir/__init__.py index 669d2706dd..6b72d46199 100644 --- a/src/QirTools/pyqir/pyqir/__init__.py +++ b/src/QirTools/pyqir/pyqir/__init__.py @@ -516,7 +516,7 @@ def get_phi_pairs_by_source_name(self, name: str): :return: the list of name-value pairs for the given source block name :rtype: list[(str, QirOperand)] """ - return list(map(lambda p: (p[0], QirOperand(p[1])) ,self.get_phi_pairs_by_source_name(name))) + return list(map(lambda p: (p[0], QirOperand(p[1])) ,self.block.get_phi_pairs_by_source_name(name))) class QirInstruction: def __new__(cls, instr: PyQirInstruction): From a5419eed86bc7b4def9f98895fcc9374c3d55d6c Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Tue, 19 Oct 2021 10:00:53 -0700 Subject: [PATCH 21/26] Fix unintended repo changes --- src/QirTools/pyqir/.gitignore | 2 +- src/QirTools/pyqir/bell_measure.ll | 502 ------------------- src/QirTools/pyqir/bell_no_measure.ll | 474 ------------------ src/QirTools/pyqir/bernstein_vazirani.ll | 569 ---------------------- src/QirTools/pyqir/pytest.ll | 582 ----------------------- 5 files changed, 1 insertion(+), 2128 deletions(-) delete mode 100644 src/QirTools/pyqir/bell_measure.ll delete mode 100644 src/QirTools/pyqir/bell_no_measure.ll delete mode 100644 src/QirTools/pyqir/bernstein_vazirani.ll delete mode 100644 src/QirTools/pyqir/pytest.ll diff --git a/src/QirTools/pyqir/.gitignore b/src/QirTools/pyqir/.gitignore index e16cd69a70..12bcf145dc 100644 --- a/src/QirTools/pyqir/.gitignore +++ b/src/QirTools/pyqir/.gitignore @@ -155,4 +155,4 @@ Cargo.lock *.pdb # We inject version numbers into Cargo.toml, so don't want them stored in repo. -Cargo.toml \ No newline at end of file +Cargo.toml diff --git a/src/QirTools/pyqir/bell_measure.ll b/src/QirTools/pyqir/bell_measure.ll deleted file mode 100644 index 002e6be9e4..0000000000 --- a/src/QirTools/pyqir/bell_measure.ll +++ /dev/null @@ -1,502 +0,0 @@ -; ModuleID = 'Bell circuit' -source_filename = "C:\\Users\\iadavis\\dev\\qsharp-compiler\\src\\QirTools\\pyqir\\qirlib\\src\\emit\\qir\\module.ll" - -%Range = type { i64, i64, i64 } -%Array = type opaque -%Qubit = type opaque -%Result = type opaque -%String = type opaque - -@PauliI = internal constant i2 0 -@PauliX = internal constant i2 1 -@PauliY = internal constant i2 -1 -@PauliZ = internal constant i2 -2 -@EmptyRange = internal constant %Range { i64 0, i64 1, i64 -1 } -@0 = internal constant [3 x i8] c", \00" -@1 = internal constant [2 x i8] c"[\00" -@2 = internal constant [3 x i8] c", \00" -@3 = internal constant [2 x i8] c"[\00" -@4 = internal constant [2 x i8] c"]\00" -@5 = internal constant [2 x i8] c"]\00" - -define internal %Array* @QuantumApplication__Run__body() { -entry: - %qr0 = call %Qubit* @__quantum__rt__qubit_allocate() - %qr1 = call %Qubit* @__quantum__rt__qubit_allocate() - %results = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) - %qc = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 2) - %qc_0_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qc, i64 0) - %qc_result_0 = bitcast i8* %qc_0_raw to %Result** - %zero_0 = call %Result* @__quantum__rt__result_get_zero() - call void @__quantum__rt__result_update_reference_count(%Result* %zero_0, i32 1) - store %Result* %zero_0, %Result** %qc_result_0, align 8 - %qc_1_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qc, i64 1) - %qc_result_1 = bitcast i8* %qc_1_raw to %Result** - %zero_1 = call %Result* @__quantum__rt__result_get_zero() - call void @__quantum__rt__result_update_reference_count(%Result* %zero_1, i32 1) - store %Result* %zero_1, %Result** %qc_result_1, align 8 - %results_result_tmp_0_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %results, i64 0) - %results_result_tmp_result_0 = bitcast i8* %results_result_tmp_0_raw to %Array** - store %Array* %qc, %Array** %results_result_tmp_result_0, align 8 - call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %qr0) - %__controlQubits__ = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) - %__controlQubits__0_result_tmp_0_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %__controlQubits__, i64 0) - %__controlQubits__0_result_tmp_result_0 = bitcast i8* %__controlQubits__0_result_tmp_0_raw to %Qubit** - store %Qubit* %qr0, %Qubit** %__controlQubits__0_result_tmp_result_0, align 8 - call void @Microsoft__Quantum__Intrinsic__X__ctl(%Array* %__controlQubits__, %Qubit* %qr1) - call void @__quantum__rt__array_update_reference_count(%Array* %__controlQubits__, i32 -1) - %measurement = call %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %qr0) - %qc0_0_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qc, i64 0) - %qc0_result_0 = bitcast i8* %qc0_0_raw to %Result** - %existing_value = load %Result*, %Result** %qc0_result_0, align 8 - call void @__quantum__rt__result_update_reference_count(%Result* %existing_value, i32 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %measurement, i32 1) - store %Result* %measurement, %Result** %qc0_result_0, align 8 - %measurement1 = call %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %qr1) - %qc1_1_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qc, i64 1) - %qc1_result_1 = bitcast i8* %qc1_1_raw to %Result** - %existing_value2 = load %Result*, %Result** %qc1_result_1, align 8 - call void @__quantum__rt__result_update_reference_count(%Result* %existing_value2, i32 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %measurement1, i32 1) - store %Result* %measurement1, %Result** %qc1_result_1, align 8 - call void @__quantum__rt__qubit_release(%Qubit* %qr0) - call void @__quantum__rt__qubit_release(%Qubit* %qr1) - ret %Array* %results -} - -declare %Qubit* @__quantum__rt__qubit_allocate() - -declare void @__quantum__rt__qubit_release(%Qubit*) - -declare %Array* @__quantum__rt__array_create_1d(i32, i64) - -declare i8* @__quantum__rt__array_get_element_ptr_1d(%Array*, i64) - -declare %Result* @__quantum__rt__result_get_zero() - -declare void @__quantum__rt__result_update_reference_count(%Result*, i32) - -declare void @__quantum__rt__array_update_alias_count(%Array*, i32) - -declare i64 @__quantum__rt__array_get_size_1d(%Array*) - -declare void @__quantum__rt__array_update_reference_count(%Array*, i32) - -declare void @__quantum__qis__x__body(%Qubit*) - -declare void @__quantum__qis__x__ctl(%Array*, %Qubit*) - -declare void @__quantum__qis__y__body(%Qubit*) - -declare void @__quantum__qis__z__body(%Qubit*) - -declare void @__quantum__qis__z__ctl(%Array*, %Qubit*) - -declare void @__quantum__qis__h__body(%Qubit*) - -define internal %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %qubit) { -entry: - %bases = call %Array* @__quantum__rt__array_create_1d(i32 1, i64 1) - %0 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %bases, i64 0) - %1 = bitcast i8* %0 to i2* - %2 = load i2, i2* @PauliZ, align 1 - store i2 %2, i2* %1, align 1 - call void @__quantum__rt__array_update_alias_count(%Array* %bases, i32 1) - %qubits = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) - %3 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qubits, i64 0) - %4 = bitcast i8* %3 to %Qubit** - store %Qubit* %qubit, %Qubit** %4, align 8 - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i32 1) - %5 = call %Result* @__quantum__qis__measure__body(%Array* %bases, %Array* %qubits) - call void @__quantum__rt__array_update_alias_count(%Array* %bases, i32 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i32 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %bases, i32 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %qubits, i32 -1) - ret %Result* %5 -} - -define internal void @Microsoft__Quantum__Intrinsic__Reset__body(%Qubit* %qubit) { -entry: - %0 = call %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %qubit) - %1 = call %Result* @__quantum__rt__result_get_one() - %2 = call i1 @__quantum__rt__result_equal(%Result* %0, %Result* %1) - call void @__quantum__rt__result_update_reference_count(%Result* %0, i32 -1) - br i1 %2, label %then0__1, label %continue__1 - -then0__1: ; preds = %entry - call void @__quantum__qis__x__body(%Qubit* %qubit) - br label %continue__1 - -continue__1: ; preds = %then0__1, %entry - ret void -} - -define internal void @Microsoft__Quantum__Intrinsic__Rx__body(double %theta, %Qubit* %qubit) { -entry: - %pauli = load i2, i2* @PauliX, align 1 - call void @__quantum__qis__r__body(i2 %pauli, double %theta, %Qubit* %qubit) - ret void -} - -define internal void @Microsoft__Quantum__Intrinsic__Ry__body(double %theta, %Qubit* %qubit) { -entry: - %pauli = load i2, i2* @PauliY, align 1 - call void @__quantum__qis__r__body(i2 %pauli, double %theta, %Qubit* %qubit) - ret void -} - -define internal void @Microsoft__Quantum__Intrinsic__Rz__body(double %theta, %Qubit* %qubit) { -entry: - %pauli = load i2, i2* @PauliZ, align 1 - call void @__quantum__qis__r__body(i2 %pauli, double %theta, %Qubit* %qubit) - ret void -} - -declare void @__quantum__qis__s__body(%Qubit*) - -declare void @__quantum__qis__s__adj(%Qubit*) - -declare void @__quantum__qis__t__body(%Qubit*) - -declare void @__quantum__qis__t__adj(%Qubit*) - -define internal void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %qubit) { -entry: - call void @__quantum__qis__h__body(%Qubit* %qubit) - ret void -} - -declare %Result* @__quantum__qis__measure__body(%Array*, %Array*) - -declare void @__quantum__qis__r__body(i2, double, %Qubit*) - -declare %Result* @__quantum__rt__result_get_one() - -declare i1 @__quantum__rt__result_equal(%Result*, %Result*) - -define internal void @Microsoft__Quantum__Intrinsic__S__body(%Qubit* %qubit) { -entry: - call void @__quantum__qis__s__body(%Qubit* %qubit) - ret void -} - -define internal void @Microsoft__Quantum__Intrinsic__S__adj(%Qubit* %qubit) { -entry: - call void @__quantum__qis__s__adj(%Qubit* %qubit) - ret void -} - -define internal void @Microsoft__Quantum__Intrinsic__T__body(%Qubit* %qubit) { -entry: - call void @__quantum__qis__t__body(%Qubit* %qubit) - ret void -} - -define internal void @Microsoft__Quantum__Intrinsic__T__adj(%Qubit* %qubit) { -entry: - call void @__quantum__qis__t__adj(%Qubit* %qubit) - ret void -} - -define internal void @Microsoft__Quantum__Intrinsic__X__body(%Qubit* %qubit) { -entry: - call void @__quantum__qis__x__body(%Qubit* %qubit) - ret void -} - -define internal void @Microsoft__Quantum__Intrinsic__X__ctl(%Array* %__controlQubits__, %Qubit* %qubit) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 1) - call void @__quantum__qis__x__ctl(%Array* %__controlQubits__, %Qubit* %qubit) - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 -1) - ret void -} - -define internal void @Microsoft__Quantum__Intrinsic__Y__body(%Qubit* %qubit) { -entry: - call void @__quantum__qis__y__body(%Qubit* %qubit) - ret void -} - -define internal void @Microsoft__Quantum__Intrinsic__Z__body(%Qubit* %qubit) { -entry: - call void @__quantum__qis__z__body(%Qubit* %qubit) - ret void -} - -define internal void @Microsoft__Quantum__Intrinsic__Z__ctl(%Array* %__controlQubits__, %Qubit* %qubit) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 1) - call void @__quantum__qis__z__ctl(%Array* %__controlQubits__, %Qubit* %qubit) - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 -1) - ret void -} - -define { i64, i8* }* @QuantumApplication__Run__Interop() #0 { -entry: - %0 = call %Array* @QuantumApplication__Run__body() - %1 = call i64 @__quantum__rt__array_get_size_1d(%Array* %0) - %2 = mul i64 %1, 8 - %3 = call i8* @__quantum__rt__memory_allocate(i64 %2) - %4 = ptrtoint i8* %3 to i64 - %5 = sub i64 %1, 1 - br label %header__1 - -header__1: ; preds = %exiting__1, %entry - %6 = phi i64 [ 0, %entry ], [ %19, %exiting__1 ] - %7 = icmp sle i64 %6, %5 - br i1 %7, label %body__1, label %exit__1 - -body__1: ; preds = %header__1 - %8 = mul i64 %6, 8 - %9 = add i64 %4, %8 - %10 = inttoptr i64 %9 to { i64, i8* }** - %11 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %0, i64 %6) - %12 = bitcast i8* %11 to %Array** - %13 = load %Array*, %Array** %12, align 8 - %14 = call i64 @__quantum__rt__array_get_size_1d(%Array* %13) - %15 = mul i64 %14, 1 - %16 = call i8* @__quantum__rt__memory_allocate(i64 %15) - %17 = ptrtoint i8* %16 to i64 - %18 = sub i64 %14, 1 - br label %header__2 - -exiting__1: ; preds = %exit__2 - %19 = add i64 %6, 1 - br label %header__1 - -exit__1: ; preds = %header__1 - %20 = call i8* @__quantum__rt__memory_allocate(i64 ptrtoint ({ i64, i8* }* getelementptr ({ i64, i8* }, { i64, i8* }* null, i32 1) to i64)) - %21 = bitcast i8* %20 to { i64, i8* }* - %22 = getelementptr { i64, i8* }, { i64, i8* }* %21, i64 0, i32 0 - store i64 %1, i64* %22, align 4 - %23 = getelementptr { i64, i8* }, { i64, i8* }* %21, i64 0, i32 1 - store i8* %3, i8** %23, align 8 - %24 = sub i64 %1, 1 - br label %header__3 - -header__2: ; preds = %exiting__2, %body__1 - %25 = phi i64 [ 0, %body__1 ], [ %36, %exiting__2 ] - %26 = icmp sle i64 %25, %18 - br i1 %26, label %body__2, label %exit__2 - -body__2: ; preds = %header__2 - %27 = mul i64 %25, 1 - %28 = add i64 %17, %27 - %29 = inttoptr i64 %28 to i8* - %30 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %13, i64 %25) - %31 = bitcast i8* %30 to %Result** - %32 = load %Result*, %Result** %31, align 8 - %33 = call %Result* @__quantum__rt__result_get_zero() - %34 = call i1 @__quantum__rt__result_equal(%Result* %32, %Result* %33) - %35 = select i1 %34, i8 0, i8 -1 - store i8 %35, i8* %29, align 1 - br label %exiting__2 - -exiting__2: ; preds = %body__2 - %36 = add i64 %25, 1 - br label %header__2 - -exit__2: ; preds = %header__2 - %37 = call i8* @__quantum__rt__memory_allocate(i64 ptrtoint ({ i64, i8* }* getelementptr ({ i64, i8* }, { i64, i8* }* null, i32 1) to i64)) - %38 = bitcast i8* %37 to { i64, i8* }* - %39 = getelementptr { i64, i8* }, { i64, i8* }* %38, i64 0, i32 0 - store i64 %14, i64* %39, align 4 - %40 = getelementptr { i64, i8* }, { i64, i8* }* %38, i64 0, i32 1 - store i8* %16, i8** %40, align 8 - store { i64, i8* }* %38, { i64, i8* }** %10, align 8 - br label %exiting__1 - -header__3: ; preds = %exiting__3, %exit__1 - %41 = phi i64 [ 0, %exit__1 ], [ %48, %exiting__3 ] - %42 = icmp sle i64 %41, %24 - br i1 %42, label %body__3, label %exit__3 - -body__3: ; preds = %header__3 - %43 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %0, i64 %41) - %44 = bitcast i8* %43 to %Array** - %45 = load %Array*, %Array** %44, align 8 - %46 = call i64 @__quantum__rt__array_get_size_1d(%Array* %45) - %47 = sub i64 %46, 1 - br label %header__4 - -exiting__3: ; preds = %exit__4 - %48 = add i64 %41, 1 - br label %header__3 - -exit__3: ; preds = %header__3 - call void @__quantum__rt__array_update_reference_count(%Array* %0, i32 -1) - ret { i64, i8* }* %21 - -header__4: ; preds = %exiting__4, %body__3 - %49 = phi i64 [ 0, %body__3 ], [ %54, %exiting__4 ] - %50 = icmp sle i64 %49, %47 - br i1 %50, label %body__4, label %exit__4 - -body__4: ; preds = %header__4 - %51 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %45, i64 %49) - %52 = bitcast i8* %51 to %Result** - %53 = load %Result*, %Result** %52, align 8 - call void @__quantum__rt__result_update_reference_count(%Result* %53, i32 -1) - br label %exiting__4 - -exiting__4: ; preds = %body__4 - %54 = add i64 %49, 1 - br label %header__4 - -exit__4: ; preds = %header__4 - call void @__quantum__rt__array_update_reference_count(%Array* %45, i32 -1) - br label %exiting__3 -} - -declare i8* @__quantum__rt__memory_allocate(i64) - -define void @QuantumApplication__Run() #1 { -entry: - %0 = call %Array* @QuantumApplication__Run__body() - %1 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @0, i32 0, i32 0)) - %2 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @1, i32 0, i32 0)) - call void @__quantum__rt__string_update_reference_count(%String* %2, i32 1) - %3 = call i64 @__quantum__rt__array_get_size_1d(%Array* %0) - %4 = sub i64 %3, 1 - br label %header__1 - -header__1: ; preds = %exiting__1, %entry - %5 = phi %String* [ %2, %entry ], [ %36, %exiting__1 ] - %6 = phi i64 [ 0, %entry ], [ %18, %exiting__1 ] - %7 = icmp sle i64 %6, %4 - br i1 %7, label %body__1, label %exit__1 - -body__1: ; preds = %header__1 - %8 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %0, i64 %6) - %9 = bitcast i8* %8 to %Array** - %10 = load %Array*, %Array** %9, align 8 - %11 = icmp ne %String* %5, %2 - br i1 %11, label %condTrue__1, label %condContinue__1 - -condTrue__1: ; preds = %body__1 - %12 = call %String* @__quantum__rt__string_concatenate(%String* %5, %String* %1) - call void @__quantum__rt__string_update_reference_count(%String* %5, i32 -1) - br label %condContinue__1 - -condContinue__1: ; preds = %condTrue__1, %body__1 - %13 = phi %String* [ %12, %condTrue__1 ], [ %5, %body__1 ] - %14 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @2, i32 0, i32 0)) - %15 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @3, i32 0, i32 0)) - call void @__quantum__rt__string_update_reference_count(%String* %15, i32 1) - %16 = call i64 @__quantum__rt__array_get_size_1d(%Array* %10) - %17 = sub i64 %16, 1 - br label %header__2 - -exiting__1: ; preds = %exit__2 - %18 = add i64 %6, 1 - br label %header__1 - -exit__1: ; preds = %header__1 - %19 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @5, i32 0, i32 0)) - %20 = call %String* @__quantum__rt__string_concatenate(%String* %5, %String* %19) - call void @__quantum__rt__string_update_reference_count(%String* %5, i32 -1) - call void @__quantum__rt__string_update_reference_count(%String* %19, i32 -1) - call void @__quantum__rt__string_update_reference_count(%String* %1, i32 -1) - call void @__quantum__rt__string_update_reference_count(%String* %2, i32 -1) - call void @__quantum__rt__message(%String* %20) - %21 = sub i64 %3, 1 - br label %header__3 - -header__2: ; preds = %exiting__2, %condContinue__1 - %22 = phi %String* [ %15, %condContinue__1 ], [ %32, %exiting__2 ] - %23 = phi i64 [ 0, %condContinue__1 ], [ %33, %exiting__2 ] - %24 = icmp sle i64 %23, %17 - br i1 %24, label %body__2, label %exit__2 - -body__2: ; preds = %header__2 - %25 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %10, i64 %23) - %26 = bitcast i8* %25 to %Result** - %27 = load %Result*, %Result** %26, align 8 - %28 = icmp ne %String* %22, %15 - br i1 %28, label %condTrue__2, label %condContinue__2 - -condTrue__2: ; preds = %body__2 - %29 = call %String* @__quantum__rt__string_concatenate(%String* %22, %String* %14) - call void @__quantum__rt__string_update_reference_count(%String* %22, i32 -1) - br label %condContinue__2 - -condContinue__2: ; preds = %condTrue__2, %body__2 - %30 = phi %String* [ %29, %condTrue__2 ], [ %22, %body__2 ] - %31 = call %String* @__quantum__rt__result_to_string(%Result* %27) - %32 = call %String* @__quantum__rt__string_concatenate(%String* %30, %String* %31) - call void @__quantum__rt__string_update_reference_count(%String* %30, i32 -1) - call void @__quantum__rt__string_update_reference_count(%String* %31, i32 -1) - br label %exiting__2 - -exiting__2: ; preds = %condContinue__2 - %33 = add i64 %23, 1 - br label %header__2 - -exit__2: ; preds = %header__2 - %34 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @4, i32 0, i32 0)) - %35 = call %String* @__quantum__rt__string_concatenate(%String* %22, %String* %34) - call void @__quantum__rt__string_update_reference_count(%String* %22, i32 -1) - call void @__quantum__rt__string_update_reference_count(%String* %34, i32 -1) - call void @__quantum__rt__string_update_reference_count(%String* %14, i32 -1) - call void @__quantum__rt__string_update_reference_count(%String* %15, i32 -1) - %36 = call %String* @__quantum__rt__string_concatenate(%String* %13, %String* %35) - call void @__quantum__rt__string_update_reference_count(%String* %13, i32 -1) - call void @__quantum__rt__string_update_reference_count(%String* %35, i32 -1) - br label %exiting__1 - -header__3: ; preds = %exiting__3, %exit__1 - %37 = phi i64 [ 0, %exit__1 ], [ %44, %exiting__3 ] - %38 = icmp sle i64 %37, %21 - br i1 %38, label %body__3, label %exit__3 - -body__3: ; preds = %header__3 - %39 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %0, i64 %37) - %40 = bitcast i8* %39 to %Array** - %41 = load %Array*, %Array** %40, align 8 - %42 = call i64 @__quantum__rt__array_get_size_1d(%Array* %41) - %43 = sub i64 %42, 1 - br label %header__4 - -exiting__3: ; preds = %exit__4 - %44 = add i64 %37, 1 - br label %header__3 - -exit__3: ; preds = %header__3 - call void @__quantum__rt__array_update_reference_count(%Array* %0, i32 -1) - call void @__quantum__rt__string_update_reference_count(%String* %20, i32 -1) - ret void - -header__4: ; preds = %exiting__4, %body__3 - %45 = phi i64 [ 0, %body__3 ], [ %50, %exiting__4 ] - %46 = icmp sle i64 %45, %43 - br i1 %46, label %body__4, label %exit__4 - -body__4: ; preds = %header__4 - %47 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %41, i64 %45) - %48 = bitcast i8* %47 to %Result** - %49 = load %Result*, %Result** %48, align 8 - call void @__quantum__rt__result_update_reference_count(%Result* %49, i32 -1) - br label %exiting__4 - -exiting__4: ; preds = %body__4 - %50 = add i64 %45, 1 - br label %header__4 - -exit__4: ; preds = %header__4 - call void @__quantum__rt__array_update_reference_count(%Array* %41, i32 -1) - br label %exiting__3 -} - -declare void @__quantum__rt__message(%String*) - -declare %String* @__quantum__rt__string_create(i8*) - -declare void @__quantum__rt__string_update_reference_count(%String*, i32) - -declare %String* @__quantum__rt__string_concatenate(%String*, %String*) - -declare %String* @__quantum__rt__result_to_string(%Result*) - -attributes #0 = { "InteropFriendly" } -attributes #1 = { "EntryPoint" } diff --git a/src/QirTools/pyqir/bell_no_measure.ll b/src/QirTools/pyqir/bell_no_measure.ll deleted file mode 100644 index a1a26909a8..0000000000 --- a/src/QirTools/pyqir/bell_no_measure.ll +++ /dev/null @@ -1,474 +0,0 @@ -; ModuleID = 'Bell circuit' -source_filename = "C:\\Users\\iadavis\\dev\\qsharp-compiler\\src\\QirTools\\pyqir\\qirlib\\src\\emit\\qir\\module.ll" - -%Range = type { i64, i64, i64 } -%Array = type opaque -%Qubit = type opaque -%Result = type opaque -%String = type opaque - -@PauliI = internal constant i2 0 -@PauliX = internal constant i2 1 -@PauliY = internal constant i2 -1 -@PauliZ = internal constant i2 -2 -@EmptyRange = internal constant %Range { i64 0, i64 1, i64 -1 } -@0 = internal constant [3 x i8] c", \00" -@1 = internal constant [2 x i8] c"[\00" -@2 = internal constant [3 x i8] c", \00" -@3 = internal constant [2 x i8] c"[\00" -@4 = internal constant [2 x i8] c"]\00" -@5 = internal constant [2 x i8] c"]\00" - -define internal %Array* @QuantumApplication__Run__body() { -entry: - %qr0 = call %Qubit* @__quantum__rt__qubit_allocate() - %qr1 = call %Qubit* @__quantum__rt__qubit_allocate() - %results = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 0) - call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %qr0) - %__controlQubits__ = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) - %__controlQubits__0_result_tmp_0_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %__controlQubits__, i64 0) - %__controlQubits__0_result_tmp_result_0 = bitcast i8* %__controlQubits__0_result_tmp_0_raw to %Qubit** - store %Qubit* %qr0, %Qubit** %__controlQubits__0_result_tmp_result_0, align 8 - call void @Microsoft__Quantum__Intrinsic__X__ctl(%Array* %__controlQubits__, %Qubit* %qr1) - call void @__quantum__rt__array_update_reference_count(%Array* %__controlQubits__, i32 -1) - call void @__quantum__rt__qubit_release(%Qubit* %qr0) - call void @__quantum__rt__qubit_release(%Qubit* %qr1) - ret %Array* %results -} - -declare %Qubit* @__quantum__rt__qubit_allocate() - -declare void @__quantum__rt__qubit_release(%Qubit*) - -declare %Array* @__quantum__rt__array_create_1d(i32, i64) - -declare i8* @__quantum__rt__array_get_element_ptr_1d(%Array*, i64) - -declare %Result* @__quantum__rt__result_get_zero() - -declare void @__quantum__rt__result_update_reference_count(%Result*, i32) - -declare void @__quantum__rt__array_update_alias_count(%Array*, i32) - -declare i64 @__quantum__rt__array_get_size_1d(%Array*) - -declare void @__quantum__rt__array_update_reference_count(%Array*, i32) - -declare void @__quantum__qis__x__body(%Qubit*) - -declare void @__quantum__qis__x__ctl(%Array*, %Qubit*) - -declare void @__quantum__qis__y__body(%Qubit*) - -declare void @__quantum__qis__z__body(%Qubit*) - -declare void @__quantum__qis__z__ctl(%Array*, %Qubit*) - -declare void @__quantum__qis__h__body(%Qubit*) - -define internal %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %qubit) { -entry: - %bases = call %Array* @__quantum__rt__array_create_1d(i32 1, i64 1) - %0 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %bases, i64 0) - %1 = bitcast i8* %0 to i2* - %2 = load i2, i2* @PauliZ, align 1 - store i2 %2, i2* %1, align 1 - call void @__quantum__rt__array_update_alias_count(%Array* %bases, i32 1) - %qubits = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) - %3 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qubits, i64 0) - %4 = bitcast i8* %3 to %Qubit** - store %Qubit* %qubit, %Qubit** %4, align 8 - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i32 1) - %5 = call %Result* @__quantum__qis__measure__body(%Array* %bases, %Array* %qubits) - call void @__quantum__rt__array_update_alias_count(%Array* %bases, i32 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i32 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %bases, i32 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %qubits, i32 -1) - ret %Result* %5 -} - -define internal void @Microsoft__Quantum__Intrinsic__Reset__body(%Qubit* %qubit) { -entry: - %0 = call %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %qubit) - %1 = call %Result* @__quantum__rt__result_get_one() - %2 = call i1 @__quantum__rt__result_equal(%Result* %0, %Result* %1) - call void @__quantum__rt__result_update_reference_count(%Result* %0, i32 -1) - br i1 %2, label %then0__1, label %continue__1 - -then0__1: ; preds = %entry - call void @__quantum__qis__x__body(%Qubit* %qubit) - br label %continue__1 - -continue__1: ; preds = %then0__1, %entry - ret void -} - -define internal void @Microsoft__Quantum__Intrinsic__Rx__body(double %theta, %Qubit* %qubit) { -entry: - %pauli = load i2, i2* @PauliX, align 1 - call void @__quantum__qis__r__body(i2 %pauli, double %theta, %Qubit* %qubit) - ret void -} - -define internal void @Microsoft__Quantum__Intrinsic__Ry__body(double %theta, %Qubit* %qubit) { -entry: - %pauli = load i2, i2* @PauliY, align 1 - call void @__quantum__qis__r__body(i2 %pauli, double %theta, %Qubit* %qubit) - ret void -} - -define internal void @Microsoft__Quantum__Intrinsic__Rz__body(double %theta, %Qubit* %qubit) { -entry: - %pauli = load i2, i2* @PauliZ, align 1 - call void @__quantum__qis__r__body(i2 %pauli, double %theta, %Qubit* %qubit) - ret void -} - -declare void @__quantum__qis__s__body(%Qubit*) - -declare void @__quantum__qis__s__adj(%Qubit*) - -declare void @__quantum__qis__t__body(%Qubit*) - -declare void @__quantum__qis__t__adj(%Qubit*) - -define internal void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %qubit) { -entry: - call void @__quantum__qis__h__body(%Qubit* %qubit) - ret void -} - -declare %Result* @__quantum__qis__measure__body(%Array*, %Array*) - -declare void @__quantum__qis__r__body(i2, double, %Qubit*) - -declare %Result* @__quantum__rt__result_get_one() - -declare i1 @__quantum__rt__result_equal(%Result*, %Result*) - -define internal void @Microsoft__Quantum__Intrinsic__S__body(%Qubit* %qubit) { -entry: - call void @__quantum__qis__s__body(%Qubit* %qubit) - ret void -} - -define internal void @Microsoft__Quantum__Intrinsic__S__adj(%Qubit* %qubit) { -entry: - call void @__quantum__qis__s__adj(%Qubit* %qubit) - ret void -} - -define internal void @Microsoft__Quantum__Intrinsic__T__body(%Qubit* %qubit) { -entry: - call void @__quantum__qis__t__body(%Qubit* %qubit) - ret void -} - -define internal void @Microsoft__Quantum__Intrinsic__T__adj(%Qubit* %qubit) { -entry: - call void @__quantum__qis__t__adj(%Qubit* %qubit) - ret void -} - -define internal void @Microsoft__Quantum__Intrinsic__X__body(%Qubit* %qubit) { -entry: - call void @__quantum__qis__x__body(%Qubit* %qubit) - ret void -} - -define internal void @Microsoft__Quantum__Intrinsic__X__ctl(%Array* %__controlQubits__, %Qubit* %qubit) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 1) - call void @__quantum__qis__x__ctl(%Array* %__controlQubits__, %Qubit* %qubit) - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 -1) - ret void -} - -define internal void @Microsoft__Quantum__Intrinsic__Y__body(%Qubit* %qubit) { -entry: - call void @__quantum__qis__y__body(%Qubit* %qubit) - ret void -} - -define internal void @Microsoft__Quantum__Intrinsic__Z__body(%Qubit* %qubit) { -entry: - call void @__quantum__qis__z__body(%Qubit* %qubit) - ret void -} - -define internal void @Microsoft__Quantum__Intrinsic__Z__ctl(%Array* %__controlQubits__, %Qubit* %qubit) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 1) - call void @__quantum__qis__z__ctl(%Array* %__controlQubits__, %Qubit* %qubit) - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 -1) - ret void -} - -define { i64, i8* }* @QuantumApplication__Run__Interop() #0 { -entry: - %0 = call %Array* @QuantumApplication__Run__body() - %1 = call i64 @__quantum__rt__array_get_size_1d(%Array* %0) - %2 = mul i64 %1, 8 - %3 = call i8* @__quantum__rt__memory_allocate(i64 %2) - %4 = ptrtoint i8* %3 to i64 - %5 = sub i64 %1, 1 - br label %header__1 - -header__1: ; preds = %exiting__1, %entry - %6 = phi i64 [ 0, %entry ], [ %19, %exiting__1 ] - %7 = icmp sle i64 %6, %5 - br i1 %7, label %body__1, label %exit__1 - -body__1: ; preds = %header__1 - %8 = mul i64 %6, 8 - %9 = add i64 %4, %8 - %10 = inttoptr i64 %9 to { i64, i8* }** - %11 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %0, i64 %6) - %12 = bitcast i8* %11 to %Array** - %13 = load %Array*, %Array** %12, align 8 - %14 = call i64 @__quantum__rt__array_get_size_1d(%Array* %13) - %15 = mul i64 %14, 1 - %16 = call i8* @__quantum__rt__memory_allocate(i64 %15) - %17 = ptrtoint i8* %16 to i64 - %18 = sub i64 %14, 1 - br label %header__2 - -exiting__1: ; preds = %exit__2 - %19 = add i64 %6, 1 - br label %header__1 - -exit__1: ; preds = %header__1 - %20 = call i8* @__quantum__rt__memory_allocate(i64 ptrtoint ({ i64, i8* }* getelementptr ({ i64, i8* }, { i64, i8* }* null, i32 1) to i64)) - %21 = bitcast i8* %20 to { i64, i8* }* - %22 = getelementptr { i64, i8* }, { i64, i8* }* %21, i64 0, i32 0 - store i64 %1, i64* %22, align 4 - %23 = getelementptr { i64, i8* }, { i64, i8* }* %21, i64 0, i32 1 - store i8* %3, i8** %23, align 8 - %24 = sub i64 %1, 1 - br label %header__3 - -header__2: ; preds = %exiting__2, %body__1 - %25 = phi i64 [ 0, %body__1 ], [ %36, %exiting__2 ] - %26 = icmp sle i64 %25, %18 - br i1 %26, label %body__2, label %exit__2 - -body__2: ; preds = %header__2 - %27 = mul i64 %25, 1 - %28 = add i64 %17, %27 - %29 = inttoptr i64 %28 to i8* - %30 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %13, i64 %25) - %31 = bitcast i8* %30 to %Result** - %32 = load %Result*, %Result** %31, align 8 - %33 = call %Result* @__quantum__rt__result_get_zero() - %34 = call i1 @__quantum__rt__result_equal(%Result* %32, %Result* %33) - %35 = select i1 %34, i8 0, i8 -1 - store i8 %35, i8* %29, align 1 - br label %exiting__2 - -exiting__2: ; preds = %body__2 - %36 = add i64 %25, 1 - br label %header__2 - -exit__2: ; preds = %header__2 - %37 = call i8* @__quantum__rt__memory_allocate(i64 ptrtoint ({ i64, i8* }* getelementptr ({ i64, i8* }, { i64, i8* }* null, i32 1) to i64)) - %38 = bitcast i8* %37 to { i64, i8* }* - %39 = getelementptr { i64, i8* }, { i64, i8* }* %38, i64 0, i32 0 - store i64 %14, i64* %39, align 4 - %40 = getelementptr { i64, i8* }, { i64, i8* }* %38, i64 0, i32 1 - store i8* %16, i8** %40, align 8 - store { i64, i8* }* %38, { i64, i8* }** %10, align 8 - br label %exiting__1 - -header__3: ; preds = %exiting__3, %exit__1 - %41 = phi i64 [ 0, %exit__1 ], [ %48, %exiting__3 ] - %42 = icmp sle i64 %41, %24 - br i1 %42, label %body__3, label %exit__3 - -body__3: ; preds = %header__3 - %43 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %0, i64 %41) - %44 = bitcast i8* %43 to %Array** - %45 = load %Array*, %Array** %44, align 8 - %46 = call i64 @__quantum__rt__array_get_size_1d(%Array* %45) - %47 = sub i64 %46, 1 - br label %header__4 - -exiting__3: ; preds = %exit__4 - %48 = add i64 %41, 1 - br label %header__3 - -exit__3: ; preds = %header__3 - call void @__quantum__rt__array_update_reference_count(%Array* %0, i32 -1) - ret { i64, i8* }* %21 - -header__4: ; preds = %exiting__4, %body__3 - %49 = phi i64 [ 0, %body__3 ], [ %54, %exiting__4 ] - %50 = icmp sle i64 %49, %47 - br i1 %50, label %body__4, label %exit__4 - -body__4: ; preds = %header__4 - %51 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %45, i64 %49) - %52 = bitcast i8* %51 to %Result** - %53 = load %Result*, %Result** %52, align 8 - call void @__quantum__rt__result_update_reference_count(%Result* %53, i32 -1) - br label %exiting__4 - -exiting__4: ; preds = %body__4 - %54 = add i64 %49, 1 - br label %header__4 - -exit__4: ; preds = %header__4 - call void @__quantum__rt__array_update_reference_count(%Array* %45, i32 -1) - br label %exiting__3 -} - -declare i8* @__quantum__rt__memory_allocate(i64) - -define void @QuantumApplication__Run() #1 { -entry: - %0 = call %Array* @QuantumApplication__Run__body() - %1 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @0, i32 0, i32 0)) - %2 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @1, i32 0, i32 0)) - call void @__quantum__rt__string_update_reference_count(%String* %2, i32 1) - %3 = call i64 @__quantum__rt__array_get_size_1d(%Array* %0) - %4 = sub i64 %3, 1 - br label %header__1 - -header__1: ; preds = %exiting__1, %entry - %5 = phi %String* [ %2, %entry ], [ %36, %exiting__1 ] - %6 = phi i64 [ 0, %entry ], [ %18, %exiting__1 ] - %7 = icmp sle i64 %6, %4 - br i1 %7, label %body__1, label %exit__1 - -body__1: ; preds = %header__1 - %8 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %0, i64 %6) - %9 = bitcast i8* %8 to %Array** - %10 = load %Array*, %Array** %9, align 8 - %11 = icmp ne %String* %5, %2 - br i1 %11, label %condTrue__1, label %condContinue__1 - -condTrue__1: ; preds = %body__1 - %12 = call %String* @__quantum__rt__string_concatenate(%String* %5, %String* %1) - call void @__quantum__rt__string_update_reference_count(%String* %5, i32 -1) - br label %condContinue__1 - -condContinue__1: ; preds = %condTrue__1, %body__1 - %13 = phi %String* [ %12, %condTrue__1 ], [ %5, %body__1 ] - %14 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @2, i32 0, i32 0)) - %15 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @3, i32 0, i32 0)) - call void @__quantum__rt__string_update_reference_count(%String* %15, i32 1) - %16 = call i64 @__quantum__rt__array_get_size_1d(%Array* %10) - %17 = sub i64 %16, 1 - br label %header__2 - -exiting__1: ; preds = %exit__2 - %18 = add i64 %6, 1 - br label %header__1 - -exit__1: ; preds = %header__1 - %19 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @5, i32 0, i32 0)) - %20 = call %String* @__quantum__rt__string_concatenate(%String* %5, %String* %19) - call void @__quantum__rt__string_update_reference_count(%String* %5, i32 -1) - call void @__quantum__rt__string_update_reference_count(%String* %19, i32 -1) - call void @__quantum__rt__string_update_reference_count(%String* %1, i32 -1) - call void @__quantum__rt__string_update_reference_count(%String* %2, i32 -1) - call void @__quantum__rt__message(%String* %20) - %21 = sub i64 %3, 1 - br label %header__3 - -header__2: ; preds = %exiting__2, %condContinue__1 - %22 = phi %String* [ %15, %condContinue__1 ], [ %32, %exiting__2 ] - %23 = phi i64 [ 0, %condContinue__1 ], [ %33, %exiting__2 ] - %24 = icmp sle i64 %23, %17 - br i1 %24, label %body__2, label %exit__2 - -body__2: ; preds = %header__2 - %25 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %10, i64 %23) - %26 = bitcast i8* %25 to %Result** - %27 = load %Result*, %Result** %26, align 8 - %28 = icmp ne %String* %22, %15 - br i1 %28, label %condTrue__2, label %condContinue__2 - -condTrue__2: ; preds = %body__2 - %29 = call %String* @__quantum__rt__string_concatenate(%String* %22, %String* %14) - call void @__quantum__rt__string_update_reference_count(%String* %22, i32 -1) - br label %condContinue__2 - -condContinue__2: ; preds = %condTrue__2, %body__2 - %30 = phi %String* [ %29, %condTrue__2 ], [ %22, %body__2 ] - %31 = call %String* @__quantum__rt__result_to_string(%Result* %27) - %32 = call %String* @__quantum__rt__string_concatenate(%String* %30, %String* %31) - call void @__quantum__rt__string_update_reference_count(%String* %30, i32 -1) - call void @__quantum__rt__string_update_reference_count(%String* %31, i32 -1) - br label %exiting__2 - -exiting__2: ; preds = %condContinue__2 - %33 = add i64 %23, 1 - br label %header__2 - -exit__2: ; preds = %header__2 - %34 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @4, i32 0, i32 0)) - %35 = call %String* @__quantum__rt__string_concatenate(%String* %22, %String* %34) - call void @__quantum__rt__string_update_reference_count(%String* %22, i32 -1) - call void @__quantum__rt__string_update_reference_count(%String* %34, i32 -1) - call void @__quantum__rt__string_update_reference_count(%String* %14, i32 -1) - call void @__quantum__rt__string_update_reference_count(%String* %15, i32 -1) - %36 = call %String* @__quantum__rt__string_concatenate(%String* %13, %String* %35) - call void @__quantum__rt__string_update_reference_count(%String* %13, i32 -1) - call void @__quantum__rt__string_update_reference_count(%String* %35, i32 -1) - br label %exiting__1 - -header__3: ; preds = %exiting__3, %exit__1 - %37 = phi i64 [ 0, %exit__1 ], [ %44, %exiting__3 ] - %38 = icmp sle i64 %37, %21 - br i1 %38, label %body__3, label %exit__3 - -body__3: ; preds = %header__3 - %39 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %0, i64 %37) - %40 = bitcast i8* %39 to %Array** - %41 = load %Array*, %Array** %40, align 8 - %42 = call i64 @__quantum__rt__array_get_size_1d(%Array* %41) - %43 = sub i64 %42, 1 - br label %header__4 - -exiting__3: ; preds = %exit__4 - %44 = add i64 %37, 1 - br label %header__3 - -exit__3: ; preds = %header__3 - call void @__quantum__rt__array_update_reference_count(%Array* %0, i32 -1) - call void @__quantum__rt__string_update_reference_count(%String* %20, i32 -1) - ret void - -header__4: ; preds = %exiting__4, %body__3 - %45 = phi i64 [ 0, %body__3 ], [ %50, %exiting__4 ] - %46 = icmp sle i64 %45, %43 - br i1 %46, label %body__4, label %exit__4 - -body__4: ; preds = %header__4 - %47 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %41, i64 %45) - %48 = bitcast i8* %47 to %Result** - %49 = load %Result*, %Result** %48, align 8 - call void @__quantum__rt__result_update_reference_count(%Result* %49, i32 -1) - br label %exiting__4 - -exiting__4: ; preds = %body__4 - %50 = add i64 %45, 1 - br label %header__4 - -exit__4: ; preds = %header__4 - call void @__quantum__rt__array_update_reference_count(%Array* %41, i32 -1) - br label %exiting__3 -} - -declare void @__quantum__rt__message(%String*) - -declare %String* @__quantum__rt__string_create(i8*) - -declare void @__quantum__rt__string_update_reference_count(%String*, i32) - -declare %String* @__quantum__rt__string_concatenate(%String*, %String*) - -declare %String* @__quantum__rt__result_to_string(%Result*) - -attributes #0 = { "InteropFriendly" } -attributes #1 = { "EntryPoint" } diff --git a/src/QirTools/pyqir/bernstein_vazirani.ll b/src/QirTools/pyqir/bernstein_vazirani.ll deleted file mode 100644 index 64fe28567a..0000000000 --- a/src/QirTools/pyqir/bernstein_vazirani.ll +++ /dev/null @@ -1,569 +0,0 @@ -; ModuleID = 'Bernstein-Vazirani' -source_filename = "C:\\Users\\iadavis\\dev\\qsharp-compiler\\src\\QirTools\\pyqir\\qirlib\\src\\emit\\qir\\module.ll" - -%Range = type { i64, i64, i64 } -%Array = type opaque -%Qubit = type opaque -%Result = type opaque -%String = type opaque - -@PauliI = internal constant i2 0 -@PauliX = internal constant i2 1 -@PauliY = internal constant i2 -1 -@PauliZ = internal constant i2 -2 -@EmptyRange = internal constant %Range { i64 0, i64 1, i64 -1 } -@0 = internal constant [3 x i8] c", \00" -@1 = internal constant [2 x i8] c"[\00" -@2 = internal constant [3 x i8] c", \00" -@3 = internal constant [2 x i8] c"[\00" -@4 = internal constant [2 x i8] c"]\00" -@5 = internal constant [2 x i8] c"]\00" - -define internal %Array* @QuantumApplication__Run__body() { -entry: - %input0 = call %Qubit* @__quantum__rt__qubit_allocate() - %input1 = call %Qubit* @__quantum__rt__qubit_allocate() - %input2 = call %Qubit* @__quantum__rt__qubit_allocate() - %input3 = call %Qubit* @__quantum__rt__qubit_allocate() - %input4 = call %Qubit* @__quantum__rt__qubit_allocate() - %target0 = call %Qubit* @__quantum__rt__qubit_allocate() - %results = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) - %output = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 5) - %output_0_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %output, i64 0) - %output_result_0 = bitcast i8* %output_0_raw to %Result** - %zero_0 = call %Result* @__quantum__rt__result_get_zero() - call void @__quantum__rt__result_update_reference_count(%Result* %zero_0, i32 1) - store %Result* %zero_0, %Result** %output_result_0, align 8 - %output_1_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %output, i64 1) - %output_result_1 = bitcast i8* %output_1_raw to %Result** - %zero_1 = call %Result* @__quantum__rt__result_get_zero() - call void @__quantum__rt__result_update_reference_count(%Result* %zero_1, i32 1) - store %Result* %zero_1, %Result** %output_result_1, align 8 - %output_2_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %output, i64 2) - %output_result_2 = bitcast i8* %output_2_raw to %Result** - %zero_2 = call %Result* @__quantum__rt__result_get_zero() - call void @__quantum__rt__result_update_reference_count(%Result* %zero_2, i32 1) - store %Result* %zero_2, %Result** %output_result_2, align 8 - %output_3_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %output, i64 3) - %output_result_3 = bitcast i8* %output_3_raw to %Result** - %zero_3 = call %Result* @__quantum__rt__result_get_zero() - call void @__quantum__rt__result_update_reference_count(%Result* %zero_3, i32 1) - store %Result* %zero_3, %Result** %output_result_3, align 8 - %output_4_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %output, i64 4) - %output_result_4 = bitcast i8* %output_4_raw to %Result** - %zero_4 = call %Result* @__quantum__rt__result_get_zero() - call void @__quantum__rt__result_update_reference_count(%Result* %zero_4, i32 1) - store %Result* %zero_4, %Result** %output_result_4, align 8 - %results_result_tmp_0_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %results, i64 0) - %results_result_tmp_result_0 = bitcast i8* %results_result_tmp_0_raw to %Array** - store %Array* %output, %Array** %results_result_tmp_result_0, align 8 - call void @Microsoft__Quantum__Intrinsic__X__body(%Qubit* %target0) - call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %input0) - call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %input1) - call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %input2) - call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %input3) - call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %input4) - call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %target0) - %__controlQubits__ = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) - %__controlQubits__0_result_tmp_0_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %__controlQubits__, i64 0) - %__controlQubits__0_result_tmp_result_0 = bitcast i8* %__controlQubits__0_result_tmp_0_raw to %Qubit** - store %Qubit* %input1, %Qubit** %__controlQubits__0_result_tmp_result_0, align 8 - call void @Microsoft__Quantum__Intrinsic__X__ctl(%Array* %__controlQubits__, %Qubit* %target0) - call void @__quantum__rt__array_update_reference_count(%Array* %__controlQubits__, i32 -1) - %__controlQubits__1 = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) - %__controlQubits__0_result_tmp_0_raw2 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %__controlQubits__1, i64 0) - %__controlQubits__0_result_tmp_result_03 = bitcast i8* %__controlQubits__0_result_tmp_0_raw2 to %Qubit** - store %Qubit* %input3, %Qubit** %__controlQubits__0_result_tmp_result_03, align 8 - call void @Microsoft__Quantum__Intrinsic__X__ctl(%Array* %__controlQubits__1, %Qubit* %target0) - call void @__quantum__rt__array_update_reference_count(%Array* %__controlQubits__1, i32 -1) - %__controlQubits__4 = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) - %__controlQubits__0_result_tmp_0_raw5 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %__controlQubits__4, i64 0) - %__controlQubits__0_result_tmp_result_06 = bitcast i8* %__controlQubits__0_result_tmp_0_raw5 to %Qubit** - store %Qubit* %input4, %Qubit** %__controlQubits__0_result_tmp_result_06, align 8 - call void @Microsoft__Quantum__Intrinsic__X__ctl(%Array* %__controlQubits__4, %Qubit* %target0) - call void @__quantum__rt__array_update_reference_count(%Array* %__controlQubits__4, i32 -1) - call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %input0) - call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %input1) - call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %input2) - call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %input3) - call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %input4) - %measurement = call %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %input0) - %output0_0_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %output, i64 0) - %output0_result_0 = bitcast i8* %output0_0_raw to %Result** - %existing_value = load %Result*, %Result** %output0_result_0, align 8 - call void @__quantum__rt__result_update_reference_count(%Result* %existing_value, i32 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %measurement, i32 1) - store %Result* %measurement, %Result** %output0_result_0, align 8 - %measurement7 = call %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %input1) - %output1_1_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %output, i64 1) - %output1_result_1 = bitcast i8* %output1_1_raw to %Result** - %existing_value8 = load %Result*, %Result** %output1_result_1, align 8 - call void @__quantum__rt__result_update_reference_count(%Result* %existing_value8, i32 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %measurement7, i32 1) - store %Result* %measurement7, %Result** %output1_result_1, align 8 - %measurement9 = call %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %input2) - %output2_2_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %output, i64 2) - %output2_result_2 = bitcast i8* %output2_2_raw to %Result** - %existing_value10 = load %Result*, %Result** %output2_result_2, align 8 - call void @__quantum__rt__result_update_reference_count(%Result* %existing_value10, i32 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %measurement9, i32 1) - store %Result* %measurement9, %Result** %output2_result_2, align 8 - %measurement11 = call %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %input3) - %output3_3_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %output, i64 3) - %output3_result_3 = bitcast i8* %output3_3_raw to %Result** - %existing_value12 = load %Result*, %Result** %output3_result_3, align 8 - call void @__quantum__rt__result_update_reference_count(%Result* %existing_value12, i32 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %measurement11, i32 1) - store %Result* %measurement11, %Result** %output3_result_3, align 8 - %measurement13 = call %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %input4) - %output4_4_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %output, i64 4) - %output4_result_4 = bitcast i8* %output4_4_raw to %Result** - %existing_value14 = load %Result*, %Result** %output4_result_4, align 8 - call void @__quantum__rt__result_update_reference_count(%Result* %existing_value14, i32 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %measurement13, i32 1) - store %Result* %measurement13, %Result** %output4_result_4, align 8 - call void @__quantum__rt__qubit_release(%Qubit* %input0) - call void @__quantum__rt__qubit_release(%Qubit* %input3) - call void @__quantum__rt__qubit_release(%Qubit* %target0) - call void @__quantum__rt__qubit_release(%Qubit* %input2) - call void @__quantum__rt__qubit_release(%Qubit* %input1) - call void @__quantum__rt__qubit_release(%Qubit* %input4) - ret %Array* %results -} - -declare %Qubit* @__quantum__rt__qubit_allocate() - -declare void @__quantum__rt__qubit_release(%Qubit*) - -declare %Array* @__quantum__rt__array_create_1d(i32, i64) - -declare i8* @__quantum__rt__array_get_element_ptr_1d(%Array*, i64) - -declare %Result* @__quantum__rt__result_get_zero() - -declare void @__quantum__rt__result_update_reference_count(%Result*, i32) - -declare void @__quantum__rt__array_update_alias_count(%Array*, i32) - -declare i64 @__quantum__rt__array_get_size_1d(%Array*) - -declare void @__quantum__rt__array_update_reference_count(%Array*, i32) - -declare void @__quantum__qis__x__body(%Qubit*) - -declare void @__quantum__qis__x__ctl(%Array*, %Qubit*) - -declare void @__quantum__qis__y__body(%Qubit*) - -declare void @__quantum__qis__z__body(%Qubit*) - -declare void @__quantum__qis__z__ctl(%Array*, %Qubit*) - -declare void @__quantum__qis__h__body(%Qubit*) - -define internal %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %qubit) { -entry: - %bases = call %Array* @__quantum__rt__array_create_1d(i32 1, i64 1) - %0 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %bases, i64 0) - %1 = bitcast i8* %0 to i2* - %2 = load i2, i2* @PauliZ, align 1 - store i2 %2, i2* %1, align 1 - call void @__quantum__rt__array_update_alias_count(%Array* %bases, i32 1) - %qubits = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) - %3 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qubits, i64 0) - %4 = bitcast i8* %3 to %Qubit** - store %Qubit* %qubit, %Qubit** %4, align 8 - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i32 1) - %5 = call %Result* @__quantum__qis__measure__body(%Array* %bases, %Array* %qubits) - call void @__quantum__rt__array_update_alias_count(%Array* %bases, i32 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i32 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %bases, i32 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %qubits, i32 -1) - ret %Result* %5 -} - -define internal void @Microsoft__Quantum__Intrinsic__Reset__body(%Qubit* %qubit) { -entry: - %0 = call %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %qubit) - %1 = call %Result* @__quantum__rt__result_get_one() - %2 = call i1 @__quantum__rt__result_equal(%Result* %0, %Result* %1) - call void @__quantum__rt__result_update_reference_count(%Result* %0, i32 -1) - br i1 %2, label %then0__1, label %continue__1 - -then0__1: ; preds = %entry - call void @__quantum__qis__x__body(%Qubit* %qubit) - br label %continue__1 - -continue__1: ; preds = %then0__1, %entry - ret void -} - -define internal void @Microsoft__Quantum__Intrinsic__Rx__body(double %theta, %Qubit* %qubit) { -entry: - %pauli = load i2, i2* @PauliX, align 1 - call void @__quantum__qis__r__body(i2 %pauli, double %theta, %Qubit* %qubit) - ret void -} - -define internal void @Microsoft__Quantum__Intrinsic__Ry__body(double %theta, %Qubit* %qubit) { -entry: - %pauli = load i2, i2* @PauliY, align 1 - call void @__quantum__qis__r__body(i2 %pauli, double %theta, %Qubit* %qubit) - ret void -} - -define internal void @Microsoft__Quantum__Intrinsic__Rz__body(double %theta, %Qubit* %qubit) { -entry: - %pauli = load i2, i2* @PauliZ, align 1 - call void @__quantum__qis__r__body(i2 %pauli, double %theta, %Qubit* %qubit) - ret void -} - -declare void @__quantum__qis__s__body(%Qubit*) - -declare void @__quantum__qis__s__adj(%Qubit*) - -declare void @__quantum__qis__t__body(%Qubit*) - -declare void @__quantum__qis__t__adj(%Qubit*) - -define internal void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %qubit) { -entry: - call void @__quantum__qis__h__body(%Qubit* %qubit) - ret void -} - -declare %Result* @__quantum__qis__measure__body(%Array*, %Array*) - -declare void @__quantum__qis__r__body(i2, double, %Qubit*) - -declare %Result* @__quantum__rt__result_get_one() - -declare i1 @__quantum__rt__result_equal(%Result*, %Result*) - -define internal void @Microsoft__Quantum__Intrinsic__S__body(%Qubit* %qubit) { -entry: - call void @__quantum__qis__s__body(%Qubit* %qubit) - ret void -} - -define internal void @Microsoft__Quantum__Intrinsic__S__adj(%Qubit* %qubit) { -entry: - call void @__quantum__qis__s__adj(%Qubit* %qubit) - ret void -} - -define internal void @Microsoft__Quantum__Intrinsic__T__body(%Qubit* %qubit) { -entry: - call void @__quantum__qis__t__body(%Qubit* %qubit) - ret void -} - -define internal void @Microsoft__Quantum__Intrinsic__T__adj(%Qubit* %qubit) { -entry: - call void @__quantum__qis__t__adj(%Qubit* %qubit) - ret void -} - -define internal void @Microsoft__Quantum__Intrinsic__X__body(%Qubit* %qubit) { -entry: - call void @__quantum__qis__x__body(%Qubit* %qubit) - ret void -} - -define internal void @Microsoft__Quantum__Intrinsic__X__ctl(%Array* %__controlQubits__, %Qubit* %qubit) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 1) - call void @__quantum__qis__x__ctl(%Array* %__controlQubits__, %Qubit* %qubit) - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 -1) - ret void -} - -define internal void @Microsoft__Quantum__Intrinsic__Y__body(%Qubit* %qubit) { -entry: - call void @__quantum__qis__y__body(%Qubit* %qubit) - ret void -} - -define internal void @Microsoft__Quantum__Intrinsic__Z__body(%Qubit* %qubit) { -entry: - call void @__quantum__qis__z__body(%Qubit* %qubit) - ret void -} - -define internal void @Microsoft__Quantum__Intrinsic__Z__ctl(%Array* %__controlQubits__, %Qubit* %qubit) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 1) - call void @__quantum__qis__z__ctl(%Array* %__controlQubits__, %Qubit* %qubit) - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 -1) - ret void -} - -define { i64, i8* }* @QuantumApplication__Run__Interop() #0 { -entry: - %0 = call %Array* @QuantumApplication__Run__body() - %1 = call i64 @__quantum__rt__array_get_size_1d(%Array* %0) - %2 = mul i64 %1, 8 - %3 = call i8* @__quantum__rt__memory_allocate(i64 %2) - %4 = ptrtoint i8* %3 to i64 - %5 = sub i64 %1, 1 - br label %header__1 - -header__1: ; preds = %exiting__1, %entry - %6 = phi i64 [ 0, %entry ], [ %19, %exiting__1 ] - %7 = icmp sle i64 %6, %5 - br i1 %7, label %body__1, label %exit__1 - -body__1: ; preds = %header__1 - %8 = mul i64 %6, 8 - %9 = add i64 %4, %8 - %10 = inttoptr i64 %9 to { i64, i8* }** - %11 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %0, i64 %6) - %12 = bitcast i8* %11 to %Array** - %13 = load %Array*, %Array** %12, align 8 - %14 = call i64 @__quantum__rt__array_get_size_1d(%Array* %13) - %15 = mul i64 %14, 1 - %16 = call i8* @__quantum__rt__memory_allocate(i64 %15) - %17 = ptrtoint i8* %16 to i64 - %18 = sub i64 %14, 1 - br label %header__2 - -exiting__1: ; preds = %exit__2 - %19 = add i64 %6, 1 - br label %header__1 - -exit__1: ; preds = %header__1 - %20 = call i8* @__quantum__rt__memory_allocate(i64 ptrtoint ({ i64, i8* }* getelementptr ({ i64, i8* }, { i64, i8* }* null, i32 1) to i64)) - %21 = bitcast i8* %20 to { i64, i8* }* - %22 = getelementptr { i64, i8* }, { i64, i8* }* %21, i64 0, i32 0 - store i64 %1, i64* %22, align 4 - %23 = getelementptr { i64, i8* }, { i64, i8* }* %21, i64 0, i32 1 - store i8* %3, i8** %23, align 8 - %24 = sub i64 %1, 1 - br label %header__3 - -header__2: ; preds = %exiting__2, %body__1 - %25 = phi i64 [ 0, %body__1 ], [ %36, %exiting__2 ] - %26 = icmp sle i64 %25, %18 - br i1 %26, label %body__2, label %exit__2 - -body__2: ; preds = %header__2 - %27 = mul i64 %25, 1 - %28 = add i64 %17, %27 - %29 = inttoptr i64 %28 to i8* - %30 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %13, i64 %25) - %31 = bitcast i8* %30 to %Result** - %32 = load %Result*, %Result** %31, align 8 - %33 = call %Result* @__quantum__rt__result_get_zero() - %34 = call i1 @__quantum__rt__result_equal(%Result* %32, %Result* %33) - %35 = select i1 %34, i8 0, i8 -1 - store i8 %35, i8* %29, align 1 - br label %exiting__2 - -exiting__2: ; preds = %body__2 - %36 = add i64 %25, 1 - br label %header__2 - -exit__2: ; preds = %header__2 - %37 = call i8* @__quantum__rt__memory_allocate(i64 ptrtoint ({ i64, i8* }* getelementptr ({ i64, i8* }, { i64, i8* }* null, i32 1) to i64)) - %38 = bitcast i8* %37 to { i64, i8* }* - %39 = getelementptr { i64, i8* }, { i64, i8* }* %38, i64 0, i32 0 - store i64 %14, i64* %39, align 4 - %40 = getelementptr { i64, i8* }, { i64, i8* }* %38, i64 0, i32 1 - store i8* %16, i8** %40, align 8 - store { i64, i8* }* %38, { i64, i8* }** %10, align 8 - br label %exiting__1 - -header__3: ; preds = %exiting__3, %exit__1 - %41 = phi i64 [ 0, %exit__1 ], [ %48, %exiting__3 ] - %42 = icmp sle i64 %41, %24 - br i1 %42, label %body__3, label %exit__3 - -body__3: ; preds = %header__3 - %43 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %0, i64 %41) - %44 = bitcast i8* %43 to %Array** - %45 = load %Array*, %Array** %44, align 8 - %46 = call i64 @__quantum__rt__array_get_size_1d(%Array* %45) - %47 = sub i64 %46, 1 - br label %header__4 - -exiting__3: ; preds = %exit__4 - %48 = add i64 %41, 1 - br label %header__3 - -exit__3: ; preds = %header__3 - call void @__quantum__rt__array_update_reference_count(%Array* %0, i32 -1) - ret { i64, i8* }* %21 - -header__4: ; preds = %exiting__4, %body__3 - %49 = phi i64 [ 0, %body__3 ], [ %54, %exiting__4 ] - %50 = icmp sle i64 %49, %47 - br i1 %50, label %body__4, label %exit__4 - -body__4: ; preds = %header__4 - %51 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %45, i64 %49) - %52 = bitcast i8* %51 to %Result** - %53 = load %Result*, %Result** %52, align 8 - call void @__quantum__rt__result_update_reference_count(%Result* %53, i32 -1) - br label %exiting__4 - -exiting__4: ; preds = %body__4 - %54 = add i64 %49, 1 - br label %header__4 - -exit__4: ; preds = %header__4 - call void @__quantum__rt__array_update_reference_count(%Array* %45, i32 -1) - br label %exiting__3 -} - -declare i8* @__quantum__rt__memory_allocate(i64) - -define void @QuantumApplication__Run() #1 { -entry: - %0 = call %Array* @QuantumApplication__Run__body() - %1 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @0, i32 0, i32 0)) - %2 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @1, i32 0, i32 0)) - call void @__quantum__rt__string_update_reference_count(%String* %2, i32 1) - %3 = call i64 @__quantum__rt__array_get_size_1d(%Array* %0) - %4 = sub i64 %3, 1 - br label %header__1 - -header__1: ; preds = %exiting__1, %entry - %5 = phi %String* [ %2, %entry ], [ %36, %exiting__1 ] - %6 = phi i64 [ 0, %entry ], [ %18, %exiting__1 ] - %7 = icmp sle i64 %6, %4 - br i1 %7, label %body__1, label %exit__1 - -body__1: ; preds = %header__1 - %8 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %0, i64 %6) - %9 = bitcast i8* %8 to %Array** - %10 = load %Array*, %Array** %9, align 8 - %11 = icmp ne %String* %5, %2 - br i1 %11, label %condTrue__1, label %condContinue__1 - -condTrue__1: ; preds = %body__1 - %12 = call %String* @__quantum__rt__string_concatenate(%String* %5, %String* %1) - call void @__quantum__rt__string_update_reference_count(%String* %5, i32 -1) - br label %condContinue__1 - -condContinue__1: ; preds = %condTrue__1, %body__1 - %13 = phi %String* [ %12, %condTrue__1 ], [ %5, %body__1 ] - %14 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @2, i32 0, i32 0)) - %15 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @3, i32 0, i32 0)) - call void @__quantum__rt__string_update_reference_count(%String* %15, i32 1) - %16 = call i64 @__quantum__rt__array_get_size_1d(%Array* %10) - %17 = sub i64 %16, 1 - br label %header__2 - -exiting__1: ; preds = %exit__2 - %18 = add i64 %6, 1 - br label %header__1 - -exit__1: ; preds = %header__1 - %19 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @5, i32 0, i32 0)) - %20 = call %String* @__quantum__rt__string_concatenate(%String* %5, %String* %19) - call void @__quantum__rt__string_update_reference_count(%String* %5, i32 -1) - call void @__quantum__rt__string_update_reference_count(%String* %19, i32 -1) - call void @__quantum__rt__string_update_reference_count(%String* %1, i32 -1) - call void @__quantum__rt__string_update_reference_count(%String* %2, i32 -1) - call void @__quantum__rt__message(%String* %20) - %21 = sub i64 %3, 1 - br label %header__3 - -header__2: ; preds = %exiting__2, %condContinue__1 - %22 = phi %String* [ %15, %condContinue__1 ], [ %32, %exiting__2 ] - %23 = phi i64 [ 0, %condContinue__1 ], [ %33, %exiting__2 ] - %24 = icmp sle i64 %23, %17 - br i1 %24, label %body__2, label %exit__2 - -body__2: ; preds = %header__2 - %25 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %10, i64 %23) - %26 = bitcast i8* %25 to %Result** - %27 = load %Result*, %Result** %26, align 8 - %28 = icmp ne %String* %22, %15 - br i1 %28, label %condTrue__2, label %condContinue__2 - -condTrue__2: ; preds = %body__2 - %29 = call %String* @__quantum__rt__string_concatenate(%String* %22, %String* %14) - call void @__quantum__rt__string_update_reference_count(%String* %22, i32 -1) - br label %condContinue__2 - -condContinue__2: ; preds = %condTrue__2, %body__2 - %30 = phi %String* [ %29, %condTrue__2 ], [ %22, %body__2 ] - %31 = call %String* @__quantum__rt__result_to_string(%Result* %27) - %32 = call %String* @__quantum__rt__string_concatenate(%String* %30, %String* %31) - call void @__quantum__rt__string_update_reference_count(%String* %30, i32 -1) - call void @__quantum__rt__string_update_reference_count(%String* %31, i32 -1) - br label %exiting__2 - -exiting__2: ; preds = %condContinue__2 - %33 = add i64 %23, 1 - br label %header__2 - -exit__2: ; preds = %header__2 - %34 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @4, i32 0, i32 0)) - %35 = call %String* @__quantum__rt__string_concatenate(%String* %22, %String* %34) - call void @__quantum__rt__string_update_reference_count(%String* %22, i32 -1) - call void @__quantum__rt__string_update_reference_count(%String* %34, i32 -1) - call void @__quantum__rt__string_update_reference_count(%String* %14, i32 -1) - call void @__quantum__rt__string_update_reference_count(%String* %15, i32 -1) - %36 = call %String* @__quantum__rt__string_concatenate(%String* %13, %String* %35) - call void @__quantum__rt__string_update_reference_count(%String* %13, i32 -1) - call void @__quantum__rt__string_update_reference_count(%String* %35, i32 -1) - br label %exiting__1 - -header__3: ; preds = %exiting__3, %exit__1 - %37 = phi i64 [ 0, %exit__1 ], [ %44, %exiting__3 ] - %38 = icmp sle i64 %37, %21 - br i1 %38, label %body__3, label %exit__3 - -body__3: ; preds = %header__3 - %39 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %0, i64 %37) - %40 = bitcast i8* %39 to %Array** - %41 = load %Array*, %Array** %40, align 8 - %42 = call i64 @__quantum__rt__array_get_size_1d(%Array* %41) - %43 = sub i64 %42, 1 - br label %header__4 - -exiting__3: ; preds = %exit__4 - %44 = add i64 %37, 1 - br label %header__3 - -exit__3: ; preds = %header__3 - call void @__quantum__rt__array_update_reference_count(%Array* %0, i32 -1) - call void @__quantum__rt__string_update_reference_count(%String* %20, i32 -1) - ret void - -header__4: ; preds = %exiting__4, %body__3 - %45 = phi i64 [ 0, %body__3 ], [ %50, %exiting__4 ] - %46 = icmp sle i64 %45, %43 - br i1 %46, label %body__4, label %exit__4 - -body__4: ; preds = %header__4 - %47 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %41, i64 %45) - %48 = bitcast i8* %47 to %Result** - %49 = load %Result*, %Result** %48, align 8 - call void @__quantum__rt__result_update_reference_count(%Result* %49, i32 -1) - br label %exiting__4 - -exiting__4: ; preds = %body__4 - %50 = add i64 %45, 1 - br label %header__4 - -exit__4: ; preds = %header__4 - call void @__quantum__rt__array_update_reference_count(%Array* %41, i32 -1) - br label %exiting__3 -} - -declare void @__quantum__rt__message(%String*) - -declare %String* @__quantum__rt__string_create(i8*) - -declare void @__quantum__rt__string_update_reference_count(%String*, i32) - -declare %String* @__quantum__rt__string_concatenate(%String*, %String*) - -declare %String* @__quantum__rt__result_to_string(%Result*) - -attributes #0 = { "InteropFriendly" } -attributes #1 = { "EntryPoint" } diff --git a/src/QirTools/pyqir/pytest.ll b/src/QirTools/pyqir/pytest.ll deleted file mode 100644 index 707c6bf431..0000000000 --- a/src/QirTools/pyqir/pytest.ll +++ /dev/null @@ -1,582 +0,0 @@ -; ModuleID = 'sample' -source_filename = "C:\\Users\\iadavis\\dev\\qsharp-compiler\\src\\QirTools\\pyqir\\qirlib\\src\\emit\\qir\\module.ll" - -%Range = type { i64, i64, i64 } -%Array = type opaque -%Qubit = type opaque -%Result = type opaque -%String = type opaque - -@PauliI = internal constant i2 0 -@PauliX = internal constant i2 1 -@PauliY = internal constant i2 -1 -@PauliZ = internal constant i2 -2 -@EmptyRange = internal constant %Range { i64 0, i64 1, i64 -1 } -@0 = internal constant [3 x i8] c", \00" -@1 = internal constant [2 x i8] c"[\00" -@2 = internal constant [3 x i8] c", \00" -@3 = internal constant [2 x i8] c"[\00" -@4 = internal constant [2 x i8] c"]\00" -@5 = internal constant [2 x i8] c"]\00" - -define internal %Array* @QuantumApplication__Run__body() { -entry: - %q0 = call %Qubit* @__quantum__rt__qubit_allocate() - %q1 = call %Qubit* @__quantum__rt__qubit_allocate() - %q2 = call %Qubit* @__quantum__rt__qubit_allocate() - %q3 = call %Qubit* @__quantum__rt__qubit_allocate() - %control0 = call %Qubit* @__quantum__rt__qubit_allocate() - %results = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 3) - %c = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 4) - %c_0_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %c, i64 0) - %c_result_0 = bitcast i8* %c_0_raw to %Result** - %zero_0 = call %Result* @__quantum__rt__result_get_zero() - call void @__quantum__rt__result_update_reference_count(%Result* %zero_0, i32 1) - store %Result* %zero_0, %Result** %c_result_0, align 8 - %c_1_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %c, i64 1) - %c_result_1 = bitcast i8* %c_1_raw to %Result** - %zero_1 = call %Result* @__quantum__rt__result_get_zero() - call void @__quantum__rt__result_update_reference_count(%Result* %zero_1, i32 1) - store %Result* %zero_1, %Result** %c_result_1, align 8 - %c_2_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %c, i64 2) - %c_result_2 = bitcast i8* %c_2_raw to %Result** - %zero_2 = call %Result* @__quantum__rt__result_get_zero() - call void @__quantum__rt__result_update_reference_count(%Result* %zero_2, i32 1) - store %Result* %zero_2, %Result** %c_result_2, align 8 - %c_3_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %c, i64 3) - %c_result_3 = bitcast i8* %c_3_raw to %Result** - %zero_3 = call %Result* @__quantum__rt__result_get_zero() - call void @__quantum__rt__result_update_reference_count(%Result* %zero_3, i32 1) - store %Result* %zero_3, %Result** %c_result_3, align 8 - %i = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 3) - %i_0_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %i, i64 0) - %i_result_0 = bitcast i8* %i_0_raw to %Result** - %zero_01 = call %Result* @__quantum__rt__result_get_zero() - call void @__quantum__rt__result_update_reference_count(%Result* %zero_01, i32 1) - store %Result* %zero_01, %Result** %i_result_0, align 8 - %i_1_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %i, i64 1) - %i_result_1 = bitcast i8* %i_1_raw to %Result** - %zero_12 = call %Result* @__quantum__rt__result_get_zero() - call void @__quantum__rt__result_update_reference_count(%Result* %zero_12, i32 1) - store %Result* %zero_12, %Result** %i_result_1, align 8 - %i_2_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %i, i64 2) - %i_result_2 = bitcast i8* %i_2_raw to %Result** - %zero_23 = call %Result* @__quantum__rt__result_get_zero() - call void @__quantum__rt__result_update_reference_count(%Result* %zero_23, i32 1) - store %Result* %zero_23, %Result** %i_result_2, align 8 - %j = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 2) - %j_0_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %j, i64 0) - %j_result_0 = bitcast i8* %j_0_raw to %Result** - %zero_04 = call %Result* @__quantum__rt__result_get_zero() - call void @__quantum__rt__result_update_reference_count(%Result* %zero_04, i32 1) - store %Result* %zero_04, %Result** %j_result_0, align 8 - %j_1_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %j, i64 1) - %j_result_1 = bitcast i8* %j_1_raw to %Result** - %zero_15 = call %Result* @__quantum__rt__result_get_zero() - call void @__quantum__rt__result_update_reference_count(%Result* %zero_15, i32 1) - store %Result* %zero_15, %Result** %j_result_1, align 8 - %results_result_tmp_0_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %results, i64 0) - %results_result_tmp_result_0 = bitcast i8* %results_result_tmp_0_raw to %Array** - store %Array* %c, %Array** %results_result_tmp_result_0, align 8 - %results_result_tmp_1_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %results, i64 1) - %results_result_tmp_result_1 = bitcast i8* %results_result_tmp_1_raw to %Array** - store %Array* %i, %Array** %results_result_tmp_result_1, align 8 - %results_result_tmp_2_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %results, i64 2) - %results_result_tmp_result_2 = bitcast i8* %results_result_tmp_2_raw to %Array** - store %Array* %j, %Array** %results_result_tmp_result_2, align 8 - %__controlQubits__ = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) - %__controlQubits__0_result_tmp_0_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %__controlQubits__, i64 0) - %__controlQubits__0_result_tmp_result_0 = bitcast i8* %__controlQubits__0_result_tmp_0_raw to %Qubit** - store %Qubit* %q0, %Qubit** %__controlQubits__0_result_tmp_result_0, align 8 - call void @Microsoft__Quantum__Intrinsic__X__ctl(%Array* %__controlQubits__, %Qubit* %control0) - call void @__quantum__rt__array_update_reference_count(%Array* %__controlQubits__, i32 -1) - %__controlQubits__6 = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) - %__controlQubits__0_result_tmp_0_raw7 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %__controlQubits__6, i64 0) - %__controlQubits__0_result_tmp_result_08 = bitcast i8* %__controlQubits__0_result_tmp_0_raw7 to %Qubit** - store %Qubit* %q1, %Qubit** %__controlQubits__0_result_tmp_result_08, align 8 - call void @Microsoft__Quantum__Intrinsic__Z__ctl(%Array* %__controlQubits__6, %Qubit* %control0) - call void @__quantum__rt__array_update_reference_count(%Array* %__controlQubits__6, i32 -1) - call void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %q0) - call void @Microsoft__Quantum__Intrinsic__Reset__body(%Qubit* %q0) - call void @Microsoft__Quantum__Intrinsic__Rx__body(double 1.500000e+01, %Qubit* %q1) - call void @Microsoft__Quantum__Intrinsic__Ry__body(double 1.600000e+01, %Qubit* %q2) - call void @Microsoft__Quantum__Intrinsic__Rz__body(double 1.700000e+01, %Qubit* %q3) - call void @Microsoft__Quantum__Intrinsic__S__body(%Qubit* %q0) - call void @Microsoft__Quantum__Intrinsic__S__adj(%Qubit* %q1) - call void @Microsoft__Quantum__Intrinsic__T__body(%Qubit* %q2) - call void @Microsoft__Quantum__Intrinsic__T__adj(%Qubit* %q3) - call void @Microsoft__Quantum__Intrinsic__X__body(%Qubit* %q0) - call void @Microsoft__Quantum__Intrinsic__Y__body(%Qubit* %q1) - call void @Microsoft__Quantum__Intrinsic__Z__body(%Qubit* %q2) - %measurement = call %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %q0) - %c0_0_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %c, i64 0) - %c0_result_0 = bitcast i8* %c0_0_raw to %Result** - %existing_value = load %Result*, %Result** %c0_result_0, align 8 - call void @__quantum__rt__result_update_reference_count(%Result* %existing_value, i32 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %measurement, i32 1) - store %Result* %measurement, %Result** %c0_result_0, align 8 - %measurement9 = call %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %q1) - %c1_1_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %c, i64 1) - %c1_result_1 = bitcast i8* %c1_1_raw to %Result** - %existing_value10 = load %Result*, %Result** %c1_result_1, align 8 - call void @__quantum__rt__result_update_reference_count(%Result* %existing_value10, i32 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %measurement9, i32 1) - store %Result* %measurement9, %Result** %c1_result_1, align 8 - %measurement11 = call %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %q2) - %c2_2_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %c, i64 2) - %c2_result_2 = bitcast i8* %c2_2_raw to %Result** - %existing_value12 = load %Result*, %Result** %c2_result_2, align 8 - call void @__quantum__rt__result_update_reference_count(%Result* %existing_value12, i32 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %measurement11, i32 1) - store %Result* %measurement11, %Result** %c2_result_2, align 8 - %measurement13 = call %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %q3) - %c3_3_raw = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %c, i64 3) - %c3_result_3 = bitcast i8* %c3_3_raw to %Result** - %existing_value14 = load %Result*, %Result** %c3_result_3, align 8 - call void @__quantum__rt__result_update_reference_count(%Result* %existing_value14, i32 -1) - call void @__quantum__rt__result_update_reference_count(%Result* %measurement13, i32 1) - store %Result* %measurement13, %Result** %c3_result_3, align 8 - call void @__quantum__rt__qubit_release(%Qubit* %q1) - call void @__quantum__rt__qubit_release(%Qubit* %q2) - call void @__quantum__rt__qubit_release(%Qubit* %q3) - call void @__quantum__rt__qubit_release(%Qubit* %control0) - call void @__quantum__rt__qubit_release(%Qubit* %q0) - ret %Array* %results -} - -declare %Qubit* @__quantum__rt__qubit_allocate() - -declare void @__quantum__rt__qubit_release(%Qubit*) - -declare %Array* @__quantum__rt__array_create_1d(i32, i64) - -declare i8* @__quantum__rt__array_get_element_ptr_1d(%Array*, i64) - -declare %Result* @__quantum__rt__result_get_zero() - -declare void @__quantum__rt__result_update_reference_count(%Result*, i32) - -declare void @__quantum__rt__array_update_alias_count(%Array*, i32) - -declare i64 @__quantum__rt__array_get_size_1d(%Array*) - -declare void @__quantum__rt__array_update_reference_count(%Array*, i32) - -declare void @__quantum__qis__x__body(%Qubit*) - -declare void @__quantum__qis__x__ctl(%Array*, %Qubit*) - -declare void @__quantum__qis__y__body(%Qubit*) - -declare void @__quantum__qis__z__body(%Qubit*) - -declare void @__quantum__qis__z__ctl(%Array*, %Qubit*) - -declare void @__quantum__qis__h__body(%Qubit*) - -define internal %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %qubit) { -entry: - %bases = call %Array* @__quantum__rt__array_create_1d(i32 1, i64 1) - %0 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %bases, i64 0) - %1 = bitcast i8* %0 to i2* - %2 = load i2, i2* @PauliZ, align 1 - store i2 %2, i2* %1, align 1 - call void @__quantum__rt__array_update_alias_count(%Array* %bases, i32 1) - %qubits = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1) - %3 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qubits, i64 0) - %4 = bitcast i8* %3 to %Qubit** - store %Qubit* %qubit, %Qubit** %4, align 8 - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i32 1) - %5 = call %Result* @__quantum__qis__measure__body(%Array* %bases, %Array* %qubits) - call void @__quantum__rt__array_update_alias_count(%Array* %bases, i32 -1) - call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i32 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %bases, i32 -1) - call void @__quantum__rt__array_update_reference_count(%Array* %qubits, i32 -1) - ret %Result* %5 -} - -define internal void @Microsoft__Quantum__Intrinsic__Reset__body(%Qubit* %qubit) { -entry: - %0 = call %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %qubit) - %1 = call %Result* @__quantum__rt__result_get_one() - %2 = call i1 @__quantum__rt__result_equal(%Result* %0, %Result* %1) - call void @__quantum__rt__result_update_reference_count(%Result* %0, i32 -1) - br i1 %2, label %then0__1, label %continue__1 - -then0__1: ; preds = %entry - call void @__quantum__qis__x__body(%Qubit* %qubit) - br label %continue__1 - -continue__1: ; preds = %then0__1, %entry - ret void -} - -define internal void @Microsoft__Quantum__Intrinsic__Rx__body(double %theta, %Qubit* %qubit) { -entry: - %pauli = load i2, i2* @PauliX, align 1 - call void @__quantum__qis__r__body(i2 %pauli, double %theta, %Qubit* %qubit) - ret void -} - -define internal void @Microsoft__Quantum__Intrinsic__Ry__body(double %theta, %Qubit* %qubit) { -entry: - %pauli = load i2, i2* @PauliY, align 1 - call void @__quantum__qis__r__body(i2 %pauli, double %theta, %Qubit* %qubit) - ret void -} - -define internal void @Microsoft__Quantum__Intrinsic__Rz__body(double %theta, %Qubit* %qubit) { -entry: - %pauli = load i2, i2* @PauliZ, align 1 - call void @__quantum__qis__r__body(i2 %pauli, double %theta, %Qubit* %qubit) - ret void -} - -declare void @__quantum__qis__s__body(%Qubit*) - -declare void @__quantum__qis__s__adj(%Qubit*) - -declare void @__quantum__qis__t__body(%Qubit*) - -declare void @__quantum__qis__t__adj(%Qubit*) - -define internal void @Microsoft__Quantum__Intrinsic__H__body(%Qubit* %qubit) { -entry: - call void @__quantum__qis__h__body(%Qubit* %qubit) - ret void -} - -declare %Result* @__quantum__qis__measure__body(%Array*, %Array*) - -declare void @__quantum__qis__r__body(i2, double, %Qubit*) - -declare %Result* @__quantum__rt__result_get_one() - -declare i1 @__quantum__rt__result_equal(%Result*, %Result*) - -define internal void @Microsoft__Quantum__Intrinsic__S__body(%Qubit* %qubit) { -entry: - call void @__quantum__qis__s__body(%Qubit* %qubit) - ret void -} - -define internal void @Microsoft__Quantum__Intrinsic__S__adj(%Qubit* %qubit) { -entry: - call void @__quantum__qis__s__adj(%Qubit* %qubit) - ret void -} - -define internal void @Microsoft__Quantum__Intrinsic__T__body(%Qubit* %qubit) { -entry: - call void @__quantum__qis__t__body(%Qubit* %qubit) - ret void -} - -define internal void @Microsoft__Quantum__Intrinsic__T__adj(%Qubit* %qubit) { -entry: - call void @__quantum__qis__t__adj(%Qubit* %qubit) - ret void -} - -define internal void @Microsoft__Quantum__Intrinsic__X__body(%Qubit* %qubit) { -entry: - call void @__quantum__qis__x__body(%Qubit* %qubit) - ret void -} - -define internal void @Microsoft__Quantum__Intrinsic__X__ctl(%Array* %__controlQubits__, %Qubit* %qubit) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 1) - call void @__quantum__qis__x__ctl(%Array* %__controlQubits__, %Qubit* %qubit) - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 -1) - ret void -} - -define internal void @Microsoft__Quantum__Intrinsic__Y__body(%Qubit* %qubit) { -entry: - call void @__quantum__qis__y__body(%Qubit* %qubit) - ret void -} - -define internal void @Microsoft__Quantum__Intrinsic__Z__body(%Qubit* %qubit) { -entry: - call void @__quantum__qis__z__body(%Qubit* %qubit) - ret void -} - -define internal void @Microsoft__Quantum__Intrinsic__Z__ctl(%Array* %__controlQubits__, %Qubit* %qubit) { -entry: - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 1) - call void @__quantum__qis__z__ctl(%Array* %__controlQubits__, %Qubit* %qubit) - call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 -1) - ret void -} - -define { i64, i8* }* @QuantumApplication__Run__Interop() #0 { -entry: - %0 = call %Array* @QuantumApplication__Run__body() - %1 = call i64 @__quantum__rt__array_get_size_1d(%Array* %0) - %2 = mul i64 %1, 8 - %3 = call i8* @__quantum__rt__memory_allocate(i64 %2) - %4 = ptrtoint i8* %3 to i64 - %5 = sub i64 %1, 1 - br label %header__1 - -header__1: ; preds = %exiting__1, %entry - %6 = phi i64 [ 0, %entry ], [ %19, %exiting__1 ] - %7 = icmp sle i64 %6, %5 - br i1 %7, label %body__1, label %exit__1 - -body__1: ; preds = %header__1 - %8 = mul i64 %6, 8 - %9 = add i64 %4, %8 - %10 = inttoptr i64 %9 to { i64, i8* }** - %11 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %0, i64 %6) - %12 = bitcast i8* %11 to %Array** - %13 = load %Array*, %Array** %12, align 8 - %14 = call i64 @__quantum__rt__array_get_size_1d(%Array* %13) - %15 = mul i64 %14, 1 - %16 = call i8* @__quantum__rt__memory_allocate(i64 %15) - %17 = ptrtoint i8* %16 to i64 - %18 = sub i64 %14, 1 - br label %header__2 - -exiting__1: ; preds = %exit__2 - %19 = add i64 %6, 1 - br label %header__1 - -exit__1: ; preds = %header__1 - %20 = call i8* @__quantum__rt__memory_allocate(i64 ptrtoint ({ i64, i8* }* getelementptr ({ i64, i8* }, { i64, i8* }* null, i32 1) to i64)) - %21 = bitcast i8* %20 to { i64, i8* }* - %22 = getelementptr { i64, i8* }, { i64, i8* }* %21, i64 0, i32 0 - store i64 %1, i64* %22, align 4 - %23 = getelementptr { i64, i8* }, { i64, i8* }* %21, i64 0, i32 1 - store i8* %3, i8** %23, align 8 - %24 = sub i64 %1, 1 - br label %header__3 - -header__2: ; preds = %exiting__2, %body__1 - %25 = phi i64 [ 0, %body__1 ], [ %36, %exiting__2 ] - %26 = icmp sle i64 %25, %18 - br i1 %26, label %body__2, label %exit__2 - -body__2: ; preds = %header__2 - %27 = mul i64 %25, 1 - %28 = add i64 %17, %27 - %29 = inttoptr i64 %28 to i8* - %30 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %13, i64 %25) - %31 = bitcast i8* %30 to %Result** - %32 = load %Result*, %Result** %31, align 8 - %33 = call %Result* @__quantum__rt__result_get_zero() - %34 = call i1 @__quantum__rt__result_equal(%Result* %32, %Result* %33) - %35 = select i1 %34, i8 0, i8 -1 - store i8 %35, i8* %29, align 1 - br label %exiting__2 - -exiting__2: ; preds = %body__2 - %36 = add i64 %25, 1 - br label %header__2 - -exit__2: ; preds = %header__2 - %37 = call i8* @__quantum__rt__memory_allocate(i64 ptrtoint ({ i64, i8* }* getelementptr ({ i64, i8* }, { i64, i8* }* null, i32 1) to i64)) - %38 = bitcast i8* %37 to { i64, i8* }* - %39 = getelementptr { i64, i8* }, { i64, i8* }* %38, i64 0, i32 0 - store i64 %14, i64* %39, align 4 - %40 = getelementptr { i64, i8* }, { i64, i8* }* %38, i64 0, i32 1 - store i8* %16, i8** %40, align 8 - store { i64, i8* }* %38, { i64, i8* }** %10, align 8 - br label %exiting__1 - -header__3: ; preds = %exiting__3, %exit__1 - %41 = phi i64 [ 0, %exit__1 ], [ %48, %exiting__3 ] - %42 = icmp sle i64 %41, %24 - br i1 %42, label %body__3, label %exit__3 - -body__3: ; preds = %header__3 - %43 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %0, i64 %41) - %44 = bitcast i8* %43 to %Array** - %45 = load %Array*, %Array** %44, align 8 - %46 = call i64 @__quantum__rt__array_get_size_1d(%Array* %45) - %47 = sub i64 %46, 1 - br label %header__4 - -exiting__3: ; preds = %exit__4 - %48 = add i64 %41, 1 - br label %header__3 - -exit__3: ; preds = %header__3 - call void @__quantum__rt__array_update_reference_count(%Array* %0, i32 -1) - ret { i64, i8* }* %21 - -header__4: ; preds = %exiting__4, %body__3 - %49 = phi i64 [ 0, %body__3 ], [ %54, %exiting__4 ] - %50 = icmp sle i64 %49, %47 - br i1 %50, label %body__4, label %exit__4 - -body__4: ; preds = %header__4 - %51 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %45, i64 %49) - %52 = bitcast i8* %51 to %Result** - %53 = load %Result*, %Result** %52, align 8 - call void @__quantum__rt__result_update_reference_count(%Result* %53, i32 -1) - br label %exiting__4 - -exiting__4: ; preds = %body__4 - %54 = add i64 %49, 1 - br label %header__4 - -exit__4: ; preds = %header__4 - call void @__quantum__rt__array_update_reference_count(%Array* %45, i32 -1) - br label %exiting__3 -} - -declare i8* @__quantum__rt__memory_allocate(i64) - -define void @QuantumApplication__Run() #1 { -entry: - %0 = call %Array* @QuantumApplication__Run__body() - %1 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @0, i32 0, i32 0)) - %2 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @1, i32 0, i32 0)) - call void @__quantum__rt__string_update_reference_count(%String* %2, i32 1) - %3 = call i64 @__quantum__rt__array_get_size_1d(%Array* %0) - %4 = sub i64 %3, 1 - br label %header__1 - -header__1: ; preds = %exiting__1, %entry - %5 = phi %String* [ %2, %entry ], [ %36, %exiting__1 ] - %6 = phi i64 [ 0, %entry ], [ %18, %exiting__1 ] - %7 = icmp sle i64 %6, %4 - br i1 %7, label %body__1, label %exit__1 - -body__1: ; preds = %header__1 - %8 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %0, i64 %6) - %9 = bitcast i8* %8 to %Array** - %10 = load %Array*, %Array** %9, align 8 - %11 = icmp ne %String* %5, %2 - br i1 %11, label %condTrue__1, label %condContinue__1 - -condTrue__1: ; preds = %body__1 - %12 = call %String* @__quantum__rt__string_concatenate(%String* %5, %String* %1) - call void @__quantum__rt__string_update_reference_count(%String* %5, i32 -1) - br label %condContinue__1 - -condContinue__1: ; preds = %condTrue__1, %body__1 - %13 = phi %String* [ %12, %condTrue__1 ], [ %5, %body__1 ] - %14 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @2, i32 0, i32 0)) - %15 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @3, i32 0, i32 0)) - call void @__quantum__rt__string_update_reference_count(%String* %15, i32 1) - %16 = call i64 @__quantum__rt__array_get_size_1d(%Array* %10) - %17 = sub i64 %16, 1 - br label %header__2 - -exiting__1: ; preds = %exit__2 - %18 = add i64 %6, 1 - br label %header__1 - -exit__1: ; preds = %header__1 - %19 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @5, i32 0, i32 0)) - %20 = call %String* @__quantum__rt__string_concatenate(%String* %5, %String* %19) - call void @__quantum__rt__string_update_reference_count(%String* %5, i32 -1) - call void @__quantum__rt__string_update_reference_count(%String* %19, i32 -1) - call void @__quantum__rt__string_update_reference_count(%String* %1, i32 -1) - call void @__quantum__rt__string_update_reference_count(%String* %2, i32 -1) - call void @__quantum__rt__message(%String* %20) - %21 = sub i64 %3, 1 - br label %header__3 - -header__2: ; preds = %exiting__2, %condContinue__1 - %22 = phi %String* [ %15, %condContinue__1 ], [ %32, %exiting__2 ] - %23 = phi i64 [ 0, %condContinue__1 ], [ %33, %exiting__2 ] - %24 = icmp sle i64 %23, %17 - br i1 %24, label %body__2, label %exit__2 - -body__2: ; preds = %header__2 - %25 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %10, i64 %23) - %26 = bitcast i8* %25 to %Result** - %27 = load %Result*, %Result** %26, align 8 - %28 = icmp ne %String* %22, %15 - br i1 %28, label %condTrue__2, label %condContinue__2 - -condTrue__2: ; preds = %body__2 - %29 = call %String* @__quantum__rt__string_concatenate(%String* %22, %String* %14) - call void @__quantum__rt__string_update_reference_count(%String* %22, i32 -1) - br label %condContinue__2 - -condContinue__2: ; preds = %condTrue__2, %body__2 - %30 = phi %String* [ %29, %condTrue__2 ], [ %22, %body__2 ] - %31 = call %String* @__quantum__rt__result_to_string(%Result* %27) - %32 = call %String* @__quantum__rt__string_concatenate(%String* %30, %String* %31) - call void @__quantum__rt__string_update_reference_count(%String* %30, i32 -1) - call void @__quantum__rt__string_update_reference_count(%String* %31, i32 -1) - br label %exiting__2 - -exiting__2: ; preds = %condContinue__2 - %33 = add i64 %23, 1 - br label %header__2 - -exit__2: ; preds = %header__2 - %34 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @4, i32 0, i32 0)) - %35 = call %String* @__quantum__rt__string_concatenate(%String* %22, %String* %34) - call void @__quantum__rt__string_update_reference_count(%String* %22, i32 -1) - call void @__quantum__rt__string_update_reference_count(%String* %34, i32 -1) - call void @__quantum__rt__string_update_reference_count(%String* %14, i32 -1) - call void @__quantum__rt__string_update_reference_count(%String* %15, i32 -1) - %36 = call %String* @__quantum__rt__string_concatenate(%String* %13, %String* %35) - call void @__quantum__rt__string_update_reference_count(%String* %13, i32 -1) - call void @__quantum__rt__string_update_reference_count(%String* %35, i32 -1) - br label %exiting__1 - -header__3: ; preds = %exiting__3, %exit__1 - %37 = phi i64 [ 0, %exit__1 ], [ %44, %exiting__3 ] - %38 = icmp sle i64 %37, %21 - br i1 %38, label %body__3, label %exit__3 - -body__3: ; preds = %header__3 - %39 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %0, i64 %37) - %40 = bitcast i8* %39 to %Array** - %41 = load %Array*, %Array** %40, align 8 - %42 = call i64 @__quantum__rt__array_get_size_1d(%Array* %41) - %43 = sub i64 %42, 1 - br label %header__4 - -exiting__3: ; preds = %exit__4 - %44 = add i64 %37, 1 - br label %header__3 - -exit__3: ; preds = %header__3 - call void @__quantum__rt__array_update_reference_count(%Array* %0, i32 -1) - call void @__quantum__rt__string_update_reference_count(%String* %20, i32 -1) - ret void - -header__4: ; preds = %exiting__4, %body__3 - %45 = phi i64 [ 0, %body__3 ], [ %50, %exiting__4 ] - %46 = icmp sle i64 %45, %43 - br i1 %46, label %body__4, label %exit__4 - -body__4: ; preds = %header__4 - %47 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %41, i64 %45) - %48 = bitcast i8* %47 to %Result** - %49 = load %Result*, %Result** %48, align 8 - call void @__quantum__rt__result_update_reference_count(%Result* %49, i32 -1) - br label %exiting__4 - -exiting__4: ; preds = %body__4 - %50 = add i64 %45, 1 - br label %header__4 - -exit__4: ; preds = %header__4 - call void @__quantum__rt__array_update_reference_count(%Array* %41, i32 -1) - br label %exiting__3 -} - -declare void @__quantum__rt__message(%String*) - -declare %String* @__quantum__rt__string_create(i8*) - -declare void @__quantum__rt__string_update_reference_count(%String*, i32) - -declare %String* @__quantum__rt__string_concatenate(%String*, %String*) - -declare %String* @__quantum__rt__result_to_string(%Result*) - -attributes #0 = { "InteropFriendly" } -attributes #1 = { "EntryPoint" } From f9e925153e9bbb68c8acb5dbce272ce816d64bbb Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Tue, 19 Oct 2021 10:02:23 -0700 Subject: [PATCH 22/26] Fix version number --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index aee2ffb271..9d7b1f6335 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -347,7 +347,7 @@ dependencies = [ [[package]] name = "pyqir" -version = "0.9999.2110-alpha" +version = "0.1.0-alpha" dependencies = [ "env_logger", "llvm-ir", From 07a2a2d4a2862a10ec504ce76871727d6da0875b Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Fri, 22 Oct 2021 14:35:53 -0700 Subject: [PATCH 23/26] Updates from PR feedback --- src/QirTools/pyqir/pyqir/__init__.py | 878 +------------------------- src/QirTools/pyqir/pyqir/builder.py | 258 ++++++++ src/QirTools/pyqir/pyqir/parser.py | 892 +++++++++++++++++++++++++++ src/QirTools/pyqir/src/parser.rs | 6 +- src/QirTools/qirlib/src/parse/mod.rs | 14 +- 5 files changed, 1162 insertions(+), 886 deletions(-) create mode 100644 src/QirTools/pyqir/pyqir/builder.py create mode 100644 src/QirTools/pyqir/pyqir/parser.py diff --git a/src/QirTools/pyqir/pyqir/__init__.py b/src/QirTools/pyqir/pyqir/__init__.py index 735d3d7285..80a5f04a43 100644 --- a/src/QirTools/pyqir/pyqir/__init__.py +++ b/src/QirTools/pyqir/pyqir/__init__.py @@ -1,879 +1,5 @@ # Copyright(c) Microsoft Corporation. # Licensed under the MIT License. -from .pyqir import * - - -class QirBuilder: - """ - The QirBuilder object describes quantum circuits and emits QIR - - :param module: name of the QIR module - :type module: str - """ - - def __init__(self, module: str): - self.pyqir = PyQIR(module) - - def cx(self, control: str, target: str): - """ - Applies controlled X operation to the target qubit - - :param control: name of the control qubit - :type control: str - :param target: name of the target qubit - :type target: str - """ - self.pyqir.cx(control, target) - - def cz(self, control: str, target: str): - """ - Applies controlled Z operation to the target qubit - - :param control: name of the control qubit - :type control: str - :param target: name of the target qubit - :type target: str - """ - self.pyqir.cz(control, target) - - def h(self, target: str): - """ - Applies H operation to the target qubit - - :param target: name of the target qubit - :type target: str - """ - self.pyqir.h(target) - - def m(self, qubit: str, target: str): - """ - Applies measurement operation or the source qubit into the target register - - :param qubit: name of the source qubit - :type qubit: str - :param target: name of the target register - :type target: str - """ - self.pyqir.m(qubit, target) - - def reset(self, target: str): - """ - Applies Reset operation to the target qubit - - :param target: name of the target qubit - :type target: str - """ - self.pyqir.reset(target) - - def rx(self, theta: float, qubit: str): - """ - Applies Rx operation to the target qubit - - :param theta: rotation value for target qubit - :type theta: float - :param qubit: name of the target qubit - :type qubit: str - """ - self.pyqir.rx(theta, qubit) - - def ry(self, theta: float, qubit: str): - """ - Applies Ry operation to the target qubit - - :param theta: rotation value for target qubit - :type theta: float - :param qubit: name of the target qubit - :type qubit: str - """ - self.pyqir.ry(theta, qubit) - - def rz(self, theta: float, qubit: str): - """ - Applies Rz operation to the target qubit - - :param theta: rotation value for target qubit - :type theta: float - :param qubit: name of the target qubit - :type qubit: str - """ - self.pyqir.rz(theta, qubit) - - def s(self, qubit: str): - """ - Applies S operation to the target qubit - - :param qubit: name of the target qubit - :type qubit: str - """ - self.pyqir.s(qubit) - - def s_adj(self, qubit: str): - """ - Applies SAdj operation to the target qubit - - :param qubit: name of the target qubit - :type qubit: str - """ - self.pyqir.s_adj(qubit) - - def t(self, qubit: str): - """ - Applies T operation to the target qubit - - :param qubit: name of the target qubit - :type qubit: str - """ - self.pyqir.t(qubit) - - def t_adj(self, qubit: str): - """ - Applies TAdj operation to the target qubit - - :param qubit: name of the target qubit - :type qubit: str - """ - self.pyqir.t_adj(qubit) - - def x(self, qubit: str): - """ - Applies X operation to the target qubit - - :param qubit: name of the target qubit - :type qubit: str - """ - self.pyqir.x(qubit) - - def y(self, qubit: str): - """ - Applies Y operation to the target qubit - - :param qubit: name of the target qubit - :type qubit: str - """ - self.pyqir.y(qubit) - - def z(self, qubit: str): - """ - Applies Z operation to the target qubit - - :param qubit: name of the target qubit - :type qubit: str - """ - self.pyqir.z(qubit) - - def dump_machine(self): - """ - - """ - self.pyqir.dump_machine() - - def add_classical_register(self, name: str, size: int): - """ - Models a classical register of the given size. The individual values - are accessed by name "" with 0 based indicies. - Example: - builder = QirBuilder("Bell circuit") - builder.add_quantum_register("qr", 2) - builder.add_classical_register("qc", 2) - builder.h("qr0") - builder.cx("qr0", "qr1") - builder.m("qr0", "qc0") - builder.m("qr1", "qc1") - builder.build("bell_measure.ll") - - :param name: name of the register - :type name: str - :param size: size of the register - :type size: int - """ - self.pyqir.add_classical_register(name, size) - - def add_quantum_register(self, name: str, size: int): - """ - Models an array of qubits of the given size. The individual values - are accessed by name "" with 0 based indicies. - Example: - builder = QirBuilder("Bell circuit") - builder.add_quantum_register("qr", 2) - builder.add_classical_register("qc", 2) - builder.h("qr0") - builder.cx("qr0", "qr1") - builder.m("qr0", "qc0") - builder.m("qr1", "qc1") - builder.build("bell_measure.ll") - - :param name: name of the register - :type name: str - :param size: size of the register - :type size: int - """ - self.pyqir.add_quantum_register(name, size) - - def build(self, file_path: str): - """ - Writes the modeled circuit to the supplied file. - - :param file_path: file path of generated QIR - :type file_path: str - """ - self.pyqir.write(file_path) - - def get_ir_string(self): - """ - Returns the modeled circuit as an LLVM IR module (human readable) string. - """ - return self.pyqir.get_ir_string() - - def get_bitcode_base64_string(self): - """ - Returns the modeled circuit as a base64 encoded LLVM bitcode module. - """ - return self.pyqir.get_bitcode_base64_string() - - def enable_logging(self): - """ - Enables the logging infrastructure - Controlled via the RUST_LOG environment variable. - See https://docs.rs/env_logger/0.9.0/env_logger/#enabling-logging for details - - Example: - in tests.py: - def test_logging(): - builder = QirBuilder("logging test") - builder.enable_logging() - builder.add_quantum_register("qr", 1) - builder.h("qr0") - builder.build("test.ll") - - PowerShell: - $env:RUST_LOG="info" - python -m pytest - Bash: - RUST_LOG=info python -m pytest - - Example Output: - [2021-09-15T16:55:46Z INFO pyqir::python] Adding qr[0] - [2021-09-15T16:55:46Z INFO pyqir::python] h => qr0 - """ - self.pyqir.enable_logging() - -class QirModule: - """ - The QirModule object parses a QIR program from bitcode into an in-memory - representation for iterating over the program structure. It contains all the - functions and global definitions from the program. - - :param bitcode_path: the path to the bitcode file for the QIR program - :type bitcode_path: string - """ - - def __init__(self, bitcode_path: str): - self.module = module_from_bitcode(bitcode_path) - - def from_pyqir_module(self, module: PyQirModule): - self.module = module - - @property - def functions(self): - """ - Gets all the functions defined in this module. - :return: a list of functions in the module - :rtype: list[QirFunction] - """ - return list(map(QirFunction, self.module.functions)) - - - def get_func_by_name(self, name: str): - """ - Gets the function with the given name, or None if no matching function is found. - - :param name: the name of the function to get - :type name: string - :return: the function matchign the name, or None if not found - :rtype: QirFunction or None - """ - return QirFunction(self.module.get_func_by_name(name)) - - def get_funcs_by_attr(self, attr: str): - """ - Gets any functions that have an attribute whose name matches the provided string. - - :param attr: the attribute to use when looking for functions - :type attr: string - :return: a list of functions - :rtype: list[QirFunction] - """ - return list(map(QirFunction, self.module.get_funcs_by_attr(attr))) - - @property - def entrypoint_funcs(self): - """ - Gets any functions with the "EntryPoint" attribute. - :return: a list of functions - :rtype: list[QirFunction] - """ - return list(map(QirFunction, self.module.get_entrypoint_funcs())) - - @property - def interop_funcs(self): - """ - Gets any functions with the "InteropFriendly" attribute. - :return: a list of functions - :rtype: list[QirFunction] - """ - return list(map(QirFunction, self.module.get_interop_funcs())) - -class QirFunction: - """ - The QirFunction object represents a single function in the QIR program. It - is made up of one or more blocks that represent function execution flow. - - :param func: the function object from the underlying representation - :param type: PyQirFunction - """ - def __init__(self, func: PyQirFunction): - self.func = func - - @property - def name(self): - """ - Gets the string name for this function. - :return: the string name of the function - :rtype: str - """ - return self.func.name - - @property - def parameters(self): - """ - Gets the list of parameters used when calling this function. - :return: the list of parameters - :rtype: list[QirParameter] - """ - return list(map(QirParameter, self.func.parameters)) - - @property - def return_type(self): - """ - Gets the return type for this function. - :return: the type of the function - :rtype: QirType - """ - return QirType(self.func.return_type) - - @property - def blocks(self): - """ - Gets all the basic blocks for this function. - :return: a list of all basic blocks - :rtype: list[QirBlock] - """ - return list(map(QirBlock, self.func.blocks)) - - @property - def required_qubits(self): - """ - Gets the number of qubits needed to execute this function based on the - "RequiredQubits" attribute, or None if that attribute is not present. - :return: the number of qubits needed or None - :rtype: int or None - """ - return self.func.required_qubits - - @property - def required_results(self): - """ - Gets the number of result bits needed to execute this function based on the - "RequiredResults" attribute, or None if that attribute is not present. - :return: the number of results needed or None - :rtype: int or None - """ - return self.func.required_results - - def get_attribute_value(self, name: str): - """ - Gets the string value of the given attribute key name, or None if that attribute - is missing or has no defined value. - :param name: the name of the attribute to look for - :type name: str - :return: the value of the attribute or None - :rtype: str - """ - return self.func.get_attribute_value(name) - - def get_block_by_name(self, name: str): - """ - Gets the block with the given name, or None if no block with that name is found. - :param name: the name of the block to look for - :type name: str - :return: the QirBlock with that name or None - :rtype: QirBlock - """ - b = self.func.get_block_by_name(name) - if b is not None: - return QirBlock(b) - return None - - def get_instruction_by_output_name(self, name: str): - """ - Gets the instruction anywhere in the function where the variable with a given name - is set. Since LLVM requires any variable is defined by only one instruction, this is - guaranteed to be no more than one instruction. This will return None if no such instruction - can be found. - :param name: the name of the variable to search for - :type name: str - :return: the QirInstruction that defines that variable or None - :rtype: QirInstruction - """ - instr = self.func.get_instruction_by_output_name(name) - if instr is not None: - return QirInstruction(instr) - return None - -class QirParameter: - """ - The QirParameter object describes a parameter in a function definition or declaration. It - includes a type and a name, where the name is used in the function body as a variable. - :param param: the the parameter object from the underlying representation - :type param: PyQirParameter - """ - def __init__(self, param: PyQirParameter): - self.param = param - - @property - def name(self): - """ - Gets the name of this parameter, used as the variable identifier within the body of the - function. - :return: the name of the parameter - :rtype: str - """ - return self.param.name - - @property - def type(self): - """ - Gets the type of this parameter as represented in the QIR. - :return: the QIR type for this parameter - :rtype: QirType - """ - return QirType(self.param.type) - -class QirBlock: - """ - The QirBlock object represents a basic block within a function body. Each basic block is - comprised of a list of instructions executed in sequence and single, special final instruction - called a terminator that indicates where execution should jump at the end of the block. - :param block: the basic block object from the underlying representation - :type block: PyQirBasicBlock - """ - def __init__(self, block: PyQirBasicBlock): - self.block = block - - @property - def name(self): - """ - Gets the identifying name for this block. This is unique within a given function and acts - as a label for any branches that transfer execution to this block. - :return: the name for this block - :rtype: str - """ - return self.block.name - - @property - def instructions(self): - """ - Gets the list of instructions that make up this block. The list is ordered; instructions are - executed from first to last unconditionally. This list does not include the special - terminator instruction (see QirBlock.terminator). - :return: the list of instructions for the block - :rtype: list[QirInstruction] - """ - return list(map(QirInstruction, self.block.instructions)) - - @property - def terminator(self): - """ - Gets the terminator instruction for this block. Every block has exactly one terminator - and it is the last intruction in the block. - :return: the terminator for this block - :rtype: QirTerminator - """ - return QirTerminator(self.block.terminator) - - @property - def phi_nodes(self): - """ - Gets any phi nodes defined for this block. Phi nodes are a special instruction that defines - variables based on which block transfered execution to this block. A block may have any number - of phi nodes, but they are always the first instructions in any given block. A block with no - phi nodes will return an empty list. - :return: the phi nodes, if any, for this block. - :rtype: list[QirInstruction] - """ - return list(map(QirInstruction, self.block.phi_nodes)) - - def get_phi_pairs_by_source_name(self, name: str): - """ - Gets the variable name, variable value pairs for any phi nodes in this block that correspond - to the given name. If the name doesn't match a block that can branch to this block or if - this block doesn't include any phi nodes, the list will be empty. - :return: the list of name-value pairs for the given source block name - :rtype: list[(str, QirOperand)] - """ - return list(map(lambda p: (p[0], QirOperand(p[1])) ,self.block.get_phi_pairs_by_source_name(name))) - -class QirInstruction: - def __new__(cls, instr: PyQirInstruction): - if instr.is_qis_call: - return super().__new__(QirQisCallInstr) - elif instr.is_qrt_call: - return super().__new__(QirQrtCallInstr) - elif instr.is_qir_call: - return super().__new__(QirQirCallInstr) - elif instr.is_call: - return super().__new__(QirCallInstr) - elif instr.is_add: - return super().__new__(QirAddInstr) - elif instr.is_sub: - return super().__new__(QirSubInstr) - elif instr.is_mul: - return super().__new__(QirMulInstr) - elif instr.is_udiv: - return super().__new__(QirUDivInstr) - elif instr.is_sdiv: - return super().__new__(QirSDivInstr) - elif instr.is_urem: - return super().__new__(QirURemInstr) - elif instr.is_srem: - return super().__new__(QirSRemInstr) - elif instr.is_and: - return super().__new__(QirAndInstr) - elif instr.is_or: - return super().__new__(QirOrInstr) - elif instr.is_xor: - return super().__new__(QirXorInstr) - elif instr.is_shl: - return super().__new__(QirShlInstr) - elif instr.is_lshr: - return super().__new__(QirLShrInstr) - elif instr.is_ashr: - return super().__new__(QirAShrInstr) - elif instr.is_fadd: - return super().__new__(QirFAddInstr) - elif instr.is_fsub: - return super().__new__(QirFSubInstr) - elif instr.is_fmul: - return super().__new__(QirFMulInstr) - elif instr.is_fdiv: - return super().__new__(QirFDivInstr) - elif instr.is_frem: - return super().__new__(QirFRemInstr) - elif instr.is_fneg: - return super().__new__(QirFNegInstr) - elif instr.is_icmp: - return super().__new__(QirICmpInstr) - elif instr.is_fcmp: - return super().__new__(QirFCmpInstr) - elif instr.is_phi: - return super().__new__(QirPhiInstr) - else: - return super().__new__(cls) - - def __init__(self, instr: PyQirInstruction): - self.instr = instr - - @property - def output_name(self): - return self.instr.output_name - - @property - def type(self): - return QirType(self.instr.type) - -class QirOpInstr(QirInstruction): - @property - def target_operands(self): - return list(map(QirOperand, self.instr.target_operands)) - -class QirAddInstr(QirOpInstr): - pass - -class QirSubInstr(QirOpInstr): - pass - -class QirMulInstr(QirOpInstr): - pass - -class QirUDivInstr(QirOpInstr): - pass - -class QirSDivInstr(QirOpInstr): - pass - -class QirURemInstr(QirOpInstr): - pass - -class QirSRemInstr(QirOpInstr): - pass - -class QirAndInstr(QirOpInstr): - pass - -class QirOrInstr(QirOpInstr): - pass - -class QirXorInstr(QirOpInstr): - pass - -class QirShlInstr(QirOpInstr): - pass - -class QirLShrInstr(QirOpInstr): - pass - -class QirAShrInstr(QirOpInstr): - pass - -class QirFAddInstr(QirOpInstr): - pass - -class QirFSubInstr(QirOpInstr): - pass - -class QirFMulInstr(QirOpInstr): - pass - -class QirFDivInstr(QirOpInstr): - pass - -class QirFRemInstr(QirOpInstr): - pass - -class QirFNegInstr(QirOpInstr): - pass - -class QirICmpInstr(QirOpInstr): - @property - def predicate(self): - return self.instr.icmp_predicate - -class QirFCmpInstr(QirOpInstr): - @property - def predicate(self): - return self.instr.fcmp_predicate - -class QirPhiInstr(QirInstruction): - @property - def incoming_values(self): - return list(map(lambda p: (QirOperand(p[0]), p[1]), self.instr.phi_incoming_values)) - - def get_incoming_values_for_name(self, name: str): - return list(map(QirOperand, self.instr.get_phi_incoming_values_for_name(name))) - -class QirCallInstr(QirInstruction): - @property - def func_name(self): - return self.instr.call_func_name - - @property - def func_args(self): - return list(map(QirOperand, self.instr.call_func_params)) - -class QirQisCallInstr(QirCallInstr): - pass - -class QirQrtCallInstr(QirCallInstr): - pass - -class QirQirCallInstr(QirCallInstr): - pass - -class QirTerminator: - def __new__(cls, term: PyQirTerminator): - if term.is_ret: - return super().__new__(QirRetTerminator) - elif term.is_br: - return super().__new__(QirBrTerminator) - elif term.is_condbr: - return super().__new__(QirCondBrTerminator) - elif term.is_switch: - return super().__new__(QirSwitchTerminator) - elif term.is_unreachable: - return super().__new__(QirUnreachableTerminator) - else: - return super().__new__(cls) - - def __init__(self, term: PyQirTerminator) -> None: - self.term = term - -class QirRetTerminator(QirTerminator): - @property - def operand(self): - return QirOperand(self.term.ret_operand) - -class QirBrTerminator(QirTerminator): - @property - def dest(self): - return self.term.br_dest - -class QirCondBrTerminator(QirTerminator): - @property - def condition(self): - return QirOperand(self.term.condbr_condition) - - @property - def true_dest(self): - return self.term.condbr_true_dest - - @property - def false_dest(self): - return self.term.condbr_false_dest - -class QirSwitchTerminator(QirTerminator): - pass - -class QirUnreachableTerminator(QirTerminator): - pass - -class QirOperand: - def __new__(cls, op: PyQirOperand): - if op.is_local: - return super().__new__(QirLocalOperand) - elif op.is_constant: - return QirConstant(op.constant) - else: - return super().__new__(cls) - - def __init__(self, op: PyQirOperand): - self.op = op - -class QirLocalOperand(QirOperand): - @property - def name(self): - return self.op.local_name - - @property - def type(self): - return QirType(self.op.local_type) - -class QirConstant: - def __new__(cls, const: PyQirConstant): - if const.is_qubit: - return super().__new__(QirQubitConstant) - elif const.is_result: - return super().__new__(QirResultConstant) - elif const.is_int: - return super().__new__(QirIntConstant) - elif const.is_float: - return super().__new__(QirDoubleConstant) - elif const.is_null: - return super().__new__(QirNullConstant) - else: - return super().__new__(cls) - - def __init__(self, const: PyQirConstant): - self.const = const - - @property - def type(self): - return QirType(self.const.type) - -class QirIntConstant(QirConstant): - @property - def value(self): - return self.const.int_value - - @property - def width(self): - return self.const.int_width - -class QirDoubleConstant(QirConstant): - @property - def value(self): - return self.const.float_double_value - -class QirNullConstant(QirConstant): - pass - -class QirQubitConstant(QirConstant): - @property - def id(self): - return self.const.qubit_static_id - -class QirResultConstant(QirConstant): - @property - def id(self): - return self.const.result_static_id - -class QirType: - def __new__(cls, ty: PyQirType): - if ty.is_qubit: - return super().__new__(QirQubitType) - elif ty.is_result: - return super().__new__(QirResultType) - elif ty.is_void: - return super().__new__(QirVoidType) - elif ty.is_integer: - return super().__new__(QirIntegerType) - elif ty.is_pointer: - return super().__new__(QirPointerType) - elif ty.is_double: - return super().__new__(QirDoubleType) - elif ty.is_array: - return super().__new__(QirArrayType) - elif ty.is_struct: - return super().__new__(QirStructType) - elif ty.is_named_struct: - return super().__new__(QirNamedStruct) - else: - return super().__new__(cls) - - def __init__(self, ty: PyQirType): - self.ty = ty - -class QirVoidType(QirType): - pass - -class QirIntegerType(QirType): - @property - def width(self): - return self.ty.integer_width - -class QirPointerType(QirType): - @property - def type(self): - return QirType(self.ty.pointer_type) - - @property - def addrspace(self): - return self.ty.pointer_addrspace - -class QirDoubleType(QirType): - pass - -class QirArrayType(QirType): - @property - def element_types(self): - return list(map(QirType, self.ty.array_element_type)) - - @property - def element_count(self): - return self.ty.array_num_elements - -class QirStructType(QirType): - @property - def struct_element_types(self): - return list(map(QirType, self.ty.struct_element_types)) - -class QirNamedStruct(QirType): - @property - def name(self): - return self.ty.named_struct_name - -class QirQubitType(QirPointerType): - pass - -class QirResultType(QirPointerType): - pass +from .parser import * +from .builder import * \ No newline at end of file diff --git a/src/QirTools/pyqir/pyqir/builder.py b/src/QirTools/pyqir/pyqir/builder.py new file mode 100644 index 0000000000..b70026e82a --- /dev/null +++ b/src/QirTools/pyqir/pyqir/builder.py @@ -0,0 +1,258 @@ +# Copyright(c) Microsoft Corporation. +# Licensed under the MIT License. + +from .pyqir import * + +class QirBuilder: + """ + The QirBuilder object describes quantum circuits and emits QIR + + :param module: name of the QIR module + :type module: str + """ + + def __init__(self, module: str): + self.pyqir = PyQIR(module) + + def cx(self, control: str, target: str): + """ + Applies controlled X operation to the target qubit + + :param control: name of the control qubit + :type control: str + :param target: name of the target qubit + :type target: str + """ + self.pyqir.cx(control, target) + + def cz(self, control: str, target: str): + """ + Applies controlled Z operation to the target qubit + + :param control: name of the control qubit + :type control: str + :param target: name of the target qubit + :type target: str + """ + self.pyqir.cz(control, target) + + def h(self, target: str): + """ + Applies H operation to the target qubit + + :param target: name of the target qubit + :type target: str + """ + self.pyqir.h(target) + + def m(self, qubit: str, target: str): + """ + Applies measurement operation or the source qubit into the target register + + :param qubit: name of the source qubit + :type qubit: str + :param target: name of the target register + :type target: str + """ + self.pyqir.m(qubit, target) + + def reset(self, target: str): + """ + Applies Reset operation to the target qubit + + :param target: name of the target qubit + :type target: str + """ + self.pyqir.reset(target) + + def rx(self, theta: float, qubit: str): + """ + Applies Rx operation to the target qubit + + :param theta: rotation value for target qubit + :type theta: float + :param qubit: name of the target qubit + :type qubit: str + """ + self.pyqir.rx(theta, qubit) + + def ry(self, theta: float, qubit: str): + """ + Applies Ry operation to the target qubit + + :param theta: rotation value for target qubit + :type theta: float + :param qubit: name of the target qubit + :type qubit: str + """ + self.pyqir.ry(theta, qubit) + + def rz(self, theta: float, qubit: str): + """ + Applies Rz operation to the target qubit + + :param theta: rotation value for target qubit + :type theta: float + :param qubit: name of the target qubit + :type qubit: str + """ + self.pyqir.rz(theta, qubit) + + def s(self, qubit: str): + """ + Applies S operation to the target qubit + + :param qubit: name of the target qubit + :type qubit: str + """ + self.pyqir.s(qubit) + + def s_adj(self, qubit: str): + """ + Applies SAdj operation to the target qubit + + :param qubit: name of the target qubit + :type qubit: str + """ + self.pyqir.s_adj(qubit) + + def t(self, qubit: str): + """ + Applies T operation to the target qubit + + :param qubit: name of the target qubit + :type qubit: str + """ + self.pyqir.t(qubit) + + def t_adj(self, qubit: str): + """ + Applies TAdj operation to the target qubit + + :param qubit: name of the target qubit + :type qubit: str + """ + self.pyqir.t_adj(qubit) + + def x(self, qubit: str): + """ + Applies X operation to the target qubit + + :param qubit: name of the target qubit + :type qubit: str + """ + self.pyqir.x(qubit) + + def y(self, qubit: str): + """ + Applies Y operation to the target qubit + + :param qubit: name of the target qubit + :type qubit: str + """ + self.pyqir.y(qubit) + + def z(self, qubit: str): + """ + Applies Z operation to the target qubit + + :param qubit: name of the target qubit + :type qubit: str + """ + self.pyqir.z(qubit) + + def dump_machine(self): + """ + + """ + self.pyqir.dump_machine() + + def add_classical_register(self, name: str, size: int): + """ + Models a classical register of the given size. The individual values + are accessed by name "" with 0 based indicies. + Example: + builder = QirBuilder("Bell circuit") + builder.add_quantum_register("qr", 2) + builder.add_classical_register("qc", 2) + builder.h("qr0") + builder.cx("qr0", "qr1") + builder.m("qr0", "qc0") + builder.m("qr1", "qc1") + builder.build("bell_measure.ll") + + :param name: name of the register + :type name: str + :param size: size of the register + :type size: int + """ + self.pyqir.add_classical_register(name, size) + + def add_quantum_register(self, name: str, size: int): + """ + Models an array of qubits of the given size. The individual values + are accessed by name "" with 0 based indicies. + Example: + builder = QirBuilder("Bell circuit") + builder.add_quantum_register("qr", 2) + builder.add_classical_register("qc", 2) + builder.h("qr0") + builder.cx("qr0", "qr1") + builder.m("qr0", "qc0") + builder.m("qr1", "qc1") + builder.build("bell_measure.ll") + + :param name: name of the register + :type name: str + :param size: size of the register + :type size: int + """ + self.pyqir.add_quantum_register(name, size) + + def build(self, file_path: str): + """ + Writes the modeled circuit to the supplied file. + + :param file_path: file path of generated QIR + :type file_path: str + """ + self.pyqir.write(file_path) + + def get_ir_string(self): + """ + Returns the modeled circuit as an LLVM IR module (human readable) string. + """ + return self.pyqir.get_ir_string() + + def get_bitcode_base64_string(self): + """ + Returns the modeled circuit as a base64 encoded LLVM bitcode module. + """ + return self.pyqir.get_bitcode_base64_string() + + def enable_logging(self): + """ + Enables the logging infrastructure + Controlled via the RUST_LOG environment variable. + See https://docs.rs/env_logger/0.9.0/env_logger/#enabling-logging for details + + Example: + in tests.py: + def test_logging(): + builder = QirBuilder("logging test") + builder.enable_logging() + builder.add_quantum_register("qr", 1) + builder.h("qr0") + builder.build("test.ll") + + PowerShell: + $env:RUST_LOG="info" + python -m pytest + Bash: + RUST_LOG=info python -m pytest + + Example Output: + [2021-09-15T16:55:46Z INFO pyqir::python] Adding qr[0] + [2021-09-15T16:55:46Z INFO pyqir::python] h => qr0 + """ + self.pyqir.enable_logging() diff --git a/src/QirTools/pyqir/pyqir/parser.py b/src/QirTools/pyqir/pyqir/parser.py new file mode 100644 index 0000000000..354817e651 --- /dev/null +++ b/src/QirTools/pyqir/pyqir/parser.py @@ -0,0 +1,892 @@ +# Copyright(c) Microsoft Corporation. +# Licensed under the MIT License. + +from .pyqir import * +from typing import List, Optional, Tuple + + +class QirType: + """ + Instances of QirType represent a type description in QIR. Specific subclasses may contain + additional properties of that type. + """ + def __new__(cls, ty: PyQirType): + if ty.is_qubit: + return super().__new__(QirQubitType) + elif ty.is_result: + return super().__new__(QirResultType) + elif ty.is_void: + return super().__new__(QirVoidType) + elif ty.is_integer: + return super().__new__(QirIntegerType) + elif ty.is_pointer: + return super().__new__(QirPointerType) + elif ty.is_double: + return super().__new__(QirDoubleType) + elif ty.is_array: + return super().__new__(QirArrayType) + elif ty.is_struct: + return super().__new__(QirStructType) + elif ty.is_named_struct: + return super().__new__(QirNamedStructType) + else: + return super().__new__(cls) + + def __init__(self, ty: PyQirType): + self.ty = ty + +class QirVoidType(QirType): + """ + Instances of QirVoidType represent a void type in QIR. + """ + pass + +class QirIntegerType(QirType): + """ + Instances of QirIntegerType represent a signed integer in QIR. Note that there is no unsigned + integer type, just unsigned arithmetic instructions. + """ + + @property + def width(self) -> int: + """ + Gets the bit width of this integer type. + """ + return self.ty.integer_width + +class QirPointerType(QirType): + """ + Instances of QirPointerType represent a pointer to some other type in QIR. + """ + + @property + def type(self) -> QirType: + """ + Gets the QirType this to which this pointer points. + """ + return QirType(self.ty.pointer_type) + + @property + def addrspace(self): + """ + Gets the address space to which this pointer points. + """ + return self.ty.pointer_addrspace + +class QirDoubleType(QirType): + """ + Instances of QirDoubleType represent the double-sized floating point type in a QIR program. + """ + pass + +class QirArrayType(QirType): + """ + Instances of the QirArrayType represent the native LLVM fixed-length array type in a QIR program. + """ + + @property + def element_types(self) -> List[QirType]: + """ + Gets the ordered list of QirTypes representing the underlying array types. + """ + return list(map(QirType, self.ty.array_element_type)) + + @property + def element_count(self) -> int: + """ + Gets the count of elements in the array. + """ + return self.ty.array_num_elements + +class QirStructType(QirType): + """ + Instances of QirStructType represent an anonymous struct with inline defined types in QIR. + """ + + @property + def struct_element_types(self) -> List[QirType]: + """ + Gets the ordered list of QirTypes representing the underlying struct types. + """ + return list(map(QirType, self.ty.struct_element_types)) + +class QirNamedStructType(QirType): + """ + Instances of QirNamedStruct represent a globally defined struct, often used to represent opaque + poitners. + """ + + @property + def name(self) -> str: + """ + Gets the name of this struct. + """ + return self.ty.named_struct_name + +class QirQubitType(QirNamedStructType): + """ + Instances of QirQubitType are specific QIR opaque pointer corresponding to the Qubit special + type. + """ + pass + +class QirResultType(QirNamedStructType): + """ + Instances of QirResultType are specific QIR opaque pointer corresponding to the Result special + type. + """ + pass + +class QirOperand: + """ + Instances of QirOperand represent an instance in a QIR program, either a local operand (variable) + or constant. + """ + def __new__(cls, op: PyQirOperand): + if op.is_local: + return super().__new__(QirLocalOperand) + elif op.is_constant: + if op.constant.is_qubit: + return super().__new__(QirQubitConstant) + elif op.constant.is_result: + return super().__new__(QirResultConstant) + elif op.constant.is_int: + return super().__new__(QirIntConstant) + elif op.constant.is_float: + return super().__new__(QirDoubleConstant) + elif op.constant.is_null: + return super().__new__(QirNullConstant) + else: + return super().__new__(cls) + else: + return super().__new__(cls) + + def __init__(self, op: PyQirOperand): + self.op = op + self.const = op.constant + +class QirLocalOperand(QirOperand): + """ + Instances of QirLocalOperand represent a typed local variable in a QIR program. + """ + + @property + def name(self) -> str: + """ + Gets the name identifier for this operand. This could be an identifier from the original + source language, a generated name based on an identifier, or a generated integer name. + """ + return self.op.local_name + + @property + def type(self) -> QirType: + """ + Gets the QirType instance representing the type for this operand. + """ + return QirType(self.op.local_type) + +class QirConstant(QirOperand): + """ + Instances of QirConstant represent a constant value in a QIR program. + """ + + @property + def type(self) -> QirType: + """ + Gets the QirType instance representing the type of this constant. + """ + return QirType(self.const.type) + +class QirIntConstant(QirConstant): + """ + Instances of QirIntConstant represent a constant integer value in a QIR program. + """ + + @property + def value(self) -> int: + """ + Gets the integer value for this constant. + """ + return self.const.int_value + + @property + def width(self) -> int: + """ + Gets the bit width for this integer constant. + """ + return self.const.int_width + +class QirDoubleConstant(QirConstant): + """ + Instances of QirDoubleConstant represent a constant double-sized float value in a QIR program. + """ + + @property + def value(self) -> float: + """ + Gets the double-sized float value for this constant. + """ + return self.const.float_double_value + +class QirNullConstant(QirConstant): + """ + Instances of QirNullConstant represent a constant null pointer in a QIR program. Use the type + property to inspect which pointer type this null represents. + """ + + @property + def value(self): + """ + The value of QirNullConstant instances is always None. + """ + return None + +class QirQubitConstant(QirConstant): + """ + Instances of QirQubitConstant represent a statically allocated qubit id in a QIR program. + """ + + @property + def value(self) -> int: + """ + Gets the integer identifier for this qubit constant. + """ + return self.const.qubit_static_id + + @property + def id(self) -> int: + """ + Gets the integer identifier for this qubit constant. + """ + return self.value + +class QirResultConstant(QirConstant): + """ + Instances of QirResultConstant represent a statically allocated result id in a QIR program. + """ + + @property + def value(self) -> int: + """ + Gets the integer identifier for the is result constant. + """ + return self.const.result_static_id + + @property + def id(self) -> int: + """ + gets the integer identifier for this result constant. + """ + return self.value + +class QirTerminator: + """ + Instances of QirTerminator represent the special final instruction at the end of a block that + indicates how control flow should transfer. + """ + + def __new__(cls, term: PyQirTerminator): + if term.is_ret: + return super().__new__(QirRetTerminator) + elif term.is_br: + return super().__new__(QirBrTerminator) + elif term.is_condbr: + return super().__new__(QirCondBrTerminator) + elif term.is_switch: + return super().__new__(QirSwitchTerminator) + elif term.is_unreachable: + return super().__new__(QirUnreachableTerminator) + else: + return super().__new__(cls) + + def __init__(self, term: PyQirTerminator) -> None: + self.term = term + +class QirRetTerminator(QirTerminator): + """ + Instances of QirRetTerminator represent the ret instruction in a QIR program. + """ + + @property + def operand(self) -> QirOperand: + """ + Gets the operand that will be returned by the ret instruction. + """ + return QirOperand(self.term.ret_operand) + +class QirBrTerminator(QirTerminator): + """ + Instances of QirBrTerminator represent a branch terminator instruction that unconditionally + jumps execution to the named destination block. + """ + + @property + def dest(self) -> str: + """ + Gets the name of the block this branch jumps to. + """ + return self.term.br_dest + +class QirCondBrTerminator(QirTerminator): + """ + Instances of QirCondBrTerminator represent a conditional branch terminator instruction that + decides which named block to jump to based on an given operand. + """ + + @property + def condition(self) -> QirOperand: + """ + Gets the QirOperand representing the condition used to determine the block to jump to. + """ + return QirOperand(self.term.condbr_condition) + + @property + def true_dest(self) -> str: + """ + Gets the name of the block that will be jumped to if the condition evaluates to true. + """ + return self.term.condbr_true_dest + + @property + def false_dest(self) -> str: + """ + Gets the name of the block that will be jumped to if the condition evaluates to false. + """ + return self.term.condbr_false_dest + +class QirSwitchTerminator(QirTerminator): + """ + Instances of QirSwitchTerminator represent a switch terminator instruction that can jump + to one or more blocks based on matching values of a given operand, or jump to a fallback block + in the case that no matches are found. + Currently unimplemented. + """ + pass + +class QirUnreachableTerminator(QirTerminator): + """ + Instances of QirUnreachableTerminator represent an unreachable terminator instruction. As the name + implies, this terminator is not expected to be reached such that some instruction in the block + before this terminator should halt program execution. + """ + pass + +class QirInstr: + """ + Instances of QirInstr represent an instruction within a block of a QIR program. See the subclasses + of this type for specifically supported instructions. + """ + + def __new__(cls, instr: PyQirInstruction): + if instr.is_qis_call: + return super().__new__(QirQisCallInstr) + elif instr.is_rt_call: + return super().__new__(QirRtCallInstr) + elif instr.is_qir_call: + return super().__new__(QirQirCallInstr) + elif instr.is_call: + return super().__new__(QirCallInstr) + elif instr.is_add: + return super().__new__(QirAddInstr) + elif instr.is_sub: + return super().__new__(QirSubInstr) + elif instr.is_mul: + return super().__new__(QirMulInstr) + elif instr.is_udiv: + return super().__new__(QirUDivInstr) + elif instr.is_sdiv: + return super().__new__(QirSDivInstr) + elif instr.is_urem: + return super().__new__(QirURemInstr) + elif instr.is_srem: + return super().__new__(QirSRemInstr) + elif instr.is_and: + return super().__new__(QirAndInstr) + elif instr.is_or: + return super().__new__(QirOrInstr) + elif instr.is_xor: + return super().__new__(QirXorInstr) + elif instr.is_shl: + return super().__new__(QirShlInstr) + elif instr.is_lshr: + return super().__new__(QirLShrInstr) + elif instr.is_ashr: + return super().__new__(QirAShrInstr) + elif instr.is_fadd: + return super().__new__(QirFAddInstr) + elif instr.is_fsub: + return super().__new__(QirFSubInstr) + elif instr.is_fmul: + return super().__new__(QirFMulInstr) + elif instr.is_fdiv: + return super().__new__(QirFDivInstr) + elif instr.is_frem: + return super().__new__(QirFRemInstr) + elif instr.is_fneg: + return super().__new__(QirFNegInstr) + elif instr.is_icmp: + return super().__new__(QirICmpInstr) + elif instr.is_fcmp: + return super().__new__(QirFCmpInstr) + elif instr.is_phi: + return super().__new__(QirPhiInstr) + else: + return super().__new__(cls) + + def __init__(self, instr: PyQirInstruction): + self.instr = instr + + @property + def output_name(self) -> Optional[str]: + """ + Gets the name of the local operand that receives the output of this instruction, or + None if the instruction does not return a value. + """ + return self.instr.output_name + + @property + def type(self) -> QirType: + """ + Gets the QirType instance representing the output of this instruction. If the instruction + has no output, the type will be an instance of QirVoidType. + """ + return QirType(self.instr.type) + +class QirOpInstr(QirInstr): + """ + Instances of QirOpInstr represent the class of instructions that have one or more operands that + they operate on. + """ + + @property + def target_operands(self) -> List[QirOperand]: + """ + Gets the list of operands that this instruction operates on. + """ + return list(map(QirOperand, self.instr.target_operands)) + +class QirAddInstr(QirOpInstr): + """ + Instances of QirAddIntr represent an integer addition instruction that takes two operands. + """ + pass + +class QirSubInstr(QirOpInstr): + """ + Instances of QirSubIntr represent an integer subtraction instruction that takes two operands. + """ + pass + +class QirMulInstr(QirOpInstr): + """ + Instances of QirMulIntr represent an integer multiplication instruction that takes two operands. + """ + pass + +class QirUDivInstr(QirOpInstr): + """ + Instances of QirUDivIntr represent an unsigned integer division instruction that takes two operands. + """ + pass + +class QirSDivInstr(QirOpInstr): + """ + Instances of QirSDivIntr represent a signed integer division instruction that takes two operands. + """ + pass + +class QirURemInstr(QirOpInstr): + """ + Instances of QirURemIntr represent an unsigned integer remainder instruction that takes two operands. + """ + pass + +class QirSRemInstr(QirOpInstr): + """ + Instances of QirSRemIntr represent a signed integer remainder instruction that takes two operands. + """ + pass + +class QirAndInstr(QirOpInstr): + """ + Instances of QirAndIntr represent a boolean and instruction that takes two operands. + """ + pass + +class QirOrInstr(QirOpInstr): + """ + Instances of QirOrIntr represent a boolean or instruction that takes two operands. + """ + pass + +class QirXorInstr(QirOpInstr): + """ + Instances of QirXorIntr represent a boolean xor instruction that takes two operands. + """ + pass + +class QirShlInstr(QirOpInstr): + """ + Instances of QirShlIntr represent a bitwise shift left instruction that takes two operands. + """ + pass + +class QirLShrInstr(QirOpInstr): + """ + Instances of QirLShrIntr represent a logical bitwise shift right instruction that takes two operands. + """ + pass + +class QirAShrInstr(QirOpInstr): + """ + Instances of QirLShrIntr represent an arithmetic bitwise shift right instruction that takes two operands. + """ + pass + +class QirFAddInstr(QirOpInstr): + """ + Instances of QirFAddIntr represent a floating-point addition instruction that takes two operands. + """ + pass + +class QirFSubInstr(QirOpInstr): + """ + Instances of QirFSubIntr represent a floating-point subtraction instruction that takes two operands. + """ + pass + +class QirFMulInstr(QirOpInstr): + """ + Instances of QirFMulIntr represent a floating-point multiplication instruction that takes two operands. + """ + pass + +class QirFDivInstr(QirOpInstr): + """ + Instances of QirFDivIntr represent a floating-point division instruction that takes two operands. + """ + pass + +class QirFRemInstr(QirOpInstr): + """ + Instances of QirFRemIntr represent a floating-point remainder instruction that takes two operands. + """ + pass + +class QirFNegInstr(QirOpInstr): + """ + Instances of QirFNegIntr represent a floating-point negation instruction that takes one operand. + """ + pass + +class QirICmpInstr(QirOpInstr): + """ + Instances of QirICmpIntr represent an integer comparison instruction that takes two operands, + and uses a specific predicate to output the boolean result of the comparison. + """ + + @property + def predicate(self) -> str: + """ + Gets a string representing the predicate operation to perform. Possible values are + "eq", "ne", "ugt", "uge", "ult", "ule", "sgt", "sge", "slt", and "sle". + """ + return self.instr.icmp_predicate + +class QirFCmpInstr(QirOpInstr): + """ + Instances of QirFCmpInstr represent a floating-point comparison instruction that takes two operands, + and uses a specific predicate to output the boolean result of the comparison. + """ + + @property + def predicate(self) -> str: + """ + Gets a string representing the predicate operation to perform. Possible values are + "false", "oeq", "ogt", "oge", "olt", "ole", "one", "ord", "uno", "ueq", "ugt", "uge", "ult", + "ule", "une", and "true" + """ + return self.instr.fcmp_predicate + +class QirPhiInstr(QirInstr): + """ + Instances of QirPhiInstr represent a phi instruction that selects a value for an operand based + on the name of the block that transferred execution to the current block. + """ + + @property + def incoming_values(self) -> List[Tuple[QirOperand, str]]: + """ + Gets a list of all the incoming value pairs for this phi node, where each pair is the QirOperand + for the value to use and the string name of the originating block. + """ + return list(map(lambda p: (QirOperand(p[0]), p[1]), self.instr.phi_incoming_values)) + + def get_incoming_value_for_name(self, name: str) -> Optional[QirOperand]: + """ + Gets the QirOperand representing the value for a given originating block, or None if that + name is not found. + :param name: the block name to search for. + """ + op = self.instr.get_phi_incoming_value_for_name(name) + if isinstance(op, PyQirOperand): + return QirOperand(op) + else: + return None + +class QirCallInstr(QirInstr): + """ + Instances of QirCallInstr represent a call instruction in a QIR program. + """ + + @property + def func_name(self) -> str: + """ + Gets the name of the function called by this instruction. + """ + return self.instr.call_func_name + + @property + def func_args(self) -> List[QirOperand]: + """ + Gets the list of QirOperand instances that are passed as arguments to the function call. + """ + return list(map(QirOperand, self.instr.call_func_params)) + +class QirQisCallInstr(QirCallInstr): + """ + Instances of QirQisCallInstr represent a call instruction where the function name begins with + "__quantum__qis__" indicating that it is a function from the QIR quantum intrinsic set. + """ + pass + +class QirRtCallInstr(QirCallInstr): + """ + Instances of QirRtCallInstr represent a call instruction where the function name begins with + "__quantum__rt__" indicating that it is a function from the QIR runtime. + """ + pass + +class QirQirCallInstr(QirCallInstr): + """ + Instances of QirQirCallInstr represent a call instruction where the function name begins with + "__quantum__qir__" indicating that it is a function from the QIR base profile. + """ + pass + +class QirBlock: + """ + Instances of the QirBlock type represent a basic block within a function body. Each basic block is + comprised of a list of instructions executed in sequence and a single, special final instruction + called a terminator that indicates where execution should jump at the end of the block. + """ + + def __init__(self, block: PyQirBasicBlock): + self.block = block + + @property + def name(self) -> str: + """ + Gets the identifying name for this block. This is unique within a given function and acts + as a label for any branches that transfer execution to this block. + """ + return self.block.name + + @property + def instructions(self) -> List[QirInstr]: + """ + Gets the list of instructions that make up this block. The list is ordered; instructions are + executed from first to last unconditionally. This list does not include the special + terminator instruction (see QirBlock.terminator). + """ + return list(map(QirInstr, self.block.instructions)) + + @property + def terminator(self) -> QirTerminator: + """ + Gets the terminator instruction for this block. Every block has exactly one terminator + and it is the last intruction in the block. + """ + return QirTerminator(self.block.terminator) + + @property + def phi_nodes(self) -> List[QirPhiInstr]: + """ + Gets any phi nodes defined for this block. Phi nodes are a special instruction that defines + variables based on which block transferred execution to this block. A block may have any number + of phi nodes, but they are always the first instructions in any given block. A block with no + phi nodes will return an empty list. + """ + return list(map(QirPhiInstr, self.block.phi_nodes)) + + def get_phi_pairs_by_source_name(self, name: str) -> List[Tuple[str, QirOperand]]: + """ + Gets the variable name, variable value pairs for any phi nodes in this block that correspond + to the given name. If the name doesn't match a block that can branch to this block or if + this block doesn't include any phi nodes, the list will be empty. + """ + return list(map(lambda p: (p[0], QirOperand(p[1])) ,self.block.get_phi_pairs_by_source_name(name))) + +class QirParameter: + """ + Instances of the QirParameter type describe a parameter in a function definition or declaration. They + include a type and a name, where the name is used in the function body as a variable. + """ + + def __init__(self, param: PyQirParameter): + self.param = param + + @property + def name(self) -> str: + """ + Gets the name of this parameter, used as the variable identifier within the body of the + function. + """ + return self.param.name + + @property + def type(self) -> QirType: + """ + Gets the type of this parameter as represented in the QIR. + """ + return QirType(self.param.type) + +class QirFunction: + """ + Instances of the QirFunction type represent a single function in the QIR program. They + are made up of one or more blocks that represent function execution flow. + """ + + def __init__(self, func: PyQirFunction): + self.func = func + + @property + def name(self) -> str: + """ + Gets the string name for this function. + """ + return self.func.name + + @property + def parameters(self) -> List[QirParameter]: + """ + Gets the list of parameters used when calling this function. + """ + return list(map(QirParameter, self.func.parameters)) + + @property + def return_type(self) -> QirType: + """ + Gets the return type for this function. + """ + return QirType(self.func.return_type) + + @property + def blocks(self) -> List[QirBlock]: + """ + Gets all the basic blocks for this function. + """ + return list(map(QirBlock, self.func.blocks)) + + @property + def required_qubits(self) -> Optional[int]: + """ + Gets the number of qubits needed to execute this function based on the + "RequiredQubits" attribute, or None if that attribute is not present. + """ + return self.func.required_qubits + + @property + def required_results(self) -> Optional[int]: + """ + Gets the number of result bits needed to execute this function based on the + "RequiredResults" attribute, or None if that attribute is not present. + """ + return self.func.required_results + + def get_attribute_value(self, name: str) -> Optional[str]: + """ + Gets the string value of the given attribute key name, or None if that attribute + is missing or has no defined value. + :param name: the name of the attribute to look for + """ + return self.func.get_attribute_value(name) + + def get_block_by_name(self, name: str) -> Optional[QirBlock]: + """ + Gets the block with the given name, or None if no block with that name is found. + :param name: the name of the block to look for + """ + b = self.func.get_block_by_name(name) + if b is not None: + return QirBlock(b) + return None + + def get_instruction_by_output_name(self, name: str) -> Optional[QirInstr]: + """ + Gets the instruction anywhere in the function where the variable with a given name + is set. Since LLVM requires any variable is defined by only one instruction, this is + guaranteed to be no more than one instruction. This will return None if no such instruction + can be found. + :param name: the name of the variable to search for + """ + instr = self.func.get_instruction_by_output_name(name) + if instr is not None: + return QirInstr(instr) + return None + +class QirModule: + """ + Instances of QirModule parse a QIR program from bitcode into an in-memory + representation for iterating over the program structure. They contain all the + functions and global definitions from the program. + """ + + def __init__(self, *args): + if isinstance(args[0], PyQirModule): + self.module = args[0] + elif isinstance(args[0], str): + self.module = module_from_bitcode(args[0]) + else: + raise TypeError("Unrecognized argument type. Input must be string path to bitcode or PyQirModule object.") + + @property + def functions(self) -> List[QirFunction]: + """ + Gets all the functions defined in this module. + """ + return list(map(QirFunction, self.module.functions)) + + + def get_func_by_name(self, name: str) -> Optional[QirFunction]: + """ + Gets the function with the given name, or None if no matching function is found. + :param name: the name of the function to get + """ + f = self.module.get_func_by_name(name) + if isinstance(f, PyQirFunction): + return QirFunction(f) + else: + return None + + def get_funcs_by_attr(self, attr: str) -> List[QirFunction]: + """ + Gets any functions that have an attribute whose name matches the provided string. + :param attr: the attribute to use when looking for functions + """ + return list(map(QirFunction, self.module.get_funcs_by_attr(attr))) + + @property + def entrypoint_funcs(self) -> List[QirFunction]: + """ + Gets any functions with the "EntryPoint" attribute. + """ + return list(map(QirFunction, self.module.get_entrypoint_funcs())) + + @property + def interop_funcs(self) -> List[QirFunction]: + """ + Gets any functions with the "InteropFriendly" attribute. + """ + return list(map(QirFunction, self.module.get_interop_funcs())) + diff --git a/src/QirTools/pyqir/src/parser.rs b/src/QirTools/pyqir/src/parser.rs index e3bd72ec53..ef518b619f 100644 --- a/src/QirTools/pyqir/src/parser.rs +++ b/src/QirTools/pyqir/src/parser.rs @@ -101,7 +101,7 @@ impl PyQirModule { fn get_funcs_by_attr(&self, attr: String) -> Vec { self.module - .get_func_by_attr_name(&attr) + .get_funcs_by_attr_name(&attr) .iter() .map(|f| PyQirFunction { function: (*f).clone(), @@ -602,8 +602,8 @@ impl PyQirInstruction { } #[getter] - fn get_is_qrt_call(&self) -> bool { - llvm_ir::instruction::Call::try_from(self.instr.clone()).map_or(false, |c| c.is_qrt()) + fn get_is_rt_call(&self) -> bool { + llvm_ir::instruction::Call::try_from(self.instr.clone()).map_or(false, |c| c.is_rt()) } #[getter] diff --git a/src/QirTools/qirlib/src/parse/mod.rs b/src/QirTools/qirlib/src/parse/mod.rs index a3e5fe3cb4..779859df15 100644 --- a/src/QirTools/qirlib/src/parse/mod.rs +++ b/src/QirTools/qirlib/src/parse/mod.rs @@ -10,13 +10,13 @@ use llvm_ir; // convenience functions as well as QIR-specific utilities. pub trait ModuleExt { - fn get_func_by_attr_name(&self, name: &str) -> Vec<&llvm_ir::Function>; + fn get_funcs_by_attr_name(&self, name: &str) -> Vec<&llvm_ir::Function>; fn get_entrypoint_funcs(&self) -> Vec<&llvm_ir::Function>; fn get_interop_funcs(&self) -> Vec<&llvm_ir::Function>; } impl ModuleExt for llvm_ir::Module { - fn get_func_by_attr_name(&self, name: &str) -> Vec<&llvm_ir::Function> { + fn get_funcs_by_attr_name(&self, name: &str) -> Vec<&llvm_ir::Function> { self.functions .iter() .filter(|f| { @@ -31,11 +31,11 @@ impl ModuleExt for llvm_ir::Module { } fn get_entrypoint_funcs(&self) -> Vec<&llvm_ir::Function> { - self.get_func_by_attr_name("EntryPoint") + self.get_funcs_by_attr_name("EntryPoint") } fn get_interop_funcs(&self) -> Vec<&llvm_ir::Function> { - self.get_func_by_attr_name("InteropFriendly") + self.get_funcs_by_attr_name("InteropFriendly") } } @@ -187,7 +187,7 @@ impl IntructionExt for llvm_ir::Instruction { pub trait CallExt { fn get_func_name(&self) -> Option; fn is_qis(&self) -> bool; - fn is_qrt(&self) -> bool; + fn is_rt(&self) -> bool; fn is_qir(&self) -> bool; } @@ -206,9 +206,9 @@ impl CallExt for llvm_ir::instruction::Call { self.get_func_name() .map_or(false, |n| n.get_string().starts_with("__quantum__qis__")) } - fn is_qrt(&self) -> bool { + fn is_rt(&self) -> bool { self.get_func_name() - .map_or(false, |n| n.get_string().starts_with("__quantum__qrt__")) + .map_or(false, |n| n.get_string().starts_with("__quantum__rt__")) } fn is_qir(&self) -> bool { self.get_func_name() From 728d968a4a6a984f2ce8725c579f8f94f0e71659 Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Fri, 22 Oct 2021 23:03:48 -0700 Subject: [PATCH 24/26] Add support for swtich instructions --- src/QirTools/pyqir/pyqir/parser.py | 25 ++++++++++++-- src/QirTools/pyqir/src/parser.rs | 54 ++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 2 deletions(-) diff --git a/src/QirTools/pyqir/pyqir/parser.py b/src/QirTools/pyqir/pyqir/parser.py index 354817e651..506246a79d 100644 --- a/src/QirTools/pyqir/pyqir/parser.py +++ b/src/QirTools/pyqir/pyqir/parser.py @@ -359,9 +359,30 @@ class QirSwitchTerminator(QirTerminator): Instances of QirSwitchTerminator represent a switch terminator instruction that can jump to one or more blocks based on matching values of a given operand, or jump to a fallback block in the case that no matches are found. - Currently unimplemented. """ - pass + + @property + def operand(self) -> QirLocalOperand: + """ + Gets the operand variable of the switch statement. + """ + return QirLocalOperand(self.term.switch_operand) + + @property + def dest_pairs(self) -> List[Tuple[QirConstant, str]]: + """ + Gets a list of pairs representing the constant values to compare the operand against and the + matching block name to jump to if the comparison succeeds. + """ + return list(map(lambda p: (QirConstant(p[0]), p[1]), self.term.switch_dests)) + + @property + def default_dest(self) -> str: + """ + Gets the name of the default block that the switch will jump to if no values match the given + operand. + """ + return self.term.switch_default_dest class QirUnreachableTerminator(QirTerminator): """ diff --git a/src/QirTools/pyqir/src/parser.rs b/src/QirTools/pyqir/src/parser.rs index ef518b619f..29ba174313 100644 --- a/src/QirTools/pyqir/src/parser.rs +++ b/src/QirTools/pyqir/src/parser.rs @@ -716,6 +716,60 @@ impl PyQirTerminator { matches!(self.term, llvm_ir::Terminator::Switch(_)) } + #[getter] + fn get_switch_operand(&self) -> Option { + match_contents!( + &self.term, + llvm_ir::Terminator::Switch(llvm_ir::terminator::Switch { + operand, + dests: _, + default_dest: _, + debugloc: _, + }), + PyQirOperand { + op: operand.clone(), + types: self.types.clone(), + } + ) + } + + #[getter] + fn get_switch_dests(&self) -> Option> { + match_contents!( + &self.term, + llvm_ir::Terminator::Switch(llvm_ir::terminator::Switch { + operand: _, + dests, + default_dest: _, + debugloc: _, + }), + dests + .iter() + .map(|(cref, name)| ( + PyQirOperand { + op: llvm_ir::Operand::ConstantOperand(cref.clone()), + types: self.types.clone() + }, + name.get_string() + )) + .collect() + ) + } + + #[getter] + fn get_switch_default_dest(&self) -> Option { + match_contents!( + &self.term, + llvm_ir::Terminator::Switch(llvm_ir::terminator::Switch { + operand: _, + dests: _, + default_dest, + debugloc: _, + }), + default_dest.get_string() + ) + } + #[getter] fn get_is_unreachable(&self) -> bool { matches!(self.term, llvm_ir::Terminator::Unreachable(_)) From ec6c57f45bf32e901c6910c9373bf2ece880a614 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Mon, 25 Oct 2021 11:37:49 -0700 Subject: [PATCH 25/26] Add CFG plotting and circuit-like export to pyqir. --- src/QirTools/pyqir/dev-environment.yml | 20 ++ .../pyqir/examples/cfg-plotting.ipynb | 215 ++++++++++++++++ src/QirTools/pyqir/pyqir/__init__.py | 2 +- src/QirTools/pyqir/pyqir/export.py | 230 ++++++++++++++++++ src/QirTools/pyqir/pyqir/parser.py | 92 ++++++- 5 files changed, 552 insertions(+), 7 deletions(-) create mode 100644 src/QirTools/pyqir/dev-environment.yml create mode 100644 src/QirTools/pyqir/examples/cfg-plotting.ipynb create mode 100644 src/QirTools/pyqir/pyqir/export.py diff --git a/src/QirTools/pyqir/dev-environment.yml b/src/QirTools/pyqir/dev-environment.yml new file mode 100644 index 0000000000..4250eab2a0 --- /dev/null +++ b/src/QirTools/pyqir/dev-environment.yml @@ -0,0 +1,20 @@ +name: pyqir-dev +channels: +- conda-forge +dependencies: +- maturin +- tox +- pip +- llvm=11 +- llvm-tools=11 +- llvmdev=11 +- notebook +- matplotlib +- qutip +# Qiskit dependencies +- scipy>=1.0 +- dill +- scikit-learn +- pip: + - retworkx + - qiskit=0.31 diff --git a/src/QirTools/pyqir/examples/cfg-plotting.ipynb b/src/QirTools/pyqir/examples/cfg-plotting.ipynb new file mode 100644 index 0000000000..67a9bc0c3b --- /dev/null +++ b/src/QirTools/pyqir/examples/cfg-plotting.ipynb @@ -0,0 +1,215 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "sticky-oregon", + "metadata": {}, + "outputs": [], + "source": [ + "import pyqir\n", + "import retworkx as rx\n", + "import retworkx.visualization\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "million-convert", + "metadata": {}, + "outputs": [], + "source": [ + "module = pyqir.QirModule('../tests/teleportchain.baseprofile.bc')" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "9867bbc1", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "module.functions[0]" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "83388cf9", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA24AAANuCAYAAABuUVpnAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAADnLElEQVR4nOzdd1hT5/sG8DsJAcJeggxBHBUX7gXuvVurRQFX3VZr1VpbO9xatVqrrbPLhTho66qjdeMCxY2Ck+1ir0BCcn5/+DU/qaiIwAlwf67LS0nOuBMI5snznveVCIIggIiIiIiIiPSWVOwARERERERE9Gos3IiIiIiIiPQcCzciIiIiIiI9x8KNiIiIiIhIz7FwIyIiIiIi0nMs3IiIiIiIiPQcCzciIiIiIiI9x8KNiIiIiIhIz7FwIyIiIiIi0nMs3IiIiIiIiPQcCzciIiIiIiI9x8KNiIiIiIhIz7FwIyIiIiIi0nMs3IiIiIiIiPQcCzciIiIiIiI9x8KNiIiIiIhIz7FwIyIiIiIi0nMs3IiIiIiIiPQcCzciIiIiIiI9x8KNiIiIiIhIz7FwIyIiIiIi0nMs3IiIiIiIiPQcCzciIiIiIiI9x8KNiIiIiIhIz7FwIyIiIiIi0nMs3IiIiIiIiPQcCzciIiIiIiI9x8KNiIiIiIhIz7FwIyIiIiIi0nMs3IiIiIiIiPQcCzciIiIiIiI9x8KNiIiIiIhIz7FwIyIiIiIi0nMs3IiIiIiIiPQcCzciIiIiIiI9x8KNiIiIiIhIz7FwIyIiIiIi0nMs3IiIiIiIiPQcCzciIiIiIiI9x8KNiIiIiIhIz7FwIyIiIiIi0nMs3IiIiIiIiPQcCzciIiIiIiI9x8KNiIiIiIhIz7FwIyIiIiIi0nMs3IiIiIiIiPQcCzciIiIiIiI9x8KNiIiIiIhIz7FwIyIiIiIi0nMs3IiIiIiIiPQcCzciIiIiIiI9x8KNiIiIiIhIz7FwIyIiIiIi0nMs3IiIiIiIiPQcCzciIiIiIiI9x8KNiIiIiIhIz7FwIyIiIiIi0nMs3IiIiIiIiPQcCzciIiIiIiI9x8KNiIiIiIhIz7FwIyIiIiIi0nMs3IiIiIiIiPQcCzciIiIiIiI9ZyB2ACr7lCoNIh6mIzVbDZVGC0OZFNamhvCobA5juUzseEREREREZR4LN3pjgiAg5H4ytobGICw6BY/Sc6CQywAJIAiARAJAAJRqDRwsjNHEzRp+zV3Rwt0GEolE7PhERERERGWORBAEQewQVDbk5mkQGBqD9SfvIVWphlKlQWF+eCQAFIYyWCnkGNO2Gnybu8LIgJ04IiIiIqLCYuFGhXI1LhUTtl5EYqYKSrWmyMdRyGWwMzPEKr/G8HSxKr6ARERERETlGAs3eiWNVsDigxHYdC4KOWptsR3XWC7F0JZV8Xl3D8ikHD5JRERERPQqLNzopVR5WowPCMOZu0lv1WV7GYVcBu8atljt1wSGBpzglIiIiIjoZfhumQqk0QoYHxCG03cTS6RoA55OXnLqTiI+2hoGjZafHxARERERvQwLNyrQ4oMROHM3qViHRxYkR63F6TtJWHIookTPQ0RERERUlrFwoxdcjUvFpnNRJdZp+y+lWoONZ6NwNS61VM5HRERERFTWsHCjfHLzNPho68US77T9V45aiwlbLyI3r3SKRSIiIiKisoSFG+UTGBqDpEyVKOdOzFRh+/lYUc5NRERERKTPWLiRjiAIWH/yXqkNkfwvpVqDdSfvgROdEhERERHlx8KNdELuJyNVqRY1Q0q2CqFRyaJmICIiIiLSNyzcSGdraAyUqrfrtsWtHgFl1OUi769UabA1JOatMhARERERlTcs3EgnLDoFJT1IUdC+ujAUAITFpJRwCiIiIiKissVA7ACkH5QqDR6l5+i+zstIQsq/65ATex0SQwUsmr0Li6Z9kRocAHVSLCQyObJvn4OBRSXY9poCI8eaSNy7DJr0J3gSNBeQSGHpPQimHm0Qv3YkbHpMQtrpQBhY2ENqpICxexNYNO2jO1/CrxNh1cYfJu+0woO0HOSoNTCWy8R4KoiIiIiI9A47bgQAiHiYDsX/CiVB0OJJ0FzI7d3hMnEjHHwXIOP8bijvhQEAsm+HwLROW1SZvA2KGs2R/O9aAIBdn08hs6iESgNmwvXTIFi2HKA7fm7MNTiNWgP7gXNhWq8TssKP6e5TPboHTUYSFNWbAgAUchkiHmaU1kMnIiIiItJ7LNwIAJCarQYkT/+tenAbGmU6rFr7QiKTQ25VGWYNuyHrZjAAwNilDhTVm0EilcG0XkeoH99/7fEt2/hDamgMqdwIJjVbIi8lAerkeABAVvgxmNRuA4lMDgCQSJ5OUkJERERERE9xqCQBAFQaLZ7Nwp+X9hiajCTELB/4/xsIWhi51IGBRSXIzKx1N0sNjCDkqSBoNZBIXz600cDcTvdviYEcJh6tkRV+HJatfZF14wQq9Zvx/6cSAFVe6S4ATkRERESkz1i4EQDAUCaF5H8dNwMLOxhYOcB57M8vbJcaHPDqAz07yGtuN6vfCYl7v4eRSx1I5EYwcq6db1NDAzaDiYiIiIie4btjAgBYmcjxbEpJQ8d3IDU0Qdq5IGjVuRC0GqieRCH3wa3XHkdmaoW81Iev3c7IuTYgkSDl6K8wrdsx332CAFibGBbpcRARERERlUcs3AgA4FHZAkr106n6JVIZKg2YCdWje4hfOxJxK/yQdOBHaHOzX3scy5YfIO3MdsQsH4i0kD9fua1pvY5QP4mCab0O+W5XqjXwqGxe9AdDRERERFTOSARBKOmlu6iM8F58FPGpylI7X+a1I8i8cgiVBy/Jd7uLtQKnpnd8yV5ERERERBUPO26k08TNGi+5Qq3YadU5yLi0H2YNuuW7XQKgiat1wTsREREREVVQLNxIx6+5KxSGJb/otfJeGOJW+kNmYgXTuu3z3acwlMGvhWuJZyAiIiIiKks4VJJ0BEGA9+KjSEjLES2Ds5UCp6Z3gORls1MSEREREVVA7LiRjkQiwZi21aCQl3zXrSAKuQxj21Zj0UZERERE9B8s3Cgf3+ausDMTZyp+OzNDDGxWRZRzExERERHpMxZulI+RgQyr/BrDWF66PxrGcilW+zeBkYE43T4iIiIiIn3Gwo1e4OlihaEtq5bakEmFXIZhraqivrNlqZyPiIiIiKisYeFGBfq8uwe8a9iWeOfNWC6Fdw1bTO/mUaLnISIiIiIqy1i4UYFkUglW+zVB6xp2JdZ5U8hlaF3DDqv9mkAm5YQkREREREQvw+UA6JU0WgFLDkVg49ko5Ki1xXRUAVJBi9HtamJ6Nw8WbUREREREr8GOG72STCrBjB61sWNMKxiq0mGAtyveFHIZnC2NoT6wGF4mj1m0EREREREVAgs3KpSM6HDk/vk1ZvTwgLOVAiaGMhS25JIAMDGUwdlKgRk9PHB0Wgesmvc5Ro0aBaVSWZKxiYiIiIjKBQ6VpNcSBAHe3t4YN24chg4dCkEQEBqVjICQGFyMScHDtJyn18FJAEEAJP/7O0etQWVLYzRxtYZfC1c0r2qTb3HtQYMGoWrVqli0aJGIj46IiIiISP+xcKPX+vPPPzF37lyEhYVBJntxopIctQYRDzOQkq2CKk8LQwMprE0M4VHZHMavmNjk8ePHqF+/Pvbv348mTZqU5EMgIiIiIirTWLjRK6nVatSrVw8rV65Et27div34mzdvxrJly3D+/HnI5fJiPz4RERERUXnAa9zolX755Re4urqia9euJXL8wYMHw9HREUuXLi2R4xMRERERlQfsuNFLZWRk4J133sH+/fvRqFGjEjtPdHQ0mjZtiuDgYHh4cCFuIiIiIqL/YseNXmrp0qXo3LlziRZtAODm5oZZs2Zh9OjR0GqLa604IiIiIqLygx03KtCDBw9Qr149hIWFoWrVqiV+Pq1Wi7Zt28LPzw8fffRRiZ+PiIiIiKgsYeFGBRo3bhzMzMxK9dqziIgItGnTBmFhYXB1dS218xIRERER6TsWbvSCZwVUZGQkbGxsSvXcCxYswOnTp/H333/nW/ONiIiIiKgi4zVu9IIZM2Zg+vTppV60AcD06dMRHx+PrVu3lvq5iYiIiIj0FTtulM+pU6fg7++PyMhIGBsbi5IhLCwMvXr1wtWrV2Fvby9KBiIiIiIifcLCjXQEQYCXlxc++ugjDBkyRNQs06dPR2xsLAIDA0XNQURERESkDzhUknT++usvKJVK+Pv7ix0Fs2fPxoULF7B3716xoxARERERiY4dNwIAqNVq1K1bFz/99BO6du0qdhwAwPHjxzFkyBBcv34dlpaWYschIiIiIhINO24EAPj5559RtWpVvSnaAKB9+/bo2bMnPv/8c7GjEBERERGJih03QkZGBt555x3s378fjRo1EjtOPmlpaahXrx62bNmCdu3aiR2HiIiIiEgU7LgRli5dis6dO+td0QYAlpaWWL16NUaNGgWlUil2HCIiIiIiUbDjVsE9ePAA9erVw8WLF+Hm5iZ2nJcaNGgQ3NzcsHjxYrGjEBERERGVOhZuFdzYsWNhYWGB7777Tuwor/T48WPUr18f+/fvR5MmTcSOQ0RERERUqli4VWA3b95E27ZtERkZCRsbG7HjvNaWLVuwdOlSnD9/HnK5XOw4RERERESlhte4VWAzZszA559/XiaKNgDw9/eHk5OT3ncHiYiIiIiKGztuFVRwcDAGDx6MyMhIGBsbix2n0KKjo9G0aVMEBwfDw8ND7DhERERERKWCHbcKSBAETJ8+HfPnzy9TRRsAuLm5Yfbs2Rg1ahS0Wq3YcYiIiIiISgULtwrozz//hFKphL+/v9hRimT8+PEAgDVr1oichIiIiIiodHCoZAWjVqtRp04drF69Gl26dBE7TpFFRESgTZs2CAsLg6urq9hxiIiIiIhKFDtuFcz69etRrVq1Ml20AYCHhwemTJmCcePGgZ89EBEREVF5x45bBZKRkYGaNWvi4MGDaNiwodhx3pparUazZs0wbdo0DB48WOw4REREREQlhoVbBTJz5kxERUVh06ZNYkcpNmFhYejZsyeuXbsGe3t7seMQEREREZUIFm4VREJCAurXr4+LFy/Czc1N7DjFavr06YiNjUVgYKDYUYiIiIiISgQLtwpizJgxsLS0LJeLV2dnZ6NBgwZYtmwZ+vbtK3YcIiIiIqJix8KtArh79y5atmyJW7duwdraWuw4JeL48eMYMmQIrl+/DktLS7HjEBEREREVKxZuFUBubi5u3bqF+vXrix2lRI0dOxYSiQRr164VOwoRERERUbFi4VZBCIIAiUQidowSlZaWhnr16mHz5s1o37692HGIiIiIiIoN13Erhwqqxct70QYAlpaWWL16NUaPHg2lUil2HCIiIiKiYsOOWzlRETpqhTVo0CC4ublh8eLFYkchIiIiIioWLNzKmd9++w2CICA9PR1+fn5wcHAQO1Kpe/z4MerXr4+///4bTZs2FTsOEREREdFb41DJckCj0QAAAgICsGfPHty7dw8BAQFQKBTIzMxEbm6uyAlLl729PZYtW4aRI0dCrVaLHYeIiIiI6K2xcCsHZDIZAGDDhg3YuHEjLCws0KFDB1hYWOD8+fM4dOiQyAlLn7+/P5ydncvlunVEREREVPFwqGQ5oVQq8d1338HY2Bjbt29HWFgYAKBLly4YOHAgRo0aJXLC0hcdHY0mTZrg1KlT8PDwEDsOEREREVGRseNWhj1fcysUCnTr1g1//PEH6tSpg/DwcAQFBSEjI6NCFm0A4Obmhjlz5mDUqFHQarVixyEiIiIiKjJ23MqBzZs3w87ODl26dMH+/fsRGhqKf//9F82bN4ePjw/atGkjdkTRaLVatG3bFr6+vpgwYYLYcYiIiIiIioSFWzmwdOlS/Pbbb2jTpg0++eQTuLu7w9jYGBqNBgYGBmLHE11ERARat26NsLAwuLm5iR2HiIiIiOiNcahkOTBt2jSEhITA0tISffr0wfjx43Hv3j0Wbf/j4eGBqVOnYty4cQUuTk5EREREpO9YuJVBz4qPxMREbNiwATExMTA3N8eSJUuwbds27N+/H7/99pvIKfXLZ599hgcPHiAgIEDsKEREREREb4xDJcuwrVu3Ijg4GA4ODmjUqBE6duwIc3NzjB49GvPmzUPlypXFjqhXwsLC0LNnT1y7dg329vZixyEiIiIiKjR23MqYU6dOAQDOnj2LGzduwN/fH4aGhjhx4gSmTZuGtm3bQqFQsGgrQJMmTTB8+HBMmjRJ7ChERERERG+EHbcy5MGDB2jRogVu3LiBr776Cr1790aXLl2gVCpx9uxZJCUlITs7G/3794eZmZnYcfWSUqmEp6cnli1bhr59+4odh4iIiIioUFi4lSHjx4+Hq6srJk6ciOHDh+Odd97Bp59+Cjs7O7GjlSnHjx/HkCFDcP36dVhaWoodh4iIiIjotThUsowIDw/Htm3bkJeXh3Xr1sHExATx8fH4+++/cfHiRWRnZ4sdscxo3749evfujcOHD4sdhYiIiIioUNhxKyN8fX1hbm6OWrVqISMjAxYWFnj06BGePHkCe3t71KhRAwMGDICVlZXYUcsEjUaDnJwcmJqaih2FiIiIiOi12HErA8LCwnDjxg2sX78eo0ePRq1atZCcnAwLCwvUrVsXKSkpuHfvHou2NyCTyV5ZtKWlpWHq1KmlmIiIiIiI6OXYcSsDtFotoqOj4e7urrstLi4Ohw4dwv379yGRSDBs2DDUqFFDxJTlR0BAAD777DNIJBJMnz4dn3zyidiRiIiIiKiCY+FWxgiCAIlEovs6PDwcERER6N+/v4ipyodHjx7hvffew/379/Hw4UOo1Wo0b94c27dvxzvvvCN2PCIiIiKqwDhUsox5VrQ9q7fr1q3Lou0tCYKAVatWoVGjRhg7dixq1qyJGzduQC6XY+DAgfjrr7/EjkhEREREFZyB2AGoaJ7vulHRqdVq1KlTB02bNkVUVBQMDQ0hlUrxySef4N9//8UXX3wBjUYjdkwiIiIiquA4VLIMEQQBcXFxqFy5MuRyudhxyo2oqChUrVo1322HDh1CmzZtsH//fgwYMECcYERERERE/8OhkmVIUFAQ+vXrB5lMJnaUcqVq1aq6oadJSUm4ffs2GjRoAAMDA6xatUo3VJKdNyIiIiISCztuZYRKpUKdOnWwbt06dOrUSew45dbKlStx+vRppKeno3v37ujXrx+6deuGq1evsstJRERERKJhx62MWLduHWrWrMmirQTdv38fu3fvxpgxYxAQEIAdO3bg/v37aNOmDVJSUpCXlyd2RCIiIiKqoFi4lQHp6emYP38+Fi9eLHaUcs3d3R0ZGRmQSqWwsbFBy5Yt0aFDBxgZGcHe3h4GBgZIS0vD8uXLxY5KRERERBUMC7cyYMmSJejRowc8PT3FjlLurVu3Dj///DOqVq2Kffv2ITAwED/++CMAYP369XB3d8eZM2dETklEREREFQ2XA9Bz8fHxWLNmDS5fvix2lAqhUaNGqFOnDgRBwIoVK2Bvb4+4uDj4+Pjg8ePH+OOPP9ChQwexYxIRERFRBcPJSfTcqFGjYGtry2GSIvnuu+8wb948jBs3DkuWLAHwdKIYQ0NDaDQazvBJRERERKWCHTc9Fh4ejj179uDWrVtiR6lQBEFAVlYW6tWrBwsLC5w4cQKNGjXCH3/8gbCwMMTGxmLz5s2QyWQQBIGLoRMRERFRieM1bnrsiy++wIwZM2BlZSV2lApFIpHAzMwMK1euxNWrV9GoUSNkZGRgxYoVcHd3h0QiwaxZs8SOSUREREQVCDtueurEiRO4fv06goKCxI5SYfXt2xe7d++GmZkZOnXqhObNm6NGjRrw8fHB+++/j+TkZNjY2Igdk4iIiIgqAHbc9JAgCPjss8+wYMECGBkZiR2nQlOpVJgzZw4AQKlU4s6dO7C0tMTatWthZmYmcjoiIiIiqihYuOmhnTt3QqPRYNCgQWJHqfA++OADODo64pNPPkF6ejrkcjnUajWcnZ0RFxeH1NRUAIBWqxU3KBERERGVa5xVUs+oVCrUqVMH69evR8eOHcWOQwAeP36MoKAgZGZmok2bNggLC8Pvv/+Ohg0b4smTJ/jxxx/h5uYGrVYLqZSfhRARERFR8WPhpmd+/PFH7N+/HwcOHBA7ChVg3rx5uHnzJi5duoRff/0VSUlJ2LJlC7Zv3y52NCIiIiIqxzg5iR5JS0vD/Pnz8e+//4odhQqQkZGBkJAQbNu2DdHR0RgzZgy+++47yGQyPH78GJUqVeLSAERERERUIjiuS48sWbIEPXv2hKenp9hRqADZ2dmIiYlBZmYm6tati9atW+Pjjz9Gq1atYG9vz6KNiIiIiEoMh0rqifj4eHh6euLy5cuoUqWK2HHoJRYtWoRTp05h3759AIDvv/8evXr1Qq1atURORkRERETlGQs3PTFq1CjY2dlh0aJFYkeh15gwYQLeffdddOrUCTKZTOw4RERERFQBsHDTA+Hh4ejQoQNu3boFKysrsePQa2RnZ0MikUChUIgdhYiIiIgqCBZueqBPnz7o2LEjpkyZInYUegNarRbp6elQqVSwt7cXOw4RERERlWOcnERkx48fx/Xr1/HRRx+JHYXekFQqxW+//YahQ4eCn38QERERUUli4SYiQRAwffp0LFy4EEZGRmLHoSL4+OOP8fDhQ2zZskXsKERERERUjrFwE9HOnTuh1WoxcOBAsaNQEcnlcvz222+YNm0aHj16JHYcIiIiIiqneI2bSFQqFWrXro2ff/4ZHTt2FDsOvaXPP/8cUVFR2L59u9hRiIiIiKgcYsdNJGvXrkWtWrVYtJUTs2fPxsWLF7F7926xoxARERFROcSOmwjS0tLwzjvv4PDhw6hfv77YcaiYnDhxAv7+/rh+/TqXdSAiIiKiYsXCTQRfffUVEhIS8Pvvv4sdhYrZuHHjoNVqsX79erGjEBEREVE5wqGSpeTMmTPw9vbGn3/+ibVr12Lu3LliR6ISsHjxYhw4cADHjh0TOwoRERERlSMs3ErJnTt3cP78efj4+MDCwgJZWVliR6ISYGlpidWrV2P06NHIzs4WOw4RERERlRMs3EqJUqmETCaDRqNBdHQ06tevj7S0NLFjUQno06cPmjVrhlmzZokdhYiIiIjKCQOxA5RlSpUGEQ/TkZqthkqjhaFMCmtTQ3hUNoexXJZv2+zsbOTm5kImk8HS0hLbt2+HpaWlSMmppK1YsQL169fHwIED0bRpU7HjEBEREVEZx8LtDQiCgJD7ydgaGoOw6BQ8Ss+BQi4DJIAgABIJAAFQqjVwsDBGEzdr+DV3RQt3G9y4cQOCIKB79+7YvHkzrK2txX44VILs7e3x/fffY8SIEbhw4QIMDQ3FjkREREREZRhnlSyE3DwNAkNjsP7kPaQq1VCqNCjMkyYBoDCUwUohR2NFMiql38Ksb74q6bikJwRBQK9eveDl5YWvv/5a7DhEREREVIaxcHuNq3GpmLD1IhIzVVCqNUU+jkIug52ZIVb5NYani1XxBSS9FhMTgyZNmuDkyZOoXbu22HGIiIiIqIxi4fYSGq2AxQcjsOlcFHLU2mI7rrFciqEtq+Lz7h6QSSXFdlzSX6tXr8aWLVsQHBwMmUz2+h2IiIiIiP6Ds0oWQJWnxZjNF7D5XHSxFm0AkKPWYvO5aIzdcgGqvOI9NumncePGQSaTYfXq1WJHISIiIqIyih23/9BoBYzZfAGn7yYWe9H2PGO5FK1r2GHd4KbsvFUAkZGR8Pb2RlhYGNzc3MSOQ0RERERlDDtu/7H4YATO3E0q0aINeNp5O30nCUsORZToeUg/1KpVC59++inGjh0LflZCRERERG+KhdtzrsalYtO5qLeahORNKNUabDwbhatxqaVyPhLXtGnT8OjRI2zevFnsKERERERUxnCo5P/k5mnQ6fsTiEtRlvq5q1grcHhqOxgZcOKK8u7ixYvo0aMHrl69CgcHB7HjEBEREVEZwY7b/wSGxiApUyXKuRMzVdh+PlaUc1Ppaty4MT788ENMmjRJ7ChEREREVIawcMPThZLXn7xXakMk/0up1mDdyXu89qmCmDVrFi5duoTdu3eLHYWIiIiIyggWbgBC7icjVakWNUNKtgqhUcmiZqDSoVAo8PPPP2PChAlITU0VOw4RERERlQHlonCLioqCRCJBXl5ekfbfGhoDpUqcbtszSpUGW0Ni8t22cOFCjBo1qsDtAwIC0LVr1wLvCw4ORq1atYo9IxWfdu3aoU+fPpg+fbrYUYiIiIioDCizk5NUrVoVv/zyCzp37oyoqCi4u7tDrVbDwMDgjY/lvfgo4lNfPilJeugupIUEQchTweQdL9h2mwCJgbxIudPD9iLr2hGonkTBtHY72PWeorvPxVqBU9M7Fum4VPakp6ejbt262LRpEzp06CB2HCIiIiLSY+Wi4/Y2lCoNHqXnvPz+e2FIOxcEh0EL4Dz+N+SlPkTqqYAin8/AzBaWXgNh5tnlhfsepOUgR6Tr7Kj0WVhYYPXq1Rg9ejSys7PFjkNEREREeqxMFm5DhgxBTEwM+vTpAzMzM+zYsQPA0+GDrq6usLOzw4IFC3Tba7VaLFq0CNWrV4etrS18fHyQnPz0erKj56/j7sJeyLx2BHGrP0TsCj+kndmu2zfz+lGYNegCw0pukBmbwdJ7EDKvHS5ydpNaXjB5pxWkCosX7lPIZYh4mKH7evbs2Rg8eHCBx9mwYQNat25d4H3Hjx+Hi4tLkTNS6enTpw+aN2+OWbNmiR2FiIiIiPRYmSzcNm/eDFdXV+zduxeZmZnw8fEBAJw6dQqRkZE4cuQI5s6di5s3bwIAVq5ciV27duHEiRNISEiAtbU1JkyYAABIz3k6KUluXDicRq+Fw6D5SD0dCHXi0+n51U+iYWjvrju3ob07tFmp0CjTi/1xSSRPJymhimXFihXYtGkTzp8/L3YUIiIiItJTZbJwe5lZs2ZBoVCgQYMGaNCgAa5cuQIAWLduHRYsWAAXFxcYGRlh9uzZCAoKQl5eHlSap5f4WXr7QSo3gqFDNRjau0P1+B4AQFDnQGpkqjvHs38LucW/ULcgAKo8bbEfl/RbpUqV8P3332PkyJFQqVi4ExEREdGLylXhVrlyZd2/TUxMkJmZCQCIjo5Gv379YGVlBSsrK9SuXRsymQyPHj2CoUwCAJCZWev2lRgYQat+et2bRG4Mbe7/X3+kVT39t8RIUez5JRLA0KBcfUuokPz8/FClShUsWbJE7ChEREREpIfKbJUgkUgKvW2VKlVw4MABpKam6v7k5OTA2dkZFsavnh1SXskNqsf3dV+rHt2H1NQKsgKuUXtbggBYmxgW+3FJ/0kkEqxZswY//PCDbogvEREREdEzZbZwc3BwwL179wq17bhx4/DVV18hOjoaAPDkyRPs3r0bAFC9ktkr9zWr1xGZV/+BKjEGmpxMpJ3ZDrP6nYucW9BqIOSpAK0GELQQ8lQQtE9nkszOVUP1OAoaDWeWrIhcXV0xd+5cjBw5kj8DRERERJRPmS3cZsyYgfnz58PKygpBQUGv3PaTTz5B37590bVrV5ibm6Nly5YICQkBABgbyl65r6JaE1i26I9HW79E/OoPYWBpD6vW/kXOnXZ6G2KWvo/0c0HICj+GmKXvI+30NgCAJDkGLZs1hqWlJTp16oSjR48iPj4eSUlJAAAzMzMEBwcXeNy6desiIKDoyxSQfhg3bhxkMhlWr14tdhQiIiIi0iNldgHu4jRp2yXsvZIAMZ8ICYC+DZywYlAjJCUlISQkBGfPnsXZs2cRGhqKypUro1WrVro/9erVg0z26qKTyqbIyEh4e3sjLCwMbm5uYschIiIiIj3Awg3AuXtJGLHxPLJV4g1PMzGU4ffhzdDC3faF+zQaDcLDw3Hu3DldMZeQkIBmzZqhZcuWaNWqFVq2bAk7OzsRklNJ+Pbbb3HixAkcOHDgja7nJCIiIqLyiYUbAEEQ4L34KBLScgq9T17aYyT88tGLx1LnAgAkcqMX7nMatRoGlvYFHs/ZSoFT0zsU+k16cnIyzp07pyvmQkND4eDgoCvinnXlDAwMCv2YSH+o1Wo0b94cU6ZMwdChQ8WOQ0REREQiY+H2PxvO3Mfig5FQqku/66aQyzCjhweGtqpa5GNoNBrcuHFD15F71pVr2rSpbnglu3Jly8WLF9GjRw9cvXoVDg4OYschIiIiIhGxcPuf3DwNOn9/ArEpxb+w9utUsVbg8NR2MDIo3mvWkpOTX7hWzt7e/oVr5diV019ffPEF7t+/j+3bt4sdhYiIiIhExMLtOVfjUuGz/ixy1NpSO6exXIqdY71Q39myxM+l0Whw8+bNfF25uLi4F7pylSpVKvEsVDhKpRINGjTAkiVL8N5774kdh4iIiIhEwsLtPxbuv4nN56JLZcikQi7D0FZumNGjdomf62WedeWeXSsXEhKi68o9u1aufv367MqJ6OTJk/Dz88P169dhZWUldhwiIiIiEgELt//QaAWM3XIBp+4klmjnzVguResadlg3uClkUv2ZNfC/Xblz584hNjZW15V7VsyxK1e6xo8fD41Gg/Xr14sdhYiIiIhEwMKtAKo8LT7aGobTd5JKpPOmkMvgXcMWq/2awNBA/9dAT0lJeeFaOTs7u3zXyhV3V04QBE6D/5z09HTUq1cPGzZsQMeOHcWOQ0RERESljIXbS2i0ApYcisDGs1HF2nkzlksxrFVVTO/moVedtjeh1WpfuFYuNjYWTZo0yVfMvW1X7saNG6hTp04xpS779u3bh8mTJ+Pq1aswMTEROw4RERERlSIWbq9xNS4VE7ZeRGKm6q26bwq5DHZmhljl1xieLlbFF1BPpKSkIDQ0VFfIhYSE6Lpyz4ZXenp6FqorJwgCQkJC8Pnnn2Pnzp2YOXMm1q5dWwqPQv/5+fnB2dkZ3333ndhRiIiIiKgUsXArhNw8DbaFxmJ98D2kZKugVGlQmCdNAkBhKIO1iSHGtq2Ggc2qFPuU//rq+a7cs4lPYmJidF25li1bok2bNrCxsXlh33PnzmHz5s0YNWoU7O3tMXnyZGzfvh1Sqf4PKy1pT548Qf369bF37140a9ZM7DhEREREVEpYuL0BQRAQGpWMgJAYXIxJwcO0HCjkMkACCAIg+d/fOWoNKlsao4mrNfxauKJ5VRterwUgNTVVd63cuXPn4Onpiblz58LY2Djfdp988gkUCgUWLVqE+Ph4rFmzBt27d0fr1q1FSq5fAgICsHjxYoSEhGDjxo1o3749PDw8xI5FRERERCWIhdtbyFFrEPEwAynZKqjytDA0kMLaxBAelc1hLK8YnbW38bIJSFq2bInFixejXbt2AAAfHx+MGDEC3bt3L+2IekkQBLRr1w6RkZFITEzEt99+i+nTp4sdi4iIiIhKEBfnegvGchkaVrESO0aZVVDRlpycjLS0NDRv3lx3W0hISL5ruir6jJPz58/H+fPnkZOTAwC4e/euyImIiIiIqKSxcCO9cu/ePUilUigUCgBPixKNRgM3NzfdNmq1Gr1790bjxo11E584ODiIFbnU3bp1K1/heufOnZduq1RpEPEwHanZaqg0WhjKpLA2ZVeYiIiIqKxh4UZ65f79+2jRogUAICcnB4cOHUKnTp0APJ3wRCqVQiaTYdq0aTh79izWrl2LDz/8ENbW1vmWIvD09IRcLhfzoZSYzZs3Y8yYMfjwww9x7949XLt2TXefIAgIuZ+MraExCItOwaP0F6/DhAAo1Ro4WBijiZs1/Jq7ooU7r8MkIiIi0me8xo30SmRkJNavX4+ZM2fi4sWL+Oeff9CpUyd07tz5pUMktVotIiMj860rFxUVhcaNG+cr5spbV06j0WD27NkIDAxEeEQkAkNjsP7kPaQq1W8886mVQo4xbavBt7lrhZn5lIiIiKgsYeFGemfy5MmYNWsWJk6cCH9/f/Ts2fONj5GWlpZvXblz587punLPhlc2aNCgXHTluNYgERERUfnHwo30zoMHD2BiYoLTp08XqWgryPNduWfryt2/fz9fV65ly5aoXLlysZyvNGi0AhYfjMCmc1HIUWuL7bjGcimGtqyKz7t7QCbl8EkiIiIifcDCjSqs/3blQkJCYGlpmW94pb525VR5WowPCMOZu0lv1WV7GYVcBu8atljt1wSGBlz4nIiIiEhsLNyI/ker1eLWrVv5rpW7f/8+GjVqlK+YE7srp9EKGLP5Ak7fTSzWTtt/GculaF3DDusGN2XnjYiIiEhkLNyIXuFZV+7Z8Mpz586J3pVbuP8mNp+LLpFO238p5DIMbeWGGT1ql/i5iIiIiOjlWLgRvQGxu3JX41Lhs/5siXba/stYLsWOMa04YQkRERGRiFi4Eb2l9PT0F2awtLS01M1e2apVKzRs2PCtu3K5eRp0+v4E4lKUxZS88KpYK3B4ajsuFUBEREQkEhZuRMXs+a7csyGW9+7d03XlnhV0jo6OBe5/6dIlSKVSNGjQIN/tG87cx+KDkaUyRPK/FHIZZvTwwNBWVUv93ERERETEwo2oVBTUlbOwsHjhWjlDQ0N07NgRwcHB+PXXXzF06FAAgCAI8F58FAlpOaI9BmcrBU5N71DgIuhEREREVLJYuBGJQBCEF66Vu3fvHho0aIALFy5ApVJBoVBg1KhRWL58Oc5Hp2LExvPIVpV+t+0ZE0MZfh/eDC3cbUXLQERERFRRcYEmIhFIJBLUqlULw4cPx7p163D16lUkJCRg3LhxePZZilKpxI8//ojatWtja2gMlCIWbQCgVGmwNSTmjfYJCAhA165dC7wvODgYtWrVKvC+mJgYmJmZQaMR9zETERER6Qt23Ij0wOzZs3Hnzh307t0bQ4YMgVQqhYODA5o3b44OHTpga2ZtxKeW/qQk/+VircCkqon44YcfcPnyZTRv3hzHjx8XOxYRERFRuWcgdgAi+n9t2rTBtm3b0KZNG9jb2wN42ulaPueQyMmeepCWAzMLS0yePBkRERE4evSo2JGIiIiIKgQOlSQqgtjYWLz//vuoVKkSbG1tMXHiRGi1WsyfPx9ubm6wt7fH0KFDkZaWBgCIioqCRCLBxo0b4erqCjs7OyxYsAAAcPDgQSxcuBDbt29HrVq1MHfuXNjb26N9+/b45ZdfEPEwHTnhR/Bwy3SkHP0VscsHIm7NSCjvXtDliVs9Asqoy7qvU4MDkLh3qe7r3PgIPNw8DTHLByLh14nIib5apMetkMvgVLcFfHx84OTk9NrtN2zYgNatWxd43/Hjx+Hi4lLgfc+er7y8vCLlJCIiIipvWLgRvSGNRoPevXvDzc0NUVFRiI+Px6BBg7BhwwZs2LABx44dw71795CZmYmJEyfm2/fUqVOIjIzEkSNHMHfuXNy8eRPdu3fHl19+iYEDByIzMxNXrlzJt09qthoAkJsQCQMbZ7h8shWWLfoj6cBKFGakc15GIh7vnANLr4GoMjkQ1h1H4slf30KTnfbGj10iAVKyVW+8HxERERG9HRZuRG8oNDQUCQkJ+O6772BqagpjY2O0bt0aAQEBmDp1KqpVqwYzMzN8++232LZtW76u0axZs6BQKNCgQQM0aNDghSKtICqNFgIAAwt7mDfsDolUBtP6HaHJTIY2K/W1+2eFH4eielMoqjeDRCKFwr0RDB1r5OvYFZYgAKo87RvvR0RERERvh9e4Eb2h2NhYuLm5wcAg/8snISEBbm5uuq/d3NyQl5eHR48e6W6rXLmy7t8mJibIzMx87fkMZVJIAMjMrHW3SeXGAACtWgkZrF+y51N5aY+RFXEK2XdC//9GbR6MXT1fe+7/kkgAQwN+3kNERERU2li4Eb2hKlWqICYmBnl5efmKNycnJ0RHR+u+jomJgYGBARwcHBAXF/fKY75qUWsrE/lrM0kNjSGoc3Vfa7JSdP82sLCDWb0OsO0x6bXHeR1BAKxNDN/6OERERET0ZvjROdEbat68ORwdHfHFF18gKysLOTk5OH36NHx9fbF8+XLcv38fmZmZuuvW/tuZK4iDgwOioqKg1b44DNGjsgVUmlcPT5TbuyPr5kkImjzkPriN7MgzuvtM63ZA9p1QKO+FQdBqIOSpkBN9FXnpiW/82JVqDWpWMkFOTg7y8vKg1WqRk5MDtVr9xsciIiIiosJj4Ub0hmQyGfbu3Ys7d+7A1dUVLi4u2L59O0aMGIEhQ4agbdu2cHd3h7GxMX788cdCHfODDz4AANja2qJx48b57lMYymBp/Oqum1XbIchLeYDYHwYh7VQATOu0091nYFEJ9v2/QdrZnYhb6Y+4VcORHvonILz5tWqOlsbYuW0rFAoFxo8fj+DgYCgUCowePVq3jZmZGYKDgwvcv27duggICCjwvh49emDhwoVvnImIiIioIuAC3ERlwKRtl7D3SgLEfLFKAPRt4IQVgxqJmIKIiIioYmLHjagM8GvuCoWhTNQMCkMZ/Fq4ipqBiIiIqKLi5CREZUALdxtYKeTIVmmK9bgxywYUeLuQp4LEIP8kJBIJkNvpEODetlgzEBEREdHrcagkURmx4cx9LD4YCaW6eIu3QlHnor5wDxu/GgEbG5vSPz8RERFRBcehkkRlhG9zV9iZiTMVv5OtBZyUUfDw8MCPP/7IWSSJiIiIShkLN6IywshAhlV+jWEsL92XrbFcinVDm2Hd6p9w9OhR7NmzB56enjhw4ECp5iAiIiKqyFi4EZUhni5WGNqyKhTy0pmoRCGXYVirqqjvbAkAqFevHv755x989913mDx5Mrp3744bN26UShYiIiKiioyFG1EZ83l3D3jXsC3xzpuxXArvGraY3s0j3+0SiQS9e/fGtWvX0L17d7Rr1w4TJ05EYuKbL+hNRERERIXDwo2ojJFJJVjt1wSta9iVWOdNIZehdQ07rPZrAplUUuA2hoaGmDx5Mm7evAkAqF27Nn744QeoVKoSyURERERUkXFWSaIySqMVsORQBDaejUKOWltsxzWWSzGsVVVM7+bx0qKtIOHh4Zg6dSqioqKwbNky9OrVCxJJ4fcnIiIiopdj4UZUxl2NS8WErReRmKl6q6UCFHIZ7MwMscqvMTxdrIp0DEEQcODAAUydOhWurq74/vvvUa9evSJnIiIiIqKnWLgRlQO5eRpsC43F+uB7SMlWQanSoDAvbAkAhaEM1iaGGNu2GgY2qwIjg7cffqlWq7F27VrMmzcPAwYMwJw5c1CpUqW3Pi4RERFRRcXCjagcEQQBoVHJCAiJwcWYFDxMy3l6HZwEEARA8r+/c9Qa5KY+wnvenhjcqiqaV7UpkWGNycnJmDNnDgICAjBjxgx8/PHHMDQUZy06IiIiorKMhRtROZaj1iDiYQZSslVQ5WlhaCCFtYkhPCqbo2mjBtiwYQOaNm1a4jlu3ryJadOm4datW1i6dCn69u3L69+IiIiI3gALN6IKasyYMahXrx4mTZpUauc8ePAgpk6dCkdHRyxfvhyenp6ldm4iIiKisozLARBVUN7e3jh9+nSpnrN79+64evUq3n//fXTu3Bljx47F48ePSzUDERERUVnEwo2ognpWuJV2093AwAATJkxAZGQkTExMUKdOHXz33XfIzc0t1RxEREREZQkLN6IKqnr16lCr1YiJiRHl/NbW1li+fDlOnz6NkydPok6dOvjrr79KvZAkIiIiKgtYuBFVUBKJBN7e3jhz5oyoOWrVqoW9e/di7dq1+Oabb9CxY0dcvnxZ1ExERERE+oaFG1EF5uXlVerXub1Mly5dcPnyZQwcOBDdunXD6NGj8ejRI7FjEREREekFFm5EFZgYE5S8ioGBAcaNG4fIyEhYWlqibt26WLx4MXJycsSORkRERCQqLgdAVIHl5ubC1tYWDx48gLm5udhxXnD79m189tlnuHr1KpYsWYL+/ftz/TciIiKqkNhxI6rAjIyM0KhRI5w7d07sKAWqWbMmdu3ahZ9//hlz585Fu3btcPHiRbFjEREREZU6Fm5EFZyXl5foE5S8TqdOnXDp0iUMHjwYPXv2xIgRI/DgwQOxYxERERGVGhZuRBWcvl3n9jIymQxjxoxBZGQkKlWqhHr16mHhwoVQKpViRyMiIiIqcSzciCo4Ly8vhISEQKPRiB2lUCwtLbF48WKEhoYiLCwMtWvXxo4dO7j+GxEREZVrnJyEiODh4YFt27ahYcOGYkd5Y8ePH8fkyZNhZmaGH374AU2bNhU7EhEREVGxY8eNiMrMcMmCtG/fHmFhYfjwww/Rp08fDB8+HAkJCWLHIiIiIipWLNyIqExMUPIqMpkMI0eORGRkJBwdHVG/fn3Mnz+f178RERFRucHCjYjKdMfteRYWFvj2229x/vx5XLlyRTcElCPCiYiIqKzjNW5EBEEQUKlSJVy5cgXOzs5ixyk2J0+exOTJk2FsbIwffvgBzZs3FzsSERERUZGw40ZEkEgk8PLyKhddt+e1bdsW58+fx+jRo/Hee+9h6NChiIuLEzsWEekRpUqDSzEpOBbxGIfCH+JYxGNcjk1FjrpszLRLRBUHO25EBABYvHgxEhISsGLFCrGjlIiMjAwsWrQIa9euxaRJk/DZZ5/BxMRE7FhEVMoEQUDI/WRsDY1BWHQKHqXnQCGXARJAEACJBIAAKNUaOFgYo4mbNfyau6KFuw0kEonY8YmoAmPhRkQAgODgYEydOhXnz58XO0qJioqKwueff44zZ85g0aJF8PX1hVTKwQdE5V1ungaBoTFYf/IeUpVqKFUaFOYNkASAwlAGK4UcY9pWg29zVxgZyEo6LhHRC1i4EREAQKlUws7ODo8fP4apqanYcUrcqVOnMHnyZBgYGOCHH35Ay5YtxY5ERCXkalwqJmy9iMRMFZRvMQRSIZfBzswQq/waw9PFqvgCEhEVAj9mJiIAgEKhgKenJ0JDQ8WOUipat26N0NBQjB8/HgMGDIC/vz9iY2PFjkVExUijFbBw/034rD+L2BTlWxVtwNPhk7EpSvisP4uF+29Co+Vn30RUeli4EZFOeVkWoLCkUimGDRuGiIgIVK9eHQ0bNsSsWbOQlZUldjQiekuqPC3GbL6AzeeikaPWFuuxc9RabD4XjbFbLkCVV7zHJiJ6GRZuRKTj7e1dphfiLiozMzPMnTsXly5dwu3bt1GrVi1s3rwZWu2r35D99NNPOH78eOmEJKJC02gFjA8Iw+m7iW/dZXsZpVqDU3cS8dHWMHbeiKhU8Bo3ItJ59OgRPDw8kJSUVKEn7Dhz5gymTJkCQRDwww8/wMvL64VtEhIS4OLiAm9vb9SqVQszZ86Eq6urCGmJ6L8W7r+JzeeiS6xoe55CLsPQVm6Y0aN2iZ+LiCq2ivvOjIhe4ODgAFtbW9y4cUPsKKLy8vLC2bNnMWnSJKxbtw45OTkvbOPn54crV64gODgYNjY2+PrrrwvcjohK19W4VGw6F1UqRRvwtPO28WwUrsallsr5iKjiYseNiPIZNmwYvLy8MHbsWLGj6AWtVvtC9zEsLAzNmjXD33//jR49egAAcnNzYWRkBEEQIAhChe5YEoklN0+DTt+fQFyKstTPXcVagcNT23GpACIqMXxnQUT5VLQJSl7nvwWYIAh4//338euvv2LdunXo0aMHkpKSEB4ejpCQEEgkEkilUjz7TIyfjRGVnsDQGCRlqkQ5d2KmCtvPc2ZaIio5LNyIKB8vL68KOUFJYW3evBlt2rTBhx9+iF27dmHixIkwMTFBVlYWpkyZgoEDByI5ORkSiQQAIJFIEB8fL3JqovJPEASsP3mv1IZI/pdSrcG6k/f4YQ0RlRgWbkSUT506dZCUlIRHjx6JHUXv5OTkYOTIkVizZo3utl69eiE8PBxZWVk4c+YMWrRogX379iEvLw8AMGbMGAwZMkSsyER6KyoqChKJRPdaeVsh95ORqlQXy7GKKiVbhY8++wajRo0q8P6AgAB07dq1SMceN24c5s2b9zbxiKiM4zVuRPSCnj17YtSoUXj//ffFjqJXEhMTcfjwYQwaNAgAkJGRgVWrViE0NBQqlQoqlQoSiQTu7u5Yu3YtHjx4gHr16iE0NBTVq1dHXl4epFIpr3+jCqtq1ar45Zdf0LlzZ0RFRcHd3R1qtRoGBgZvfexJ2y5h75UEPHtTkx66C2khQRDyVDB5xwu23SZAYiAv0rHTw/Yi69oRqJ5EwbR2O9j1nlLgdhIAfRs4YcWgRoU67jfffINdu3bh5s2b+PrrrzF79uwi5SOiioHvHojoBbzOrWB2dna6ou3ZGm/R0dEYO3Ys9u3bh48++gihoaH46KOPAAAjRozAoEGDUL16dWRlZcHAwABSqRQajThDuYjKs7DoFF3RprwXhrRzQXAYtADO439DXupDpJ4KKPKxDcxsYek1EGaeXV65nQAgLCal0MetUaMGlixZgl69ehU5GxFVHCzciOgFLNxeTyqVQi6XIyIiAn/88Qdu376NVatWoV+/fvD09MSJEydw4cIF/Pjjjzh58iQmTpyIDz/8EDExMZDJOOscVTxDhgxBTEwM+vTpAzMzM+zYsQPA0+GDrq6usLOzw4IFC3Tba7VaLFq0CNWrV4etrS18fHyQnJwM4P+HWW7cuFG3b8SBDbp9M68fhVmDLjCs5AaZsRksvQch89rhImc3qeUFk3daQaqweO224Xt/ha+ff4H3bdiwAa1bt9Z9PWzYMPTo0QPm5uavPe7w4cPx9ddfFz40EZU7LNyI6AXNmjXDtWvXoFSW/pTaZYmxsTEOHDgADw8PfPbZZzh16hRmzZoFAPj444/x1VdfQSqVIjAwEK1bt0aTJk3QvXt3nD9/Pt9x2IGjimDz5s1wdXXF3r17kZmZCR8fHwDAqVOnEBkZiSNHjmDu3Lm4efMmAGDlypXYtWsXTpw4gYSEBFhbW2PChAn5jvls31Vb/kLKqW1QJz6d1VH9JBqG9u667Qzt3aHNSoVGmV7ij1MukyA9R9xr7YiofGLhRkQvMDU1RZ06dXDhwgWxo+g9Y2NjTJ06FatWrcKff/4JNzc3/Pjjj8jLy8PkyZMBAHl5eQgNDcXEiRNx8OBBVKtWDQB03QOZTMaZ6KjCmjVrFhQKBRo0aIAGDRrgypUrAIB169ZhwYIFcHFxgZGREWbPno2goKB8k5k829e+ai0YO7hD9fgeAEBQ50BqZKrb7tm/hdzS+TBKlactlfMQUcXCwo2ICsThkm/G2dlZtxj3H3/8gWXLluk6aT///DMMDQ2xbds2uLq6wsTEBDNnzsTcuXPRunVrnD59Wrd8AFFFU7lyZd2/TUxMkJmZCeDp9aP9+vWDlZUVrKysULt2bchksnwz3j7bV6XRQiI3gladAwCQyI2hzc3WbadVPf23xEhR4o8HADRafhBDRMXv7adxIqJyydvbG5s2bRI7Rpl0/PhxAMDatWtx6dIl/PTTT6hZsyb27duHBg0aYNu2bVi1ahXu37+PyMhIfPnll1i/fj3c3d1ffWCiMu5NPqCoUqUKfvvtN3h7e79wX1RUVL6vDWX5P4eWV3KD6vF9mNZuAwBQPboPqakVZIW4Rq04yKT8IIaIih87bkRUIG9vb5w5c0Y3eyK9uZEjR8LMzAxNmzbFtWvX4OLiArVajTt37qB///7o1q0b9u3bh4YNG+qGTRKVZw4ODrh3716hth03bhy++uorREdHAwCePHmC3bt3F7itlUn+af7N6nVE5tV/oEqMgSYnE2lntsOsfuci5xa0Ggh5KkCrAQQthDwVBO3Lr001NCjc2yu1Wo2cnBxotVrk5eUhJyeH17wS0UuxcCOiAjk5OcHc3By3bt0SO0qZJZfLsWzZMuzduxcTJ07EokWLEBsbi5iYGKxfvx47duzAgwcPcP78eRbIVCHMmDED8+fPh5WVFYKCgl657SeffIK+ffuia9euMDc3R8uWLRESElLgth6VLfD86ERFtSawbNEfj7Z+ifjVH8LA0h5WrQue6bEw0k5vQ8zS95F+LghZ4ccQs/R9pJ3eBgDIS3uMmGUDkJf2GACg1giwMP7/QtLMzAzBwcEFHnf06NFQKBQIDAzEggULoFAosHnzZgBAcHAwzMzMipyZiMofLsBNRC/l7++Pjh07YuTIkWJHKTfi4uIwfvx4zJ49G02aNAEAPH78GPb29iInIyobNBoNgoODUalSJbi5uemKG+/FRxGfKv5MuC7WCpya3lHsGERUDrHjRkQvxQlKip+LiwveffddjB49GiNGjMCVK1dgZ2enu5/DpIheLSUlBR07dkSLFi1gbW0NY2NjWFpawt1cC7GvLJMAaOJqLXIKIiqv2HEjope6cuUKfHx8EBkZKXaUcicvLw87duxAixYtUL16dQBPFxwODQ3Ft99+i6VLl6JmzZoipyTSP3l5efDw8MDdu3cBPJ3wxMPDA+v+OoqxWy8jW/XyDz/y0h4j4ZePXrhdUOc+PZbc6IX7nEathoFl4TriJoYy/D68GVq42xZqeyKiN8FZJYnoperVq4eHDx/iyZMnqFSpkthxyhUDAwP4+fnlu00qlaJRo0bw9vZGq1atMGzYMHzzzTewsrISJySRnhAEASEhIQgICMCOHTtgYmICQ0NDSCQSNG7cGEePHoWRkRGsFPJXFm4GlvZw/fTV19a9DWsTQzSvalNixyeiio1DJYnopWQyGVq0aIGzZ8+KHaXCMDIywvTp0xEeHo6MjAzUqlULa9asybfoMFFFERkZiZkzZ6JmzZoYNmwYKlWqhNOnT+PixYvQaDSoW7cu/v33XxgbG0MikWBM22pQyGWiZFXIZRjbthrXZCSiEsPCjYheide5icPBwQHr16/HoUOHsHPnTjRs2BD//POP2LGIStyDBw+wfPlyNG3aFO3bt0dGRga2bduGiIgIzJw5EzVq1IC1tTX27duHY8eOwdTUVLevb3NX2JkZipLbzswQA5tVEeXcRFQx8Bo3Inql0NBQnD17Fp988onYUSosQRCwZ88efPrpp/Dw8MCyZctQq1YtsWMRFZv09HT8+eefCAgIwIULF/Duu+/qZrWVyd6sg3Y1LhU+688iR116S2wYy6XYOdYL9Z0tS+2cRFTxsHAjolcSBAE5OTlQKBRiR6nwcnNz8dNPP2HRokXw9/fHzJkzYWPD62mobMrNzcXBgwcREBCAQ4cOoUOHDvDz80OfPn3e+vfNwv03sflcNJTqkp+lVSGXYWgrN8zoUbvEz0VEFRuHShLRK0kkEhZtesLIyAiffvopwsPDkZubCw8PD/z0009Qq9ViRyMqFK1WixMnTmDMmDFwcnLC999/j86dO+P+/fvYtWsXfHx8iuX3zefdPeBdwxbG8pJ9m2Msl8K7hi2md/Mo0fMQEQHsuBERlVnXrl3DlClTkJCQgO+//x7du3cXOxJRga5evYqAgAAEBgbCysoK/v7+8PX1haura4mdU5WnxUdbw3D6TlKJdN4Uchm8a9hitV8TGBrwc3AiKnks3IioyLKzs2FiYiJ2jApNEATs27cPn376KWrUqIFly5ahdm0O2SLxRUdHIzAwEAEBAUhLS4Ofnx/8/f1Rv379Usug0QpYcigCG89GFes1b8ZyKYa1qorp3Twgk3IWSSIqHSzciOiNabVaSKVSdOjQAVu2bIGzs7PYkSo8lUqFVatWYeHChfD19cWsWbNga8tFgKl0JSUlYefOndi6dStu3LiB/v37w9/fH61bt4ZUKl5X6mpcKiZsvYjETNVbdd8UchnszAyxyq8xPF2sii8gEVEhsLdPRK8lCAKe/4zn2RswJycnhISEiBWLnmNoaIgpU6bg5s2b0Gg08PDwwIoVK3j9G5W47OxsbN++HX379kW1atVw9OhRfPrpp0hISMC6devQtm1bUYs2APB0scLhqe3wRXcPOFspYGIoQ2H7ZBIAJoYyOFspMKOHBw5PbceijYhEwY4bEb2RxMRE3L17FxkZGVi2bBlq1KiBH3/8UexY9B/Xr1/H1KlTERMTg2XLlqFnz55cGJiKTV5eHo4ePYqAgADs2bMHzZo1g7+/P/r16wcLCwux472SIAgIjUpGQEgMLsak4GFaztNFuyWAIACS//2dnauGXJ2F7k3fgV8LVzSvasPXEBGJioUbEb1SVlYWgoOD8ejRI8THxyMrKwsSiQSmpqaIjIxEZGQkzp49K3ZMKoAgCNi/fz+mTp2KqlWr4vvvv0fdunXFjkV6RKvVQhCEQq2VJggCLly4gICAAGzfvh0uLi7w9/fHwIED4ejoWAppS0aOWoOIhxlIyVZBlaeFoYEU1iaGkGU8RO8e3RAdHS12RCIiAICB2AGISL/l5ubi2LFjsLGxgZGREQwMDJCXl4fk5GSsXLkS7du3h1Kp5JIBekgikaBXr17o2rUrVq9ejfbt28PHxwdz5syBnZ2d2PFIDzw/hDErKwumpqYQBCFfZ+n27dvYunUrAgICoNVq4e/vj+PHj5ebReCN5TI0rGL1wu2CYImsrCzEx8fzOl4i0gu8xo2IXsnGxgYKhQL379/HjRs3EBkZiXPnzuHu3buwsLBAtWrVcOPGDbFj0ivI5XJ88skniIiIgEwmQ+3atbF8+XKoVCqxo5HIoqOjMXLkSLRu3RqLFi3C/fv38xVtMTExaN26NZKSkrB582bcvn0bc+bMKTdF26tIJBK0atWKIwqISG9wqCQRvdb69euRkJCAqlWrwtHREfHx8QgODkb37t0xcOBAAHjhU3rSXzdv3sSnn36KO3fuYNmyZejduze/d+WURqOBVCqFRCLRzQYbFxcHJycnSCQSLFu2DE5OThgwYAA++ugjSCQSLFq0SDcjqUajgSAIMDComAN0Fi5ciKSkJCxbtkzsKERELNyI6PWSkpKgUqlgbW0NY2NjAE8X1P3jjz8wZ84caDSaQl0jQ/rlwIED+PTTT+Hs7Izvv/++VNfXopKRmJiIX3/9FUlJSViyZInu9ueHM7/zzjtYu3Yt2rZti/79+6NmzZqIj49HREQEJkyYgCFDhsDIyEish6BXjh8/jhkzZrDrRkR6gUMliei1bG1t4ejoCGNjY2g0GiQkJCA+Ph5mZmYAwKKtjOrRoweuXLmCd999F506dcL48ePx5MkTsWPRG8rJyUFgYCC6d++ORo0aITExEb6+vsjJycE///yD33//HfPnz8etW7cAAL169cKRI0eQkpICExMTREREYOrUqbh06RJGjRrFJSSe06xZM1y9ehW5ubliRyEiYuFGRIV37NgxfPvtt1i6dCkOHTqEJ0+eICMjQ+xY9BbkcjkmTpyIiIgIGBkZoU6dOli2bBmvfysjMjIy0LFjR+zduxeOjo4YPHgwRowYgSdPnsDf3x+hoaEwNjZGZmYm7ty5AwAYNGgQjh07Bo1Gg2bNmsHBwQHNmjUDAPz88884ePAgNJqiL1JdnpiamqJWrVq4ePGi2FGIiFi4EVHh7N69G8uXL4dWq0XTpk3Rr18/DB8+HCYmJmJHo2JgY2ODH374AcHBwTh27Bjq1q2L3bt3g6Pp9Zu5uTmOHDmCrVu3YurUqZDL5di0aRO+/fZbODk54euvv8bAgQNhZmaGO3fuQKVSoUWLFkhKSsLFixfx8ccfIy8vD++//z7q1KmD3bt3w8nJiV3053h5eeHMmTNixyAi4nIARFQ4p0+fRvXq1TFz5kyxo1AJ8vDwwL59+3Do0CFMnToVK1euxPLly+Hp6Sl2NHqJZ9euOTs7Q6vVolKlSqhRowZq1qyJ7OxsmJiYoGbNmrh06ZJukiErKyv88ssv6NmzJ3755RdERETA2dkZNjY2Ij8a/dOqVSv89ddfYscgImLHjYgKp2fPnjAzM0N2djbu37+PjRs3Yvjw4Rg0aBAAsDNTznTr1g1XrlxB//790aVLF4wdOxaPHz8WOxa9go2NDVxdXaFSqWBkZIT09HTd96xdu3awtLTEkCFD8O6776JFixZ47733oNVqIZfLUb9+fRZtL/FsSQD+jiMisXFWSSIqlLS0NDRq1Ajx8fGoVasW6tSpA09PTzRu3Bjdu3cXOx6VoJSUFMyfPx8bN27E559/jkmTJnHWQT3zbDmO8+fPY8+ePTAyMsLDhw8xYMAAtG/fHgCgVquxceNGNG3aFA0bNhQ1b1kiCAIcHR0REhICNzc3seMQUQXGwo2ICi0oKAguLi6oXr061Go1bG1t+Qa+Arl16xY+++wzXL9+HUuXLsV7773H9d9KmSAIuHjxImrWrAkLC4sX7s/NzcXChQshl8tx8eJFvPvuu/Dz84NcLhchbfnRr18/DBw4UDfCgIhIDCzciOiNCIKAjRs34ty5c3jy5Am8vb3Rp08f1KxZU7fAL5Vvhw8fxpQpU2Bra4vly5ejUaNGYkcq9+7evYutW7ciICAAKpUKv/76K9q1a5fv9fas67Zp0yYYGxujdu3aXJuvmCxZsgRxcXFYuXKl2FGIqALjOywiKjSNRoOvv/4aW7ZsgaWlJe7fv4+aNWvi888/FzsalaLOnTvj0qVL8PX1RY8ePTBq1Cg8fPhQ7FjlzpMnT/DTTz+hVatWaNWqFR49eoTff/8dd+/eRYcOHV74kORZ93PIkCHw8fFh0VaMvLy8uAg3EYmOhRsRFdqjR49w5swZHD58GDNnzoSVlRX69OmDu3fvAgC7bRWIgYEBxo4di8jISFhbW6NevXpYtGgRcnJyxI5WpmVmZiIgIAA9e/ZEzZo1cfbsWXzzzTeIj4/XFXGvG57K4avFr0mTJrhx4ways7PFjkJEFRjfZRFRoTk5OSE5ORkpKSkwNTVFamoq5s+fj9q1a3PGwQrK0tIS3333Hc6dO4eQkBDUrl0bQUFBpTYDn1KlwaWYFByLeIxD4Q9xLOIxLsemIkdddhaQVqvV2L9/P/z9/eHi4oKAgAD4+/sjLi5OV8TxGjVxKRQK1K1bFxcuXBA7ChFVYLzGjYjeSK9evTB48GD4+vpi9uzZiIyMxIwZM+Dp6am7xoYqrmPHjmHKlCmwsLDA8uXL0aRJk2I9viAICLmfjK2hMQiLTsGj9Bwo5DJAAggCIJEAEAClWgMHC2M0cbOGX3NXtHC30aufTUEQcPbsWQQEBGDnzp2oXr06/P394ePjA3t7e7HjUQEmT54MR0dHDg0nItGwcCOiNxIWFobc3Fy0aNECT548QVpaGmrWrMlhkqSj0Wjw+++/45tvvkGPHj2wYMECODo6vtUxc/M0CAyNwfqT95CqVEOp0qAw/3lJACgMZbBSyDGmbTX4NneFkYHsrbK8jZs3byIgIABbt26FoaEh/P394efnh+rVq4uWiQpn+/btCAwMxK5du8SOQkQVFAs3IiIqEenp6Vi4cCF++eUXTJkyBVOnToVCoXjj41yNS8WErReRmKmC8i2GQCrkMtiZGWKVX2N4ulgV+ThvKj4+Htu2bUNAQAAePnwIX19f+Pv7o1GjRnrVBaRXi4mJQdOmTfHo0SN+34hIFCzciKhItFot8vLyIJfL+SaGXunevXuYPn06Lly4gMWLF8PHx0f3MxMTEwNXV9cC99NoBSw+GIFN56KQo9YWWx5juRRDW1bF5909IJOWzM9uWloa/vjjDwQEBODSpUt477334O/vj/bt20MmE6/jR0UnCAKqVKmCEydOsENKRKLg2CYiKhKpVIo2bdrg0qVLYkchPVetWjUEBQVh48aNWLRoEdq0aYPz58/j8uXLqFq1KoKCgl7YR5WnxZjNF7D5XHSxFm0AkKPWYvO5aIzdcgGqvOI7dm5uLv766y8MGDAArq6u2Lt3L8aPH4/4+Hj89ttv6NSpE4u2MkwikaBVq1ZcFoCIRMPCjYiKzNPTE6dPnxY7BpUR7dq1w4ULFzBixAj07dsXnTt3hiAIGDVqFJ48eaLbTqMVMD4gDKfvJr7V0MhXUao1OHUnER9tDYNGW/SBJ1qtFseOHcPo0aPh5OSElStXonv37oiKitIVcUUZHkr6qVWrVjhz5ozYMYiogmLhRkRF5uXlxcKN3ohMJsOIESOwbNkypKenA3i6dtmwYcN02yw+GIEzd5OKvdP2XzlqLU7fScKSQxFvtJ8gCLh8+TI+++wzuLq6YsqUKXjnnXdw+fJlHDt2DKNGjYK1tXUJpSYxcSFuIhITr3EjoiK7desWOnfujJiYGLGjUBlTt25d3Lt3DwYGBlAqldBoNFiyZAm6+Y6Gz/qzJV60Pc9YLsWOMa1eO2FJVFQUtm7dioCAAGRlZcHPzw/+/v6oW7du6QQl0eXm5sLGxgaPHj2CmZmZ2HGIqIJh4UZERSYIAhwcHBAWFoYqVaqIHYfKkNu3byMqKgrp6elIT0/HlStX0K5jZyyLMEFcirLU81SxVuDw1HYvLBWQmJiInTt3IiAgABEREfjggw/g7+8PLy8vLoFRQXl5eWH+/Pno2LGj2FGIqIIxEDsAEZVdEolEN1xy0KBBYsehMqRmzZqoWbNmvts2nLmPpMxIUfIkZqqw/XwshraqiuzsbOzZswcBAQE4efIkevTogc8//xzdunWDoaGhKPlIfzwbLsnCjYhKGz8uJKK34u3tzevc6K0JgoD1J++V2GQkr6NUa7Din3AMGToUzs7O2LBhA3x8fBAXF4dt27ahT58+LNoIADizJBGJhoUbkR6KioqCRCJBXl6e2FFey8vLC3v27EHr1q2LtH9wcDBq1apVzKmKbvbs2Rg8eLDYMYrN636WFi5ciFGjRpXIuQMCAtC1a9dCbRtyPxmpSnWJ5CismJCDOBZ8BhERETh48CCGDBkCc3PzUjt/1apVcfjw4VI7X3Epq7lfZ/jw4fj6669fuP1Z4fYmV5ro6++VN3mNAiX7+4KIXo+FG1EJMzMz0/2RSqVQKBS6rwMCAsSO94KXvcE4dOgQ2rZtC3Nzc1SqVAnt2rXDnj170KRJEzx8+BAaTdE6JW3atEFkZPEPjwsICNA9zwqFAlKpNN/3Qh8V9AY4NzcXM2bMgKurKxQKBWrWrImlS5e+0ZvGV/nyyy/xyy+/ACi4yHvZz4NEIsGdO3deeWx/f3/8888/hcqxNTQGStXLf4YeBnyB6O/6IWbZAMSu8MPjPxcgLzO5UMcuLEFiAK2RORwcHIr1uEUxe/ZsyOXyfD+zVlZWhdp3w4YNRf4gpbwoyefAyckJ5ubmuHXrVokcHwAeP34MX19fODk5wdLSEt7e3ggJCSn28/z3Nfq61/Xzvy+IqPSxcCMqYZmZmbo/zxblffa1v7+/2PHyeVlXJigoCB988AGGDh2KuLg4PHr0CHPnzsXevXthbGwMV1dXZGRklHLaV/P399c9zwcOHICTk1O+74U+eVVn9YMPPsCRI0ewf/9+ZGRkYPPmzVi3bh0+/fTTUkxY8sKiU/C6UtSm6zi4fhoEpzHroM3JQsqRn1/YRtC+3VDLzNzi6XIXR7d84MCB+X5mU1NT3z4YFYuSHi6ZmZmJZs2aISwsDMnJyRg2bBh69eqld7+7iKh0sXAjEolWq8WiRYtQvXp12NrawsfHB8nJBXcQ0tLSMHLkSDg6OsLZ2Rlff/21rsO1YcMGeHt74+OPP4alpSU8PDxw5MgR3b4JCQno27cvbGxsUKNGDfz88/+/2Z09ezYGDBiAwYMHw8LCAmvXrsXChQuxfft2mJmZoUGDBhAEAVOnTsU333yDUaNGwdLSElKpFO3atdMdq2bNmsjIyMC0adNgbW0Nd3d3HDhwQHee33//HbVr14a5uTmqVauGdevW6e47fvw4XFxcdF9XrVoVS5cuhaenJywtLTFw4EDk5OQUz5P+3HPSv39/VKpUCe7u7li5cuVLtz137hy8vLxgZWWFBg0a4Pjx47r72rdvjxkzZqB58+awtLTEu+++m+97uGfPHtStWxdWVlZo3749bt68me9xLl68GJ6enjA1NYWvry9iYmLQp08fmJmZYcmSJThy5Aj++ecf/PHHH6hXrx4MDAzQsmVLbNmyBStWrMC9e/d0x3q+U1dQl+y3336Dk5MTHB0dsWzZsgK3bdu2LQDAysoKZmZmhX5jumHDBlSrVg3m5uZwd3fXdZL/2/WQSCRYu3YtatasCWtra0yYMAGCIECp0uBhahaSj/yC2BV+iFszEulhexG9qHeBhZhMYQ7TWl5QP4kGAMStHoG0c0FI+HUiYpb1h6DVIDc+Ag83T0PM8oFI+HUicqKv6vbPvHoY8WtGIub7DxC3ZiQyw4/p7lPlaTF56tQi/xwvXrwYlStXxocffvja1/jmzZvh5uYGW1tbLFiwoFDP9euey5s3b2LcuHE4e/Zsvi7d33//jUaNGsHCwgJVqlTB7Nmzdcd61mnduHEjXF1dYWdnly+PUqnEsGHDYG1tjdq1a2PJkiX5XrPPe9Vjfnae33//HVWqVIG1tTXWrl2L8+fPw9PTE1ZWVpg4cWK+4/3222+oXbs2rK2t0a1bN0RHRxf5OSiKxMREdOnSBebm5mjXrp3u/F5eXvjrr7/QrFkzWFpaolmzZvkW5r5//z7atWsHc3NzdOnSBYmJibr7evXqhR9//DHfeTw9PbFr1y7d19WqVcPUqVPh6OgImUyGMWPGQKVSvXR0Qm5uLqZNmwZXV1c4ODhg3LhxUCqfzs7as2fPfB/0DBw4ECNGjACQ/zX67PXfoEEDmJmZYfv27S+cR1+HfBJVFCzciESycuVK7Nq1CydOnEBCQoLujUdBhg0bBgMDA9y5cweXLl3CP//8k2+4SkhICKpVq4bExETMmTMH77//vu7Nkq+vL1xcXJCQkICgoCB8+eWX+Qq73bt3Y8CAAUhNTcXIkSPx5Zdf6j7pv3LlCiIjIxEbG4sBAwa89LHUqFEDsbGxqFWrFhITEzF9+nSMHDlSN5zP3t4e+/btQ3p6On7//XdMmTIFFy9efOnxduzYgYMHD+L+/fu4evUqNmzY8CZP7StptVr06dMHDRo0QHx8PI4cOYIffvgBhw4demHb+Ph49OrVC19//TWSk5OxdOlS9O/fH0+ePNFts2nTJvz2229ISEiAgYEBJk2aBODpGne+vr744Ycf8OTJE/Ts2RN9+vSBSqXS7RsYGIi///4bqampCAwMzNeRnT59Ov7991+0aNHihaUWWrRoARcXl3zfx9c5duwYbt++jX/++QeLFi0q8JqkkydPAgBSU1ORmZmJVq1avfa4WVlZmDRpEg4cOICMjAycOXMGDRs2fOn2+/btw/nz53HlyhXs2LEDhw4dQsTDdORc+xc598Lg+OFKOH64Aspb5156DE12GrIiz8DQofr/57hxAvYfzEKVyduhyUrB451zYOk1EFUmB8K640g8+etbaLLToFXlIPnwOtj7zIHr1J2oPOQ7GNpX0x0nNyESFg5uRfo5fvjwIZKTkxEdHY3169e/8jV+48YNjB8/Hps3b0ZCQgKSkpIQFxf32uf7dc9l7dq1sXbtWrRq1Spfl87U1BSbNm1Camoq/v77b6xZsyZfoQAAp06dQmRkJI4cOYK5c+fqPmiYM2cOoqKicO/ePfz777/YsmXLSzMV5vdaSEgIbt++je3bt2Py5MlYsGABDh8+jPDwcOzYsQMnTpwAAOzatQsLFy7En3/+iSdPnqBNmzbw9fUt8nNQFAEBAfjmm2+QmJiIhg0b6kZJ1KlTB/v27cOkSZOQlJSEqVOnolevXkhKSgIA+Pn5oUmTJkhMTMQ333yDjRs36o45bNiwfM/hlStXEB8fj549e740x+XLl6FSqVCjRo0C7//8889x69YtXL58GXfu3EF8fDzmzp0L4Gnxu3nzZhw9ehQBAQE4f/48VqxY8cIxnr3+r1y5gszMTAwcOPANny0iKmks3IhEsm7dOixYsAAuLi4wMjLC7NmzERQU9MIQq0ePHuHAgQP44YcfYGpqCnt7e0yZMgXbtm3TbWNvb4/JkydDLpdj4MCBqFWrFv7++2/Exsbi1KlTWLx4MYyNjdGwYUOMGjUKmzdv1u3bqlUrvPfee7rr7/7r2RsRR0fHlz6WZ28mRowYAZlMhmHDhuHBgwd49OgRgKefMFevXh0SiQTt2rVD165dERwc/NLjTZo0CU5OTrCxsUGfPn1w+fLl1z+hhXT+/Hk8efIEM2fOhKGhIapVq4bRo0fnez6f2bJlC3r27ImePXtCKpWiS5cuaNq0Kfbv36/bZsiQIahXrx5MTU0xb9487NixAxqNBtu3b0evXr3QpUsXyOVyTJs2DUqlMt+n8pMmTUKVKlUKfN6Bp5/2v+x5d3R0zFdAvs6sWbNgamqK+vXr48MPP0RgYGCh930dqVSK69evQ6lUwtHR8ZULUn/xxRewsrKCq6srOnTogMuXLyM1W4208JMwb9oXBhZ2kBmbwaLVBy/sm/LvesQsH4gHv30MmZk1rDv9/yQJFk36wMCiEqRyI2SFH4eielMoqjeDRCKFwr0RDB1rQHn3wtONJVKonkRDq86FgZkNDCu56Y5jaGmPDu/5FunnWCqVYs6cOTAyMoJCoXjlazwoKAi9e/dG27ZtYWRkhHnz5r2wLtyOHTtgZWWl+9OhQ4fXPpcv0759e9SvXx9SqRSenp7w9fXVFUjPzJo1CwqFAg0aNECDBg1w5coVXY4vv/wS1tbWcHFx0X04UZDC/F775ptvYGxsjK5du+q6zfb29nB2dkabNm1w6dIl3bFmzJiB2rVrw8DAAF9++SUuX76cr+v2Js9BUfTq1Uv3PVqwYAHOnj2L2NhYxMTEAAD69u0LAwMD+Pr6wsPDA3v37kVMTAzOnz+PefPmwcjICG3btkWfPn10x3z33Xdx+/Zt3L59G8DTzuvAgQNfOmtpeno6hgwZglmzZsHS0vKF+wVBwM8//4zly5fDxsYG5ubm+PLLL3W/0ypXroy1a9di2LBh+OSTT7Bp06ZSnXSHiIoP13EjEkl0dDT69euX782aTCbTvUl8fju1Wp3vDbxWq83XhXF2doZEItF97ebmhoSEBCQkJOj+I3/+vgsXLui+ft3C2ba2tgCABw8ewN3dvcBtLCwsYGRkhPDwcHh6esLExAQAdNdjHDhwAHPmzMGtW7eg1WqRnZ2N+vXrv/SclStX1v3bxMQECQkJr8z4JqKjo5GQkJBv+JRGo0GbNm0K3Hbnzp3Yu3ev7ja1Wp3vDfTzz5+bmxvUajUSExORkJAAN7f/LwikUimqVKmC+Pj4AvctiJ2dne7N3X89ePAAlSpVeuX+z/tvzmvXrhVqPwMDA6jV+Wd7fPa1XC6Hqakptm/fjqVLl2LkyJHw9vbGsmXL4OHhUeDx/vu9zczMhEqjhTojCaYWdv9/XnO7F/a17jIG5g26FXhcmcX/Pxd5aY+RFXEK2XdC/38DbR6MXT0hNTRGpXenIz30LyQdWAljl9qw7jgSctunz4+BmTVUeVpdPqDwP8eVKlWCsbGx7utXvcYTEhLyfU9MTU11r7VnfHx8XtndKui5fJmQkBB88cUXuH79OlQqFXJzc/HBB/mL45cd779ZX/VzW5jfa89P/qJQKF74+tl5o6Oj8cknn+Qb5icIAuLj43WvrTd5Dori+cdqZmYGGxsbJCQk4PHjx7CxsUFISIhuVkY3NzfEx8frOo2mpqa6fd3c3BAbGwsAMDIy0n1vZ82ahcDAQAQFBRV4fqVSiT59+qBly5aYMWNGgds8efIE2dnZaNKkie42QRDyTRjVu3dvTJw4EbVq1arwE9cQlWXsuBGJpEqVKjhw4ABSU1N1f3JycuDs7PzCdkZGRkhMTNRtl56ejvDwcN028fHx+WYZjImJgZOTE5ycnJCcnJxv4pCYmJh853i+4Cvo61q1aqFKlSr4448/Xvl4LCwsClzPLTc3F/3798e0adPw6NEjpKamomfPnsU2K+KbqlKlCtzd3fM97xkZGfm6aM9vO2TIkHzbZmVl4YsvvtBt8+zNGPD0uZXL5bCzs4OTk1O+zoAgCIiNjX2j575z584ICQnJdw4ACA0NRUxMjO6aFFNTU2RnZ+vuf/jw4QuP5b85nZycXtjmv+cHAFdXV0RFReW77f79+5DJZLrH0q1bN/z777948OABPDw8MHr06BeO8yqGMink5jbIy0jS3ZaXkfiKPQrwXHYDCzuY1esA1ynb///Pp3/A8n9dPEW1JnAYNB8uEzfBwMYFSQfyX29kaPDif42F+Tn+7/P3qte4o6Njvu9Jdna2rrv9tgr6Pvr5+aFv376IjY1FWloaxo0bV+jXoKOjY75hnP/9eXxeYX+vFUaVKlWwbt26fMdSKpXw8vJ67b4FPQdF8fxjzczMRHJysu53q1wuz3cd6LPfrY6OjkhJSUFWVla++543bNgwBAQE4MiRIzAxMSlwWHJubi7ee+89ODs757ue8r/s7OygUCgQHh6ue57S0tLyFbFfffUVateujQcPHhRrt52IShcLNyKRjBs3Dl999ZXuzf2TJ0+we/fuF7ZzdHRE165d8emnnyI9PR1arRZ3797NN8zp8ePHWLlyJdRqNXbu3ImbN2+iZ8+eqFKlCry8vDBjxgzk5OTg6tWr+PXXX185m6WDgwOioqKg1T7tOkgkEnz//feYN28efv/9d12GU6dOYcyYMbr9Xla4Pft0v1KlSjAwMMCBAwcKPUV8SWjevDksLCywePFiKJVKaDQaXL9+HefPn39h28GDB2Pv3r04dOgQNBoNcnJycPz48XxvYrds2YIbN24gOzsbM2fOxIABAyCTyeDj44O///4bR44cgVqtxrJly2BkZPTKN50ODg66CUeAp4Vbp06d0L9/f4SHh0Oj0eDcuXPw9/fH0KFDdevfNWzYENu2bYNarcaFCxcK/PR+3rx5yM7ORnh4OH7//fcCr1+pVKkSpFJpvgzdu3dHZGQkNm/eDLVajeTkZHz55ZcYMGAADAwM8OjRI+zZswdZWVkwMjKCmZkZZDJZ4b4Z/2NlIodFnbbIuLAHeRmJ0OZkIv1cwR2IwjCt2wHZd0KhvBcGQauBkKdCTvRV5KUnQpOVguzbIdCqciAxkENqqAAk+f8rtDZ5cchaUX6OX/UaHzBgAPbt24dTp05BpVJh5syZutfc23JwcEBcXFy+6ykzMjJgY2MDY2NjhIaGYuvWrYU+no+PD7799lukpKQgPj4eP/3000u3LezvtcIYN24cvv32W92HVGlpadi5c2eh9i3oOSiK/fv3675H33zzje6a0549eyItLQ1//PEH8vLysH37dty4cQO9e/eGm5sbmjZtilmzZkGlUuHUqVP5uvbA0yHqUqkUn376KYYMGfLCedVqNQYMGACFQoFNmza9MIz2eVKpFKNHj8aUKVPw+PFjAE8/zHt23e7Jkyfx+++/Y9OmTdi0aRM+/vjjfJ3/5/33dxAR6RcWbkQi+eSTT9C3b1907doV5ubmaNmy5UvX6dm0aRNUKhXq1KkDa2trDBgwAA8ePNDd36JFC9y+fRt2dnb46quvEBQUpBt2FRgYiKioKDg5OaFfv36YM2cOunTp8tJcz4ZP2draonHjxgCevsncvn27bmZCBwcHfP3113j33Xd1+72scDM3N8fKlSvh4+MDa2trbN26FX379n3zJ6yYyGQy7N27F5cvX4a7uzvs7OwwatQopKWlvbBtlSpVsHv3bixcuBCVKlVClSpV8N133+V7gz1kyBAMHz4clStXRk5Ojm6Gylq1amHLli34+OOPYWdnh71792Lv3r0vvY4FAGbMmIH58+fDysoKS5cuBQD88ccf6NChA7p37w5jY2O0atUK3bt3x/r163X7zZs3D3fv3oW1tTVmzZoFPz+/F47drl071KhRA506dcK0adMKXHTXxMQEX331Fby9vWFlZYVz587B3t4e+/fvx7p162Bvb4969erB0tISa9asAfB02O6yZct01ySeOHECq1evLuR34ymPyhZQeHaFcdVGePDrx0j4/RMoqjUFpLIXiqrCMLCoBPv+3yDt7E7ErfRH3KrhSA/9ExC0EAQB6aF/IW7VUMT+4IucmGuw6faRbl+NAHhUfvH6n6L8HL/qNV63bl2sWrUKfn5+cHR01F0/9rxns7s+/+fZG/NX6dixI+rWrYvKlSvDzu7pkNPVq1dj5syZMDc3x9y5c+Hj4/Pa4zwzc+ZMuLi4wN3dHZ07d8aAAQNgZGT0xo/5TfXr1w+ff/45Bg0aBAsLC9SrVy/fLJ+vUtBzUBR+fn6YM2cObGxsEBYWppsx1dbWFtu2bUN4eDhsbW2xZMkS7Nu3T3eurVu3IiQkBDY2NpgzZw6GDh36wrGHDh2Ka9eu6WZpHDduHMaNGwcAOHPmDPbt24d//vlHN8urmZmZ7prK4ODgfOtRLl68GDVq1EDLli1hYWGBzp07IzIyEunp6Rg6dCh++uknODs7o3Xr1hg5ciQ+/PDDAjuus2fPxrBhw2BlZYUdO3YgJiYGZmZmL3QMiUgcEkGs8UpEVCw2bNiAX375BadOnRI1h1arhZ2dHa5fv17gMLzyqH379hg8eDBGjRr1+o2LybBhwxAfH4/9+/e/sggsa7wXH0V8qlL3tfLuBSQdWgWXj34v1Rwu1gqcmt6xVM9Z1qxZswbbtm17YXKTiqhGjRrYvXv3KyfkeZlNmzZh/fr1ov/uJqKygx03IioWUqkUXl5e+WZNpOL3yy+/oEuXLq9cTkGfXb9+HY6OjvD09ET//v0xY8YMzJw5E56VjaG8ex6CVoO8jESkng6EyTuvX46gOEkANHG1LtVzlgUPHjzA6dOnodVqERkZiWXLlqFfv35ix9ILRV2IOzs7G6tXr8433JyI6HVYuBFRsfH29i5wuGRxWLhw4QvDxszMzCCRSAq8vUePHiWSQ2xyuRyff/45WrZsKXaUIqlatSqSkpJw7do1/Pnnn1i0aBEWL16MnrWskX56K2J/GIQHv38CuW0VWLUp3YV+FYYy+LVwLdVzlgUqlQpjx46Fubk5OnbsiHfffRcfffTR63fUI3Xr1i3w94S7u3uBtz8bEvk6Rfmw6tChQ6hUqRIcHBwKHNZMRPQyHCpJRMXm5MmTmDZtGkJDQ1+/MVUoWq0Wp0+fRmBgIH799VfdpBFWVlY4f/48qlevDu/FR5GQliNaRmcrBU5N71BsMxJS+Xf58mX4+vrqFisnIipJ7LgRUbFp2rQpwsPD801NTxWXIAi4ePEiPvvsM1StWhUfffQRXFxcsHLlShgaGsLKygpnz55FjRo1IJFIMKZtNSjkbzYjZXFRyKUY27YaizZ6I/Xq1UNcXBySk5PFjkJEFQALNyIqNiYmJqhXr16BU+tTxREZGYnZs2fDw8MDAwYMgKGhIfbv349r167hyy+/xPDhw9G6dWsEBwfnW6jbt7kr7MxEmHBFEJCbloh3ZG+4dhxVeAYGBmjevDnOnTsndhQiqgBYuBFRsSrJ69xIf8XGxmLp0qVo0qQJ2rdvj9TUVGzatAl3797FggULUK9ePd22RkZGOHLkSL7bAMDIQIZVfo1hLC/d/5qM5TKMriPBu316YcqUKfkWrCd6naJOUEJE9KZYuBFRsWLhVnE8efIEa9asQdu2bdGwYUNERERgyZIliIuLww8//IAWLVq88dBDTxcrDG1ZtdSGTCrkMgzzqooZYwcjPDwcKSkpqFu3Lvbs2VMq56eyr1WrVpxNl4hKBScnIaJi9eDBA9StWxeJiYmQSvnZUHmTnp6OXbt2ITAwEGfOnEHPnj3h6+uLbt26vXRR5jel0QoYu+UCTt1JRI5a+/odishYLkXrGnZYN7gpZNL/LzCPHTuGsWPHon79+li5ciWcnZ1LLAOVfUlJSXB3d0dKSgpkMnGu0SSiioHvqoioWDk6OsLKyoqzrJUjOTk5+PPPPzFgwABUqVIFO3fuxNChQxEfH4/AwED07du32Io2AJBJJVjt1wSta9iVWOdNIZehdQ07rPZrkq9oA4AOHTrg6tWrqFevHho0aIAff/wRGo2mRHJQ2WdrawsnJydcv35d7ChEVM6xcCOiYuft7c2hQ2VcXl4eDh06hOHDh8PR0RE//fQTunXrhvv372Pv3r3w9fWFmZlZiZ3f0ECKdYObYmgrt2K/5s1YLsXQVm5YN7gpDA0KPraxsTHmzJmD4OBg7Ny5E15eXrh8+XKx5qDyg8Mliag0sHAjomLH69zKJq1Wi1OnTmHChAlwdnbGzJkz0bBhQ4SHh+Po0aMYPXo0bGxsSi2PTCrBjB61sWNMK1SxVrx1900hl6GKtQI7xrTCjB61X+i0FaR27do4fvw4xowZg65du+Kzzz5DVlbWW+Wg8sfLy4sTlBBRieM1bkRU7K5du4b3338ft2/fFjsKvYYgCLhy5QoCAwOxbds2mJmZwc/PD4MGDUL16tXFjqeTm6fBttBYrA++h5RsFZQqDQrzn5cEgMJQBmsTQ4xtWw0Dm1WBkUHRCsDHjx9j6tSpOH36NFatWoWePXsW6ThU/ly/fh39+vXj7zwiKlEs3Iio2Gm1WtjY2CAyMhIODg5ix6EC3L59G4GBgQgMDEROTg4GDRoEX19f1K9fX68XoRYEAaFRyQgIicHFmBQ8TMt52omTAIIASP73d45ag8qWxmjiag2/Fq5oXtWm2B7Xv//+i/Hjx6Nx48ZYsWIFHB0di+W4VHY9+51369Yt2Nvbix2HiMopFm5EVCK6d++OsWPHol+/fmJHof+Ji4vD9u3bERgYiLi4OPj4+MDX1xctW7bU62LtVXLUGkQ8zEBKtgqqPC0MDaSwNjGER2VzGJfgkgJKpRLz58/H+vXrMW/ePIwZM4azqFZw3bp1w4QJE9C3b1+xoxBROcXCjYhKxLx585Ceno7vvvtO7CgVWmJiIoKCghAYGIhr166hX79+8PX1Rfv27WFgYCB2vDLv+vXrGDt2LARBwLp161C/fn2xI5FIZs+ejdzcXHz77bdiRyGicoofDxJRieAEJeLJyMjAli1b0KtXL1SvXh3Hjh3DlClT8ODBA/z666/o3Lkzi7ZiUq9ePQQHB2PYsGHo2LEjZsyYgezsbLFjkQg4syQRlTR23IioRGRlZcHe3h5JSUkwNjYWO06ZlZeXBwMDAwiC8MrhjDk5OThw4AACAwNx6NAhtGnTBr6+vujbty/Mzc1LMXHF9fDhQ0yePBnnz5/HmjVr0LVrV7EjUSlKTU2Fi4sLUlJSIJfLxY5DROUQO25EVCJMTU1Ru3ZtXLhwQewoZYpWq0Vubi4uXbqEo0eP4tNPPwWAAos2jUaDf/75Bx9++CGcnJywcuVKdO7cGffu3cO+ffvg7+/Poq0UVa5cGdu2bcNPP/2EsWPHwt/fH48ePRI7FpUSKysrVK1aFVevXhU7ChGVUyzciKjEeHl5cejQG5JKpbh27RoWLFiAZs2aISMjAwEBAVCr1S9sGxoaiq+++gr169fHtWvXcOzYMYwZMwa2trYiJKdnevTogevXr8PFxQX169fHL7/8Aq1WK3YsKgX8nUdEJYlDJYmoxGzfvh1bt27F7t27xY5SpmzevBkqlQojR47EpUuX8OOPP6JXr17o378/tFqtbvbC5/9N+unKlSsYM2YMDA0NsW7dOtSpU0fsSFSC7t27B0tLS354QkQlgv/jE1GJ8fb2xpkzZ8DPh95MbGwsbt68CQBo1KgR2rZtixUrVrywHYs2/degQQOcOXMGgwYNQrt27fDNN98gJydH7FhUQqpVq8aijYhKDP/XJ6IS4+LiAhMTE9y6dUvsKGVKx44d8ffff+u+Hjx4MCIiIvDkyRMWa2WQTCbDhAkTcPnyZdy8eROenp44evSo2LGIiKiM4TsAIipRXl5eXBbgNbKzs6HRaHRfN27cGAqFAleuXAEAGBgY5Cvm2MEsm5ydnREUFIRly5bhww8/xLBhw/DkyROxYxERURnBwo2IStSz4ZKUX2ZmJgICAtC7d2907Ngx3+QjhoaGaN26NX7++WcAT6f69/LyQlZWFoCCZ5iksqNPnz4IDw+Hra0t6tWrhw0bNrAYJyKi12LhRkQlJjY2Fmlpadi5cyfc3d3RokULsSOJKjc3F7t27cLAgQPh7OyMgIAADBw4EP/+++8La9199NFHOHv2LGJjY2FsbIyIiAg0adJEpORU3MzMzPD999/jwIED+Omnn9CxY0dERkaKHYuKSVpaGg4ePIgFCxZg9OjRWLNmDaKioqBSqcSORkRlGAs3IioxzZo1w7x585Ceno6oqCg4ODiIHanUaTQaHD58GCNHjoSjoyOWL1+ODh064O7du9i/fz+GDBlS4FprHh4eGDduHBYvXoz4+Hi4uroiOztbhEdAJalx48Y4d+4c3n33XXh7e2Pu3LnIzc0VOxYV0Z49e9ChQwfUr18fCxcuxJ07d9CkSROYmJhgzJgxCAsLEzsiEZVhXA6AiErMoUOH0K9fPyiVShgZGWH58uUYP3682LFKnCAIOHfuHAIDA7Fjxw64uLjA19cXAwcOhIuLyxsda+/evVCpVGjfvj3MzMxgZGRUQqlJbLGxsZg4cSIiIyOxbt06tGvXTuxI9Ab++ecfHD58GF5eXujevfsLXfSMjAykpKTA1dVVpIREVNaxcCOiErV06VJ8+eWXEAQBV69eRe3atcWOVCIEQcC1a9cQGBiIbdu2wdjYGL6+vhg0aBDeeeedtz42r2urOP766y9MmjQJXbt2xXfffQcbGxuxI9FrpKWl4ddff0X79u3RuHHjfPdpNBocOnQIa9euRZ06dbBo0SKRUhJRWcfCjYhKlCAI6NSpE06ePAm1Wl3uCpC7d+8iMDAQgYGByMjIgK+vL3x9fdGgQYNy91ip9KSnp+Prr7/Gjh07sHTpUvj7+/PnSY8JgoDo6GiEhYXBxsYG1apVg1qtxpkzZ3Dq1CnIZDIMGTIEXl5eYkclojKMhRsRlTilUokDBw6gR+93EfEwHanZaqg0WhjKpLA2NYRHZXMYy2Vixyy0hIQE7NixA4GBgbh//z4++OAD+Pr6wsvLi+usUbEKDQ3F2LFjYWdnhzVr1qBGjRpiR6KXOHbsGPbv3w9TU1NcvHgRkZGRcHR0RO/evdG3b1+888477J4T0Vth4UZEJUYQBITcT8bW0BiERafgUXoOFHIZIAEEAZBIAAiAUq2Bg4UxmrhZw6+5K1q42+jdm5vk5GT88ccfCAwMxKVLl/Duu+/C19cXnTp1goGBgdjxqBzLy8vDihUr8O2332LKlCn47LPPYGhoKHYseonk5GQIggBbW1uxoxBROcPCjYiKXW6eBoGhMVh/8h5SlWooVRoU5heNBIDCUAYrhRxj2laDb3NXGBmI14nLzMzEnj17EBgYiJMnT6Jr167w9fVFz549X5h4gKikRUVFYcKECYiOjsa6devg7e0tdiT6D61Wm6/rrtVqAYCdeCIqFizciKhYXY1LxYStF5GYqYJSrSnycRRyGezMDLHKrzE8XayKL+Br5Obm4uDBgwgMDMSBAwfg5eUFX19fvPfee7CwsCi1HEQFEQQBQUFBmDx5Mnr37o1FixbB2tpa7FhERFQK+BEQERULjVbAwv034bP+LGJTlG9VtAFPh0/Gpijhs/4sFu6/CY225D5j0mg0OHLkCEaNGgUnJycsW7YM7dq1w507d3DgwAEMHTqURRvpBYlEgg8++ADh4eGQyWSoW7cutm3bBn4Gq39ycnJw4MABsWMQUTnCjhsRvTVVnhbjA8Jw5m7SWxdsBVHIZfCuYYvVfk1gaFA8nzcJgoCQkBDdWmtOTk66tdaqVKlSLOcgKmlnz57FmDFj4OLigtWrV8Pd3V3sSPQ/2dnZqFSpEpKSkji0moiKBTtuRPRWNFoB4wPCcPpuYokUbcDT7tupO4n4aGvYW3ferl+/ji+//BLVq1fH8OHDYWNjg+PHjyMsLAzTpk1j0UZlSqtWrXDx4kW0a9cOzZo1w5IlS6BWq8WORQBMTExQu3ZthIWFiR2FiMoJFm5E9FYWH4zAmbtJyFFrS/Q8OWotTt9JwpJDEW+8771797Bw4ULUr18fPXr0gFqtxh9//IGbN29i1qxZqFWrVgkkJiodcrkcX3zxBUJDQ3HkyBE0bdoU586dEzsWAfDy8sKZM2fEjkFE5QQLNyIqsqtxqdh0LqrEOm3/pVRrsPFsFK7Gpb522wcPHmDFihVo2bIlWrZsibi4OKxevRrR0dH47rvv0KhRI71bcoDobVSrVg0HDx7EF198gX79+mHChAlIS0sTO1aF1qpVK5w9e1bsGERUTrBwI6Iiyc3T4KOtF0u80/ZfOWotJmy9iNy8F4vFlJQU/PLLL+jUqRPq1KmDixcvYvbs2YiPj8fq1avRpk0bTstN5ZpEIoGvry/Cw8OhVqtRt25dBAUFcfISkTwr3Pj8E1Fx4OQkRFQkG87cx+KDkaXWbXueQi7DjB4eGNqqKrKysnRrrZ04cQJdunTRrbWmUChKPRuRPgkODsbYsWNRvXp1rFq1Cq6urmJHqlAEQYCzszNOnz7NiWOI6K3xo2ciemOCIGD9yXuiFG3A0yGTPx6+CV8/Pzg7O2Pjxo3o378/YmJiEBQUhP79+7NoIwLQpk0bXL58GS1atEDjxo3x/fffIy8vT+xYFYZEIuFwSSIqNizciOiNhdxPRqpS3Jnr0nI0qNq0E27fvo2DBw9i2LBhsLS0FDUTkT4yNDTE119/jbNnz+Lvv/9G8+bNceHChdful5yczBkRiwELNyIqLizciCqgqKgoSCSSIn/yvjU0BkqVON22Z9RaCbKdGqNSpUq62xYuXIhRo0YVuH1AQAC6du1a4H3BwcGcWZLKvZo1a+Lw4cOYMmUKevfujcmTJyMjI+Ol2zdt2hTdu3fHrFmzeI3WW+DMkkRUXHiNG1EFUbVqVfzyyy/o3LkzoqKi4O7uDrVaDQMDgzc+lvfio4hPVb70/vTQXUgLCYKQp4LJO16w7TYBEgP5G59HyFMj6Z/VyIm6DG1OJgysHGHdbigU1ZsCAFysFTg1veMbH5eooktMTMRnn30GZ2dnzJ49+4XfA4GBgTh+/DjWrVuHESNG4OrVq/j777/h4OAgUuKyKycnB7a2tnj8+DFMTU3FjkNEZdibv2MjogpNqdLgUXrOy++/F4a0c0Fw8F0AmbktnvwxH6mnAmDdfvgbn0vQamBgbofKfosgs6wE5d0LeLJ7MZxG/AQDKwc8SMtBjloDY7nsLR4RUcVjZ2eH33//HRqNBjJZ/tdPdnY2hgwZgsDAQADAb7/9huvXr8PBwaHA7enVjI2NUb9+fVy4cAHt2rUTOw4RlWEcKklUAQwZMgQxMTHo06cPzMzMsGPHDgBPhw+6urrCzs4OCxYs0G2v1WqxaNEiVK9eHba2tvDx8UFycjIA4Oj567i7sBcyrx1B3OoPEbvCD2lntuv2zbx+FGYNusCwkhtkxmaw9B6EzGuHi5RbamgMqzb+MLBygEQihUmN5jCwdEDuwzsAns4uGfHw/4d6zZ49G4MHDy7wWBs2bEDr1q0LvO/48eNwcXEpUkaisqygImzw4MEYOnQofv75ZwwfPhw5OTmoXbs2tFqtbnuttnSXASnrOFySiIoDCzeiCmDz5s1wdXXF3r17kZmZCR8fHwDAqVOnEBkZiSNHjmDu3Lm4efMmAGDlypXYtWsXTpw4gYSEBFhbW2PChAkAgPScp5OS5MaFw2n0WjgMmo/U04FQJ8YCANRPomFo///TXhvau0OblQqNMv2tH4cmKwXq5HgYVno6pblEAqRkq976uET0VGhoKGJjY/Hbb7/hn3/+QY0aNRAREYFjx46hRYsWCAoKAgBIpVIWb2+AE5QQUXFg4UZUgc2aNQsKhQINGjRAgwYNcOXKFQDAunXrsGDBAri4uMDIyAizZ89GUND/tXff4VGV6RvH78kkIRPSE1pIo0noQqRJFUXEBRVFOsIqVRDrqiwWFGVFcVVEEKyoNMV1BRWsoIAUBaUHpSUEpCSQRtpk5vz+YJkfJYEQkpxJ8v1cVy6SmTPn3HOYzDVPnve87xLl5+crz3H6stjADoPk4VVF3jXqyrt6HeUd2ydJMuw58qjy/9dxnPneyC38mriiMBz5Sl46XX7NrpdXaOTp2wwpL58Pj0BJcDgcuuGGGzRv3jzXbU888YQaNmyo5s2b68MPP9TMmTO1YMECORwOeXh4aO/evXr66adNTF0+sBA3gJJA4QZUYjVr1nR97+vrq8zMTElSQkKC+vTpo6CgIAUFBalRo0ayWq06evSovK0WSZLVL9j1WItnFTntp697s3j5yJmb5brPmXf6e0uV4q+rZhhOJX/xsmT1VEj3Mf9/XIvk7cnbGFASUlNT9cILL6hx48aSpPz8fH344YcaPXq0evfurRUrVmjs2LHatGmTa8jk4MGDdfz4cUmiKLmIiIgI2Ww27dmzx+woAMoxPvEAlYTFYinytpGRkVq+fLlSU1NdXzk5Oapdu7YCfC4+O6RXtWjlHdvv+jnv6H55VA2S1RZQrNyGYSjlqxlynEpVtT7/lMXqedZ9UrCvd7H2C+BcoaGhuvfeeyWd7r6dOHFC69atU6dOnbRhwwYlJiZq4MCBatq0qaTTnfnk5GTNmjVL0un3GIfD3GVC3BnDJQFcKQo3oJKoUaOG9u3bV6Rtx4wZo0mTJikhIUGSdPz4cX3++eeSpHrV/C76WL+m3ZS59RvlJSfKkZOptJ8Xy6/ZDcXOfeLrN2RPOajqfZ+Sh1eVc+7LtjsUW9O/2PsGUDCr1SpfX19t3rxZPj4+kiQ/Pz91795df//735WTk6OJEyfq/ffflyTXgt7MOFk4CjcAV4rCDagkJk6cqOeee05BQUGuCQYKc//99+uWW27RjTfeKH9/f7Vr104bNmyQJPl4X/yDma1unALb3qGjC/6pQ7P+Ls/A6grqOLhYmfPTjinz9xXKO7pPSa8PVeLLfZX4cl9l7lgpSQpxpiksOFCJiYkFPt7Pz0+rV68u8L4mTZpo/vz5xcoFVAZ+fn6aMmWKvvzyS/Xt21fPPfec63q2u+66Sz179lTHjh313HPP6fnnn1f79u31n//8x+TU7ouZJQFcKRbgBnDZJiz6Tcu2HJaZbx4WSbe0CNdrA1qamAKoHN544w2lpKToqaee0nfffafBgwcrISFBVqtVPXr00COPPKIaNWro6aef1vTp0xUbG+t6LGu/nZaXl6eQkBD99ddf8vdnpACAy0fHDcBlG9QmSrZLdN5Km83bqkFto0zNAFQW48aN05NPPilJuvXWWzV16lT5+PjIy8tL3bt317p16xQXF6dFixYpNjZWWVlZ+uOPPySdHj7J34glb29vXX311dq4caPZUQCUU56X3gQAztW2ToiCbF7Kyiv6RAT5acd0+O17L7jdsOdKkiznXb8mSeEjZskzsHqB+wv29VabmJAiHx/AlTkzwdHixYvVq1cvff755+rRo4cmTpyonj17asmSJerbt6/Wr1+vV155RUFBQfrjjz/0xhtvuGaqrOzODJe8/vrrzY4CoBxiqCSAYnn/5/2atmK3su1lP4uczcuqiT1jdVf7mDI/NgDJ6XRqypQpWrZsmaZMmaKffvpJvr6+6tSpk6ZNm6aEhATt3LlTn376qT7++GMtWLCA4ZKSPvvsM7311lv66quvzI4CoBxiqCSAYhnYJkphfuZMxR/m563+rSNNOTYAycPDQ08//bSmTJmiF154Qb6+vurWrZv279+vmJgYDRw4UG3bttXq1asVHR2tjIwMhkvq9MyS69evl9PpNDsKgHKIjhuAYtualKp+c9cpx152H0J8vDz0yehr1ax2YJkdE0DRjBw5Utddd50GDRqk7du364UXXpC3t7fefPNNeXuz5qIk1a1bV19++aUaNWpkdhQA5QwdNwDF1jwiSHe1i5HNq2yGQNm8rBrWPoaiDXBT3bt317vvvqvt27eradOm+uijj/Tyyy9TtJ2F9dwAFBeFG4Ar8thNsepQP1Q+XqX7duLj5aEO9UP1aI/YS28MwBT9+vXT7bffrttvv10vv/yykpKSFBwcLEkMlfwfCjcAxUXhBuCKWD0smjUoTh3rh5Va583mZVXH+mGaNShOVg9LqRwDQMm49957tW7dOnXo0EE1atRw3Z6RkaEFCxZU+gKOhbgBFBfXuAEoEQ6noRe/jte8dQdK9Jo3Hy8PDWsfo0d7xFK0AeVYQkKC+vbtq6pVq+rNN988Z5HuyiQ/P1/BwcE6ePCggoKCzI4DoByh4wagRFg9LJrYs5E+HtVekcG2K+6+2bysigy26eNR7TWxZyOKNqCci46O1vr163X77berY8eOmjx5snJycsyOVeY8PT0VFxenDRs2mB0FQDlD4QagRDWPCNJ3D3XR4zfFqnaQTb7eVhW15LJI8vW2qnaQTRN7xuq7h7qoeURQKaYFUJasVqsmTJig33//XVu2bFGLFi20atUqs2OVOYZLAigOhkoCKDWGYWjjgROavyFRmxNP6khazulOnEUyDMnyv39z7A7VDPRRXFSwBrWNUpuYEFksdNiAiu6///2v7rvvPnXv3l0vvfSSQkNDzY5UJpYtW6bXX39d33zzjdlRAJQjFG4AykyO3aH4Ixk6mZWnvHynvD09FOzrrdia/vIpoyUFALiXjIwMPfnkk1q0aJFefPFFDR06tML/4eb48eOqX7++Tpw4IauV9z4ARUPhBgAATPfrr79q1KhRCgkJ0ezZs9WgQQOzI5Wqq666Sp9++qmaNWtmdhQA5QTXuAEAANNdc8012rhxo26++Wa1b99ezz33nPLy8syOVWpYzw3A5aJwAwAAbsHT01MPPfSQNm3apA0bNujqq6/WmjVrzI5VKijcAFwuCjcAAOBWoqOjtXTpUk2ZMkUDBgzQyJEjdfLkSbNjlShmlgRwuSjcAACA27FYLLrjjju0Y8cOeXt7q3Hjxlq4cKEqyqX5TZo00ZEjR5SSkmJ2FADlBIUbAABwW4GBgXrjjTf02Wef6YUXXlDPnj21b98+s2NdMavVqtatW2v9+vVmRwFQTlC4AQAAt9euXTv9+uuv6tatm9q0aaMXXnhBdrvd7FhXhOGSAC4HhRsAACgXvLy89Oijj+qXX37Rjz/+qFatWpXrCT6YoATA5WAdNwAAUO4YhqHFixfroYce0m233aapU6cqKCjI7FiX5eTJk4qKitLJkyfl6elpdhwAbo6OGwAAKHcsFosGDBigHTt2yOl0qkmTJvrkk0/K1eQlwcHBioyM1LZt28yOAqAcoHADAADlVnBwsN588019/PHHmjx5snr16qUDBw6YHavIGC4JoKgo3AAAQLnXoUMH/fbbb+rQoYOuueYaTZ8+Xfn5+WbHuiQKNwBFxTVuAACgQtmzZ4/Gjh2r5ORkzZkzR23atDE7UqF27typ3r17a+/evWZHAeDm6LgBAIAKpX79+vrmm2/0yCOP6NZbb9WECROUnp5udqwCxcbG6sSJEzp27JjZUQC4OQo3AABQ4VgsFg0ePFjbt2/XqVOn1KRJE3322Wdmx7qAh4eH2rZty3BJAJdE4QYAACqs0NBQvfPOO/roo480ceJE3XbbbTp48KDZsc7BQtwAioLCDQAAVHhdunTRli1b1KpVK7Vs2VKvvvqqHA6H2bEkMUEJgKJhchIAAFCp7N69W2PGjFFGRobmzp2rVq1amZonPT1d4eHhOnnypLy8vEzNAsB90XEDAACVSsOGDfXDDz9o/Pjx6tmzpx566CFlZmaalicgIEB169bV77//bloGAO6Pwg0AAFQ6FotFw4cP1/bt23XixAk1adJEy5YtMy0PwyUBXApDJQEAQKX3ww8/aMyYMWrWrJlmzJih2rVrl+nx33//fX322WcaMmSIfHx81Lt37zI9PgD3R+EGAAAgKScnR1OnTtXs2bM1efJkjRkzRlartVSPabfb1b9/f/3www9KS0uTt7e3rr32Wq1cubJUjwug/GGoJAAAgCQfHx89++yz+vHHH7Vo0SJde+212rJlS6ke09PTU0ePHlVWVpbrtl69epXqMQGUTxRuAAAAZ2ncuLF+/PFHjRw5Ut27d9ejjz6qU6dOlcqxLBaLli1bpmrVqkk6vSD3ddddVyrHAlC+UbgBAACcx8PDQyNGjNC2bdt06NAhNW3aVMuXLy+VY4WEhOjbb7+Vl5eX7Ha7WrRoUSrHAVC+cY0bAADAJXzzzTcaO3asWrdurVdeeUW1atUq8WPMnDlT8+fP1w8/rlH8kXSlZtmV53DK2+qh4Kreiq3pLx+v0r3mDoD7onADAAAogqysLD333HN66623NGXKFI0aNUoeHlc+eMkwDG3Yf0ILNiZqU8JJHU3Pkc3LKlkkw5AsFkmGlG13qEaAj+KigzWoTZTa1gmRxWK58icGoFygcAMAALgM27Zt0+jRo2WxWDRnzhw1bdq0WPvJzXdo4cZEzf1pn1Kz7crOc6goH8oskmzeVgXZvDSqc10NbBOlKp504oCKjsINAADgMjmdTs2dO1dPPvmkRo4cqSeffFI2m63Ij9+alKpxCzYrOTNP2XZHsXPYvKwK8/PWG4NaqXlEULH3A8D9MTkJAADAZfLw8NCYMWO0detW7d27V82aNdO3334rSdq5c6dGjhypgv427nAamvrVLvWbu04HT2ZfUdEmnR4+efBktvrNXaepX+2Sw8nf44GKio4bAADAFfrqq680btw4tW/fXlu2bNHu3bv1zjvvaNiwYa5t8vKdGjt/k37em3LFBVtBbF5WdagfqlmD4uTtyd/mgYqGwg0AAKAEnDp1Sn369HF13gICAnTgwAEFBwfL4TQ06sNftXZvsnLszlLL4OPloY71wzRnyDWyejBxCVCR8OcYAACAEnDq1CmtWbPG9XNGRoZGjBghSZq2Il4/700p1aJNknLsTq3dk6IXv44v1eMAKHsUbgAAACUgNzdXPXr0UMuWLVW7dm15enrqP//5j9bsPKgP1h8oleGRBcm2OzRv3QFtTUotk+MBKBsMlQQAACglWbl23fjaaiWdzC7zY0cG2/TdQ11YKgCoIOi4AQAAlJKPNyUpJTPPlGMnZ+Zp8S8HTTk2gJJH4QYAAFAKDMPQ3J/2ldkQyfNl2x2a89O+ApclAFD+ULgBAACUgg37Tyg1225qhpNZedp44ISpGQCUDAo3AACAK9CzZ0/NmzfvgtsXbExUdp453bYzsvMcWrAh8ZLbzZ8/XzfeeGOB961evVoNGzYs1vGnTp3qmlkTwJVhchIAAIAimjx5svbs2aOPPvroktt2mPaDDqWW/aQkZ5zatVoZv34u+7H96nRtO61ateqK95mbm6t7771X3333nU6cOKH69etr6tSp6tmz55UHBnBRnmYHAAAAqGiy8xw6mp5jagYPm7/8r7lVjhNJcholM0lJfn6+IiMj9eOPPyoqKkpfffWV+vXrp23btikmJqZEjgGgYAyVBAAAFdbBgwd1++23q1q1agoNDdX48ePldDr13HPPKTo6WtWrV9ddd92ltLQ0SdKBAwdksVg0b948RUVFKSwsTM8//7wkacWKFZo6daoWL14sPz8/tWjRQpLUtWtXvf3225Kk999/Xx07dtTo8fdr/7/7K2n2Pcre+6srT9Ksu5V94HfXz6mr5yt52XTXz7mH4nXkw0eU+Ep/HX5nvHISthb7udtirlbVRp1kCwpT1iWGbJ7JXZBVq1YpIiJCklS1alVNnjxZMTEx8vDwUK9evVSnTh1t2rSpwMdOnjxZQ4YMKfZzAPD/KNwAAECF5HA41KtXL0VHR+vAgQM6dOiQBgwYoPfff1/vv/++Vq5cqX379ikzM1Pjx48/57Fr1qzR7t279f333+vZZ5/Vrl27dNNNN+mf//yn+vfvr8zMTG3ZsqXA427YsEHVIuqo0aOLFdj2DqUsn1GkmR3zM5J17JNnFHhtf0U+sFDB3e7R8c/+JUdW2hWfi3xH6VwZc/ToUf3xxx9q0qRJqewfwP+jcAMAABXSxo0bdfjwYb300kuqWrWqfHx81LFjR82fP18PPfSQ6tatKz8/P/3rX//SokWLlJ+f73rs008/LZvNphYtWqhFixaFFmkFiY6O1o13DJYsVlVt1k2OzBNynkq95ONO7VglW71rZKvXWhaLh2x1Wsq7Vv1zOnbF5SyFKQ3sdrsGDx6sYcOGKTY2tsT3D+BcXOMGAAAqpIMHDyo6Olqenud+3Dl8+LCio6NdP0dHRys/P19Hjx513VazZk3X976+vsrMzCzycWvWrClvq4csFsnDy0eS5LRny6rgiz4uP+2YTsWvUdaejf9/ozNfPlHNi3zswnhYLFe8j7M5nU4NHTpU3t7emjlzZonuG0DBKNwAAECFFBkZqcTEROXn559TvIWHhyshIcH1c2Jiojw9PVWjRg0lJSVddJ+WIhZAQb5eUgFNLg9vHxn2XNfPjlMnXd97BoTJr+l1Cu05oUjHKCp7fr7SUk9o/fr1atiwoYKDL15AXophGLrnnnt09OhRffXVV/Ly8iqhpAAuhqGSAACgQmrTpo1q1aqlxx9/XKdOnVJOTo7Wrl2rgQMH6pVXXtH+/fuVmZnpum7t/M5cQWrUqKEDBw7I6XRedLvYmgHKtl84IYhX9To6tesnGY585f71p7J2/+y6r2qT65S1Z6Oy922S4XTIyM9TTsJW5acnX/6Tl1z7cDgNnUo7oXHjxikyMlLVq1dXp06dNHLkSE2fPl3Lli3TkSNHinQdniSNHTtWu3bt0rJly2Sz2YqVDcDlo3ADAAAVktVq1bJly7Rnzx5FRUUpIiJCixcv1t13362hQ4eqc+fOqlOnjnx8fPT6668XaZ933nmnJCk0NFStWrUqdDubt1U1AnwuuD2o81Dln/xLB18doLQ181W1cRfXfZ4B1VT9jieVtu4TJc0YrKQ3hit9438k4+JFYmFObV+pxOm368TXs3T82DFt3rxZffv21e+//65nn31WH374oTZs2KBZs2bp5Zdf1rp169SoUSPddtttCgsL06hRo/Tzzz+7ZtyUpISEBM2ZM0e///67atasKT8/P/n5+Wn+/PmSTncv/fz8lJh46UW/AVweFuAGAAAoBRMW/aZlWw4XNGKyzFgk3dIiXK8NaHnJbbOzs7Vnzx7t3r3b9RUfH6/du3fLy8tLsbGxatiwoesrNjZWdevWZagkUEYo3AAAAErB+n0punveL5dcQ600+Xpb9d7w1mpbJ7TY+zAMQ0ePHj2nkDvzlZSUpOjoaFchd3ZRFxYWVoLP5FxPPPGETpw4oVatWqlx48Zq0KCBqlWrVmrHA9wBhRsAAEApMAxDHab9oMNpOVe8r8SX+xZ8jPw8WTy9L7i9er/J8olsqtpBNq159LoiT6pyuXJzc8/p0p1d2Hl4eFzQoWvYsKHq1asnb+8LM1+OtWvXatu2bXrnnXd08OBBxcTE6OjRo1q2bJmaNm0qp9MpDw+uCLpc2XkOxR9JV2qWXXkOp7ytHgqu6q3Ymv7y8bKaHa/So3ADAAAoJe//vF/TVuwucKKS0mbzsmpiz1jd1T6mzI9tGIaOHz9+QYcuPj5eBw8eVGRkZIFDL6tVq3ZZReYbb7whq9Wq0aNHy+FwFDrBjGEY5+z3/J8rK8MwtGH/CS3YmKhNCSd1ND1HNi+rZJEMQ7JYJBlStt2hGgE+iosO1qA2UWpbJ4TzZwIKNwAAgFKSm+/QDf/+UQdPZpf5sSODbfruoS6q4ulenZK8vDzt3bv3gg5dfHy8DMO4oEPXpk0b1a5d+4JCIS0tTdOmTVNgYKB+++03NWjQQPHx8br++uvVrFkz1a5dWzExMeY8STeXm+/Qwo2JmvvTPqVm25Wd5yjStZgWnZ54J8jmpVGd62pgmyi3e31VZBRuAAAApWhrUqr6zV2nHHvxZocsDh8vD30y+lo1qx1YZse8UoZhKDk5+YIOXa9evXTPPffIaj23QDhw4IDmzp2roKAgrVu3TjVq1NATTzyhrVu3avny5YqNjdW4ceO0b98+jR8/Xp999pmqVKmivXv36tixY2rYsKFCQkJMerbm2ZqUqnELNis5M++KOsE2L6vC/Lz1xqBWah4RVHIBUSgW4AYAAChFzSOCdFe7GH24PqFMhkzavKy6q310uSrapNOLm1erVk3VqlVTx44dC93uzDDHY8eOydPTU2lpaYqKitLAgQMVERGh3NxcffPNN4qOjpYkxcfHKzs7W1WqVNGmTZu0cOFCJSYm6vDhw+rXr58mTJhQKYZOOpyGpq2I1wfrD5TIHxGy7Q4dPJmtfnPX6a52MXrsplhZPSr2OTQbV20CAACUssduilWH+qHy8Srdj14+Xh7qUD9Uj/aILdXjuINjx46pSpUqysnJUVBQkGrVqiXp9FpzHh4erm7ajh071KxZM504cUJvvPGGEhMT9fHHH+vZZ5/Vnj17tG/fvgpftOXlOzXqw1/14fqEEu/85tid+nB9gkZ/9Kvy8suuq1wZUbgBAACUMquHRbMGxalj/bDTkz+UApuXVR3rh2nWoLhK0fnYv3+/7Ha7UlNTFRAQID8/P0mS3W7XqVOnXIXc9u3b1aBBA+3atUs5OTnKycnRDTfcoHHjxmnHjh06fvy4a58V8Qoih9PQ2PmbtHZvcql1fLPtDq3Zk6x7F2ySw1nxzqG7YKgkAABAGfD29NCcIdfoxa/jNW9dyQxXO82Qj+fp4ZGP9qj4w9XOdMeuvvpqJScnKy8vTyEhIa7CrVWrVnr11Vf166+/ytvbW1999ZX+9re/KSYmRunp6Zo/f74CA08PI83KyjpnAfH09HQ99thj2r9//wWzXhY0QUp5MG1FvH7em1Lq11jm2J1auydFL34dr4k9G5XqsSorJicBAAAoYyU5QYQ9I0UDo7I05cGRJZiwfJs5c6a+/PJLNWjQQEuXLtWnn36quLg4DR8+XE2bNlWvXr0UEnJ6SvuwsDBXQWYYhg4ePKht27ZdMOvlqVOndNVVV10w6+VVV10lX19fk59xwcyaGOfjUe2ZsKQUULgBAACYIDffoUUbD2ru6n06mZV32VOyB/t6a3Tnumrhd0rXX9dFW7ZsUe3atUs7drmTm5srT09PWa1WHThwQE888YQSEhKUm5urV199Vddee22R9pOamnrOjJdnCru9e/eqWrVq5xRzZ74iIiJMWwg8N9+h6//9o5JYiqLCoHADAAAwkWEY2njghOZvSNTmxJM6knbhIsiGIeXYHaoZ6KO4qGANahulNjH/vwjyU089pe3bt+s///mPyc+mfHE4HBcsM1CcfSQkJFzQodu9e7fS09PVoEGDArt0Z4Z2lpbKuvh7RUbhBgAA4EZy7A7FH8nQyaw85eU75e3poWBfb8XW9JdPIROb5OTkqEWLFpo2bZpuu+22sg2MQqWnpxfYpduzZ49CQkIu6NDFxsYqMjKyyF26AwcOqHbt2udcpyed/mNAh2k/6HBaTmk8rSKpHWTTmkevK5fXBborCjcAAIAK4Mcff9SQIUO0Y8cOBQQEmB0HF+F0OpWYmKjdu3dr7dq1mjJlirp27ao///xTJ06ccHXpzi/s/P39z9lPRESEAgMD9d///lcNGjRw3b5+X4runveLsvLKvtt2RtaGT9SuWr6WLv7ogvvmz5+vefPm6Ztvvrns/Y4ZM0a1a9fWk08+WRIxyxUKNwAAgArinnvuka+vr15//XWzo+AiYmJi9Pbbb+uGG27QgQMHVKdOHdntdnl6eiojI0N//PHHOR263bt3688//1RQUJCriKtbt64ef/xxGYYhm82ml19+WaNHj5bFYtGERb9p2ZbDMiSlb/yv0jYskZGfJ9+rrlVoj3GyeHpdMuP5jHy7Ur6ZpZwDv8uZkynPoFoK7nKXbPWuKXB7i6RbWoTrtQEtL7nv6667Ttu3b1dubq7q1KmjZ599VrfeeutlZ6zoWA4AAACggnjppZfUpEkTDR48WO3atTM7DorB399fcXFxiouLO+d2p9OppKQkVyH3888/y2KxyOl0KisrS2PHjtVbb72lTZs2aVPCSRmSsvdtUtr6Jaox8HlZ/UN1/NPnlLpmvoK7Dr/sXIbTIU//MNUc9IKsgdWUvfdXHf98msLvninPoBoXbi9pU+LJIu37tddeU+PGjeXp6akNGzbohhtu0B9//OFaiw+nsQA3AABABRESEqKXX35Zo0aNkt1uNzsOCjB06FAlJiaqd+/e8vPz08cffyzp9PDBqKgohYWF6fnnn3dt73Q69cILL6hBgwZq2bKl3n77bQ0ePFh9+/Z1XT/m7e0tHx8f/fHHH5r87BQdTT99bVvm9h/k16K7vKtFy+rjp8AOA5S57bti5fbw9lFQp8HyDKohi8VDvvXbyDOwhnKP7Clw+9TV87XlgynKKWBylPfff18dO3Z0/dy8eXN5ep7uJ1ksFtntdh08eLDA/Q4fPlxPPPFEsZ5DeUfhBgAAUIEMHDhQ4eHhevnll82OggJ8+OGHioqK0rJly5SZmal+/fpJktasWaPdu3fr+++/17PPPqtdu3ZJkmbMmKH//ve/+vHHH3X48GEFBwdr3Lhxio6OVv/+/SVJQ4YM0YkTJ7RmzRpNff45WVIPSZLsxxPkXb2O69je1evIeSpVjuz0K34ejlMnZT9xSN7VogrdxuphUfyRjCLtr1evXvLx8VHbtm3VtWtXXXNNwUMwKzMKNwAAgArEYrFo9uzZmj59uvbu3Wt2HBTR008/LZvNphYtWqhFixbasmWLJGnOnDl6/vnnFRERoSpVqmjy5MlasmSJrr76aj333HOSpGeeecb12LoNGyvn6D5JkmHPkUeVqq5jnPneyL2ytd0MR76Sl06XX7Pr5RUaedFtT2blFWmfX3zxhTIyMvTVV1+pR48epq1/5844IwAAABVMnTp19Nhjj2nMmDFiHrryoWbNmq7vfX19lZmZKUlKSEhQnz59FBQUpKCgIDVq1EhWq1VHjx4t8LHeVWxy5p0uzCxePnLmZrnuc+ad/t5SxVbsnIbhVPIXL0tWT4V0H3PJ7fPynUXet5eXl3r27Kmvv/5aS5cuLXbGiorCDQAAoAJ68MEHlZycrI8+unA6dpjrctY2i4yM1PLly5Wamur6ysnJUe3atQvc3uOsfXtVi1besf2un/OO7pdH1SBZbcVbLsIwDKV8NUOOU6mq1uefslgvPc+ht+fllxv5+fl0iwtA4QYAAFABeXp6au7cufrHP/6h5ORks+PgLDVq1NC+ffuKtO2YMWM0adIkJSQkSJKOHz+uzz//vNDtPa3/X7j5Ne2mzK3fKC85UY6cTKX9vFh+zW4odu4TX78he8pBVe/7lDy8qhTpMcG+3he9Pz4+XsuXL1d2drbsdrs++ugj/fTTT+rSpUuxc1ZUFG4AAAAVVOvWrTVgwAA98sgjZkfBWSZOnKjnnntOQUFBWrJkyUW3vf/++3XLLbfoxhtvlL+/v9q1a6cNGzYUur2vt1V2x+nhsba6cQpse4eOLvinDs36uzwDqyuo4+BiZc5PO6bM31co7+g+Jb0+VIkv91Xiy32VuWOl6/7El/sqP+2Y6zEOp6HYmqcXDffz89Pq1asv2K9hGJo8ebKqV6+uatWq6bXXXtPixYvVqlUrSdLq1avl5+dXrMwVDQtwAwAAVGAZGRlq2rSp3nvvPXXr1s3sOCgDHab9oEOpVzYBSUmICLZpzaO85koKHTcAAIAKzN/fXzNnztTo0aOVnW3+h3mUvrjoYBX9KrrSYZEUFxVscoqKhY4bAABAJXDnnXfqqquuOmdxZ1RM6/el6O55vygr78LFr6XTwxoPv33vBbcb9lxJkqWA69fCR8ySZ2D1Imfw9bbqveGt1bZOaJEfg4ujcAMAAKgE/vrrLzVv3lwrV65U06ZNzY6DUmQYhjpM+0GH03JMy1A7yKY1j153WTNo4uIYKgkAAFAJ1KpVS1OmTNGoUaPkdBZ9bS2UPxaLRaM615XNy2rK8W1eVo3uXJeirYRRuAEAAFQSo0aNksVi0Zw5c8yOglI2sE2UwvwuPhV/aQnz81b/1pGmHLsiY6gkAABAJbJjxw517dpVv//+e6GLOKNi2JqUqn5z1ynHXnYdVh8vD30y+lo1qx1YZsesLOi4AQAAVCJNmjTRmDFjNGHCBLOjoJQ1jwjSXe1iymzIpM3LqmHtYyjaSgmFGwAAQCUzadIkbdu2TZ9//rnZUVDKHrspVh3qh8rHq3Q/9vt4eahD/VA92iO2VI9TmTFUEgAAoBJauXKlhg0bph07dsjf39/sOChFeflO3btgk9buSVG2veAlAq6EzcuqDvVDNWtQnLw96QuVFgo3AACASuruu++Wv7+/XnvtNbOjoJQ5nIZe/Dpe89YdKNFr3ny8PDSsfYwe7RErqwezSJYmCjcAAIBKKiUlRU2aNNHSpUvVpk0bs+OgDGxNStW4BZuVnJl3Rd03m5dVYX7eemNQKzWPCCq5gCgUhRsAAEAlNn/+fL344ov69ddf5eXlZXYclIHcfIcWbkjU04tWyxYUptx8Q0UpCCySbN5WBft6a3TnuurfOlJVPM1ZK64yonADAACoxAzD0E033aTrr79ejz76qNlxUEZWr16tsffeq3eWrtL8DYnanHhSR9JyTs9AaZEMQ7L8798cu0M1A30UFxWsQW2j1CYmhMW1TUDhBgAAUMnt27dPbdq00caNG1W3bl2z46AMjB07VlFRUZo4caLrthy7Q/FHMnQyK095+U55e3oo2NdbsTX95VNGSwqgcBRuAAAA0Isvvqjvv/9eK1asoJtSwdntdoWHh2vjxo2qU6eO2XFQRMzXCQAAAD344IM6evSoFixYYHYUlLJvv/1WDRo0oGgrZyjcAAAAIC8vL82dO1cPP/ywUlJSzI6DUrRgwQINGjTI7Bi4TAyVBAAAgMv999+vjIwMvfvuu2ZHQSnIyspSeHi4du/erRo1apgdB5eBjhsAAABcnnvuOX333XdauXKl2VFQCpYtW6a2bdtStJVDFG4AAABw8ff318yZMzV69Gjl5OSYHQcljGGS5RdDJQEAAHCBvn37qlGjRpoyZYrZUVBCTp48qZiYGB08eFABAQFmx8FlouMGAACAC8yYMUNvvvmmduzYYXYUlJBPP/1U3bt3p2grpyjcAAAAcIHw8HA9++yzGjVqlJxOp9lxUAIYJlm+UbgBAACgQKNHj5ZhGJo7d67ZUXCFDh8+rN9++00333yz2VFQTBRuAAAAKJCHh4fmzp2rJ598UocPHzY7Dq7A4sWLddttt8nHx8fsKCgmCjcAAAAUqmnTpho9erTuv/9+s6PgCjBMsvxjVkkAAABcVHZ2tpo3b65///vf6t27t9lxcJn+/PNPderUSUlJSfL09DQ7DoqJjhsAAAAuymazac6cORo3bpwyMjLMjoPLtHDhQvXr14+irZyj4wYAAIAi+fvf/67AwEC9+uqrZkdBERmGoUaNGun9999Xu3btzI6DK0DhBgAAgCJJSUlRkyZNtGzZMrVu3drsOCiCzZs3q2/fvtq7d68sFovZcXAFGCoJAACAIgkNDdX06dM1cuRI2e12s+OgCBYuXKiBAwdStFUAdNwAAABQZIZhqEePHurevbv+8Y9/mB0HF+F0OhUVFaWvv/5aTZo0MTsOrhAdNwAAABSZxWLR7NmzNW3aNO3fv9/sOLiI1atXKyQkhKKtgqBwAwAAwGWpV6+e/vGPf2js2LFi8Jb7WrhwIWu3VSAMlQQAAMBls9vtuuaaa/T4449r4MCBZsfBefLy8hQeHq5ff/1VMTExZsdBCaDjBgAAgMvm5eWluXPn6qGHHtKJEyfMjoPzfPPNN2rYsCFFWwVC4QYAAIBiadu2rfr27cskJW6IYZIVD0MlAQAAUGzp6elq0qSJPvzwQ3Xt2tXsOJB06tQp1a5dW3/88YeqV69udhyUEDpuAAAAKLaAgADNnDlTo0ePVk5OjtlxIGnp0qVq164dRVsFQ+EGAACAK3LrrbeqSZMm+te//mV2FIhhkhUVQyUBAABwxQ4dOqSrr75aP/74oxo3bmx2nEorJSVFdevW1cGDBxUQEGB2HJQgOm4AAAC4YrVr19aUKVO0evVq1nYz0aeffqoePXpQtFVAdNwAAABQIgzDUE5Ojmw2m9lRKq3rrrtOEyZMUJ8+fcyOghJGxw0AAAAlwmKxXLRoy8vL04wZM8owUeWSlJSkLVu2qGfPnmZHQSnwNDsAAAAAKr7vv/9eQ4YMUXp6uqxWq8aNG2d2pApn8eLF6tOnj3x8fMyOglJAxw0AAAClJi0tTbfddpvuuOMO/fXXX0pOTtZ7772npKQks6NVOAsXLtTAgQPNjoFSQuEGAACAUjFv3jw1aNBAnTt3VuPGjZWQkCCbzaYePXro7bffNjtehbJ7924dOnRI1113ndlRUEoYKgkAAIASlZ+fr6ZNm6pRo0bau3ev/P39FRAQoDFjxmj58uV6/vnnderUKbNjVigLFy5U//79ZbVazY6CUkLhBgAAgBLl6empL7/8UvXq1XPdNmLECAUEBCgrK0vr169Xt27dZBiGLBaLiUkrBsMwtHDhQn3wwQdmR0EpYqgkAAAASly9evVc67mlpqYqKSlJN910k6xWqyZNmqTVq1fLYrHI4XCYnLT827x5s/Lz89WmTRuzo6AU0XEDAABAqTjTTfvggw+0bt06ZWRkaODAgZo5c6ZGjhypzZs3M7SvBCxYsECDBg2ie1nBUbgBAACg1Pz555/68ssv9fDDDysyMlJ33XWXFixYoLi4OKWkpCgwMFCennwkLS6Hw6FFixbp22+/NTsKShlDJQEAAFBqIiMjdfjwYdWqVUuNGjXSNddco4YNG8pqtZ5TtK1YscLkpOXT6tWrVa1aNTVu3NjsKChlFG4AAAAoNT4+Pnr11Vf1wgsvqGnTpvruu+/0zjvv6M0335Snp6eWLl2qGjVq6KWXXpLT6TQ7brlzZpgkKj6LceaqUQAAAKCU3HfffTp06JBee+01RUZGKi0tTQMGDNBvv/2mV155hYWjiyEvL0/h4eHavHmzoqKizI6DUkbHDQAAAKVu+vTp+s9//qPIyEjNmjVLMTExioyM1F9//XVO0UbXrei+/vprNWrUiKKtkuBKUAAAAJQ6b29vpaamqmXLlvL19dXSpUvVqVMnffbZZ4qPj5fT6dSkSZPk4UFfoagYJlm58JsBAACAUmexWBQUFKRJkyZpx44d6tSpk44fP65XX31V1atX1/Lly/XFF19IoutWFJmZmVq+fLn69u1rdhSUEQo3AAAAlJkRI0bov//9r3bv3q1q1aqpVq1a6tixo6ZOnapXX31Vkui6FcHSpUt17bXXqlq1amZHQRnhtwIAAABlatu2bXrppZckSTabTUlJSercubOef/555eXlmZyufGCYZOVD4QYAAIAy9cQTT2jnzp2aOXOmjh8/rpycHElS27ZtlZeXJ4fDIYkhk4VxOp3q1q2b+vTpY3YUlCGWAwAAAECZW7VqldasWaPMzEz17t1bO3bs0OLFi10LSb/++usmJ3RvdrtdXl5eZsdAGaJwAwAAgKmef/55bd26VT/88IP27Nmjf/zjH2rWrJnuu+8+GYYhi8VidkTAdAyVBAAAgGkSEhL05Zdfat68eZo4caImT56sYcOGadWqVcrNzaVoA/6HddwAAABgmsTERPn4+MjHx0cPPfSQunbtqv3792vQoEGqUqWK2fHcgtPpdM206XQ6ZbFYKGgrITpuAAAAME2nTp3k5+enl19+WdLpa9siIiLUtGlTk5O5Dw8PDx05csT1/ZmijSueKheucQMAAICpdu3apaeeekqTJk3S1VdfzXVtZ+nbt6+ioqJkGIY2b96sunXr6p577lHHjh3NjoYyRuEGAAAA0x06dEiBgYHy8/MzO4rbyMzMVHJyshITExUUFKTc3FwtWbJEX3zxhRo2bKgHHnhAnTt3NjsmygiFGwAAANxGfn6+MjMz5e/vL6vVanYcU02cOFEWi0VTp0495/b8/HwtWrRIO3fu1IgRI1S3bl2TEqIscY0bAAAA3IbVatXQoUP12muvmR3FdP/617/k5+en6dOnKy0tzXW7p6enbrvtNsXExOiVV15RamqqeSFRZui4AQAAwK38+eefat++vX799VfFxMSYHcdUO3fu1L/+9S/98MMP6tChg/r27atevXrp1KlTOnXqlKpWraqwsDCuCawEKNwAAADgdqZOnaq1a9fqiy++oCiRdOTIES1evFhLlizRyZMnddNNNyknJ0e33nqrunfvbnY8lAEKNwAAALidvLw8xcXF6cknn1S/fv3MjuNWMjMzdfLkSUVGRpodBWWIwg0AAABuad26dbrjjju0Y8cOBQcHmx3HNDk5OfLx8TE7BkzG5CQAAABwS+3bt1efPn302GOPmR3FNLm5uXrwwQeVm5trdhSYjMINAAAAbmvq1Kn66quvtHr1arOjmGLFihXasWOHqlSpYnYUmIzCDQAAAG4rMDBQM2bM0KhRoypl12nhwoUaNGiQ2THgBrjGDQAAAG7NMAz16dNHrVq10lNPPWV2nDKTkZGhiIgI7d27V2FhYWbHgcnouAEAAMCtWSwWvf7665oxY4bi4+PNjlNmPv/8c3Xq1ImiDZIo3AAAAFAOREZG6umnn9bo0aPldDrNjlMmFi5cqIEDB5odA26CoZIAAAAoFxwOh6699lqNGjVK99xzj9lxStXx48dVv359HTp0SH5+fmbHgRug4wYAAIBywWq16q233tLEiRN19OhRs+OUqiVLlujmm2+maIMLhRsAAADKjebNm+vuu+/Wgw8+aHaUUsUwSZyPoZIAAAAoV7KystSsWTPNnDlTPXv2NDtOiUtMTFTLli31119/ydvb2+w4cBN03AAAAFCu+Pr6avbs2br33nt16tQps+OUuEWLFumOO+6gaMM5KNwAAABQ7tx4443q2LGjJk+ebHaUEscwSRSEoZIAAAAol44fP66mTZtqxYoVatmypdlxSsTOnTvVvXt3JSYmymq1mh0HboSOGwAAAMqlatWqadq0aRo5cqQcDofZcUrEwoULNWDAAIo2XIDCDQAAAOXWsGHDFBAQoNdff93sKFfMMAyGSaJQDJUEAABAufbnn3+qffv22rx5s6KiosyOU2wbN27UkCFDtHv3blksFrPjwM3QcQMAAEC51qBBAz344IO69957VZ57EgsWLNCgQYMo2lAgOm4AAAAo9/Ly8tSqVSs9/fTTuvPOO82Oc9kcDociIiK0atUqNWzY0Ow4cEN03AAAAFDueXt7a+7c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VhiGYZzz2klKSjJCQkKML7/80nA4HMY333xjhISEGMeOHTMMwzC6dOlihIeHG9u2bTMyMzON22+/3fXY3bt3G76+vsY333xj5OXlGdOmTTPq1atn5ObmFvrcz/7dOuOdd94x0tPTjZycHOP+++83WrRo4bqvsHP67bffGpsTThjVOg8yvMMbGhH3fWRETJhvVKkdawRe29+IfvwLo8bAqYYsHkbgtQOMqH/816h+59OGxbOKEfHAIiP68S+MKpFNjZCe9xnRj3/h+qoxcKph9Q81oh//wqje7xnDu0Y9I/KBRUbUY8uM8BGzjdrjPzCiH//CqNr0eiPgvOOMvP8fRl5envHll18aNpvNOHHihGEYhtG/f3+jf//+xqlTp4wdO3YYERER5/wfSzL+/PNPwzAMY8eOHUaNGjWMt99+2/X+MnToUCMzM9PIysoyPvvsM6NevXrGzp07DbvdbkyZMsVo3759kV6bhb2mDcMwPvzwQyM5Odmw2+3G9OnTjRo1ahjZ2dmu18v57z8Xe6+bPXu20bBhQyMxMdFISUkxunbtes77ZJcuXYy33nrLKMjKlSsNq9VqPPnkkwWey4JeD5f6fbrYe167du2Mhx9+2MjNzTVWr15t+Pv7u17fl/P+fjF03AAAKCNz5szR888/r4iICFWpUkWTJ0/WkiVLLhgudPToUS1fvlyvvvqqqlatqurVq+vBBx/UokWLXNtUr15dDzzwgLy8vNS/f381bNhQX375pQ4ePKg1a9Zo2rRp8vHx0dVXX60RI0boww8/dD22ffv2uu2221zX350vJSVFklSrVq2LPp/o6GiNHDlSVqtVw4YN019//aWjR49Kkv72t7+pXr16slgs6tKli2688cZz/vJ+vgkTJig8PFwhISHq3bu3fv/990uez8sRHh4uwzCUmpqqL774QjExMfr73/8uT09PtWrVSnfccYeWLFni2r5Pnz6Ki4uTj4+P+vTpIx8fH911112yWq3q37+/q+O2fv16ZWZm6vHHH5e3t7e6deumXr16aeHCha593X777WrTpo08PT01ePBg13Pz8vJSRkaG4uPjZRiGGjVqdMlzPmHCBEVGRrr+3+68806Fh4fLw8ND/fv3V4MGDbRx48YCH2sYht566y298sorCgkJkb+/v/75z3+e87o63y+//KLjx4/rqaeekre3t+rWrauR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h/T1119fuPP/adOmjQICAjRt2jRlZ2fL4XBo+/btBS6vMGTIEC1btkxff/21HA6HcnJytGrVqnMKjY8++kg7d+5UVlaWnnrqKfXt21dWq1X9+vXTl19+qe+//152u10vv/yyqlSp4ioiCnL+OcrIyFCVKlUUGhqqrKws/fOf/7zo9mcL8vVSUNMuSvt5sRxZaXJkpSlt7SJVbXpdgdufr2qjTsrc9p1yD++WYRinC7Nf/quqjTtLknL/+uP0fY58Wbx8ZPH0liyFfwwP9vW+4Dar1arbb79dkydPVlZWluLj4/XBBx8UKV9BxowZo3/961+ugiEtLU2ffPKJpIu/Ni8mIyNDnp6eqlatmvLz8/Xss88qPT290O0v9V7Xr18/zZgxQ0lJSTp58qReeOGFYj/f853/erjU79PFREdH65prrtHkyZOVl5endevWFTq7ZVHe3wtD4QYAQBm5//77dcstt+jGG2+Uv7+/2rVrpw0bNhS47QcffKC8vDw1btxYwcHB6tu3r/766y/X/W3bttWff/6psLAwTZo0SUuWLHENcVy4cKEOHDig8PBw9enTR88884y6d+9eaK4777xT0ulhRa1atZIk9e3bV4sXL9a7776r8PBw1ahRQ0888YRuvfXWSz5Pf39/zZgxQ/369VNwcLAWLFhQ6PUepeHw4cOuNZ1at26tbdu2adWqVbrxxhtd+b755hstWrRI4eHhqlmzph577DHl5uZe9rG8vb21dOlSLV++XGFhYbr33nv1wQcfKDY29pKPTU9P18iRIxUcHKzo6GiFhobqkUcekSTdc8892rlzp4KCgnTbbbcV+PjGjRvr4YcfVvv27VWjRg1t27ZNHTp0cN3frVs3NWnSRDVr1lRYWJgkadq0aapfv77atWungIAA3XDDDRe95sdqtWrZsmX6/fffVadOHYWFhWnEiBEFXjcWGRmpzz//XFOnTlW1atUUGRmpl1566Zxu5NChQzV8+HDVrFlTOTk5rhkqGzZsqI8++kj33XefwsLCtGzZMi1btkze3hcWMGdMnDhRzz33nIKCgjR9+nTdddddio6OVu3atdW4cWO1a9funO0vdk5jawbIr31/eddsoL/eGa+/3hkv7xr1FHRt/0KPfzZb3TgFdxmmlK9e08FX+unYx5Pl1/R6+V19kyTJmZullOWv6+CrA3Ro9t3ysPkr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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plt.figure(figsize=(12, 12))\n", + "rx.visualization.mpl_draw(\n", + " module.functions[0].control_flow_graph(),\n", + " with_labels=True,\n", + " labels=lambda block: getattr(block, \"name\", block),\n", + " edge_labels=str,\n", + " node_size=1200\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "bf321ded", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "// Generated from QIR block continue__1.i.i.i.\n", + "OPENQASM 2.0;\n", + "include \"qelib1.inc\";\n", + "\n", + "qreg q[1];\n", + "creg c[1];\n", + "measure q[0] -> c[0];\n", + "// Requires nonstandard reset gate:\n", + "reset q[0];\n", + "// %1 = c[0]\n" + ] + } + ], + "source": [ + "print(module.functions[0].blocks[2].as_openqasm_20())" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "279d92ca", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " ┌─┐ \n", + "q_0: ┤M├─|0>─\n", + " └╥┘ \n", + "c: 1/═╩══════\n", + " 0 \n" + ] + } + ], + "source": [ + "print(module.functions[0].blocks[2].as_qiskit_circuit())" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "2aeecb0f", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "// Generated from QIR block then0__2.i.i.i.\n", + "OPENQASM 2.0;\n", + "include \"qelib1.inc\";\n", + "\n", + "qreg q[1];\n", + "x q[0];\n" + ] + } + ], + "source": [ + "print(module.functions[0].blocks[3].as_openqasm_20())" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "6284c364", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "# Requires nonstandard reset gate:\n", + "# %1 = 0\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\cgran\\Anaconda3\\envs\\pyqir-dev\\lib\\site-packages\\qutip\\qip\\circuit.py:274: UserWarning: Unknown gate reset\n", + " warnings.warn(\"Unknown gate %s\" % name)\n" + ] + }, + { + "data": { + "text/plain": [ + "' & & \\\\qw \\\\cwx[1] & \\\\qw & \\\\qw \\\\\\\\ \\n & & \\\\meter & \\\\gate{reset} & \\\\qw \\\\\\\\ \\n'" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "circ = module.functions[0].blocks[2].as_qutip_circuit()\n", + "circ.latex_code()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "68a15b8d", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.7" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/src/QirTools/pyqir/pyqir/__init__.py b/src/QirTools/pyqir/pyqir/__init__.py index 80a5f04a43..fa576d1cc9 100644 --- a/src/QirTools/pyqir/pyqir/__init__.py +++ b/src/QirTools/pyqir/pyqir/__init__.py @@ -2,4 +2,4 @@ # Licensed under the MIT License. from .parser import * -from .builder import * \ No newline at end of file +from .builder import * diff --git a/src/QirTools/pyqir/pyqir/export.py b/src/QirTools/pyqir/pyqir/export.py new file mode 100644 index 0000000000..45e64ab111 --- /dev/null +++ b/src/QirTools/pyqir/pyqir/export.py @@ -0,0 +1,230 @@ +# Copyright(c) Microsoft Corporation. +# Licensed under the MIT License. + +# TODO: Support additional simple gates +# TODO: Support gates w/ classical arguments +# TODO: Handle nonstandard extensions to OpenQASM better. + +from types import MappingProxyType +from abc import ABCMeta, abstractmethod +from typing import Any, Callable, Dict, List, Optional, Set, Union, Generic, TypeVar +from .pyqir import * + +try: + import qiskit as qk +except ImportError: + qk = None + +try: + import qutip as qt + import qutip.qip.circuit + import qutip.qip.operations +except ImportError: + qt = None + +TOutput = TypeVar('TOutput') + +# TODO: Better names for these utility functions. +def _resolve_id(value: Any, default: str = "unsupported") -> Union[int, str]: + if hasattr(value, "id"): + return value.id + return default + +def _resolve(value, in_): + id = _resolve_id(value) + if id not in in_: + in_[id] = len(in_) + return in_[id] + +class CircuitLikeExporter(Generic[TOutput], metaclass=ABCMeta): + @abstractmethod + def on_simple_gate(self, name, *qubits) -> None: + pass + + @abstractmethod + def on_measure(self, qubit, result) -> None: + pass + + @abstractmethod + def on_comment(self, text) -> None: + pass + + @abstractmethod + def export(self) -> TOutput: + pass + + @abstractmethod + def qubit_as_expr(self, qubit) -> str: + pass + + @abstractmethod + def result_as_expr(self, result) -> str: + pass + +class OpenQasm20Exporter(CircuitLikeExporter[str]): + header: List[str] + lines: List[str] + + qubits: Dict[Any, Optional[int]] + results: Dict[Any, Optional[int]] + + qreg = "q" + creg = "c" + + def __init__(self, block_name: str): + self.lines = [] + self.header = [ + f"// Generated from QIR block {block_name}.", + "OPENQASM 2.0;", + 'include "qelib1.inc";', + "" + ] + self.qubits = dict() + self.results = dict() + + def qubit_as_expr(self, qubit) -> str: + id_qubit = _resolve_id(qubit) + if id_qubit not in self.qubits: + self.qubits[id_qubit] = len(self.qubits) + return f"{self.qreg}[{self.qubits[id_qubit]}]" + + def result_as_expr(self, result) -> str: + id_result = _resolve_id(result) + if id_result not in self.results: + self.results[id_result] = len(self.results) + return f"{self.creg}[{self.results[id_result]}]" + + def export(self) -> str: + declarations = [] + if self.qubits: + declarations.append( + f"qreg {self.qreg}[{len(self.qubits)}];" + ) + if self.results: + declarations.append( + f"creg {self.creg}[{len(self.results)}];" + ) + + return "\n".join( + self.header + declarations + self.lines + ) + + def on_comment(self, text) -> None: + # TODO: split text into lines first. + self.lines.append(f"// {text}") + + def on_simple_gate(self, name, *qubits) -> None: + qubit_args = [self.qubit_as_expr(qubit) for qubit in qubits] + self.lines.append(f"{name} {', '.join(map(str, qubit_args))};") + + def on_measure(self, qubit, result) -> None: + self.lines.append(f"measure {self.qubit_as_expr(qubit)} -> {self.result_as_expr(result)};") + +class QiskitExporter(CircuitLikeExporter["qk.QuantumCircuit"]): + def __init__(self, block_name: str): + self.oq2_exporter = OpenQasm20Exporter(block_name) + def qubit_as_expr(self, qubit) -> str: + return self.oq2_exporter.qubit_as_expr(qubit) + def result_as_expr(self, result) -> str: + return self.oq2_exporter.result_as_expr(result) + def on_comment(self, text) -> None: + return self.oq2_exporter.on_comment(text) + def on_measure(self, qubit, result) -> None: + return self.oq2_exporter.on_measure(qubit, result) + def on_simple_gate(self, name, *qubits) -> None: + return self.oq2_exporter.on_simple_gate(name, *qubits) + def export(self) -> "qk.QuantumCircuit": + return qk.QuantumCircuit.from_qasm_str(self.oq2_exporter.export()) + +class QuTiPExporter(CircuitLikeExporter["qt.qip.circuit.QubitCircuit"]): + actions: List[Callable[["qt.qip.circuit.QubitCircuit"], None]] + + qubits: Dict[Any, int] + results: Dict[Any, int] + + gate_names = MappingProxyType({ + 'x': 'X', + 'y': 'Y', + 'z': 'Z', + 'reset': 'reset' + }) + + def __init__(self): + self.actions = [] + self.qubits = {} + self.results = {} + + def export(self) -> TOutput: + circuit = qt.qip.circuit.QubitCircuit(N=len(self.qubits), num_cbits=len(self.results)) + for action in self.actions: + action(circuit) + return circuit + + def qubit_as_expr(self, qubit) -> str: + return repr(_resolve(qubit, self.qubits)) + + def result_as_expr(self, result) -> str: + return repr(_resolve(result, self.results)) + + def on_simple_gate(self, name, *qubits) -> None: + targets = [_resolve(qubit, self.qubits) for qubit in qubits] + self.actions.append(lambda circuit: + circuit.add_gate( + self.gate_names[name], + targets=targets + ) + ) + + def on_measure(self, qubit, result) -> None: + targets = [_resolve(qubit, self.qubits)] + classical_store = _resolve(result, self.results) + self.actions.append(lambda circuit: + circuit.add_measurement( + "MZ", + targets=targets, + classical_store=classical_store + ) + ) + + def on_comment(self, text) -> None: + print(f"# {text}") + +def export_to(block, exporter: CircuitLikeExporter[TOutput]) -> Optional[TOutput]: + if not block.is_circuit_like: + return None + + qis_gate_mappings = { + '__quantum__qis__x__body': 'x', + '__quantum__qis__y__body': 'y', + '__quantum__qis__z__body': 'z', + '__quantum__qis__h__body': 'h', + '__quantum__qis__cnot__body': 'cnot' + } + + for instruction in block.instructions: + # Translate simple gates (that is, only quantum args). + if instruction.func_name in qis_gate_mappings: + exporter.on_simple_gate(qis_gate_mappings[instruction.func_name], *instruction.func_args) + + # Reset requires nonstandard support. + elif instruction.func_name == "__quantum__qis__reset__body": + exporter.on_comment("Requires nonstandard reset gate:") + exporter.on_simple_gate("reset", *instruction.func_args) + + # Measurements are special in OpenQASM 2.0, so handle them here. + elif instruction.func_name == "__quantum__qis__mz__body": + target, result = instruction.func_args + exporter.on_measure(target, result) + # target = lookup_qubit(target) + # result = lookup_result(result) + # lines.append(f"measure {target} -> {result};") + + # Handle special cases of QIR functions as needed. + elif instruction.func_name == "__quantum__qir__read_result": + exporter.on_comment(f"%{instruction.output_name} = {exporter.result_as_expr(instruction.func_args[0])}") + + else: + exporter.on_comment("// Unsupported QIS operation:") + exporter.on_comment(f"// {instruction.func_name} {', '.join(map(str, instruction.func_args))}") + + return exporter.export() diff --git a/src/QirTools/pyqir/pyqir/parser.py b/src/QirTools/pyqir/pyqir/parser.py index 506246a79d..b50688489b 100644 --- a/src/QirTools/pyqir/pyqir/parser.py +++ b/src/QirTools/pyqir/pyqir/parser.py @@ -2,8 +2,30 @@ # Licensed under the MIT License. from .pyqir import * +from . import export from typing import List, Optional, Tuple +try: + import retworkx as rx +except ImportError: + rx = None + +try: + import retworkx.visualization as rxv +except ImportError: + rxv = None + +try: + import qiskit as qk +except ImportError: + qk = None + +try: + import qutip as qt + import qutip.qip.circuit + import qutip.qip.operations +except ImportError: + qt = None class QirType: """ @@ -208,7 +230,7 @@ def value(self) -> int: Gets the integer value for this constant. """ return self.const.int_value - + @property def width(self) -> int: """ @@ -284,7 +306,7 @@ class QirTerminator: Instances of QirTerminator represent the special final instruction at the end of a block that indicates how control flow should transfer. """ - + def __new__(cls, term: PyQirTerminator): if term.is_ret: return super().__new__(QirRetTerminator) @@ -360,7 +382,7 @@ class QirSwitchTerminator(QirTerminator): to one or more blocks based on matching values of a given operand, or jump to a fallback block in the case that no matches are found. """ - + @property def operand(self) -> QirLocalOperand: """ @@ -698,7 +720,7 @@ class QirQirCallInstr(QirCallInstr): class QirBlock: """ Instances of the QirBlock type represent a basic block within a function body. Each basic block is - comprised of a list of instructions executed in sequence and a single, special final instruction + comprised of a list of instructions executed in sequence and a single, special final instruction called a terminator that indicates where execution should jump at the end of the block. """ @@ -717,7 +739,7 @@ def name(self) -> str: def instructions(self) -> List[QirInstr]: """ Gets the list of instructions that make up this block. The list is ordered; instructions are - executed from first to last unconditionally. This list does not include the special + executed from first to last unconditionally. This list does not include the special terminator instruction (see QirBlock.terminator). """ return list(map(QirInstr, self.block.instructions)) @@ -743,11 +765,34 @@ def phi_nodes(self) -> List[QirPhiInstr]: def get_phi_pairs_by_source_name(self, name: str) -> List[Tuple[str, QirOperand]]: """ Gets the variable name, variable value pairs for any phi nodes in this block that correspond - to the given name. If the name doesn't match a block that can branch to this block or if + to the given name. If the name doesn't match a block that can branch to this block or if this block doesn't include any phi nodes, the list will be empty. """ return list(map(lambda p: (p[0], QirOperand(p[1])) ,self.block.get_phi_pairs_by_source_name(name))) + @property + def is_circuit_like(self) -> bool: + return all( + isinstance(instruction, (QirQisCallInstr, QirQirCallInstr)) + for instruction in self.instructions + ) + # TODO: Check all args are qubit constants. + + def as_openqasm_20(self) -> Optional[str]: + """ + If this block is circuit-like (that is, consists only of quantum instructions), + converts it to a representation in OpenQASM 2.0; otherwise, returns `None`. + + Note that the returned representation does not include leading phi nodes, nor trailing terminators. + """ + return export.export_to(self, export.OpenQasm20Exporter(self.name)) + + def as_qiskit_circuit(self) -> Optional["qk.QuantumCircuit"]: + return export.export_to(self, export.QiskitExporter(self.name)) + + def as_qutip_circuit(self) -> Optional["qt.qip.circuit.QubitCircuit"]: + return export.export_to(self, export.QuTiPExporter()) + class QirParameter: """ Instances of the QirParameter type describe a parameter in a function definition or declaration. They @@ -781,6 +826,9 @@ class QirFunction: def __init__(self, func: PyQirFunction): self.func = func + def __repr__(self) -> str: + return f"" + @property def name(self) -> str: """ @@ -856,6 +904,38 @@ def get_instruction_by_output_name(self, name: str) -> Optional[QirInstr]: return QirInstr(instr) return None + + def control_flow_graph(self) -> "rx.Digraph": + cfg = rx.PyDiGraph(check_cycle=False, multigraph=True) + blocks = self.blocks + block_indices = { + block.name: cfg.add_node(block) + for block in blocks + } + + idx_return = cfg.add_node("Return") + idx_bottom = None + + for idx_block, block in enumerate(blocks): + term = block.terminator + if isinstance(term, QirCondBrTerminator): + cfg.add_edge(idx_block, block_indices[term.true_dest], True) + cfg.add_edge(idx_block, block_indices[term.false_dest], False) + elif isinstance(term, QirBrTerminator): + cfg.add_edge(idx_block, block_indices[term.dest], ()) + elif isinstance(term, QirRetTerminator): + cfg.add_edge(idx_block, idx_return, ()) + elif isinstance(term, QirSwitchTerminator): + print(f"Not yet implemented: {term}") + elif isinstance(term, QirUnreachableTerminator): + if idx_bottom is None: + idx_bottom = cfg.add_node("⊥") + cfg.add_edge(idx_block, idx_bottom) + else: + print(f"Not yet implemented: {term}") + + return cfg + class QirModule: """ Instances of QirModule parse a QIR program from bitcode into an in-memory From 273564f1ba4ec2ca533241b0266571afa6be8e5a Mon Sep 17 00:00:00 2001 From: Chris Granade Date: Wed, 27 Oct 2021 16:10:32 -0700 Subject: [PATCH 26/26] Update __init__.py --- src/QirTools/pyqir/pyqir/__init__.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/QirTools/pyqir/pyqir/__init__.py b/src/QirTools/pyqir/pyqir/__init__.py index 7907f008db..fa576d1cc9 100644 --- a/src/QirTools/pyqir/pyqir/__init__.py +++ b/src/QirTools/pyqir/pyqir/__init__.py @@ -3,5 +3,3 @@ from .parser import * from .builder import * -======= -from .builder import *