Skip to main content

Module control_flow

Module control_flow 

Source
Expand description

Expression-based classical control-flow IR.

This module defines the third layer of cqlib’s dynamic-circuit classical control model: structured control-flow operations that consume typed, side-effect-free classical expressions.

The model is intentionally split into three layers:

  1. Runtime classical values and storage are defined by crate::circuit::classical. Those types identify circuit-local classical storage and value types.
  2. Classical expressions are defined by ClassicalExpr. Expressions are strongly typed and have no side effects. They only read runtime classical variables, combine literals, cast explicitly, compare values, select between values, or extract/pack bits.
  3. Control-flow operations are defined in this module by ClassicalControlOp and the concrete operation structs. They consume ClassicalExpr values to decide which structured body executes.

This module is IR only. It does not allocate classical storage, execute a circuit, or lower control flow to backend instructions.

§Core Concepts

ClassicalExpr represents a runtime classical computation. It has a static crate::circuit::ClassicalType and can report the classical variables and immutable values it reads. The expression layer does not write storage, measure qubits, branch, or loop.

ControlBody owns the operations inside a structured control-flow region. A body is a sequence of ordinary circuit crate::circuit::Operation values that belongs to an operation such as IfOp, WhileOp, ForOp, or SwitchOp.

ClassicalControlOp is the sum type for structured classical control operations:

  • IfOp executes a then body, and optionally an else body, when a boolean condition is evaluated at runtime.
  • WhileOp repeats a body while a boolean condition remains true.
  • ForOp models an unsigned half-open runtime range loop, [start, stop), with an explicit unsigned loop variable and step.
  • SwitchOp selects one body by matching an unsigned expression against exact case values. Cases do not fall through.
  • ClassicalControlOp::Break exits the nearest enclosing loop or switch.
  • ClassicalControlOp::Continue advances the nearest enclosing loop.

Conditions for IfOp and WhileOp must have type Bool; measured Bit values must be explicitly cast with ClassicalExpr::bit_to_bool. Ordered comparisons are restricted to UInt expressions. Bit-vector to integer interpretation is explicit through ClassicalExpr::bit_vec_to_uint, preserving the rule that bit index 0 is the least-significant bit.

§Resource Queries

Control-flow IR nodes expose lightweight dependency queries:

  • classical_var_reads() returns classical variables read by controlling expressions.
  • classical_value_reads() returns immutable classical values read by controlling expressions.
  • classical_writes() currently reports direct writes introduced by the control operation itself, such as a ForOp loop variable.
  • used_qubits() reports qubits referenced directly by structured bodies.

These methods are structural summaries for validation, remapping, and future lowering passes. They are not a complete data-flow analysis for nested dynamic-circuit execution.

Classical handles are circuit-local. When circuits are composed, classical variables and values from the source circuit are copied into the destination circuit’s classical tables and every expression/control body reference is remapped to the new local ID.

§Examples

Build a boolean condition from a measured bit-like variable:

bit_var: ClassicalVar<Bit>

bit_expr  = ClassicalExpr::var(bit_var)
condition = ClassicalExpr::bit_to_bool(bit_expr)
if_op     = IfOp::new(condition, then_body, else_body)

Build an unsigned comparison for a loop or branch condition:

counter: ClassicalVar<UInt(8)>

lhs       = ClassicalExpr::var(counter)
rhs       = ClassicalExpr::uint_literal(8, 10)
condition = ClassicalExpr::lt(lhs, rhs)
while_op  = WhileOp::new(condition, body)

Build a switch over an unsigned runtime expression:

state: ClassicalVar<UInt(2)>

target = ClassicalExpr::var(state)
cases  = [
  SwitchCase::new(0, zero_body),
  SwitchCase::new(1, one_body),
  SwitchCase::new(2, two_body),
]
switch = SwitchOp::new(target, cases, default_body)

Build a runtime for loop:

i: ClassicalVar<UInt(8)>

start = ClassicalExpr::uint_literal(8, 0)
stop  = ClassicalExpr::uint_literal(8, 16)
step  = ClassicalExpr::uint_literal(8, 1)
for_op = ForOp::new(i, start, stop, step, body)

§Design Boundaries

This module deliberately does not define post-selection or runtime assertions as first-class control-flow operations. Post-selection belongs to execution/result filtering semantics, while assertions belong to diagnostics or verification. They can be added later as separate IR families once their backend behavior and failure model are specified.

Structs§

ControlBody
Structured control-flow body.
ForOp
Unsigned runtime range loop with half-open [start, stop) semantics.
IfOp
Conditional execution controlled by a boolean classical expression.
SwitchCase
Exact-value switch case.
SwitchOp
Exact-value switch over an unsigned classical expression.
WhileOp
Loop controlled by a boolean classical expression.

Enums§

ClassicalControlKind
Stable category of a classical control-flow operation.
ClassicalControlOp
Expression-based classical control-flow operation.