QIR Error When Running a Quantum Job on the IonQ Simulator

Dimitri Berthault 20 Reputation points
2024-04-10T11:36:56.5266667+00:00

Hi, i'm trying to submit QIR jobs to the ionq simulator just like in this tutorial: https://learn.microsoft.com/en-us/azure/quantum/quickstart-microsoft-provider-format?tabs=tabid-portal%2Ctabid-pyquil
and i encountered an issue.
This QIR routine runs fine :

%Qubit = type opaque
%Result = type opaque

define void @main() #0 {
entry:
  call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 0 to %Qubit*))
  br label %header0

header0:
  %0 = phi i64 [ 1, %entry ], [ %2, %loop0 ]
  %1 = icmp slt i64 %0, 9
  br i1 %1, label %loop0, label %continue0

loop0:
  call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 0 to %Qubit*))
  call void @__quantum__qis__cnot__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Qubit* inttoptr (i64 1 to %Qubit*))
  call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 1 to %Qubit*))
  %2 = add i64 %0, 1
  br label %header0

continue0:
  call void @__quantum__qis__rz__body(double 0.0, %Qubit* inttoptr (i64 0 to %Qubit*))
  call void @__quantum__qis__mz__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*)) #1
  call void @__quantum__qis__mz__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 1 to %Result*)) #1
  call void @__quantum__rt__array_record_output(i64 2, i8* null)
  call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null)
  call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 1 to %Result*), i8* null)
  ret void
}

declare void @__quantum__qis__h__body(%Qubit*)
declare void @__quantum__qis__cnot__body(%Qubit*, %Qubit*)
declare void @__quantum__qis__x__body(%Qubit*)
declare void @__quantum__qis__rz__body(double, %Qubit*)
declare void @__quantum__qis__mz__body(%Qubit*, %Result* writeonly) #1
declare void @__quantum__rt__result_record_output(%Result*, i8*)
declare void @__quantum__rt__array_record_output(i64, i8*)

attributes #0 = { "entry_point" "required_num_qubits"="2" "required_num_results"="2" "output_labeling_schema" "qir_profiles"="base_profile" "irreversible" }
attributes #1 = { "irreversible" }

!llvm.module.flags = !{!0, !1, !2, !3}

!0 = !{i32 1, !"qir_major_version", i32 1}
!1 = !{i32 7, !"qir_minor_version", i32 0}
!2 = !{i32 1, !"dynamic_qubit_management", i1 false}
!3 = !{i32 1, !"dynamic_result_management", i1 false}

But this one doesn't :

%Qubit = type opaque
%Result = type opaque

define void @main() #0 {
entry:
  call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 0 to %Qubit*))
  %0 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 0 to %Result*))
  br i1 %0, label %then0, label %continue0

then0:
  call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 0 to %Qubit*))
  call void @__quantum__qis__cnot__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Qubit* inttoptr (i64 1 to %Qubit*))
  call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 1 to %Qubit*))
  br label %continue0

continue0:
  call void @__quantum__qis__rz__body(double 0.0, %Qubit* inttoptr (i64 0 to %Qubit*))
  call void @__quantum__qis__mz__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*)) #1
  call void @__quantum__qis__mz__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 1 to %Result*)) #1
  call void @__quantum__rt__array_record_output(i64 2, i8* null)
  call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null)
  call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 1 to %Result*), i8* null)
  ret void
}

declare void @__quantum__qis__h__body(%Qubit*)
declare i1 @__quantum__qis__read_result__body(%Result*)
declare void @__quantum__qis__cnot__body(%Qubit*, %Qubit*)
declare void @__quantum__qis__x__body(%Qubit*)
declare void @__quantum__qis__rz__body(double, %Qubit*)
declare void @__quantum__qis__mz__body(%Qubit*, %Result* writeonly) #1
declare void @__quantum__rt__result_record_output(%Result*, i8*)
declare void @__quantum__rt__array_record_output(i64, i8*)

attributes #0 = { "entry_point" "required_num_qubits"="2" "required_num_results"="2" "output_labeling_schema" "qir_profiles"="base_profile" "irreversible" }
attributes #1 = { "irreversible" }

!llvm.module.flags = !{!0, !1, !2, !3}

