QIR Generation with Q# Using Magic Commands#

In this example, QIR is generated from Q# code for teleportation to transfer the binary representation of “hello world!”, followed with ASCII decoding. Teleportation technique contains heterogeneous instructions at the compilation time. The interdependent conditionals following the measurement of the source and the auxiliary qubits in teleportation determine the next quantum gate operations on the target qubit.

Computations involving heterogeneous instructions at compile time can benefit from QIR enabled compilers. QIR is generated in LLVM, which is backed by decades of classical compilation research and development. Hybrid quantum algorithms were defined to rely on both classical and quantum resources to fulfill the abstract computational model of the algorithm. In the next series of tutorials, a hybrid classical-quantum algorithm such as VQE or HHL (?) will be used to demonstrate further capabilities of QIR.

// Building on https://github.com/microsoft/Quantum/blob/main/samples/getting-started/teleportation/TeleportationSample.qs
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
open Microsoft.Quantum.Intrinsic;
open Microsoft.Quantum.Canon;
open Microsoft.Quantum.Measurement;
open Microsoft.Quantum.Core;
open Microsoft.Quantum.Arrays;
    // Converts data type: int to bool 
    operation int2bool(bit: Int) : Bool {
            if (bit == 1){return true;}
            else {return false;}
        }
    // Converts data type: bool to int 
     operation bool2int(msg: Bool) : Int {
            if (msg == true){return 1;}
            else {return 0;}
        }
    // Pure quantum section of teleportation technique 
    operation Teleport (msg : Qubit, target : Qubit) : Unit {
        use register = Qubit();
    
        H(register);
        CNOT(register, target);
    
        CNOT(msg, register);
        H(msg);
    
    
        if (MResetZ(msg) == One) { Z(target); }
    
        if (IsResultOne(MResetZ(register))) { X(target); }
    }
    // Interdependent conditional section of teleportation technique 
    operation TeleportClassicalMessage (message : Bool) : Bool {
       
        use (msg, target) = (Qubit(), Qubit());
    
       
        if (message) {
            X(msg);
        }
    
     
        Teleport(msg, target);
    
        
        return MResetZ(target) == One;
    }
    
    • int2bool
    • bool2int
    • Teleport
    • TeleportClassicalMessage
    // Runs teleporation with 2 loops: classical and hetrogenous 
    operation Greetings() : Unit { 
        mutable binary=[1, 0, 1, 0, 0];
        let msg = ForEach(int2bool, binary);
        let transferred= ForEach(TeleportClassicalMessage, msg);
        for index in 0 .. Length(transferred)-1 {
            Message($"{transferred[index]}");
        }     
    }
    
    • Greetings
    %simulate Greetings
    
    True
    
    False
    
    True
    
    False
    
    False
    
    ()
    
    %qir Greetings
    
    ; ModuleID = '/tmp/tmpejydWC.bc'
    
    %Tuple = type opaque
    %Array = type opaque
    %Callable = type opaque
    %String = type opaque
    %Qubit = type opaque
    %Result = type opaque
    
    @SNIPPET__int2bool__FunctionTable = internal constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @SNIPPET__int2bool__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* null, void (%Tuple*, %Tuple*, %Tuple*)* null, void (%Tuple*, %Tuple*, %Tuple*)* null]
    @SNIPPET__TeleportClassicalMessage__FunctionTable = internal constant [4 x void (%Tuple*, %Tuple*, %Tuple*)*] [void (%Tuple*, %Tuple*, %Tuple*)* @SNIPPET__TeleportClassicalMessage__body__wrapper, void (%Tuple*, %Tuple*, %Tuple*)* null, void (%Tuple*, %Tuple*, %Tuple*)* null, void (%Tuple*, %Tuple*, %Tuple*)* null]
    @0 = internal constant [5 x i8] c"true\00"
    @1 = internal constant [6 x i8] c"false\00"
    @2 = internal constant [3 x i8] c"()\00"
    
    define internal void @ENTRYPOINT__Greetings__body() {
    entry:
      call void @SNIPPET__Greetings__body()
      ret void
    }
    
    define internal void @SNIPPET__Greetings__body() {
    entry:
      %binary = alloca %Array*, align 8
      %0 = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 5)
      %1 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %0, i64 0)
      %2 = bitcast i8* %1 to i64*
      %3 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %0, i64 1)
      %4 = bitcast i8* %3 to i64*
      %5 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %0, i64 2)
      %6 = bitcast i8* %5 to i64*
      %7 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %0, i64 3)
      %8 = bitcast i8* %7 to i64*
      %9 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %0, i64 4)
      %10 = bitcast i8* %9 to i64*
      store i64 1, i64* %2, align 4
      store i64 0, i64* %4, align 4
      store i64 1, i64* %6, align 4
      store i64 0, i64* %8, align 4
      store i64 0, i64* %10, align 4
      store %Array* %0, %Array** %binary, align 8
      call void @__quantum__rt__array_update_alias_count(%Array* %0, i32 1)
      %11 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @SNIPPET__int2bool__FunctionTable, [2 x void (%Tuple*, i32)*]* null, %Tuple* null)
      %msg = call %Array* @Microsoft__Quantum__Arrays___35562116677345e0944256b6d342d497_ForEach__body(%Callable* %11, %Array* %0)
      call void @__quantum__rt__array_update_alias_count(%Array* %msg, i32 1)
      %12 = call %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]* @SNIPPET__TeleportClassicalMessage__FunctionTable, [2 x void (%Tuple*, i32)*]* null, %Tuple* null)
      %transferred = call %Array* @Microsoft__Quantum__Arrays___64c6375bfc954430924edecdbdf36db0_ForEach__body(%Callable* %12, %Array* %msg)
      call void @__quantum__rt__array_update_alias_count(%Array* %transferred, i32 1)
      %13 = call i64 @__quantum__rt__array_get_size_1d(%Array* %transferred)
      %14 = sub i64 %13, 1
      br label %header__1
    
    header__1:                                        ; preds = %exiting__1, %entry
      %index = phi i64 [ 0, %entry ], [ %22, %exiting__1 ]
      %15 = icmp sle i64 %index, %14
      br i1 %15, label %body__1, label %exit__1
    
    body__1:                                          ; preds = %header__1
      %16 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %transferred, i64 %index)
      %17 = bitcast i8* %16 to i1*
      %18 = load i1, i1* %17, align 1
      br i1 %18, label %condTrue__1, label %condFalse__1
    
    condTrue__1:                                      ; preds = %body__1
      %19 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @0, i32 0, i32 0))
      br label %condContinue__1
    
    condFalse__1:                                     ; preds = %body__1
      %20 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @1, i32 0, i32 0))
      br label %condContinue__1
    
    condContinue__1:                                  ; preds = %condFalse__1, %condTrue__1
      %21 = phi %String* [ %19, %condTrue__1 ], [ %20, %condFalse__1 ]
      call void @__quantum__rt__message(%String* %21)
      call void @__quantum__rt__string_update_reference_count(%String* %21, i32 -1)
      br label %exiting__1
    
    exiting__1:                                       ; preds = %condContinue__1
      %22 = add i64 %index, 1
      br label %header__1
    
    exit__1:                                          ; preds = %header__1
      call void @__quantum__rt__array_update_alias_count(%Array* %0, i32 -1)
      call void @__quantum__rt__array_update_alias_count(%Array* %msg, i32 -1)
      call void @__quantum__rt__array_update_alias_count(%Array* %transferred, i32 -1)
      call void @__quantum__rt__capture_update_reference_count(%Callable* %11, i32 -1)
      call void @__quantum__rt__callable_update_reference_count(%Callable* %11, i32 -1)
      call void @__quantum__rt__array_update_reference_count(%Array* %msg, i32 -1)
      call void @__quantum__rt__capture_update_reference_count(%Callable* %12, i32 -1)
      call void @__quantum__rt__callable_update_reference_count(%Callable* %12, i32 -1)
      call void @__quantum__rt__array_update_reference_count(%Array* %transferred, i32 -1)
      call void @__quantum__rt__array_update_reference_count(%Array* %0, i32 -1)
      ret void
    }
    
    define internal void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* %control, %Qubit* %target) {
    entry:
      %__controlQubits__ = call %Array* @__quantum__rt__array_create_1d(i32 8, i64 1)
      %0 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %__controlQubits__, i64 0)
      %1 = bitcast i8* %0 to %Qubit**
      store %Qubit* %control, %Qubit** %1, align 8
      call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 1)
      call void @__quantum__qis__x__ctl(%Array* %__controlQubits__, %Qubit* %target)
      call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 -1)
      call void @__quantum__rt__array_update_reference_count(%Array* %__controlQubits__, i32 -1)
      ret void
    }
    
    declare %Array* @__quantum__rt__array_create_1d(i32, i64)
    
    declare i8* @__quantum__rt__array_get_element_ptr_1d(%Array*, i64)
    
    declare void @__quantum__rt__array_update_alias_count(%Array*, i32)
    
    declare void @__quantum__qis__x__ctl(%Array*, %Qubit*)
    
    declare void @__quantum__rt__array_update_reference_count(%Array*, i32)
    
    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__CNOT__ctl(%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 %Array* @__quantum__rt__array_create_1d(i32 8, i64 1)
      %4 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %3, i64 0)
      %5 = bitcast i8* %4 to %Qubit**
      store %Qubit* %control, %Qubit** %5, align 8
      %__controlQubits__1 = call %Array* @__quantum__rt__array_concatenate(%Array* %__controlQubits__, %Array* %3)
      call void @__quantum__rt__array_update_reference_count(%Array* %__controlQubits__1, i32 1)
      call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__1, i32 1)
      call void @__quantum__qis__x__ctl(%Array* %__controlQubits__1, %Qubit* %target)
      call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__1, i32 -1)
      call void @__quantum__rt__array_update_reference_count(%Array* %3, i32 -1)
      call void @__quantum__rt__array_update_reference_count(%Array* %__controlQubits__1, i32 -1)
      call void @__quantum__rt__array_update_reference_count(%Array* %__controlQubits__1, i32 -1)
      call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 -1)
      ret void
    }
    
    declare %Array* @__quantum__rt__array_concatenate(%Array*, %Array*)
    
    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 ptrtoint ({ %Qubit*, %Qubit* }* getelementptr ({ %Qubit*, %Qubit* }, { %Qubit*, %Qubit* }* null, i32 1) to i64))
      %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
    }
    
    declare %Tuple* @__quantum__rt__tuple_create(i64)
    
    declare void @__quantum__rt__tuple_update_reference_count(%Tuple*, i32)
    
    define internal void @Microsoft__Quantum__Intrinsic__H__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__H__adj(%Qubit* %qubit) {
    entry:
      call void @__quantum__qis__h__body(%Qubit* %qubit)
      ret void
    }
    
    define internal void @Microsoft__Quantum__Intrinsic__H__ctl(%Array* %__controlQubits__, %Qubit* %qubit) {
    entry:
      call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 1)
      call void @__quantum__qis__h__ctl(%Array* %__controlQubits__, %Qubit* %qubit)
      call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 -1)
      ret void
    }
    
    declare void @__quantum__qis__h__ctl(%Array*, %Qubit*)
    
    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 @__quantum__qis__h__ctl(%Array* %__controlQubits__, %Qubit* %qubit)
      call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 -1)
      ret void
    }
    
    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*
      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)
      %2 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %qubits, i64 0)
      %3 = bitcast i8* %2 to %Qubit**
      store %Qubit* %qubit, %Qubit** %3, align 8
      call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i32 1)
      %4 = 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* %4
    }
    
    declare %Result* @__quantum__qis__measure__body(%Array*, %Array*)
    
    define internal %Result* @Microsoft__Quantum__Intrinsic__Measure__body(%Array* %bases, %Array* %qubits) {
    entry:
      call void @__quantum__rt__array_update_alias_count(%Array* %bases, i32 1)
      call void @__quantum__rt__array_update_alias_count(%Array* %qubits, i32 1)
      %0 = 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)
      ret %Result* %0
    }
    
    define internal void @Microsoft__Quantum__Intrinsic__X__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__X__adj(%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__X__ctladj(%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__Z__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__Z__adj(%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
    }
    
    declare void @__quantum__qis__z__ctl(%Array*, %Qubit*)
    
    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 @__quantum__qis__z__ctl(%Array* %__controlQubits__, %Qubit* %qubit)
      call void @__quantum__rt__array_update_alias_count(%Array* %__controlQubits__, i32 -1)
      ret void
    }
    
    define internal %Result* @Microsoft__Quantum__Measurement__MResetZ__body(%Qubit* %target) {
    entry:
      %result = call %Result* @Microsoft__Quantum__Intrinsic__M__body(%Qubit* %target)
      %0 = call %Result* @__quantum__rt__result_get_one()
      %1 = call i1 @__quantum__rt__result_equal(%Result* %result, %Result* %0)
      br i1 %1, label %then0__1, label %continue__1
    
    then0__1:                                         ; preds = %entry
      call void @__quantum__qis__x__body(%Qubit* %target)
      br label %continue__1
    
    continue__1:                                      ; preds = %then0__1, %entry
      ret %Result* %result
    }
    
    declare %Result* @__quantum__rt__result_get_one()
    
    declare i1 @__quantum__rt__result_equal(%Result*, %Result*)
    
    define internal %Array* @Microsoft__Quantum__Arrays___35562116677345e0944256b6d342d497_ForEach__body(%Callable* %action, %Array* %array) {
    entry:
      %retval = alloca %Array*, align 8
      call void @__quantum__rt__capture_update_alias_count(%Callable* %action, i32 1)
      call void @__quantum__rt__callable_update_alias_count(%Callable* %action, i32 1)
      call void @__quantum__rt__array_update_alias_count(%Array* %array, i32 1)
      %length = call i64 @__quantum__rt__array_get_size_1d(%Array* %array)
      %0 = icmp eq i64 %length, 0
      br i1 %0, label %then0__1, label %continue__1
    
    then0__1:                                         ; preds = %entry
      %1 = call %Array* @__quantum__rt__array_create_1d(i32 1, i64 0)
      call void @__quantum__rt__capture_update_alias_count(%Callable* %action, i32 -1)
      call void @__quantum__rt__callable_update_alias_count(%Callable* %action, i32 -1)
      call void @__quantum__rt__array_update_alias_count(%Array* %array, i32 -1)
      ret %Array* %1
    
    continue__1:                                      ; preds = %entry
      %2 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %array, i64 0)
      %3 = bitcast i8* %2 to i64*
      %4 = load i64, i64* %3, align 4
      %5 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint ({ i64 }* getelementptr ({ i64 }, { i64 }* null, i32 1) to i64))
      %6 = bitcast %Tuple* %5 to { i64 }*
      %7 = getelementptr inbounds { i64 }, { i64 }* %6, i32 0, i32 0
      store i64 %4, i64* %7, align 4
      %8 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint ({ i1 }* getelementptr ({ i1 }, { i1 }* null, i32 1) to i64))
      call void @__quantum__rt__callable_invoke(%Callable* %action, %Tuple* %5, %Tuple* %8)
      %9 = bitcast %Tuple* %8 to { i1 }*
      %10 = getelementptr inbounds { i1 }, { i1 }* %9, i32 0, i32 0
      %first = load i1, i1* %10, align 1
      %11 = call %Array* @__quantum__rt__array_create_1d(i32 1, i64 %length)
      %12 = sub i64 %length, 1
      br label %header__1
    
    header__1:                                        ; preds = %exiting__1, %continue__1
      %13 = phi i64 [ 0, %continue__1 ], [ %17, %exiting__1 ]
      %14 = icmp sle i64 %13, %12
      br i1 %14, label %body__1, label %exit__1
    
    body__1:                                          ; preds = %header__1
      %15 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %11, i64 %13)
      %16 = bitcast i8* %15 to i1*
      store i1 %first, i1* %16, align 1
      br label %exiting__1
    
    exiting__1:                                       ; preds = %body__1
      %17 = add i64 %13, 1
      br label %header__1
    
    exit__1:                                          ; preds = %header__1
      store %Array* %11, %Array** %retval, align 8
      call void @__quantum__rt__array_update_alias_count(%Array* %11, i32 1)
      %18 = sub i64 %length, 1
      br label %header__2
    
    header__2:                                        ; preds = %exiting__2, %exit__1
      %idx = phi i64 [ 1, %exit__1 ], [ %34, %exiting__2 ]
      %19 = icmp sle i64 %idx, %18
      br i1 %19, label %body__2, label %exit__2
    
    body__2:                                          ; preds = %header__2
      %20 = load %Array*, %Array** %retval, align 8
      call void @__quantum__rt__array_update_alias_count(%Array* %20, i32 -1)
      %21 = call %Array* @__quantum__rt__array_copy(%Array* %20, i1 false)
      %22 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %array, i64 %idx)
      %23 = bitcast i8* %22 to i64*
      %24 = load i64, i64* %23, align 4
      %25 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint ({ i64 }* getelementptr ({ i64 }, { i64 }* null, i32 1) to i64))
      %26 = bitcast %Tuple* %25 to { i64 }*
      %27 = getelementptr inbounds { i64 }, { i64 }* %26, i32 0, i32 0
      store i64 %24, i64* %27, align 4
      %28 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint ({ i1 }* getelementptr ({ i1 }, { i1 }* null, i32 1) to i64))
      call void @__quantum__rt__callable_invoke(%Callable* %action, %Tuple* %25, %Tuple* %28)
      %29 = bitcast %Tuple* %28 to { i1 }*
      %30 = getelementptr inbounds { i1 }, { i1 }* %29, i32 0, i32 0
      %31 = load i1, i1* %30, align 1
      %32 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %21, i64 %idx)
      %33 = bitcast i8* %32 to i1*
      store i1 %31, i1* %33, align 1
      call void @__quantum__rt__array_update_alias_count(%Array* %21, i32 1)
      store %Array* %21, %Array** %retval, align 8
      call void @__quantum__rt__array_update_reference_count(%Array* %20, i32 -1)
      call void @__quantum__rt__tuple_update_reference_count(%Tuple* %25, i32 -1)
      call void @__quantum__rt__tuple_update_reference_count(%Tuple* %28, i32 -1)
      br label %exiting__2
    
    exiting__2:                                       ; preds = %body__2
      %34 = add i64 %idx, 1
      br label %header__2
    
    exit__2:                                          ; preds = %header__2
      %35 = load %Array*, %Array** %retval, align 8
      call void @__quantum__rt__capture_update_alias_count(%Callable* %action, i32 -1)
      call void @__quantum__rt__callable_update_alias_count(%Callable* %action, i32 -1)
      call void @__quantum__rt__array_update_alias_count(%Array* %array, i32 -1)
      call void @__quantum__rt__array_update_alias_count(%Array* %35, i32 -1)
      call void @__quantum__rt__tuple_update_reference_count(%Tuple* %5, i32 -1)
      call void @__quantum__rt__tuple_update_reference_count(%Tuple* %8, i32 -1)
      ret %Array* %35
    }
    
    declare void @__quantum__rt__capture_update_alias_count(%Callable*, i32)
    
    declare void @__quantum__rt__callable_update_alias_count(%Callable*, i32)
    
    declare i64 @__quantum__rt__array_get_size_1d(%Array*)
    
    declare void @__quantum__rt__callable_invoke(%Callable*, %Tuple*, %Tuple*)
    
    declare %Array* @__quantum__rt__array_copy(%Array*, i1)
    
    define internal %Array* @Microsoft__Quantum__Arrays___64c6375bfc954430924edecdbdf36db0_ForEach__body(%Callable* %action, %Array* %array) {
    entry:
      %retval = alloca %Array*, align 8
      call void @__quantum__rt__capture_update_alias_count(%Callable* %action, i32 1)
      call void @__quantum__rt__callable_update_alias_count(%Callable* %action, i32 1)
      call void @__quantum__rt__array_update_alias_count(%Array* %array, i32 1)
      %length = call i64 @__quantum__rt__array_get_size_1d(%Array* %array)
      %0 = icmp eq i64 %length, 0
      br i1 %0, label %then0__1, label %continue__1
    
    then0__1:                                         ; preds = %entry
      %1 = call %Array* @__quantum__rt__array_create_1d(i32 1, i64 0)
      call void @__quantum__rt__capture_update_alias_count(%Callable* %action, i32 -1)
      call void @__quantum__rt__callable_update_alias_count(%Callable* %action, i32 -1)
      call void @__quantum__rt__array_update_alias_count(%Array* %array, i32 -1)
      ret %Array* %1
    
    continue__1:                                      ; preds = %entry
      %2 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %array, i64 0)
      %3 = bitcast i8* %2 to i1*
      %4 = load i1, i1* %3, align 1
      %5 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint ({ i1 }* getelementptr ({ i1 }, { i1 }* null, i32 1) to i64))
      %6 = bitcast %Tuple* %5 to { i1 }*
      %7 = getelementptr inbounds { i1 }, { i1 }* %6, i32 0, i32 0
      store i1 %4, i1* %7, align 1
      %8 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint ({ i1 }* getelementptr ({ i1 }, { i1 }* null, i32 1) to i64))
      call void @__quantum__rt__callable_invoke(%Callable* %action, %Tuple* %5, %Tuple* %8)
      %9 = bitcast %Tuple* %8 to { i1 }*
      %10 = getelementptr inbounds { i1 }, { i1 }* %9, i32 0, i32 0
      %first = load i1, i1* %10, align 1
      %11 = call %Array* @__quantum__rt__array_create_1d(i32 1, i64 %length)
      %12 = sub i64 %length, 1
      br label %header__1
    
    header__1:                                        ; preds = %exiting__1, %continue__1
      %13 = phi i64 [ 0, %continue__1 ], [ %17, %exiting__1 ]
      %14 = icmp sle i64 %13, %12
      br i1 %14, label %body__1, label %exit__1
    
    body__1:                                          ; preds = %header__1
      %15 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %11, i64 %13)
      %16 = bitcast i8* %15 to i1*
      store i1 %first, i1* %16, align 1
      br label %exiting__1
    
    exiting__1:                                       ; preds = %body__1
      %17 = add i64 %13, 1
      br label %header__1
    
    exit__1:                                          ; preds = %header__1
      store %Array* %11, %Array** %retval, align 8
      call void @__quantum__rt__array_update_alias_count(%Array* %11, i32 1)
      %18 = sub i64 %length, 1
      br label %header__2
    
    header__2:                                        ; preds = %exiting__2, %exit__1
      %idx = phi i64 [ 1, %exit__1 ], [ %34, %exiting__2 ]
      %19 = icmp sle i64 %idx, %18
      br i1 %19, label %body__2, label %exit__2
    
    body__2:                                          ; preds = %header__2
      %20 = load %Array*, %Array** %retval, align 8
      call void @__quantum__rt__array_update_alias_count(%Array* %20, i32 -1)
      %21 = call %Array* @__quantum__rt__array_copy(%Array* %20, i1 false)
      %22 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %array, i64 %idx)
      %23 = bitcast i8* %22 to i1*
      %24 = load i1, i1* %23, align 1
      %25 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint ({ i1 }* getelementptr ({ i1 }, { i1 }* null, i32 1) to i64))
      %26 = bitcast %Tuple* %25 to { i1 }*
      %27 = getelementptr inbounds { i1 }, { i1 }* %26, i32 0, i32 0
      store i1 %24, i1* %27, align 1
      %28 = call %Tuple* @__quantum__rt__tuple_create(i64 ptrtoint ({ i1 }* getelementptr ({ i1 }, { i1 }* null, i32 1) to i64))
      call void @__quantum__rt__callable_invoke(%Callable* %action, %Tuple* %25, %Tuple* %28)
      %29 = bitcast %Tuple* %28 to { i1 }*
      %30 = getelementptr inbounds { i1 }, { i1 }* %29, i32 0, i32 0
      %31 = load i1, i1* %30, align 1
      %32 = call i8* @__quantum__rt__array_get_element_ptr_1d(%Array* %21, i64 %idx)
      %33 = bitcast i8* %32 to i1*
      store i1 %31, i1* %33, align 1
      call void @__quantum__rt__array_update_alias_count(%Array* %21, i32 1)
      store %Array* %21, %Array** %retval, align 8
      call void @__quantum__rt__array_update_reference_count(%Array* %20, i32 -1)
      call void @__quantum__rt__tuple_update_reference_count(%Tuple* %25, i32 -1)
      call void @__quantum__rt__tuple_update_reference_count(%Tuple* %28, i32 -1)
      br label %exiting__2
    
    exiting__2:                                       ; preds = %body__2
      %34 = add i64 %idx, 1
      br label %header__2
    
    exit__2:                                          ; preds = %header__2
      %35 = load %Array*, %Array** %retval, align 8
      call void @__quantum__rt__capture_update_alias_count(%Callable* %action, i32 -1)
      call void @__quantum__rt__callable_update_alias_count(%Callable* %action, i32 -1)
      call void @__quantum__rt__array_update_alias_count(%Array* %array, i32 -1)
      call void @__quantum__rt__array_update_alias_count(%Array* %35, i32 -1)
      call void @__quantum__rt__tuple_update_reference_count(%Tuple* %5, i32 -1)
      call void @__quantum__rt__tuple_update_reference_count(%Tuple* %8, i32 -1)
      ret %Array* %35
    }
    
    define internal i1 @Microsoft__Quantum__Canon__IsResultOne__body(%Result* %input) {
    entry:
      %0 = call %Result* @__quantum__rt__result_get_one()
      %1 = call i1 @__quantum__rt__result_equal(%Result* %input, %Result* %0)
      ret i1 %1
    }
    
    define internal void @SNIPPET__int2bool__body__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) {
    entry:
      %0 = bitcast %Tuple* %arg-tuple to { i64 }*
      %1 = getelementptr inbounds { i64 }, { i64 }* %0, i32 0, i32 0
      %2 = load i64, i64* %1, align 4
      %3 = call i1 @SNIPPET__int2bool__body(i64 %2)
      %4 = bitcast %Tuple* %result-tuple to { i1 }*
      %5 = getelementptr inbounds { i1 }, { i1 }* %4, i32 0, i32 0
      store i1 %3, i1* %5, align 1
      ret void
    }
    
    declare %Callable* @__quantum__rt__callable_create([4 x void (%Tuple*, %Tuple*, %Tuple*)*]*, [2 x void (%Tuple*, i32)*]*, %Tuple*)
    
    define internal void @SNIPPET__TeleportClassicalMessage__body__wrapper(%Tuple* %capture-tuple, %Tuple* %arg-tuple, %Tuple* %result-tuple) {
    entry:
      %0 = bitcast %Tuple* %arg-tuple to { i1 }*
      %1 = getelementptr inbounds { i1 }, { i1 }* %0, i32 0, i32 0
      %2 = load i1, i1* %1, align 1
      %3 = call i1 @SNIPPET__TeleportClassicalMessage__body(i1 %2)
      %4 = bitcast %Tuple* %result-tuple to { i1 }*
      %5 = getelementptr inbounds { i1 }, { i1 }* %4, i32 0, i32 0
      store i1 %3, i1* %5, align 1
      ret void
    }
    
    declare %String* @__quantum__rt__string_create(i8*)
    
    declare void @__quantum__rt__string_update_reference_count(%String*, i32)
    
    declare void @__quantum__rt__message(%String*)
    
    declare void @__quantum__rt__capture_update_reference_count(%Callable*, i32)
    
    declare void @__quantum__rt__callable_update_reference_count(%Callable*, i32)
    
    define internal i1 @SNIPPET__int2bool__body(i64 %bit) {
    entry:
      %0 = icmp eq i64 %bit, 1
      br i1 %0, label %then0__1, label %else__1
    
    then0__1:                                         ; preds = %entry
      ret i1 true
    
    else__1:                                          ; preds = %entry
      ret i1 false
    
    continue__1:                                      ; No predecessors!
      unreachable
    }
    
    define internal i1 @SNIPPET__TeleportClassicalMessage__body(i1 %message) {
    entry:
      %msg = call %Qubit* @__quantum__rt__qubit_allocate()
      %target = call %Qubit* @__quantum__rt__qubit_allocate()
      br i1 %message, label %then0__1, label %continue__1
    
    then0__1:                                         ; preds = %entry
      call void @__quantum__qis__x__body(%Qubit* %msg)
      br label %continue__1
    
    continue__1:                                      ; preds = %then0__1, %entry
      call void @SNIPPET__Teleport__body(%Qubit* %msg, %Qubit* %target)
      %0 = call %Result* @Microsoft__Quantum__Measurement__MResetZ__body(%Qubit* %target)
      %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)
      call void @__quantum__rt__qubit_release(%Qubit* %msg)
      call void @__quantum__rt__qubit_release(%Qubit* %target)
      ret i1 %2
    }
    
    define internal void @SNIPPET__Teleport__body(%Qubit* %msg, %Qubit* %target) {
    entry:
      %register = call %Qubit* @__quantum__rt__qubit_allocate()
      call void @__quantum__qis__h__body(%Qubit* %register)
      call void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* %register, %Qubit* %target)
      call void @Microsoft__Quantum__Intrinsic__CNOT__body(%Qubit* %msg, %Qubit* %register)
      call void @__quantum__qis__h__body(%Qubit* %msg)
      %0 = call %Result* @Microsoft__Quantum__Measurement__MResetZ__body(%Qubit* %msg)
      %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__z__body(%Qubit* %target)
      br label %continue__1
    
    continue__1:                                      ; preds = %then0__1, %entry
      %3 = call %Result* @Microsoft__Quantum__Measurement__MResetZ__body(%Qubit* %register)
      %4 = call i1 @Microsoft__Quantum__Canon__IsResultOne__body(%Result* %3)
      call void @__quantum__rt__result_update_reference_count(%Result* %3, i32 -1)
      br i1 %4, label %then0__2, label %continue__2
    
    then0__2:                                         ; preds = %continue__1
      call void @__quantum__qis__x__body(%Qubit* %target)
      br label %continue__2
    
    continue__2:                                      ; preds = %then0__2, %continue__1
      call void @__quantum__rt__qubit_release(%Qubit* %register)
      ret void
    }
    
    declare %Qubit* @__quantum__rt__qubit_allocate()
    
    declare %Array* @__quantum__rt__qubit_allocate_array(i64)
    
    declare void @__quantum__rt__qubit_release(%Qubit*)
    
    declare void @__quantum__rt__result_update_reference_count(%Result*, i32)
    
    define void @ENTRYPOINT__Greetings__Interop() #0 {
    entry:
      call void @ENTRYPOINT__Greetings__body()
      ret void
    }
    
    define void @ENTRYPOINT__Greetings() #1 {
    entry:
      call void @ENTRYPOINT__Greetings__body()
      %0 = call %String* @__quantum__rt__string_create(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @2, i32 0, i32 0))
      call void @__quantum__rt__message(%String* %0)
      call void @__quantum__rt__string_update_reference_count(%String* %0, i32 -1)
      ret void
    }
    
    attributes #0 = { "InteropFriendly" }
    attributes #1 = { "EntryPoint" }