> ## Documentation Index
> Fetch the complete documentation index at: https://docs.qbraid.com/llms.txt
> Use this file to discover all available pages before exploring further.

# QIR Profiles

QIR (Quantum Intermediate Representation) profiles in `qbraid-qir` define the rules, restrictions,
and capabilities that govern how OpenQASM 3 programs are converted to QIR. When converting a QASM
program to QIR using `qbraid-qir`, you must specify a profile—either **Base** or **Adaptive**—which
determines the allowed quantum operations, branching, measurement handling, and output recording.
This ensures that the generated QIR is compliant with the requirements of the target quantum backend
or workflow.

## Available Profiles

### Base Profile

* **Name:** `Base`
* **Capabilities:**
  * Conditional execution (`if` statements) is supported.
  * Only sequential output recording is supported.
* **Restrictions:**
  * No forward branching (no `goto` or loops).
  * Qubit reuse after measurement is **not** allowed.
  * Measurement tracking is **not** enabled.
  * No grouped output recording.
  * No qubit reuse after measurement.
  * Barriers must cover **all** qubits (no subset barriers).
  * Only a fixed set of gates is supported.

### Adaptive Profile

* **Name:** `AdaptiveExecution`
* **Capabilities:**
  * Conditional execution and forward branching are supported.
  * Qubit reuse after measurement is **allowed**.
  * Measurement tracking is enabled.
  * Grouped output recording is supported (register structure is preserved).
  * Barriers must cover **all** qubits.
  * Supports a broader set of gates and more flexible control flow.
* **Restrictions:**
  * Subset barriers are **not** allowed (barriers must cover all qubits).
  * Only constant parameters for parameterized gates.

## How to Use

When converting QASM to QIR, specify the profile using the `profile` argument:

<CodeGroup>
  ```python converting qasm to qir theme={null}
  from qbraid_qir.qasm3 import qasm3_to_qir

  qasm3_code = """
  OPENQASM 3;
  qubit[2] q;
  bit[2] c;
  h q[0];
  c[0] = measure q[0];
  if (c[0]) {
      x q[1];
  }
  c[1] = measure q[1];
  """

  # Convert using the Base profile
  qir_base = qasm3_to_qir(qasm3_code, profile="base")
  print(qir_base)

  # Convert using the Adaptive profile
  qir_adaptive = qasm3_to_qir(qasm3_code, profile="adaptive")
  print(qir_adaptive)
  ```

  ```llvm base profile output theme={null}
  ; ModuleID = 'program-b27e5a7a-4b58-11f0-824a-cae339f58535'
  source_filename = "program-b27e5a7a-4b58-11f0-824a-cae339f58535"

  %Qubit = type opaque
  %Result = type opaque

  define void @program-b27e5a7a-4b58-11f0-824a-cae339f58535() #0 {
  entry:
    call void @__quantum__rt__initialize(i8* null)
    call void @__quantum__qis__h__body(%Qubit* null)
    call void @__quantum__qis__mz__body(%Qubit* null, %Result* null)
    %0 = call i1 @__quantum__qis__read_result__body(%Result* null)
    br i1 %0, label %then, label %else

  then:                                             ; preds = %entry
    call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 1 to %Qubit*))
    br label %continue

  else:                                             ; preds = %entry
    br label %continue

  continue:                                         ; preds = %else, %then
    call void @__quantum__qis__mz__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 1 to %Result*))
    call void @__quantum__rt__result_record_output(%Result* null, i8* null)
    call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 1 to %Result*), i8* null)
    ret void
  }

  declare void @__quantum__rt__initialize(i8*)

  declare void @__quantum__qis__h__body(%Qubit*)

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

  declare i1 @__quantum__qis__read_result__body(%Result*)

  declare void @__quantum__qis__x__body(%Qubit*)

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

  attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="base" "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}
  ```

  ```llvm adaptive profile output theme={null}
  ; ModuleID = 'program-b27f2086-4b58-11f0-824a-cae339f58535'
  source_filename = "program-b27f2086-4b58-11f0-824a-cae339f58535"

  %Qubit = type opaque
  %Result = type opaque

  define void @program-b27f2086-4b58-11f0-824a-cae339f58535() #0 {
  entry:
    call void @__quantum__rt__initialize(i8* null)
    call void @__quantum__qis__h__body(%Qubit* null)
    call void @__quantum__qis__mz__body(%Qubit* null, %Result* null)
    %0 = call i1 @__quantum__qis__read_result__body(%Result* null)
    br i1 %0, label %then, label %else

  then:                                             ; preds = %entry
    call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 1 to %Qubit*))
    br label %continue

  else:                                             ; preds = %entry
    br label %continue

  continue:                                         ; preds = %else, %then
    call void @__quantum__qis__mz__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 1 to %Result*))
    call void @__quantum__rt__array_record_output(i64 2, i8* null)
    call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 1 to %Result*), i8* null)
    call void @__quantum__rt__result_record_output(%Result* null, i8* null)
    ret void
  }

  declare void @__quantum__rt__initialize(i8*)

  declare void @__quantum__qis__h__body(%Qubit*)

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

  declare i1 @__quantum__qis__read_result__body(%Result*)

  declare void @__quantum__qis__x__body(%Qubit*)

  declare void @__quantum__rt__array_record_output(i64, i8*)

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

  attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="adaptive" "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}
  ```
</CodeGroup>

The `qir_base` and `qir_adaptive` variables will contain the generated QIR code for the specified profile.

## Example QASM Programs

<Tabs>
  <Tab title="Base Profile">
    ```qasm theme={null}
    OPENQASM 3;
    qubit[2] q;
    bit[2] c;
    h q[0];
    c[0] = measure q[0];
    x q[1];      // Allowed
    reset q[0];  // Not allowed in Base profile (qubit reuse forbidden)
    ```

    The last line will cause an error in the Base profile because qubit reuse after measurement is not
    permitted
  </Tab>

  <Tab title="Adaptive Profile">
    ```qasm theme={null}
    OPENQASM 3;
    qubit[2] q;
    bit[2] c;
    h q[0];
    c[0] = measure q[0];
    reset q[0];  // Allowed in Adaptive profile
    x q[0];     // Allowed in Adaptive profile
    ```

    This program is valid in the Adaptive profile, which allows qubit reuse after measurement and reset.
  </Tab>

  <Tab title="Conditional Branching">
    ```qasm theme={null}
    OPENQASM 3;
    qubit[2] q;
    bit[2] c;
    h q[0];
    c[0] = measure q[0];
    if (c[0]) {
        x q[1];
    }
    ```

    Both profiles support conditional execution, but only the `Adaptive` profile supports more advanced
    branching and measurement-based control flow.
  </Tab>
</Tabs>

## Conclusion

When converting QASM to QIR with `qbraid-qir`, always choose the profile that **matches your target
backend's requirements** The `Base` profile is strict and suitable for simple, hardware-oriented
workflows, while the `Adaptive` profile enables more advanced quantum programming features such as
qubit reuse, grouped output, and flexible control flow.