!0 = !{i32 1, !"qir_major_version", i32 1}
!1 = !{i32 7, !"qir_minor_version", i32 0}
!2 = !{i32 1, !"dynamic_qubit_management", i1 false}
!3 = !{i32 1, !"dynamic_result_management", i1 false}

It fails with the error:

Cannot retrieve results as job execution failed(status: Failed.error: {'additional_properties': {}, 'code': 'QATTransformationFailed', 'message': "error - /controller/artifacts/preProcessedQir.bc:11,43 - Opcode 'br' is not allowed for this adaptor (generic).

(full error at the end)

I don't understand what is the problem with this QIR routine, it says its due to the br usage but I use br in the same way in the first one and it runs fine.
I also used the qir-runner from QIR Alliance on both routines with valid results.
Can someone help me understand what's going on?

full error message:

RuntimeError
error - /controller/artifacts/preProcessedQir.bc:17,22 - Opcode 'br' is not allowed for this adaptor (generic).
error - /controller/artifacts/preProcessedQir.bc:17,22 - Fatal error: QIR is not valid within the defined adaptor
IR did not validate to the adaptor constraints.
; # Components
; disable-spec......................................: false
; disable-qat.......................................: false
; disable-adaptor.replacement-linking...............: false
; disable-adaptor.llvm-optimization.................: false
; disable-adaptor.remove-non-entrypoint-functions...: false
; disable-adaptor.target-qis-mapping................: false
; disable-adaptor.target-profile-mapping............: false
; disable-adaptor.straightline-code-requirement.....: false
; disable-adaptor.static-resources..................: false
; disable-adaptor.grouping..........................: false
; disable-target.profile............................: false
; disable-target.qis................................: false
;
; # Specification
; spec-version......................................: 0.9
; entry-point-attr..................................: entry_point
; qir-profiles-attr.................................: qir_profiles
; output-labeling-schema-attr.......................: output_labeling_schema
; required-num-qubits-attr..........................: requiredQubits
; required-num-results-attr.........................: requiredResults
; max-index-qubits-attr.............................: maxQubitIndex
; max-index-results-attr............................: maxResultIndex
; replace-with-attr.................................: replaceWith
; irreversible-attr.................................: irreversible
; qir-runtime-prefix................................: __quantum__rt__
;
; # QAT base configuration
; load..............................................:
; apply.............................................: true
; validate..........................................: true
; adaptor...........................................: provider_ea35
; adaptor-pipeline..................................: replacement-linking,llvm-optimization,remove-non-entrypoint-functions,target-qis-mapping,static-resources,target-profile-mapping,straightline-code-requirement,grouping
; emit-human-readable-llvm..........................: false
; target-def........................................: /controller/target_ea35.yaml
; save-config.......................................:
; verify-module.....................................: true
; experimental......................................: false
; dump-config.......................................: true
; add-ir-debug......................................: false
; strip-existing-dbg................................: false
; output............................................: /controller/artifacts/QATOutput.bc
; save-logs.........................................:
; version...........................................: false
; help..............................................: false
;
; # Replacement linking
; replace-functions.................................:
; remove-call-attributes............................: false
;
; # LLVM optimizations
; unroll-loops......................................: true
; allow-partial.....................................: true
; allow-peeling.....................................: true
; allow-runtime.....................................: true
; allow-upper-bound.................................: true
; allow-profile-based-peeling.......................: true
; full-unroll-count.................................: 1024
; unroll-opt-level..................................: 3
; only-when-forced..................................: false
; forget-scev.......................................: false
; always-inline.....................................: true
; inlining-parameter................................: 2147483647
; eliminate-constants...............................: true
; eliminate-dead-code...............................: true
; eliminate-memory..................................: true
;
; # Remove Non-Entrypoint Functions
;
; # Target QIS mapping
; delete-dead-code..................................: false
; clone-functions...................................: false
; transform-execution-path-only.....................: false
; max-recursion.....................................: 1
; assume-no-except..................................: false
; reuse-qubits......................................: false
; reuse-results.....................................: false
; optimize-result-one...............................: true
; optimize-result-zero..............................: true
; optimize-result-comparison........................: true
; use-static-qubit-array-allocation.................: true
; use-static-qubit-allocation.......................: true
; use-static-result-allocation......................: true
; disable-reference-counting........................: true
; disable-alias-counting............................: true
; disable-string-support............................: true
; disable-initialize-support........................: true
; disable-record-output-support.....................: false
;
; # Target profile mapping
; lower-switch......................................: true
; should-eleminate-zext-i1..........................: true
; defer-measurements................................: true
;
; # Post transform validation
; disable-straightline-code-requirement.............: true
;
; # Static resource manipulation
; annotate-qubit-use................................: true
; annotate-result-use...............................: true
; annotate-max-qubit-index..........................: true
; annotate-max-result-index.........................: true
; reindex-qubits....................................: true
; replace-qubit-on-reset............................: true
; inline-after-id-change............................: true
;
; # Grouping quantum instructions
; group-qis.........................................: false
;
; # Target profile validation
; allow-internal-calls..............................: true
; allow-poison......................................: false
; allow-undef.......................................: false
; opcodes...........................................: inttoptr,;ret,;call,
; allowlist-opcodes.................................: true
; allowlist-external-calls..........................: true
; allowlist-pointer-types...........................: true
; allow-primitive-return............................: true
; allow-struct-return...............................: true
; allow-pointer-return..............................: true
; external-calls....................................: __quantum__rt__tuple_record_output:void (i64, i8*),__quantum__rt__result_record_output:void (%Result*, i8*),__quantum__rt__array_record_output:void (i64, i8*)
; allowed-pointer-types.............................: Qubit*,Result*,i8*
;
; # Target QIS validation
; allowed-qis.......................................: __quantum__qis__ry__body:void (double, %Qubit*),__quantum__qis__rx__body:void (double, %Qubit*),__quantum__qis__y__body:void (%Qubit*),__quantum__qis__h__body:void (%Qubit*),__quantum__qis__t__adj:void (%Qubit*),__quantum__qis__s__body:void (%Qubit*),__quantum__qis__z__body:void (%Qubit*),__quantum__qis__cnot__body:void (%Qubit*, %Qubit*),__quantum__qis__rz__body:void (double, %Qubit*),__quantum__qis__swap__body:void (%Qubit*, %Qubit*),__quantum__qis__cz__body:void (%Qubit*, %Qubit*),__quantum__qis__x__body:void (%Qubit*),__quantum__qis__mz__body:void (%Qubit*, %Result*),__quantum__qis__t__body:void (%Qubit*),__quantum__qis__read_result__body:i1 (%Result*),__quantum__qis__s__adj:void (%Qubit*)
; allow-any-qis.....................................: false
; irreversible-operations...........................: __quantum__qis__mz__body
; requires-qubits...................................: true
; requires-results..................................: true
;
"
Azure Quantum
Azure Quantum
An Azure service that provides quantum computing and optimization solutions.
60 questions
0 comments No comments
{count} votes

Accepted answer
  1. Prrudram-MSFT 22,391 Reputation points
    2024-04-15T09:01:44.04+00:00

    Hello @Dimitri Berthault

    Thank you for reaching out to the Microsoft Q&A platform.

    The reason why the job failed is because IonQ targets do not support control flow. Because of this, the br and phi instructions are disallowed for IonQ targets, and that’s why the second code is returning an error. The reason why the first program succeeds is because none of the branch instructions depend on measurement results and can be optimized away, which also makes the phi instruction no longer needed. QIR processing in the Azure Quantum service performs these optimizations before submitting the program to IonQ and the resulting QIR (which does not contain any br and phi instructions) is the following: ; ModuleID = 'translatedInputData.bc'

    source_filename = "qat-link"

     

    %Qubit = type opaque

    %Result = type opaque

     

    define void @main() #0 {

    entry:

      call void @__quantum__qis__h__body(%Qubit* null)

      call void @__quantum__qis__h__body(%Qubit* null)

      call void @__quantum__qis__cnot__body(%Qubit* null, %Qubit* nonnull inttoptr (i64 1 to %Qubit*))

      call void @__quantum__qis__x__body(%Qubit* nonnull inttoptr (i64 1 to %Qubit*))

      call void @__quantum__qis__h__body(%Qubit* null)

      call void @__quantum__qis__cnot__body(%Qubit* null, %Qubit* nonnull inttoptr (i64 1 to %Qubit*))

      call void @__quantum__qis__x__body(%Qubit* nonnull inttoptr (i64 1 to %Qubit*))

      call void @__quantum__qis__h__body(%Qubit* null)

      call void @__quantum__qis__cnot__body(%Qubit* null, %Qubit* nonnull inttoptr (i64 1 to %Qubit*))

      call void @__quantum__qis__x__body(%Qubit* nonnull inttoptr (i64 1 to %Qubit*))

      call void @__quantum__qis__h__body(%Qubit* null)

      call void @__quantum__qis__cnot__body(%Qubit* null, %Qubit* nonnull inttoptr (i64 1 to %Qubit*))

      call void @__quantum__qis__x__body(%Qubit* nonnull inttoptr (i64 1 to %Qubit*))

      call void @__quantum__qis__h__body(%Qubit* null)

      call void @__quantum__qis__cnot__body(%Qubit* null, %Qubit* nonnull inttoptr (i64 1 to %Qubit*))

      call void @__quantum__qis__x__body(%Qubit* nonnull inttoptr (i64 1 to %Qubit*))

      call void @__quantum__qis__h__body(%Qubit* null)

      call void @__quantum__qis__cnot__body(%Qubit* null, %Qubit* nonnull inttoptr (i64 1 to %Qubit*))

      call void @__quantum__qis__x__body(%Qubit* nonnull inttoptr (i64 1 to %Qubit*))

      call void @__quantum__qis__h__body(%Qubit* null)

      call void @__quantum__qis__cnot__body(%Qubit* null, %Qubit* nonnull inttoptr (i64 1 to %Qubit*))

      call void @__quantum__qis__x__body(%Qubit* nonnull inttoptr (i64 1 to %Qubit*))

      call void @__quantum__qis__h__body(%Qubit* null)

      call void @__quantum__qis__cnot__body(%Qubit* null, %Qubit* nonnull inttoptr (i64 1 to %Qubit*))

      call void @__quantum__qis__x__body(%Qubit* nonnull inttoptr (i64 1 to %Qubit*))

      call void @__quantum__qis__rz__body(double 0.000000e+00, %Qubit* null)

      call void @__quantum__qis__mz__body(%Qubit* null, %Result* null) #1

      call void @__quantum__qis__mz__body(%Qubit* nonnull inttoptr (i64 1 to %Qubit*), %Result* nonnull inttoptr (i64 1 to %Result*)) #1

      call void @__quantum__rt__array_record_output(i64 2, i8* null)

      call void @__quantum__rt__result_record_output(%Result* null, i8* null)

      call void @__quantum__rt__result_record_output(%Result* nonnull inttoptr (i64 1 to %Result*), i8* null)

      ret void

    }

     

    declare void @__quantum__qis__h__body(%Qubit*)

    declare void @__quantum__qis__cnot__body(%Qubit*, %Qubit*)

    declare void @__quantum__qis__x__body(%Qubit*)

    declare void @__quantum__qis__rz__body(double, %Qubit*)

    declare void @__quantum__qis__mz__body(%Qubit*, %Result* writeonly) #1

    declare void @__quantum__rt__array_record_output(i64, i8*)

    declare void @__quantum__rt__result_record_output(%Result*, i8*)

     

    attributes #0 = { "EntryPoint" "entry_point" "entrypoint_index"="0" "irreversible" "maxQubitIndex"="1" "maxResultIndex"="1" "num_required_qubits"="2" "num_required_results"="2" "output_labeling_schema" "qir_profiles"="base_profile" "requiredQubits"="2" "requiredResults"="2" "required_num_qubits"="2" "required_num_results"="2" }

    attributes #1 = { "irreversible" }

     

    !llvm.module.flags = !{!0, !1, !2, !3}

     

    !0 = !{i32 1, !"qir_major_version", i32 1}

    !1 = !{i32 7, !"qir_minor_version", i32 0}

    !2 = !{i32 1, !"dynamic_qubit_management", i1 false}

    !3 = !{i32 1, !"dynamic_result_management", i1 false} I hope this helps. Please let us know if you have any questions.

     If I have answered your query, please click "Accept as answer" as a token of appreciation

    1 person found this answer helpful.
    0 comments No comments

0 additional answers

Sort by: Most helpful