Repository: microsoft/qsharp
Pull request #1387 (2024-04-15 07:06:40)

Partial Evaluation Output Recording support
This adds logic to insert output recording calls for recognized types into RIR programs generated by partial evaluation.

github-actions[bot]: ## Benchmark for 4d59a6b
  <details>
    <summary>Click to view benchmark</summary>

| Test | Base         | PR               | % |
|------|--------------|------------------|---|
| Array append evaluation | 342.6±6.79µs | 337.1±6.31µs | -1.61% |
| Array literal evaluation | 190.6±2.72µs | **180.8±2.79µs** | **-5.14%** |
| Array update evaluation | 421.6±1.72µs | 421.1±6.98µs | -0.12% |
| Core + Standard library compilation | 17.0±0.52ms | 17.4±0.49ms | +2.35% |
| Deutsch-Jozsa evaluation | 5.1±0.04ms | 5.1±0.04ms | 0.00% |
| Large file parity evaluation | 33.8±1.08ms | 33.6±0.27ms | -0.59% |
| Large input file compilation | **11.5±0.12ms** | 11.7±0.54ms | **+1.74%** |
| Large input file compilation (interpreter) | **44.6±0.87ms** | 45.6±1.63ms | **+2.24%** |
| Large nested iteration | 33.7±0.29ms | **33.3±2.00ms** | **-1.19%** |
| Perform Runtime Capabilities Analysis (RCA) on Deutsch-Jozsa sample | 1488.6±37.23µs | 1485.5±43.50µs | -0.21% |
| Perform Runtime Capabilities Analysis (RCA) on large file sample | 7.8±0.37ms | **7.7±0.08ms** | **-1.28%** |
| Perform Runtime Capabilities Analysis (RCA) on teleport sample | 1400.5±31.69µs | 1404.0±135.53µs | +0.25% |
| Perform Runtime Capabilities Analysis (RCA) on the core and std libraries | 21.3±0.19ms | 21.3±0.37ms | 0.00% |
| Teleport evaluation | 81.4±3.97µs | 81.8±3.80µs | +0.49% |

  </details>
  
github-actions[bot]: ## Benchmark for 99b9752
  <details>
    <summary>Click to view benchmark</summary>

| Test | Base         | PR               | % |
|------|--------------|------------------|---|
| Array append evaluation | **331.1±1.57µs** | 345.6±4.10µs | **+4.38%** |
| Array literal evaluation | **170.3±0.89µs** | 201.9±16.58µs | **+18.56%** |
| Array update evaluation | **412.1±3.77µs** | 429.7±7.93µs | **+4.27%** |
| Core + Standard library compilation | 18.2±0.82ms | **16.9±0.26ms** | **-7.14%** |
| Deutsch-Jozsa evaluation | **5.1±0.04ms** | 5.2±0.04ms | **+1.96%** |
| Large file parity evaluation | 33.7±0.39ms | 33.7±0.32ms | 0.00% |
| Large input file compilation | 11.8±0.29ms | **11.3±0.40ms** | **-4.24%** |
| Large input file compilation (interpreter) | 45.9±1.50ms | 47.1±2.62ms | +2.61% |
| Large nested iteration | **32.9±1.38ms** | 33.7±0.54ms | **+2.43%** |
| Perform Runtime Capabilities Analysis (RCA) on Deutsch-Jozsa sample | 1499.9±33.09µs | 1495.7±52.95µs | -0.28% |
| Perform Runtime Capabilities Analysis (RCA) on large file sample | 7.9±0.12ms | 7.8±0.14ms | -1.27% |
| Perform Runtime Capabilities Analysis (RCA) on teleport sample | 1413.9±77.19µs | 1406.7±62.01µs | -0.51% |
| Perform Runtime Capabilities Analysis (RCA) on the core and std libraries | 21.6±0.35ms | **21.2±0.41ms** | **-1.85%** |
| Teleport evaluation | 80.5±3.64µs | 81.9±3.74µs | +1.74% |

  </details>
  
github-actions[bot]: ## Benchmark for 9f14a9e
  <details>
    <summary>Click to view benchmark</summary>

| Test | Base         | PR               | % |
|------|--------------|------------------|---|
| Array append evaluation | 371.3±2.99µs | **343.4±3.45µs** | **-7.51%** |
| Array literal evaluation | **171.0±1.03µs** | 200.3±7.13µs | **+17.13%** |
| Array update evaluation | **416.3±2.73µs** | 429.1±2.78µs | **+3.07%** |
| Core + Standard library compilation | 20.0±0.60ms | 19.8±0.45ms | -1.00% |
| Deutsch-Jozsa evaluation | **5.1±0.04ms** | 5.3±0.05ms | **+3.92%** |
| Large file parity evaluation | 33.7±0.12ms | 33.8±0.59ms | +0.30% |
| Large input file compilation | 12.9±0.53ms | **11.7±0.30ms** | **-9.30%** |
| Large input file compilation (interpreter) | 50.9±1.63ms | 51.4±1.24ms | +0.98% |
| Large nested iteration | **33.1±0.68ms** | 33.7±0.28ms | **+1.81%** |
| Perform Runtime Capabilities Analysis (RCA) on Deutsch-Jozsa sample | 1530.6±115.15µs | 1534.1±131.34µs | +0.23% |
| Perform Runtime Capabilities Analysis (RCA) on large file sample | 8.1±0.13ms | 8.1±0.13ms | 0.00% |
| Perform Runtime Capabilities Analysis (RCA) on teleport sample | 1443.1±125.82µs | 1440.7±110.57µs | -0.17% |
| Perform Runtime Capabilities Analysis (RCA) on the core and std libraries | 22.1±0.22ms | **21.9±0.20ms** | **-0.90%** |
| Teleport evaluation | 82.4±3.97µs | 82.4±4.03µs | 0.00% |

  </details>
  
github-actions[bot]: ## Benchmark for 8f40caf
  <details>
    <summary>Click to view benchmark</summary>

| Test | Base         | PR               | % |
|------|--------------|------------------|---|
| Array append evaluation | 341.4±2.27µs | **338.7±3.19µs** | **-0.79%** |
| Array literal evaluation | 190.0±5.79µs | 187.8±2.37µs | -1.16% |
| Array update evaluation | 422.3±2.62µs | 421.7±3.17µs | -0.14% |
| Core + Standard library compilation | 18.2±1.05ms | 17.7±0.96ms | -2.75% |
| Deutsch-Jozsa evaluation | **5.1±0.31ms** | 5.2±0.04ms | **+1.96%** |
| Large file parity evaluation | 33.8±0.15ms | 33.8±0.66ms | 0.00% |
| Large input file compilation | 11.7±0.33ms | 11.7±0.62ms | 0.00% |
| Large input file compilation (interpreter) | 47.5±1.44ms | 46.5±1.60ms | -2.11% |
| Large nested iteration | 33.6±0.61ms | **32.8±0.28ms** | **-2.38%** |
| Perform Runtime Capabilities Analysis (RCA) on Deutsch-Jozsa sample | 1509.8±125.94µs | 1490.4±41.57µs | -1.28% |
| Perform Runtime Capabilities Analysis (RCA) on large file sample | 7.8±0.12ms | 7.7±0.11ms | -1.28% |
| Perform Runtime Capabilities Analysis (RCA) on teleport sample | 1421.5±71.42µs | 1410.8±73.15µs | -0.75% |
| Perform Runtime Capabilities Analysis (RCA) on the core and std libraries | 21.5±0.28ms | 21.4±0.88ms | -0.47% |
| Teleport evaluation | 81.2±3.56µs | 81.3±3.94µs | +0.12% |

  </details>
  
github-actions[bot]: ## Benchmark for aa6f34d
  <details>
    <summary>Click to view benchmark</summary>

| Test | Base         | PR               | % |
|------|--------------|------------------|---|
| Array append evaluation | 347.2±2.81µs | **337.9±2.54µs** | **-2.68%** |
| Array literal evaluation | 195.3±4.87µs | **172.3±3.98µs** | **-11.78%** |
| Array update evaluation | 434.4±2.47µs | **419.8±1.67µs** | **-3.36%** |
| Core + Standard library compilation | 17.7±0.86ms | 17.4±0.78ms | -1.69% |
| Deutsch-Jozsa evaluation | 5.1±0.03ms | **5.0±0.05ms** | **-1.96%** |
| Large file parity evaluation | 33.7±0.25ms | **33.6±0.07ms** | **-0.30%** |
| Large input file compilation | 11.6±0.26ms | 11.7±0.28ms | +0.86% |
| Large input file compilation (interpreter) | 46.1±1.73ms | 45.9±1.40ms | -0.43% |
| Large nested iteration | 34.2±0.24ms | **33.2±0.26ms** | **-2.92%** |
| Perform Runtime Capabilities Analysis (RCA) on Deutsch-Jozsa sample | 1516.6±117.54µs | 1498.4±41.60µs | -1.20% |
| Perform Runtime Capabilities Analysis (RCA) on large file sample | 7.8±0.09ms | 7.8±0.10ms | 0.00% |
| Perform Runtime Capabilities Analysis (RCA) on teleport sample | 1414.5±34.09µs | 1409.6±35.77µs | -0.35% |
| Perform Runtime Capabilities Analysis (RCA) on the core and std libraries | 21.2±0.20ms | 21.3±0.23ms | +0.47% |
| Teleport evaluation | 81.4±3.81µs | 81.6±4.21µs | +0.25% |

  </details>
  
github-actions[bot]: ## Benchmark for c0e523c
  <details>
    <summary>Click to view benchmark</summary>

| Test | Base         | PR               | % |
|------|--------------|------------------|---|
| Array append evaluation | **348.1±2.63µs** | 361.8±7.88µs | **+3.94%** |
| Array literal evaluation | 189.9±1.00µs | 190.6±1.33µs | +0.37% |
| Array update evaluation | **434.7±2.05µs** | 444.8±3.13µs | **+2.32%** |
| Core + Standard library compilation | 17.1±0.36ms | 17.1±0.42ms | 0.00% |
| Deutsch-Jozsa evaluation | **5.1±0.04ms** | 5.2±0.22ms | **+1.96%** |
| Large file parity evaluation | **33.6±0.10ms** | 33.8±0.07ms | **+0.60%** |
| Large input file compilation | **11.5±0.13ms** | 11.8±0.14ms | **+2.61%** |
| Large input file compilation (interpreter) | 44.7±0.99ms | 45.2±0.96ms | +1.12% |
| Large nested iteration | **34.4±0.49ms** | 35.4±0.20ms | **+2.91%** |
| Perform Runtime Capabilities Analysis (RCA) on Deutsch-Jozsa sample | 1491.6±32.14µs | 1501.4±33.49µs | +0.66% |
| Perform Runtime Capabilities Analysis (RCA) on large file sample | 7.7±0.07ms | 7.7±0.07ms | 0.00% |
| Perform Runtime Capabilities Analysis (RCA) on teleport sample | 1404.2±27.03µs | 1411.6±39.05µs | +0.53% |
| Perform Runtime Capabilities Analysis (RCA) on the core and std libraries | 21.1±0.19ms | 21.1±0.19ms | 0.00% |
| Teleport evaluation | 81.7±4.05µs | 82.3±4.42µs | +0.73% |

  </details>
  
github-actions[bot]: ## Benchmark for 29a4672
  <details>
    <summary>Click to view benchmark</summary>

| Test | Base         | PR               | % |
|------|--------------|------------------|---|
| Array append evaluation | 343.6±1.32µs | **332.9±11.76µs** | **-3.11%** |
| Array literal evaluation | 201.3±0.78µs | **179.8±1.08µs** | **-10.68%** |
| Array update evaluation | 427.4±1.10µs | **417.3±1.22µs** | **-2.36%** |
| Core + Standard library compilation | 17.4±0.58ms | 17.9±1.07ms | +2.87% |
| Deutsch-Jozsa evaluation | 5.1±0.07ms | **5.0±0.04ms** | **-1.96%** |
| Large file parity evaluation | 33.9±1.02ms | **33.7±0.18ms** | **-0.59%** |
| Large input file compilation | 11.6±0.29ms | 11.7±0.41ms | +0.86% |
| Large input file compilation (interpreter) | 46.2±1.40ms | 46.7±1.58ms | +1.08% |
| Large nested iteration | 33.6±0.22ms | **32.6±0.32ms** | **-2.98%** |
| Perform Runtime Capabilities Analysis (RCA) on Deutsch-Jozsa sample | 1496.4±65.15µs | 1507.0±56.21µs | +0.71% |
| Perform Runtime Capabilities Analysis (RCA) on large file sample | 8.0±0.14ms | 7.9±0.12ms | -1.25% |
| Perform Runtime Capabilities Analysis (RCA) on teleport sample | 1409.7±70.14µs | 1420.2±47.27µs | +0.74% |
| Perform Runtime Capabilities Analysis (RCA) on the core and std libraries | 21.6±0.32ms | 21.6±0.30ms | 0.00% |
| Teleport evaluation | 82.3±4.10µs | 79.8±3.55µs | -3.04% |

  </details>
  
github-actions[bot]: ## Benchmark for a142099
  <details>
    <summary>Click to view benchmark</summary>

| Test | Base         | PR               | % |
|------|--------------|------------------|---|
| Array append evaluation | 348.3±8.26µs | **334.1±2.66µs** | **-4.08%** |
| Array literal evaluation | 201.0±4.03µs | **174.4±4.80µs** | **-13.23%** |
| Array update evaluation | 431.5±9.27µs | **416.8±2.78µs** | **-3.41%** |
| Core + Standard library compilation | **17.9±1.12ms** | 19.4±1.32ms | **+8.38%** |
| Deutsch-Jozsa evaluation | **5.1±0.05ms** | 5.2±0.35ms | **+1.96%** |
| Large file parity evaluation | 33.9±0.17ms | 33.8±0.15ms | -0.29% |
| Large input file compilation | 12.0±0.57ms | 12.4±0.85ms | +3.33% |
| Large input file compilation (interpreter) | 50.5±3.36ms | 50.6±2.51ms | +0.20% |
| Large nested iteration | 34.0±0.66ms | **32.9±0.30ms** | **-3.24%** |
| Perform Runtime Capabilities Analysis (RCA) on Deutsch-Jozsa sample | 1490.6±30.66µs | 1488.8±38.12µs | -0.12% |
| Perform Runtime Capabilities Analysis (RCA) on large file sample | **7.8±0.08ms** | 7.9±0.31ms | **+1.28%** |
| Perform Runtime Capabilities Analysis (RCA) on teleport sample | 1408.3±36.44µs | 1410.2±53.96µs | +0.13% |
| Perform Runtime Capabilities Analysis (RCA) on the core and std libraries | 21.6±0.50ms | 21.5±0.34ms | -0.46% |
| Teleport evaluation | 81.3±3.85µs | 83.8±3.96µs | +3.08% |

  </details>
  

Patch:
diff --git a/compiler/qsc_partial_eval/src/evaluation_context.rs b/compiler/qsc_partial_eval/src/evaluation_context.rs
index be2306a6..ef213f33 100644
--- a/compiler/qsc_partial_eval/src/evaluation_context.rs
+++ b/compiler/qsc_partial_eval/src/evaluation_context.rs
@@ -72,6 +72,7 @@ pub struct Scope {
     pub callable: Option<(LocalItemId, FunctorApp)>,
     pub args_runtime_properties: Vec<ValueKind>,
     pub env: Env,
+    last_expr: Option<ExprId>,
     hybrid_exprs: FxHashMap<ExprId, Value>,
     hybrid_vars: FxHashMap<LocalVarId, Value>,
 }
@@ -87,12 +88,14 @@ impl Scope {
             callable,
             args_runtime_properties,
             env: Env::default(),
+            last_expr: None,
             hybrid_exprs: FxHashMap::default(),
             hybrid_vars: FxHashMap::default(),
         }
     }
 
-    pub fn get_expr_value(&self, expr_id: ExprId) -> &Value {
+    // Potential candidate for removal if only the last expression value is needed.
+    pub fn _get_expr_value(&self, expr_id: ExprId) -> &Value {
         self.hybrid_exprs
             .get(&expr_id)
             .expect("expression value does not exist")
@@ -105,10 +108,21 @@ impl Scope {
     }
 
     pub fn insert_expr_value(&mut self, expr_id: ExprId, value: Value) {
+        self.last_expr = Some(expr_id);
         self.hybrid_exprs.insert(expr_id, value);
     }
 
     pub fn insert_local_var_value(&mut self, local_var_id: LocalVarId, value: Value) {
         self.hybrid_vars.insert(local_var_id, value);
     }
+
+    pub fn clear_last_expr(&mut self) {
+        self.last_expr = None;
+    }
+
+    pub fn last_expr_value(&self) -> Value {
+        self.last_expr
+            .and_then(|expr_id| self.hybrid_exprs.get(&expr_id))
+            .map_or_else(Value::unit, Clone::clone)
+    }
 }
diff --git a/compiler/qsc_partial_eval/src/lib.rs b/compiler/qsc_partial_eval/src/lib.rs
index 20021dd8..4b369525 100644
--- a/compiler/qsc_partial_eval/src/lib.rs
+++ b/compiler/qsc_partial_eval/src/lib.rs
@@ -26,9 +26,12 @@ use qsc_fir::{
     visit::Visitor,
 };
 use qsc_rca::{ComputeKind, ComputePropertiesLookup, PackageStoreComputeProperties};
-use qsc_rir::rir::{
-    self, Callable, CallableId, CallableType, ConditionCode, Instruction, Literal, Operand,
-    Program, Variable,
+use qsc_rir::{
+    builder,
+    rir::{
+        self, Callable, CallableId, CallableType, ConditionCode, Instruction, Literal, Operand,
+        Program, Variable,
+    },
 };
 use rustc_hash::FxHashMap;
 use std::{collections::hash_map::Entry, rc::Rc, result::Result};
@@ -54,6 +57,10 @@ pub enum Error {
     #[diagnostic(code("Qsc.PartialEval.EvaluationFailed"))]
     EvaluationFailed(qsc_eval::Error),
 
+    #[error("failed to evaluate array element expression")]
+    #[diagnostic(code("Qsc.PartialEval.FailedToEvaluateArrayElementExpression"))]
+    FailedToEvaluateArrayElementExpression(#[label] Span),
+
     #[error("failed to evaluate {0}")]
     #[diagnostic(code("Qsc.PartialEval.FailedToEvaluateCallable"))]
     FailedToEvaluateCallable(String, #[label] Span),
@@ -144,28 +151,18 @@ impl<'a> PartialEvaluator<'a> {
         }
     }
 
-    fn bind_expr_to_pat(&mut self, pat_id: PatId, expr_id: ExprId) {
+    fn bind_value_to_pat(&mut self, pat_id: PatId, value: Value) {
         let pat = self.get_pat(pat_id);
         match &pat.kind {
             PatKind::Bind(ident) => {
-                let expr_value = self
-                    .eval_context
-                    .get_current_scope_mut()
-                    .get_expr_value(expr_id)
-                    .clone();
-                self.bind_value_to_ident(ident, expr_value);
+                self.bind_value_to_ident(ident, value);
             }
             PatKind::Tuple(pats) => {
-                let expr = self.get_expr(expr_id);
-                match &expr.kind {
-                    ExprKind::Tuple(exprs) => {
-                        assert!(pats.len() == exprs.len());
-                        for (pat_id, expr_id) in pats.iter().zip(exprs.iter()) {
-                            self.bind_expr_to_pat(*pat_id, *expr_id);
-                        }
-                    }
-                    _ => panic!("expected a tuple expression to bind to a tuple pattern"),
-                };
+                let tup = value.unwrap_tuple();
+                assert!(pats.len() == tup.len());
+                for (pat_id, value) in pats.iter().zip(tup.iter()) {
+                    self.bind_value_to_pat(*pat_id, value.clone());
+                }
             }
             PatKind::Discard => {
                 // Nothing to bind to.
@@ -228,8 +225,16 @@ impl<'a> PartialEvaluator<'a> {
             return Err(error);
         }
 
-        // Insert the return expression.
+        // Get the final value from the execution context.
+        let ret_val = self.eval_context.get_current_scope().last_expr_value();
+        let output_recording: Vec<Instruction> = self.generate_output_recording_instructions(
+            ret_val,
+            &self.get_expr(self.entry.expr.expr).ty,
+        );
+
+        // Insert the return expression and return the generated program.
         let current_block = self.get_current_block_mut();
+        current_block.0.extend(output_recording);
         current_block.0.push(Instruction::Return);
 
         // Set the number of qubits and results used by the program.
@@ -300,8 +305,8 @@ impl<'a> PartialEvaluator<'a> {
         let store_expr_id = StoreExprId::from((current_package_id, expr_id));
         let expr = self.package_store.get_expr(store_expr_id);
         match &expr.kind {
-            ExprKind::Array(_) => Err(Error::Unimplemented("Array Expr".to_string(), expr.span)),
-            ExprKind::ArrayLit(_) => Err(Error::Unimplemented("Array Lit".to_string(), expr.span)),
+            ExprKind::Array(exprs) => self.eval_expr_array(exprs),
+            ExprKind::ArrayLit(_) => panic!("array of literal values should always be classical"),
             ExprKind::ArrayRepeat(_, _) => {
                 Err(Error::Unimplemented("Array Repeat".to_string(), expr.span))
             }
@@ -496,8 +501,10 @@ impl<'a> PartialEvaluator<'a> {
         match callable_decl.name.name.as_ref() {
             "__quantum__rt__qubit_allocate" => self.allocate_qubit(),
             "__quantum__rt__qubit_release" => self.release_qubit(&args_value),
-            "__quantum__qis__m__body" => self.measure_qubit(mz_callable(), &args_value),
-            "__quantum__qis__mresetz__body" => self.measure_qubit(mresetz_callable(), &args_value),
+            "__quantum__qis__m__body" => self.measure_qubit(builder::mz_decl(), &args_value),
+            "__quantum__qis__mresetz__body" => {
+                self.measure_qubit(builder::mresetz_decl(), &args_value)
+            }
             _ => self.eval_expr_call_to_intrinsic_qis(store_item_id, callable_decl, args_value),
         }
     }
@@ -555,9 +562,7 @@ impl<'a> PartialEvaluator<'a> {
 
         // Check whether evaluating the block failed.
         if self.errors.is_empty() {
-            // Once we have proper support for evaluating all kinds of callables (not just parameterless unitary
-            // callables), we should the variable that stores the callable return value here.
-            Ok(Value::unit())
+            Ok(popped_scope.last_expr_value())
         } else {
             // Evaluating the block failed, generate an error specific to the callable.
             let global_callable = self
@@ -724,8 +729,21 @@ impl<'a> PartialEvaluator<'a> {
         }
     }
 
+    fn eval_expr_array(&mut self, exprs: &Vec<ExprId>) -> Result<Value, Error> {
+        let mut values = Vec::with_capacity(exprs.len());
+        for expr_id in exprs {
+            let maybe_value = self.try_eval_expr(*expr_id);
+            let Ok(value) = maybe_value else {
+                let expr = self.get_expr(*expr_id);
+                return Err(Error::FailedToEvaluateArrayElementExpression(expr.span));
+            };
+            values.push(value);
+        }
+        Ok(Value::Array(values.into()))
+    }
+
     fn eval_expr_tuple(&mut self, exprs: &Vec<ExprId>) -> Result<Value, Error> {
-        let mut values = Vec::<Value>::new();
+        let mut values = Vec::with_capacity(exprs.len());
         for expr_id in exprs {
             let maybe_value = self.try_eval_expr(*expr_id);
             let Ok(value) = maybe_value else {
@@ -806,7 +824,8 @@ impl<'a> PartialEvaluator<'a> {
                 let result_operand = Operand::Literal(Literal::Result(
                     id.try_into().expect("could not convert result ID to u32"),
                 ));
-                let read_result_callable_id = self.get_or_insert_callable(read_result_callable());
+                let read_result_callable_id =
+                    self.get_or_insert_callable(builder::read_result_decl());
                 let variable_id = self.resource_manager.next_var();
                 let variable_ty = rir::Ty::Boolean;
                 let variable = Variable {
@@ -951,8 +970,7 @@ impl<'a> PartialEvaluator<'a> {
     fn try_eval_block(&mut self, block_id: BlockId) -> Result<Value, ()> {
         self.visit_block(block_id);
         if self.errors.is_empty() {
-            // This should change eventually, but return UNIT for now.
-            Ok(Value::unit())
+            Ok(self.eval_context.get_current_scope().last_expr_value())
         } else {
             Err(())
         }
@@ -963,15 +981,210 @@ impl<'a> PartialEvaluator<'a> {
         // error.
         self.visit_expr(expr_id);
         if self.errors.is_empty() {
-            let expr_value = self
-                .eval_context
-                .get_current_scope()
-                .get_expr_value(expr_id);
-            Ok(expr_value.clone())
+            Ok(self.eval_context.get_current_scope().last_expr_value())
         } else {
             Err(())
         }
     }
+
+    fn generate_output_recording_instructions(
+        &mut self,
+        ret_val: Value,
+        ty: &Ty,
+    ) -> Vec<Instruction> {
+        let mut instrs = Vec::new();
+
+        match ret_val {
+            Value::Array(vals) => self.record_array(ty, &mut instrs, &vals),
+            Value::Tuple(vals) => self.record_tuple(ty, &mut instrs, &vals),
+            Value::Result(res) => self.record_result(&mut instrs, res),
+            Value::Var(var) => self.record_variable(ty, &mut instrs, var),
+            Value::Bool(val) => self.record_bool(&mut instrs, val),
+            Value::Int(val) => self.record_int(&mut instrs, val),
+
+            Value::BigInt(_)
+            | Value::Closure(_)
+            | Value::Double(_)
+            | Value::Global(_, _)
+            | Value::Pauli(_)
+            | Value::Qubit(_)
+            | Value::Range(_)
+            | Value::String(_) => panic!("unsupported value type in output recording"),
+        }
+
+        instrs
+    }
+
+    fn record_int(&mut self, instrs: &mut Vec<Instruction>, val: i64) {
+        let int_record_callable_id = self.get_int_record_callable();
+        instrs.push(Instruction::Call(
+            int_record_callable_id,
+            vec![
+                Operand::Literal(Literal::Integer(val)),
+                Operand::Literal(Literal::Pointer),
+            ],
+            None,
+        ));
+    }
+
+    fn record_bool(&mut self, instrs: &mut Vec<Instruction>, val: bool) {
+        let bool_record_callable_id = self.get_bool_record_callable();
+        instrs.push(Instruction::Call(
+            bool_record_callable_id,
+            vec![
+                Operand::Literal(Literal::Bool(val)),
+                Operand::Literal(Literal::Pointer),
+            ],
+            None,
+        ));
+    }
+
+    fn record_variable(&mut self, ty: &Ty, instrs: &mut Vec<Instruction>, var: Var) {
+        let (record_callable_id, record_ty) = match ty {
+            Ty::Prim(Prim::Bool) => (self.get_bool_record_callable(), rir::Ty::Boolean),
+            Ty::Prim(Prim::Int) => (self.get_int_record_callable(), rir::Ty::Integer),
+            _ => panic!("unsupported variable type in output recording"),
+        };
+        instrs.push(Instruction::Call(
+            record_callable_id,
+            vec![
+                Operand::Variable(Variable {
+                    variable_id: var.0.into(),
+                    ty: record_ty,
+                }),
+                Operand::Literal(Literal::Pointer),
+            ],
+            None,
+        ));
+    }
+
+    fn record_result(&mut self, instrs: &mut Vec<Instruction>, res: val::Result) {
+        let result_record_callable_id = self.get_result_record_callable();
+        instrs.push(Instruction::Call(
+            result_record_callable_id,
+            vec![
+                Operand::Literal(Literal::Result(
+                    res.unwrap_id()
+                        .try_into()
+                        .expect("result id should fit into u32"),
+                )),
+                Operand::Literal(Literal::Pointer),
+            ],
+            None,
+        ));
+    }
+
+    fn record_tuple(&mut self, ty: &Ty, instrs: &mut Vec<Instruction>, vals: &Rc<[Value]>) {
+        let Ty::Tuple(elem_tys) = ty else {
+            panic!("expected tuple type for tuple value");
+        };
+        let tuple_record_callable_id = self.get_tuple_record_callable();
+        instrs.push(Instruction::Call(
+            tuple_record_callable_id,
+            vec![
+                Operand::Literal(Literal::Integer(
+                    vals.len()
+                        .try_into()
+                        .expect("tuple length should fit into u32"),
+                )),
+                Operand::Literal(Literal::Pointer),
+            ],
+            None,
+        ));
+        for (val, elem_ty) in vals.iter().zip(elem_tys.iter()) {
+            instrs.extend(self.generate_output_recording_instructions(val.clone(), elem_ty));
+        }
+    }
+
+    fn record_array(&mut self, ty: &Ty, instrs: &mut Vec<Instruction>, vals: &Rc<Vec<Value>>) {
+        let Ty::Array(elem_ty) = ty else {
+            panic!("expected array type for array value");
+        };
+        let array_record_callable_id = self.get_array_record_callable();
+        instrs.push(Instruction::Call(
+            array_record_callable_id,
+            vec![
+                Operand::Literal(Literal::Integer(
+                    vals.len()
+                        .try_into()
+                        .expect("array length should fit into u32"),
+                )),
+                Operand::Literal(Literal::Pointer),
+            ],
+            None,
+        ));
+        for val in vals.iter() {
+            instrs.extend(self.generate_output_recording_instructions(val.clone(), elem_ty));
+        }
+    }
+
+    fn get_array_record_callable(&mut self) -> CallableId {
+        if let Some(id) = self.callables_map.get("__quantum__rt__array_record_output") {
+            return *id;
+        }
+
+        let callable = builder::array_record_decl();
+        let callable_id = self.resource_manager.next_callable();
+        self.callables_map
+            .insert("__quantum__rt__array_record_output".into(), callable_id);
+        self.program.callables.insert(callable_id, callable);
+        callable_id
+    }
+
+    fn get_tuple_record_callable(&mut self) -> CallableId {
+        if let Some(id) = self.callables_map.get("__quantum__rt__tuple_record_output") {
+            return *id;
+        }
+
+        let callable = builder::tuple_record_decl();
+        let callable_id = self.resource_manager.next_callable();
+        self.callables_map
+            .insert("__quantum__rt__tuple_record_output".into(), callable_id);
+        self.program.callables.insert(callable_id, callable);
+        callable_id
+    }
+
+    fn get_result_record_callable(&mut self) -> CallableId {
+        if let Some(id) = self
+            .callables_map
+            .get("__quantum__rt__result_record_output")
+        {
+            return *id;
+        }
+
+        let callable = builder::result_record_decl();
+        let callable_id = self.resource_manager.next_callable();
+        self.callables_map
+            .insert("__quantum__rt__result_record_output".into(), callable_id);
+        self.program.callables.insert(callable_id, callable);
+        callable_id
+    }
+
+    fn get_bool_record_callable(&mut self) -> CallableId {
+        if let Some(id) = self.callables_map.get("__quantum__rt__bool_record_output") {
+            return *id;
+        }
+
+        let callable = builder::bool_record_decl();
+        let callable_id = self.resource_manager.next_callable();
+        self.callables_map
+            .insert("__quantum__rt__bool_record_output".into(), callable_id);
+        self.program.callables.insert(callable_id, callable);
+        callable_id
+    }
+
+    fn get_int_record_callable(&mut self) -> CallableId {
+        if let Some(id) = self.callables_map.get("__quantum__rt__int_record_output") {
+            return *id;
+        }
+
+        let callable = builder::int_record_decl();
+        let callable_id = self.resource_manager.next_callable();
+        self.callables_map
+            .insert("__quantum__rt__int_record_output".into(), callable_id);
+        self.program.callables.insert(callable_id, callable);
+        callable_id
+    }
 }
 
 impl<'a> Visitor<'a> for PartialEvaluator<'a> {
@@ -1040,13 +1253,16 @@ impl<'a> Visitor<'a> for PartialEvaluator<'a> {
         let store_stmt_id = StoreStmtId::from((self.get_current_package_id(), stmt_id));
         let stmt = self.package_store.get_stmt(store_stmt_id);
         match stmt.kind {
-            StmtKind::Expr(expr_id) | StmtKind::Semi(expr_id) => {
+            StmtKind::Expr(expr_id) => {
+                self.visit_expr(expr_id);
+            }
+            StmtKind::Semi(expr_id) => {
                 self.visit_expr(expr_id);
+                self.eval_context.get_current_scope_mut().clear_last_expr();
             }
             StmtKind::Local(_, pat_id, expr_id) => {
-                let maybe_expr_value = self.try_eval_expr(expr_id);
-                if maybe_expr_value.is_ok() {
-                    self.bind_expr_to_pat(pat_id, expr_id);
+                if let Ok(value) = self.try_eval_expr(expr_id) {
+                    self.bind_value_to_pat(pat_id, value);
                 }
             }
             StmtKind::Item(_) => {
@@ -1118,36 +1334,6 @@ fn map_fir_type_to_rir_type(ty: &Ty) -> rir::Ty {
     }
 }
 
-fn mresetz_callable() -> Callable {
-    Callable {
-        name: "__quantum__qis__mresetz__body".to_string(),
-        input_type: vec![rir::Ty::Qubit, rir::Ty::Result],
-        output_type: None,
-        body: None,
-        call_type: CallableType::Measurement,
-    }
-}
-
-fn mz_callable() -> Callable {
-    Callable {
-        name: "__quantum__qis__mz__body".to_string(),
-        input_type: vec![rir::Ty::Qubit, rir::Ty::Result],
-        output_type: None,
-        body: None,
-        call_type: CallableType::Measurement,
-    }
-}
-
-fn read_result_callable() -> Callable {
-    Callable {
-        name: "__quantum__rt__read_result__body".to_string(),
-        input_type: vec![rir::Ty::Result],
-        output_type: Some(rir::Ty::Boolean),
-        body: None,
-        call_type: CallableType::Readout,
-    }
-}
-
 fn resolve_call_arg_operands(args_value: Value) -> Vec<rir::Operand> {
     let mut operands = Vec::<rir::Operand>::new();
     if let Value::Tuple(elements) = args_value {
diff --git a/compiler/qsc_passes/src/loop_unification.rs b/compiler/qsc_passes/src/loop_unification.rs
index 147bbb4e..7edef042 100644
--- a/compiler/qsc_passes/src/loop_unification.rs
+++ b/compiler/qsc_passes/src/loop_unification.rs
@@ -1,7 +1,6 @@
 // Copyright (c) Microsoft Corporation.
 // Licensed under the MIT License.
 
-use core::panic;
 use std::mem::take;
 
 use qsc_data_structures::span::Span;
diff --git a/compiler/qsc_rir/src/builder.rs b/compiler/qsc_rir/src/builder.rs
index 5ed292af..135f74c7 100644
--- a/compiler/qsc_rir/src/builder.rs
+++ b/compiler/qsc_rir/src/builder.rs
@@ -116,6 +116,28 @@ pub fn result_record_decl() -> Callable {
     }
 }
 
+#[must_use]
+pub fn int_record_decl() -> Callable {
+    Callable {
+        name: "__quantum__rt__integer_record_output".to_string(),
+        input_type: vec![Ty::Integer, Ty::Pointer],
+        output_type: None,
+        body: None,
+        call_type: CallableType::OutputRecording,
+    }
+}
+
+#[must_use]
+pub fn bool_record_decl() -> Callable {
+    Callable {
+        name: "__quantum__rt__bool_record_output".to_string(),
+        input_type: vec![Ty::Boolean, Ty::Pointer],
+        output_type: None,
+        body: None,
+        call_type: CallableType::OutputRecording,
+    }
+}
+
 #[must_use]
 pub fn array_record_decl() -> Callable {
     Callable {
@@ -127,6 +149,17 @@ pub fn array_record_decl() -> Callable {
     }
 }
 
+#[must_use]
+pub fn tuple_record_decl() -> Callable {
+    Callable {
+        name: "__quantum__rt__tuple_record_output".to_string(),
+        input_type: vec![Ty::Integer, Ty::Pointer],
+        output_type: None,
+        body: None,
+        call_type: CallableType::OutputRecording,
+    }
+}
+
 /// Creates a new program with a single, entry callable that has block 0 as its body.
 #[must_use]
 pub fn new_program() -> Program {
diff --git a/compiler/qsc_rir/src/passes/unreachable_code_check.rs b/compiler/qsc_rir/src/passes/unreachable_code_check.rs
index 31066bb8..ebe20d79 100644
--- a/compiler/qsc_rir/src/passes/unreachable_code_check.rs
+++ b/compiler/qsc_rir/src/passes/unreachable_code_check.rs
@@ -1,7 +1,6 @@
 // Copyright (c) Microsoft Corporation.
 // Licensed under the MIT License.
 
-use core::panic;
 use std::iter::once;
 
 use crate::{


Test patch:
diff --git a/compiler/qsc/src/interpret/tests.rs b/compiler/qsc/src/interpret/tests.rs
index b6c9efac..aca47931 100644
--- a/compiler/qsc/src/interpret/tests.rs
+++ b/compiler/qsc/src/interpret/tests.rs
@@ -727,7 +727,7 @@ mod given_interpreter {
                     open Microsoft.Quantum.Math;
                     open QIR.Intrinsic;
                     @EntryPoint()
-                    operation Main() : Unit {
+                    operation Main() : Result {
                         use q = Qubit();
                         let pi_over_2 = 4.0 / 2.0;
                         __quantum__qis__rz__body(pi_over_2, q);
@@ -735,6 +735,7 @@ mod given_interpreter {
                         __quantum__qis__rz__body(some_angle, q);
                         set some_angle = ArcCos(-1.0) / PI();
                         __quantum__qis__rz__body(some_angle, q);
+                        __quantum__qis__mresetz__body(q)
                     }
                 }"#
                 },
@@ -750,12 +751,88 @@ mod given_interpreter {
                   call void @__quantum__qis__rz__body(double 2.0, %Qubit* inttoptr (i64 0 to %Qubit*))
                   call void @__quantum__qis__rz__body(double 0.0, %Qubit* inttoptr (i64 0 to %Qubit*))
                   call void @__quantum__qis__rz__body(double 1.0, %Qubit* inttoptr (i64 0 to %Qubit*))
+                  call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
+                  call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null)
                   ret void
                 }
 
                 declare void @__quantum__qis__rz__body(double, %Qubit*)
 
-                attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="adaptive_profile" "required_num_qubits"="1" "required_num_results"="0" }
+                declare void @__quantum__qis__mresetz__body(%Qubit*, %Result*) #1
+
+                declare void @__quantum__rt__result_record_output(%Result*, i8*)
+
+                attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="adaptive_profile" "required_num_qubits"="1" "required_num_results"="1" }
+                attributes #1 = { "irreversible" }
+
+                ; module flags
+
+                !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}
+            "#]]
+            .assert_eq(&res);
+        }
+
+        #[test]
+        fn adaptive_qirgen_nested_output_types() {
+            let mut interpreter = Interpreter::new(
+                true,
+                SourceMap::default(),
+                PackageType::Lib,
+                TargetCapabilityFlags::Adaptive,
+                LanguageFeatures::default(),
+            )
+            .expect("interpreter should be created");
+            let (result, output) = line(
+                &mut interpreter,
+                indoc! {r#"
+                namespace Test {
+                    open QIR.Intrinsic;
+                    @EntryPoint()
+                    operation Main() : (Result, (Bool, Bool)) {
+                        use q = Qubit();
+                        let r = __quantum__qis__mresetz__body(q);
+                        (r, (r == One, r == Zero))
+                    }
+                }"#
+                },
+            );
+            is_only_value(&result, &output, &Value::unit());
+            let res = interpreter.qirgen("Test.Main()").expect("expected success");
+            expect![[r#"
+                %Result = type opaque
+                %Qubit = type opaque
+
+                define void @ENTRYPOINT__main() #0 {
+                block_0:
+                  call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
+                  %var_0 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 0 to %Result*))
+                  %var_1 = icmp eq i1 %var_0, true
+                  %var_2 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 0 to %Result*))
+                  %var_3 = icmp eq i1 %var_2, false
+                  call void @__quantum__rt__tuple_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__tuple_record_output(i64 2, i8* null)
+                  call void @__quantum__rt__bool_record_output(i1 %var_1, i8* null)
+                  call void @__quantum__rt__bool_record_output(i1 %var_3, i8* null)
+                  ret void
+                }
+
+                declare void @__quantum__qis__mresetz__body(%Qubit*, %Result*) #1
+
+                declare i1 @__quantum__qis__read_result__body(%Result*)
+
+                declare void @__quantum__rt__tuple_record_output(i64, i8*)
+
+                declare void @__quantum__rt__result_record_output(%Result*, i8*)
+
+                declare void @__quantum__rt__bool_record_output(i1, i8*)
+
+                attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="adaptive_profile" "required_num_qubits"="1" "required_num_results"="1" }
                 attributes #1 = { "irreversible" }
 
                 ; module flags
diff --git a/compiler/qsc_eval/src/tests.rs b/compiler/qsc_eval/src/tests.rs
index b130e8bd..479ccbdd 100644
--- a/compiler/qsc_eval/src/tests.rs
+++ b/compiler/qsc_eval/src/tests.rs
@@ -3,7 +3,6 @@
 
 #![allow(clippy::needless_raw_string_hashes)]
 
-use core::panic;
 use std::rc::Rc;
 
 use crate::{
@@ -173,7 +172,7 @@ fn check_partial_eval_stmt(
             &mut GenericReceiver::new(&mut out),
         ) {
             Ok(_) => {}
-            Err(err) => panic!("Unexpected error: {:?}", err),
+            Err(err) => panic!("Unexpected error: {err:?}"),
         }
     }
 
diff --git a/compiler/qsc_partial_eval/tests/branching.rs b/compiler/qsc_partial_eval/tests/branching.rs
index dfce3fb7..f8364ee0 100644
--- a/compiler/qsc_partial_eval/tests/branching.rs
+++ b/compiler/qsc_partial_eval/tests/branching.rs
@@ -1,58 +1,18 @@
 // Copyright (c) Microsoft Corporation.
 // Licensed under the MIT License.
 
-#![allow(clippy::needless_raw_string_hashes, clippy::similar_names)]
+#![allow(
+    clippy::needless_raw_string_hashes,
+    clippy::similar_names,
+    clippy::too_many_lines
+)]
 
 pub mod test_utils;
 
+use expect_test::expect;
 use indoc::indoc;
-use qsc_rir::rir::{
-    BlockId, Callable, CallableId, CallableType, Instruction, Literal, Operand, Ty, Variable,
-};
-use test_utils::{
-    assert_block_instructions, assert_block_last_instruction, assert_callable,
-    compile_and_partially_evaluate, mresetz_callable, read_result_callable,
-};
-
-fn single_qubit_intrinsic_op_a() -> Callable {
-    Callable {
-        name: "opA".to_string(),
-        input_type: vec![Ty::Qubit],
-        output_type: None,
-        body: None,
-        call_type: CallableType::Regular,
-    }
-}
-
-fn single_qubit_intrinsic_op_b() -> Callable {
-    Callable {
-        name: "opB".to_string(),
-        input_type: vec![Ty::Qubit],
-        output_type: None,
-        body: None,
-        call_type: CallableType::Regular,
-    }
-}
-
-fn single_qubit_intrinsic_op_c() -> Callable {
-    Callable {
-        name: "opC".to_string(),
-        input_type: vec![Ty::Qubit],
-        output_type: None,
-        body: None,
-        call_type: CallableType::Regular,
-    }
-}
-
-fn single_qubit_intrinsic_op_d() -> Callable {
-    Callable {
-        name: "opD".to_string(),
-        input_type: vec![Ty::Qubit],
-        output_type: None,
-        body: None,
-        call_type: CallableType::Regular,
-    }
-}
+use qsc_rir::rir::CallableId;
+use test_utils::{assert_blocks, assert_callable, compile_and_partially_evaluate};
 
 #[test]
 fn if_expression_with_true_condition() {
@@ -71,18 +31,26 @@ fn if_expression_with_true_condition() {
         "#,
     });
     let op_a_callable_id = CallableId(1);
-    assert_callable(&program, op_a_callable_id, &single_qubit_intrinsic_op_a());
-    assert_block_instructions(
+    assert_callable(
+        &program,
+        op_a_callable_id,
+        &expect![[r#"
+        Callable:
+            name: opA
+            call_type: Regular
+            input_type:
+                [0]: Qubit
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
+    assert_blocks(
         &program,
-        BlockId(0),
-        &[
-            Instruction::Call(
-                op_a_callable_id,
-                vec![Operand::Literal(Literal::Qubit(0))],
-                None,
-            ),
-            Instruction::Return,
-        ],
+        &expect![[r#"
+        Blocks:
+        Block 0:Block:
+            Call id(1), args( Qubit(0), )
+            Call id(2), args( Integer(0), Pointer, )
+            Return"#]],
     );
 }
 
@@ -102,10 +70,14 @@ fn if_expression_with_false_condition() {
         }
         "#,
     });
-    // This program is expected to just have the entry-point callable, whose block only has a return
-    // intruction.
-    assert_eq!(program.callables.iter().count(), 1);
-    assert_block_instructions(&program, BlockId(0), &[Instruction::Return]);
+    assert_blocks(
+        &program,
+        &expect![[r#"
+        Blocks:
+        Block 0:Block:
+            Call id(1), args( Integer(0), Pointer, )
+            Return"#]],
+    );
 }
 
 #[test]
@@ -128,18 +100,26 @@ fn if_else_expression_with_true_condition() {
         "#,
     });
     let op_a_callable_id = CallableId(1);
-    assert_callable(&program, op_a_callable_id, &single_qubit_intrinsic_op_a());
-    assert_block_instructions(
+    assert_callable(
+        &program,
+        op_a_callable_id,
+        &expect![[r#"
+        Callable:
+            name: opA
+            call_type: Regular
+            input_type:
+                [0]: Qubit
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
+    assert_blocks(
         &program,
-        BlockId(0),
-        &[
-            Instruction::Call(
-                op_a_callable_id,
-                vec![Operand::Literal(Literal::Qubit(0))],
-                None,
-            ),
-            Instruction::Return,
-        ],
+        &expect![[r#"
+        Blocks:
+        Block 0:Block:
+            Call id(1), args( Qubit(0), )
+            Call id(2), args( Integer(0), Pointer, )
+            Return"#]],
     );
 }
 
@@ -163,18 +143,26 @@ fn if_else_expression_with_false_condition() {
         "#,
     });
     let op_b_callable_id = CallableId(1);
-    assert_callable(&program, op_b_callable_id, &single_qubit_intrinsic_op_b());
-    assert_block_instructions(
+    assert_callable(
         &program,
-        BlockId(0),
-        &[
-            Instruction::Call(
-                op_b_callable_id,
-                vec![Operand::Literal(Literal::Qubit(0))],
-                None,
-            ),
-            Instruction::Return,
-        ],
+        op_b_callable_id,
+        &expect![[r#"
+        Callable:
+            name: opB
+            call_type: Regular
+            input_type:
+                [0]: Qubit
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
+    assert_blocks(
+        &program,
+        &expect![[r#"
+        Blocks:
+        Block 0:Block:
+            Call id(1), args( Qubit(0), )
+            Call id(2), args( Integer(0), Pointer, )
+            Return"#]],
     );
 }
 
@@ -201,18 +189,26 @@ fn if_elif_else_expression_with_true_elif_condition() {
         "#,
     });
     let op_b_callable_id = CallableId(1);
-    assert_callable(&program, op_b_callable_id, &single_qubit_intrinsic_op_b());
-    assert_block_instructions(
+    assert_callable(
+        &program,
+        op_b_callable_id,
+        &expect![[r#"
+        Callable:
+            name: opB
+            call_type: Regular
+            input_type:
+                [0]: Qubit
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
+    assert_blocks(
         &program,
-        BlockId(0),
-        &[
-            Instruction::Call(
-                op_b_callable_id,
-                vec![Operand::Literal(Literal::Qubit(0))],
-                None,
-            ),
-            Instruction::Return,
-        ],
+        &expect![[r#"
+        Blocks:
+        Block 0:Block:
+            Call id(1), args( Qubit(0), )
+            Call id(2), args( Integer(0), Pointer, )
+            Return"#]],
     );
 }
 
@@ -236,41 +232,62 @@ fn if_expression_with_dynamic_condition() {
 
     // Verify the callables added to the program.
     let mresetz_callable_id = CallableId(1);
-    assert_callable(&program, mresetz_callable_id, &mresetz_callable());
+    assert_callable(
+        &program,
+        mresetz_callable_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__qis__mresetz__body
+            call_type: Measurement
+            input_type:
+                [0]: Qubit
+                [1]: Result
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
     let read_result_callable_id = CallableId(2);
-    assert_callable(&program, read_result_callable_id, &read_result_callable());
+    assert_callable(
+        &program,
+        read_result_callable_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__qis__read_result__body
+            call_type: Readout
+            input_type:
+                [0]: Result
+            output_type: Boolean
+            body: <NONE>"#]],
+    );
     let op_a_callable_id = CallableId(3);
-    assert_callable(&program, op_a_callable_id, &single_qubit_intrinsic_op_a());
-
-    // Set the IDs of the blocks we want to verify.
-    let initial_block_id = BlockId(0);
-    let continuation_block_id = BlockId(1);
-    let if_block_id = BlockId(2);
-
-    // Verify the branch instruction in the initial-block.
-    let condition_var = Variable {
-        variable_id: 1.into(),
-        ty: Ty::Boolean,
-    };
-    let branch_inst = Instruction::Branch(condition_var, if_block_id, continuation_block_id);
-    assert_block_last_instruction(&program, initial_block_id, &branch_inst);
-
-    // Verify the instructions in the if-block.
-    assert_block_instructions(
+    assert_callable(
         &program,
-        if_block_id,
-        &[
-            Instruction::Call(
-                op_a_callable_id,
-                vec![Operand::Literal(Literal::Qubit(0))],
-                None,
-            ),
-            Instruction::Jump(continuation_block_id),
-        ],
+        op_a_callable_id,
+        &expect![[r#"
+        Callable:
+            name: opA
+            call_type: Regular
+            input_type:
+                [0]: Qubit
+            output_type: <VOID>
+            body: <NONE>"#]],
     );
 
-    // Verify the instructions in the continuation-block.
-    assert_block_instructions(&program, continuation_block_id, &[Instruction::Return]);
+    assert_blocks(
+        &program,
+        &expect![[r#"
+            Blocks:
+            Block 0:Block:
+                Call id(1), args( Qubit(0), Result(0), )
+                Variable(0, Boolean) = Call id(2), args( Result(0), )
+                Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false)
+                Branch Variable(1, Boolean), 2, 1
+            Block 1:Block:
+                Call id(4), args( Integer(0), Pointer, )
+                Return
+            Block 2:Block:
+                Call id(3), args( Qubit(0), )
+                Jump(1)"#]],
+    );
 }
 
 #[test]
@@ -296,58 +313,78 @@ fn if_else_expression_with_dynamic_condition() {
 
     // Verify the callables added to the program.
     let mresetz_callable_id = CallableId(1);
-    assert_callable(&program, mresetz_callable_id, &mresetz_callable());
+    assert_callable(
+        &program,
+        mresetz_callable_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__qis__mresetz__body
+            call_type: Measurement
+            input_type:
+                [0]: Qubit
+                [1]: Result
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
     let read_result_callable_id = CallableId(2);
-    assert_callable(&program, read_result_callable_id, &read_result_callable());
+    assert_callable(
+        &program,
+        read_result_callable_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__qis__read_result__body
+            call_type: Readout
+            input_type:
+                [0]: Result
+            output_type: Boolean
+            body: <NONE>"#]],
+    );
     let op_a_callable_id = CallableId(3);
-    assert_callable(&program, op_a_callable_id, &single_qubit_intrinsic_op_a());
+    assert_callable(
+        &program,
+        op_a_callable_id,
+        &expect![[r#"
+        Callable:
+            name: opA
+            call_type: Regular
+            input_type:
+                [0]: Qubit
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
     let op_b_callable_id = CallableId(4);
-    assert_callable(&program, op_b_callable_id, &single_qubit_intrinsic_op_b());
-
-    // Set the IDs of the blocks we want to verify.
-    let initial_block_id = BlockId(0);
-    let continuation_block_id = BlockId(1);
-    let if_block_id = BlockId(2);
-    let else_block_id = BlockId(3);
-
-    // Verify the branch instruction in the initial-block.
-    let condition_var = Variable {
-        variable_id: 1.into(),
-        ty: Ty::Boolean,
-    };
-    let branch_inst = Instruction::Branch(condition_var, if_block_id, else_block_id);
-    assert_block_last_instruction(&program, initial_block_id, &branch_inst);
-
-    // Verify the instructions in the if-block.
-    assert_block_instructions(
+    assert_callable(
         &program,
-        if_block_id,
-        &[
-            Instruction::Call(
-                op_a_callable_id,
-                vec![Operand::Literal(Literal::Qubit(0))],
-                None,
-            ),
-            Instruction::Jump(continuation_block_id),
-        ],
+        op_b_callable_id,
+        &expect![[r#"
+        Callable:
+            name: opB
+            call_type: Regular
+            input_type:
+                [0]: Qubit
+            output_type: <VOID>
+            body: <NONE>"#]],
     );
 
-    // Verify the instructions in the else-block.
-    assert_block_instructions(
+    assert_blocks(
         &program,
-        else_block_id,
-        &[
-            Instruction::Call(
-                op_b_callable_id,
-                vec![Operand::Literal(Literal::Qubit(0))],
-                None,
-            ),
-            Instruction::Jump(continuation_block_id),
-        ],
+        &expect![[r#"
+        Blocks:
+        Block 0:Block:
+            Call id(1), args( Qubit(0), Result(0), )
+            Variable(0, Boolean) = Call id(2), args( Result(0), )
+            Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(true)
+            Branch Variable(1, Boolean), 2, 3
+        Block 1:Block:
+            Call id(5), args( Integer(0), Pointer, )
+            Return
+        Block 2:Block:
+            Call id(3), args( Qubit(0), )
+            Jump(1)
+        Block 3:Block:
+            Call id(4), args( Qubit(0), )
+            Jump(1)"#]],
     );
-
-    // Verify the instructions in the continuation-block.
-    assert_block_instructions(&program, continuation_block_id, &[Instruction::Return]);
 }
 
 #[test]
@@ -377,89 +414,101 @@ fn if_elif_else_expression_with_dynamic_condition() {
 
     // Verify the callables added to the program.
     let mresetz_callable_id = CallableId(1);
-    assert_callable(&program, mresetz_callable_id, &mresetz_callable());
+    assert_callable(
+        &program,
+        mresetz_callable_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__qis__mresetz__body
+            call_type: Measurement
+            input_type:
+                [0]: Qubit
+                [1]: Result
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
     let read_result_callable_id = CallableId(2);
-    assert_callable(&program, read_result_callable_id, &read_result_callable());
+    assert_callable(
+        &program,
+        read_result_callable_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__qis__read_result__body
+            call_type: Readout
+            input_type:
+                [0]: Result
+            output_type: Boolean
+            body: <NONE>"#]],
+    );
     let op_a_callable_id = CallableId(3);
-    assert_callable(&program, op_a_callable_id, &single_qubit_intrinsic_op_a());
-    let op_b_callable_id = CallableId(4);
-    assert_callable(&program, op_b_callable_id, &single_qubit_intrinsic_op_b());
-    let op_c_callable_id = CallableId(5);
-    assert_callable(&program, op_c_callable_id, &single_qubit_intrinsic_op_c());
-
-    // Set the IDs of the blocks we want to verify.
-    let initial_block_id = BlockId(0);
-    let continuation_block_id = BlockId(1);
-    let if_block_id = BlockId(2);
-    let else_block_id = BlockId(3);
-    let nested_continuation_block_id = BlockId(4);
-    let nested_if_block_id = BlockId(5);
-    let nested_else_block_id = BlockId(6);
-
-    // Verify the branch instruction in the initial-block.
-    let condition_var = Variable {
-        variable_id: 1.into(),
-        ty: Ty::Boolean,
-    };
-    let branch_inst = Instruction::Branch(condition_var, if_block_id, else_block_id);
-    assert_block_last_instruction(&program, initial_block_id, &branch_inst);
-
-    // Verify the instructions in the if-block.
-    assert_block_instructions(
+    assert_callable(
         &program,
-        if_block_id,
-        &[
-            Instruction::Call(
-                op_a_callable_id,
-                vec![Operand::Literal(Literal::Qubit(2))],
-                None,
-            ),
-            Instruction::Jump(continuation_block_id),
-        ],
+        op_a_callable_id,
+        &expect![[r#"
+        Callable:
+            name: opA
+            call_type: Regular
+            input_type:
+                [0]: Qubit
+            output_type: <VOID>
+            body: <NONE>"#]],
     );
-
-    // Verify the branch instruction in the else-block.
-    let nested_condition_var = Variable {
-        variable_id: 3.into(),
-        ty: Ty::Boolean,
-    };
-    let nested_branch_inst = Instruction::Branch(
-        nested_condition_var,
-        nested_if_block_id,
-        nested_else_block_id,
+    let op_b_callable_id = CallableId(4);
+    assert_callable(
+        &program,
+        op_b_callable_id,
+        &expect![[r#"
+        Callable:
+            name: opB
+            call_type: Regular
+            input_type:
+                [0]: Qubit
+            output_type: <VOID>
+            body: <NONE>"#]],
     );
-    assert_block_last_instruction(&program, else_block_id, &nested_branch_inst);
-
-    // Verify the instructions in the nested-if-block.
-    assert_block_instructions(
+    let op_c_callable_id = CallableId(5);
+    assert_callable(
         &program,
-        nested_if_block_id,
-        &[
-            Instruction::Call(
-                op_b_callable_id,
-                vec![Operand::Literal(Literal::Qubit(2))],
-                None,
-            ),
-            Instruction::Jump(nested_continuation_block_id),
-        ],
+        op_c_callable_id,
+        &expect![[r#"
+        Callable:
+            name: opC
+            call_type: Regular
+            input_type:
+                [0]: Qubit
+            output_type: <VOID>
+            body: <NONE>"#]],
     );
 
-    // Verify the instructions in the nested-else-block.
-    assert_block_instructions(
+    assert_blocks(
         &program,
-        nested_else_block_id,
-        &[
-            Instruction::Call(
-                op_c_callable_id,
-                vec![Operand::Literal(Literal::Qubit(2))],
-                None,
-            ),
-            Instruction::Jump(nested_continuation_block_id),
-        ],
+        &expect![[r#"
+        Blocks:
+        Block 0:Block:
+            Call id(1), args( Qubit(0), Result(0), )
+            Call id(1), args( Qubit(1), Result(1), )
+            Variable(0, Boolean) = Call id(2), args( Result(0), )
+            Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(true)
+            Branch Variable(1, Boolean), 2, 3
+        Block 1:Block:
+            Call id(6), args( Integer(0), Pointer, )
+            Return
+        Block 2:Block:
+            Call id(3), args( Qubit(2), )
+            Jump(1)
+        Block 3:Block:
+            Variable(2, Boolean) = Call id(2), args( Result(1), )
+            Variable(3, Boolean) = Icmp Eq, Variable(2, Boolean), Bool(true)
+            Branch Variable(3, Boolean), 5, 6
+        Block 4:Block:
+            Jump(1)
+        Block 5:Block:
+            Call id(4), args( Qubit(2), )
+            Jump(4)
+        Block 6:Block:
+            Call id(5), args( Qubit(2), )
+            Jump(4)"#]],
     );
-
-    // Verify the instructions in the continuation-block.
-    assert_block_instructions(&program, continuation_block_id, &[Instruction::Return]);
 }
 
 #[test]
@@ -484,41 +533,62 @@ fn if_expression_with_dynamic_condition_and_nested_if_expression_with_true_condi
 
     // Verify the callables added to the program.
     let mresetz_callable_id = CallableId(1);
-    assert_callable(&program, mresetz_callable_id, &mresetz_callable());
+    assert_callable(
+        &program,
+        mresetz_callable_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__qis__mresetz__body
+            call_type: Measurement
+            input_type:
+                [0]: Qubit
+                [1]: Result
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
     let read_result_callable_id = CallableId(2);
-    assert_callable(&program, read_result_callable_id, &read_result_callable());
+    assert_callable(
+        &program,
+        read_result_callable_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__qis__read_result__body
+            call_type: Readout
+            input_type:
+                [0]: Result
+            output_type: Boolean
+            body: <NONE>"#]],
+    );
     let op_a_callable_id = CallableId(3);
-    assert_callable(&program, op_a_callable_id, &single_qubit_intrinsic_op_a());
-
-    // Set the IDs of the blocks we want to verify.
-    let initial_block_id = BlockId(0);
-    let continuation_block_id = BlockId(1);
-    let if_block_id = BlockId(2);
-
-    // Verify the branch instruction in the initial-block.
-    let condition_var = Variable {
-        variable_id: 1.into(),
-        ty: Ty::Boolean,
-    };
-    let branch_inst = Instruction::Branch(condition_var, if_block_id, continuation_block_id);
-    assert_block_last_instruction(&program, initial_block_id, &branch_inst);
-
-    // Verify the instructions in the if-block.
-    assert_block_instructions(
+    assert_callable(
         &program,
-        if_block_id,
-        &[
-            Instruction::Call(
-                op_a_callable_id,
-                vec![Operand::Literal(Literal::Qubit(0))],
-                None,
-            ),
-            Instruction::Jump(continuation_block_id),
-        ],
+        op_a_callable_id,
+        &expect![[r#"
+        Callable:
+            name: opA
+            call_type: Regular
+            input_type:
+                [0]: Qubit
+            output_type: <VOID>
+            body: <NONE>"#]],
     );
 
-    // Verify the instructions in the continuation-block.
-    assert_block_instructions(&program, continuation_block_id, &[Instruction::Return]);
+    assert_blocks(
+        &program,
+        &expect![[r#"
+        Blocks:
+        Block 0:Block:
+            Call id(1), args( Qubit(0), Result(0), )
+            Variable(0, Boolean) = Call id(2), args( Result(0), )
+            Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false)
+            Branch Variable(1, Boolean), 2, 1
+        Block 1:Block:
+            Call id(4), args( Integer(0), Pointer, )
+            Return
+        Block 2:Block:
+            Call id(3), args( Qubit(0), )
+            Jump(1)"#]],
+    );
 }
 
 #[test]
@@ -543,32 +613,48 @@ fn if_expression_with_dynamic_condition_and_nested_if_expression_with_false_cond
 
     // Verify the callables added to the program.
     let mresetz_callable_id = CallableId(1);
-    assert_callable(&program, mresetz_callable_id, &mresetz_callable());
+    assert_callable(
+        &program,
+        mresetz_callable_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__qis__mresetz__body
+            call_type: Measurement
+            input_type:
+                [0]: Qubit
+                [1]: Result
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
     let read_result_callable_id = CallableId(2);
-    assert_callable(&program, read_result_callable_id, &read_result_callable());
-
-    // Set the IDs of the blocks we want to verify.
-    let initial_block_id = BlockId(0);
-    let continuation_block_id = BlockId(1);
-    let if_block_id = BlockId(2);
-
-    // Verify the branch instruction in the initial-block.
-    let condition_var = Variable {
-        variable_id: 1.into(),
-        ty: Ty::Boolean,
-    };
-    let branch_inst = Instruction::Branch(condition_var, if_block_id, continuation_block_id);
-    assert_block_last_instruction(&program, initial_block_id, &branch_inst);
-
-    // Verify the instructions in the if-block.
-    assert_block_instructions(
+    assert_callable(
         &program,
-        if_block_id,
-        &[Instruction::Jump(continuation_block_id)],
+        read_result_callable_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__qis__read_result__body
+            call_type: Readout
+            input_type:
+                [0]: Result
+            output_type: Boolean
+            body: <NONE>"#]],
     );
 
-    // Verify the instructions in the continuation-block.
-    assert_block_instructions(&program, continuation_block_id, &[Instruction::Return]);
+    assert_blocks(
+        &program,
+        &expect![[r#"
+        Blocks:
+        Block 0:Block:
+            Call id(1), args( Qubit(0), Result(0), )
+            Variable(0, Boolean) = Call id(2), args( Result(0), )
+            Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false)
+            Branch Variable(1, Boolean), 2, 1
+        Block 1:Block:
+            Call id(3), args( Integer(0), Pointer, )
+            Return
+        Block 2:Block:
+            Jump(1)"#]],
+    );
 }
 
 #[test]
@@ -596,58 +682,78 @@ fn if_else_expression_with_dynamic_condition_and_nested_if_expression_with_true_
 
     // Verify the callables added to the program.
     let mresetz_callable_id = CallableId(1);
-    assert_callable(&program, mresetz_callable_id, &mresetz_callable());
+    assert_callable(
+        &program,
+        mresetz_callable_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__qis__mresetz__body
+            call_type: Measurement
+            input_type:
+                [0]: Qubit
+                [1]: Result
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
     let read_result_callable_id = CallableId(2);
-    assert_callable(&program, read_result_callable_id, &read_result_callable());
+    assert_callable(
+        &program,
+        read_result_callable_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__qis__read_result__body
+            call_type: Readout
+            input_type:
+                [0]: Result
+            output_type: Boolean
+            body: <NONE>"#]],
+    );
     let op_a_callable_id = CallableId(3);
-    assert_callable(&program, op_a_callable_id, &single_qubit_intrinsic_op_a());
+    assert_callable(
+        &program,
+        op_a_callable_id,
+        &expect![[r#"
+        Callable:
+            name: opA
+            call_type: Regular
+            input_type:
+                [0]: Qubit
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
     let op_b_callable_id = CallableId(4);
-    assert_callable(&program, op_b_callable_id, &single_qubit_intrinsic_op_b());
-
-    // Set the IDs of the blocks we want to verify.
-    let initial_block_id = BlockId(0);
-    let continuation_block_id = BlockId(1);
-    let if_block_id = BlockId(2);
-    let else_block_id = BlockId(3);
-
-    // Verify the branch instruction in the initial-block.
-    let condition_var = Variable {
-        variable_id: 1.into(),
-        ty: Ty::Boolean,
-    };
-    let branch_inst = Instruction::Branch(condition_var, if_block_id, else_block_id);
-    assert_block_last_instruction(&program, initial_block_id, &branch_inst);
-
-    // Verify the instructions in the if-block.
-    assert_block_instructions(
+    assert_callable(
         &program,
-        if_block_id,
-        &[
-            Instruction::Call(
-                op_a_callable_id,
-                vec![Operand::Literal(Literal::Qubit(0))],
-                None,
-            ),
-            Instruction::Jump(continuation_block_id),
-        ],
+        op_b_callable_id,
+        &expect![[r#"
+        Callable:
+            name: opB
+            call_type: Regular
+            input_type:
+                [0]: Qubit
+            output_type: <VOID>
+            body: <NONE>"#]],
     );
 
-    // Verify the instructions in the else-block.
-    assert_block_instructions(
+    assert_blocks(
         &program,
-        else_block_id,
-        &[
-            Instruction::Call(
-                op_b_callable_id,
-                vec![Operand::Literal(Literal::Qubit(0))],
-                None,
-            ),
-            Instruction::Jump(continuation_block_id),
-        ],
+        &expect![[r#"
+        Blocks:
+        Block 0:Block:
+            Call id(1), args( Qubit(0), Result(0), )
+            Variable(0, Boolean) = Call id(2), args( Result(0), )
+            Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(true)
+            Branch Variable(1, Boolean), 2, 3
+        Block 1:Block:
+            Call id(5), args( Integer(0), Pointer, )
+            Return
+        Block 2:Block:
+            Call id(3), args( Qubit(0), )
+            Jump(1)
+        Block 3:Block:
+            Call id(4), args( Qubit(0), )
+            Jump(1)"#]],
     );
-
-    // Verify the instructions in the continuation-block.
-    assert_block_instructions(&program, continuation_block_id, &[Instruction::Return]);
 }
 
 #[test]
@@ -675,49 +781,64 @@ fn if_else_expression_with_dynamic_condition_and_nested_if_expression_with_false
 
     // Verify the callables added to the program.
     let mresetz_callable_id = CallableId(1);
-    assert_callable(&program, mresetz_callable_id, &mresetz_callable());
+    assert_callable(
+        &program,
+        mresetz_callable_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__qis__mresetz__body
+            call_type: Measurement
+            input_type:
+                [0]: Qubit
+                [1]: Result
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
     let read_result_callable_id = CallableId(2);
-    assert_callable(&program, read_result_callable_id, &read_result_callable());
+    assert_callable(
+        &program,
+        read_result_callable_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__qis__read_result__body
+            call_type: Readout
+            input_type:
+                [0]: Result
+            output_type: Boolean
+            body: <NONE>"#]],
+    );
     let op_a_callable_id = CallableId(3);
-    assert_callable(&program, op_a_callable_id, &single_qubit_intrinsic_op_a());
-
-    // Set the IDs of the blocks we want to verify.
-    let initial_block_id = BlockId(0);
-    let continuation_block_id = BlockId(1);
-    let if_block_id = BlockId(2);
-    let else_block_id = BlockId(3);
-
-    // Verify the branch instruction in the initial-block.
-    let condition_var = Variable {
-        variable_id: 1.into(),
-        ty: Ty::Boolean,
-    };
-    let branch_inst = Instruction::Branch(condition_var, if_block_id, else_block_id);
-    assert_block_last_instruction(&program, initial_block_id, &branch_inst);
-
-    // Verify the instructions in the if-block.
-    assert_block_instructions(
+    assert_callable(
         &program,
-        if_block_id,
-        &[
-            Instruction::Call(
-                op_a_callable_id,
-                vec![Operand::Literal(Literal::Qubit(0))],
-                None,
-            ),
-            Instruction::Jump(continuation_block_id),
-        ],
+        op_a_callable_id,
+        &expect![[r#"
+        Callable:
+            name: opA
+            call_type: Regular
+            input_type:
+                [0]: Qubit
+            output_type: <VOID>
+            body: <NONE>"#]],
     );
 
-    // Verify the instructions in the else-block.
-    assert_block_instructions(
+    assert_blocks(
         &program,
-        else_block_id,
-        &[Instruction::Jump(continuation_block_id)],
+        &expect![[r#"
+        Blocks:
+        Block 0:Block:
+            Call id(1), args( Qubit(0), Result(0), )
+            Variable(0, Boolean) = Call id(2), args( Result(0), )
+            Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(true)
+            Branch Variable(1, Boolean), 2, 3
+        Block 1:Block:
+            Call id(4), args( Integer(0), Pointer, )
+            Return
+        Block 2:Block:
+            Call id(3), args( Qubit(0), )
+            Jump(1)
+        Block 3:Block:
+            Jump(1)"#]],
     );
-
-    // Verify the instructions in the continuation-block.
-    assert_block_instructions(&program, continuation_block_id, &[Instruction::Return]);
 }
 
 #[test]
@@ -743,62 +864,69 @@ fn if_expression_with_dynamic_condition_and_nested_if_expression_with_dynamic_co
 
     // Verify the callables added to the program.
     let mresetz_callable_id = CallableId(1);
-    assert_callable(&program, mresetz_callable_id, &mresetz_callable());
+    assert_callable(
+        &program,
+        mresetz_callable_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__qis__mresetz__body
+            call_type: Measurement
+            input_type:
+                [0]: Qubit
+                [1]: Result
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
     let read_result_callable_id = CallableId(2);
-    assert_callable(&program, read_result_callable_id, &read_result_callable());
-    let op_a_callable_id = CallableId(3);
-    assert_callable(&program, op_a_callable_id, &single_qubit_intrinsic_op_a());
-
-    // Set the IDs of the blocks we want to verify.
-    let initial_block_id = BlockId(0);
-    let continuation_block_id = BlockId(1);
-    let if_block_id = BlockId(2);
-    let nested_continuation_block_id = BlockId(3);
-    let nested_if_block_id = BlockId(4);
-
-    // Verify the branch instruction in the initial block.
-    let condition_var = Variable {
-        variable_id: 1.into(),
-        ty: Ty::Boolean,
-    };
-    let branch_inst = Instruction::Branch(condition_var, if_block_id, continuation_block_id);
-    assert_block_last_instruction(&program, initial_block_id, &branch_inst);
-
-    // Verify the branch instruction in the if-block.
-    let nested_condition_var = Variable {
-        variable_id: 3.into(),
-        ty: Ty::Boolean,
-    };
-    let nested_branch_inst = Instruction::Branch(
-        nested_condition_var,
-        nested_if_block_id,
-        nested_continuation_block_id,
+    assert_callable(
+        &program,
+        read_result_callable_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__qis__read_result__body
+            call_type: Readout
+            input_type:
+                [0]: Result
+            output_type: Boolean
+            body: <NONE>"#]],
     );
-    assert_block_last_instruction(&program, if_block_id, &nested_branch_inst);
-
-    // Verify the instructions in the nested-if-block.
-    assert_block_instructions(
+    let op_a_callable_id = CallableId(3);
+    assert_callable(
         &program,
-        nested_if_block_id,
-        &[
-            Instruction::Call(
-                op_a_callable_id,
-                vec![Operand::Literal(Literal::Qubit(2))],
-                None,
-            ),
-            Instruction::Jump(nested_continuation_block_id),
-        ],
+        op_a_callable_id,
+        &expect![[r#"
+        Callable:
+            name: opA
+            call_type: Regular
+            input_type:
+                [0]: Qubit
+            output_type: <VOID>
+            body: <NONE>"#]],
     );
 
-    // Verify the instructions in the nested-continuation-block.
-    assert_block_instructions(
+    assert_blocks(
         &program,
-        nested_continuation_block_id,
-        &[Instruction::Jump(continuation_block_id)],
+        &expect![[r#"
+        Blocks:
+        Block 0:Block:
+            Call id(1), args( Qubit(0), Result(0), )
+            Call id(1), args( Qubit(1), Result(1), )
+            Variable(0, Boolean) = Call id(2), args( Result(0), )
+            Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false)
+            Branch Variable(1, Boolean), 2, 1
+        Block 1:Block:
+            Call id(4), args( Integer(0), Pointer, )
+            Return
+        Block 2:Block:
+            Variable(2, Boolean) = Call id(2), args( Result(1), )
+            Variable(3, Boolean) = Icmp Eq, Variable(2, Boolean), Bool(true)
+            Branch Variable(3, Boolean), 4, 3
+        Block 3:Block:
+            Jump(1)
+        Block 4:Block:
+            Call id(3), args( Qubit(2), )
+            Jump(3)"#]],
     );
-
-    // Verify the instructions in the continuation-block.
-    assert_block_instructions(&program, continuation_block_id, &[Instruction::Return]);
 }
 
 #[allow(clippy::too_many_lines)]
@@ -836,134 +964,123 @@ fn doubly_nested_if_else_expressions_with_dynamic_conditions() {
 
     // Verify the callables added to the program.
     let mresetz_callable_id = CallableId(1);
-    assert_callable(&program, mresetz_callable_id, &mresetz_callable());
-    let read_result_callable_id = CallableId(2);
-    assert_callable(&program, read_result_callable_id, &read_result_callable());
-    let op_a_callable_id = CallableId(3);
-    assert_callable(&program, op_a_callable_id, &single_qubit_intrinsic_op_a());
-    let op_b_callable_id = CallableId(4);
-    assert_callable(&program, op_b_callable_id, &single_qubit_intrinsic_op_b());
-    let op_c_callable_id = CallableId(5);
-    assert_callable(&program, op_c_callable_id, &single_qubit_intrinsic_op_c());
-    let op_d_callable_id = CallableId(6);
-    assert_callable(&program, op_d_callable_id, &single_qubit_intrinsic_op_d());
-
-    // Set the IDs of the blocks we want to verify.
-    let initial_block_id = BlockId(0);
-    let continuation_block_id = BlockId(1);
-    let if_block_id = BlockId(2);
-    let else_block_id = BlockId(6);
-    let first_nested_continuation_block_id = BlockId(3);
-    let first_nested_if_block_id = BlockId(4);
-    let first_nested_else_block_id = BlockId(5);
-    let second_nested_continuation_block_id = BlockId(7);
-    let second_nested_if_block_id = BlockId(8);
-    let second_nested_else_block_id = BlockId(9);
-
-    // Verify the branch instruction in the initial-block.
-    let condition_var = Variable {
-        variable_id: 1.into(),
-        ty: Ty::Boolean,
-    };
-    let branch_inst = Instruction::Branch(condition_var, if_block_id, else_block_id);
-    assert_block_last_instruction(&program, initial_block_id, &branch_inst);
-
-    // Verify the branch instruction in the if-block.
-    let first_nested_condition_var = Variable {
-        variable_id: 3.into(),
-        ty: Ty::Boolean,
-    };
-    let first_nested_branch_inst = Instruction::Branch(
-        first_nested_condition_var,
-        first_nested_if_block_id,
-        first_nested_else_block_id,
-    );
-    assert_block_last_instruction(&program, if_block_id, &first_nested_branch_inst);
-
-    // Verify the instructions in the first nested if-block.
-    assert_block_instructions(
+    assert_callable(
         &program,
-        first_nested_if_block_id,
-        &[
-            Instruction::Call(
-                op_a_callable_id,
-                vec![Operand::Literal(Literal::Qubit(2))],
-                None,
-            ),
-            Instruction::Jump(first_nested_continuation_block_id),
-        ],
+        mresetz_callable_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__qis__mresetz__body
+            call_type: Measurement
+            input_type:
+                [0]: Qubit
+                [1]: Result
+            output_type: <VOID>
+            body: <NONE>"#]],
     );
-
-    // Verify the instructions in the first nested else-block.
-    assert_block_instructions(
+    let read_result_callable_id = CallableId(2);
+    assert_callable(
         &program,
-        first_nested_else_block_id,
-        &[
-            Instruction::Call(
-                op_b_callable_id,
-                vec![Operand::Literal(Literal::Qubit(2))],
-                None,
-            ),
-            Instruction::Jump(first_nested_continuation_block_id),
-        ],
+        read_result_callable_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__qis__read_result__body
+            call_type: Readout
+            input_type:
+                [0]: Result
+            output_type: Boolean
+            body: <NONE>"#]],
     );
-
-    // Verify the instructions in the first nested continuation-block.
-    assert_block_instructions(
+    let op_a_callable_id = CallableId(3);
+    assert_callable(
         &program,
-        first_nested_continuation_block_id,
-        &[Instruction::Jump(continuation_block_id)],
+        op_a_callable_id,
+        &expect![[r#"
+        Callable:
+            name: opA
+            call_type: Regular
+            input_type:
+                [0]: Qubit
+            output_type: <VOID>
+            body: <NONE>"#]],
     );
-
-    // Verify the branch instruction in the else-block.
-    let second_nested_condition_var = Variable {
-        variable_id: 5.into(),
-        ty: Ty::Boolean,
-    };
-    let second_nested_branch_inst = Instruction::Branch(
-        second_nested_condition_var,
-        second_nested_if_block_id,
-        second_nested_else_block_id,
+    let op_b_callable_id = CallableId(4);
+    assert_callable(
+        &program,
+        op_b_callable_id,
+        &expect![[r#"
+        Callable:
+            name: opB
+            call_type: Regular
+            input_type:
+                [0]: Qubit
+            output_type: <VOID>
+            body: <NONE>"#]],
     );
-    assert_block_last_instruction(&program, else_block_id, &second_nested_branch_inst);
-
-    // Verify the instructions in the second nested if-block.
-    assert_block_instructions(
+    let op_c_callable_id = CallableId(5);
+    assert_callable(
         &program,
-        second_nested_if_block_id,
-        &[
-            Instruction::Call(
-                op_c_callable_id,
-                vec![Operand::Literal(Literal::Qubit(2))],
-                None,
-            ),
-            Instruction::Jump(second_nested_continuation_block_id),
-        ],
+        op_c_callable_id,
+        &expect![[r#"
+        Callable:
+            name: opC
+            call_type: Regular
+            input_type:
+                [0]: Qubit
+            output_type: <VOID>
+            body: <NONE>"#]],
     );
-
-    // Verify the instructions in the second nested else-block.
-    assert_block_instructions(
+    let op_d_callable_id = CallableId(6);
+    assert_callable(
         &program,
-        second_nested_else_block_id,
-        &[
-            Instruction::Call(
-                op_d_callable_id,
-                vec![Operand::Literal(Literal::Qubit(2))],
-                None,
-            ),
-            Instruction::Jump(second_nested_continuation_block_id),
-        ],
+        op_d_callable_id,
+        &expect![[r#"
+        Callable:
+            name: opD
+            call_type: Regular
+            input_type:
+                [0]: Qubit
+            output_type: <VOID>
+            body: <NONE>"#]],
     );
 
-    // Verify the instructions in the second nested continuation-block.
-    assert_block_instructions(
+    assert_blocks(
         &program,
-        second_nested_continuation_block_id,
-        &[Instruction::Jump(continuation_block_id)],
+        &expect![[r#"
+        Blocks:
+        Block 0:Block:
+            Call id(1), args( Qubit(0), Result(0), )
+            Call id(1), args( Qubit(1), Result(1), )
+            Variable(0, Boolean) = Call id(2), args( Result(0), )
+            Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false)
+            Branch Variable(1, Boolean), 2, 6
+        Block 1:Block:
+            Call id(7), args( Integer(0), Pointer, )
+            Return
+        Block 2:Block:
+            Variable(2, Boolean) = Call id(2), args( Result(1), )
+            Variable(3, Boolean) = Icmp Eq, Variable(2, Boolean), Bool(false)
+            Branch Variable(3, Boolean), 4, 5
+        Block 3:Block:
+            Jump(1)
+        Block 4:Block:
+            Call id(3), args( Qubit(2), )
+            Jump(3)
+        Block 5:Block:
+            Call id(4), args( Qubit(2), )
+            Jump(3)
+        Block 6:Block:
+            Variable(4, Boolean) = Call id(2), args( Result(1), )
+            Variable(5, Boolean) = Icmp Eq, Variable(4, Boolean), Bool(true)
+            Branch Variable(5, Boolean), 8, 9
+        Block 7:Block:
+            Jump(1)
+        Block 8:Block:
+            Call id(5), args( Qubit(2), )
+            Jump(7)
+        Block 9:Block:
+            Call id(6), args( Qubit(2), )
+            Jump(7)"#]],
     );
-
-    // Verify the instructions in the continuation-block.
-    assert_block_instructions(&program, continuation_block_id, &[Instruction::Return]);
 }
 
 #[test]
@@ -988,53 +1105,75 @@ fn if_expression_with_dynamic_condition_and_subsequent_call_to_operation() {
 
     // Verify the callables added to the program.
     let mresetz_callable_id = CallableId(1);
-    assert_callable(&program, mresetz_callable_id, &mresetz_callable());
+    assert_callable(
+        &program,
+        mresetz_callable_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__qis__mresetz__body
+            call_type: Measurement
+            input_type:
+                [0]: Qubit
+                [1]: Result
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
     let read_result_callable_id = CallableId(2);
-    assert_callable(&program, read_result_callable_id, &read_result_callable());
+    assert_callable(
+        &program,
+        read_result_callable_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__qis__read_result__body
+            call_type: Readout
+            input_type:
+                [0]: Result
+            output_type: Boolean
+            body: <NONE>"#]],
+    );
     let op_a_callable_id = CallableId(3);
-    assert_callable(&program, op_a_callable_id, &single_qubit_intrinsic_op_a());
+    assert_callable(
+        &program,
+        op_a_callable_id,
+        &expect![[r#"
+        Callable:
+            name: opA
+            call_type: Regular
+            input_type:
+                [0]: Qubit
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
     let op_b_callable_id = CallableId(4);
-    assert_callable(&program, op_b_callable_id, &single_qubit_intrinsic_op_b());
-
-    // Set the IDs of the blocks we want to verify.
-    let initial_block_id = BlockId(0);
-    let continuation_block_id = BlockId(1);
-    let if_block_id = BlockId(2);
-
-    // Verify the branch instruction in the initial-block.
-    let condition_var = Variable {
-        variable_id: 1.into(),
-        ty: Ty::Boolean,
-    };
-    let branch_inst = Instruction::Branch(condition_var, if_block_id, continuation_block_id);
-    assert_block_last_instruction(&program, initial_block_id, &branch_inst);
-
-    // Verify the instructions in the if-block.
-    assert_block_instructions(
+    assert_callable(
         &program,
-        if_block_id,
-        &[
-            Instruction::Call(
-                op_a_callable_id,
-                vec![Operand::Literal(Literal::Qubit(0))],
-                None,
-            ),
-            Instruction::Jump(continuation_block_id),
-        ],
+        op_b_callable_id,
+        &expect![[r#"
+        Callable:
+            name: opB
+            call_type: Regular
+            input_type:
+                [0]: Qubit
+            output_type: <VOID>
+            body: <NONE>"#]],
     );
 
-    // Verify the instructions in the continuation-block.
-    assert_block_instructions(
+    assert_blocks(
         &program,
-        continuation_block_id,
-        &[
-            Instruction::Call(
-                op_b_callable_id,
-                vec![Operand::Literal(Literal::Qubit(0))],
-                None,
-            ),
-            Instruction::Return,
-        ],
+        &expect![[r#"
+        Blocks:
+        Block 0:Block:
+            Call id(1), args( Qubit(0), Result(0), )
+            Variable(0, Boolean) = Call id(2), args( Result(0), )
+            Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false)
+            Branch Variable(1, Boolean), 2, 1
+        Block 1:Block:
+            Call id(4), args( Qubit(0), )
+            Call id(5), args( Integer(0), Pointer, )
+            Return
+        Block 2:Block:
+            Call id(3), args( Qubit(0), )
+            Jump(1)"#]],
     );
 }
 
@@ -1063,69 +1202,90 @@ fn if_else_expression_with_dynamic_condition_and_subsequent_call_to_operation()
 
     // Verify the callables added to the program.
     let mresetz_callable_id = CallableId(1);
-    assert_callable(&program, mresetz_callable_id, &mresetz_callable());
+    assert_callable(
+        &program,
+        mresetz_callable_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__qis__mresetz__body
+            call_type: Measurement
+            input_type:
+                [0]: Qubit
+                [1]: Result
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
     let read_result_callable_id = CallableId(2);
-    assert_callable(&program, read_result_callable_id, &read_result_callable());
+    assert_callable(
+        &program,
+        read_result_callable_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__qis__read_result__body
+            call_type: Readout
+            input_type:
+                [0]: Result
+            output_type: Boolean
+            body: <NONE>"#]],
+    );
     let op_a_callable_id = CallableId(3);
-    assert_callable(&program, op_a_callable_id, &single_qubit_intrinsic_op_a());
+    assert_callable(
+        &program,
+        op_a_callable_id,
+        &expect![[r#"
+        Callable:
+            name: opA
+            call_type: Regular
+            input_type:
+                [0]: Qubit
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
     let op_b_callable_id = CallableId(4);
-    assert_callable(&program, op_b_callable_id, &single_qubit_intrinsic_op_b());
-    let op_c_callable_id = CallableId(5);
-    assert_callable(&program, op_c_callable_id, &single_qubit_intrinsic_op_c());
-
-    // Set the IDs of the blocks we want to verify.
-    let initial_block_id = BlockId(0);
-    let continuation_block_id = BlockId(1);
-    let if_block_id = BlockId(2);
-    let else_block_id = BlockId(3);
-
-    // Verify the branch instruction in the initial-block.
-    let condition_var = Variable {
-        variable_id: 1.into(),
-        ty: Ty::Boolean,
-    };
-    let branch_inst = Instruction::Branch(condition_var, if_block_id, else_block_id);
-    assert_block_last_instruction(&program, initial_block_id, &branch_inst);
-
-    // Verify the instructions in the if-block.
-    assert_block_instructions(
+    assert_callable(
         &program,
-        if_block_id,
-        &[
-            Instruction::Call(
-                op_a_callable_id,
-                vec![Operand::Literal(Literal::Qubit(0))],
-                None,
-            ),
-            Instruction::Jump(continuation_block_id),
-        ],
+        op_b_callable_id,
+        &expect![[r#"
+        Callable:
+            name: opB
+            call_type: Regular
+            input_type:
+                [0]: Qubit
+            output_type: <VOID>
+            body: <NONE>"#]],
     );
-
-    // Verify the instructions in the else-block.
-    assert_block_instructions(
+    let op_c_callable_id = CallableId(5);
+    assert_callable(
         &program,
-        else_block_id,
-        &[
-            Instruction::Call(
-                op_b_callable_id,
-                vec![Operand::Literal(Literal::Qubit(0))],
-                None,
-            ),
-            Instruction::Jump(continuation_block_id),
-        ],
+        op_c_callable_id,
+        &expect![[r#"
+        Callable:
+            name: opC
+            call_type: Regular
+            input_type:
+                [0]: Qubit
+            output_type: <VOID>
+            body: <NONE>"#]],
     );
 
-    // Verify the instructions in the continuation-block.
-    assert_block_instructions(
+    assert_blocks(
         &program,
-        continuation_block_id,
-        &[
-            Instruction::Call(
-                op_c_callable_id,
-                vec![Operand::Literal(Literal::Qubit(0))],
-                None,
-            ),
-            Instruction::Return,
-        ],
+        &expect![[r#"
+        Blocks:
+        Block 0:Block:
+            Call id(1), args( Qubit(0), Result(0), )
+            Variable(0, Boolean) = Call id(2), args( Result(0), )
+            Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(true)
+            Branch Variable(1, Boolean), 2, 3
+        Block 1:Block:
+            Call id(5), args( Qubit(0), )
+            Call id(6), args( Integer(0), Pointer, )
+            Return
+        Block 2:Block:
+            Call id(3), args( Qubit(0), )
+            Jump(1)
+        Block 3:Block:
+            Call id(4), args( Qubit(0), )
+            Jump(1)"#]],
     );
 }
diff --git a/compiler/qsc_partial_eval/tests/classical_args.rs b/compiler/qsc_partial_eval/tests/classical_args.rs
index 6bec1ea1..d3a85f67 100644
--- a/compiler/qsc_partial_eval/tests/classical_args.rs
+++ b/compiler/qsc_partial_eval/tests/classical_args.rs
@@ -5,22 +5,11 @@
 
 pub mod test_utils;
 
+use expect_test::expect;
 use indoc::indoc;
-use qsc_rir::rir::{
-    BlockId, Callable, CallableId, CallableType, Instruction, Literal, Operand, Ty,
-};
+use qsc_rir::rir::{BlockId, CallableId};
 use test_utils::{assert_block_instructions, assert_callable, compile_and_partially_evaluate};
 
-fn double_to_unit_intrinsic_op() -> Callable {
-    Callable {
-        name: "op".to_string(),
-        input_type: vec![Ty::Double],
-        output_type: None,
-        body: None,
-        call_type: CallableType::Regular,
-    }
-}
-
 #[test]
 fn call_to_intrinsic_operation_using_double_literal() {
     let program = compile_and_partially_evaluate(indoc! {r#"
@@ -33,18 +22,26 @@ fn call_to_intrinsic_operation_using_double_literal() {
         }
     "#});
     let op_callable_id = CallableId(1);
-    assert_callable(&program, op_callable_id, &double_to_unit_intrinsic_op());
+    assert_callable(
+        &program,
+        op_callable_id,
+        &expect![[r#"
+        Callable:
+            name: op
+            call_type: Regular
+            input_type:
+                [0]: Double
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
     assert_block_instructions(
         &program,
         BlockId(0),
-        &[
-            Instruction::Call(
-                op_callable_id,
-                vec![Operand::Literal(Literal::Double(1.0))],
-                None,
-            ),
-            Instruction::Return,
-        ],
+        &expect![[r#"
+            Block:
+                Call id(1), args( Double(1), )
+                Call id(2), args( Integer(0), Pointer, )
+                Return"#]],
     );
 }
 
@@ -63,28 +60,28 @@ fn calls_to_intrinsic_operation_using_inline_expressions() {
         }
     "#});
     let op_callable_id = CallableId(1);
-    assert_callable(&program, op_callable_id, &double_to_unit_intrinsic_op());
+    assert_callable(
+        &program,
+        op_callable_id,
+        &expect![[r#"
+        Callable:
+            name: op
+            call_type: Regular
+            input_type:
+                [0]: Double
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
     assert_block_instructions(
         &program,
         BlockId(0),
-        &[
-            Instruction::Call(
-                op_callable_id,
-                vec![Operand::Literal(Literal::Double(0.0))],
-                None,
-            ),
-            Instruction::Call(
-                op_callable_id,
-                vec![Operand::Literal(Literal::Double(1.0))],
-                None,
-            ),
-            Instruction::Call(
-                op_callable_id,
-                vec![Operand::Literal(Literal::Double(1.0))],
-                None,
-            ),
-            Instruction::Return,
-        ],
+        &expect![[r#"
+            Block:
+                Call id(1), args( Double(0), )
+                Call id(1), args( Double(1), )
+                Call id(1), args( Double(1), )
+                Call id(2), args( Integer(0), Pointer, )
+                Return"#]],
     );
 }
 
@@ -106,27 +103,27 @@ fn calls_to_intrinsic_operation_using_variables() {
         }
     "#});
     let op_callable_id = CallableId(1);
-    assert_callable(&program, op_callable_id, &double_to_unit_intrinsic_op());
+    assert_callable(
+        &program,
+        op_callable_id,
+        &expect![[r#"
+        Callable:
+            name: op
+            call_type: Regular
+            input_type:
+                [0]: Double
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
     assert_block_instructions(
         &program,
         BlockId(0),
-        &[
-            Instruction::Call(
-                op_callable_id,
-                vec![Operand::Literal(Literal::Double(2.0))],
-                None,
-            ),
-            Instruction::Call(
-                op_callable_id,
-                vec![Operand::Literal(Literal::Double(4.0))],
-                None,
-            ),
-            Instruction::Call(
-                op_callable_id,
-                vec![Operand::Literal(Literal::Double(8.0))],
-                None,
-            ),
-            Instruction::Return,
-        ],
+        &expect![[r#"
+            Block:
+                Call id(1), args( Double(2), )
+                Call id(1), args( Double(4), )
+                Call id(1), args( Double(8), )
+                Call id(2), args( Integer(0), Pointer, )
+                Return"#]],
     );
 }
diff --git a/compiler/qsc_partial_eval/tests/dynamic_vars.rs b/compiler/qsc_partial_eval/tests/dynamic_vars.rs
index 8d44fd8e..a3c9c7b7 100644
--- a/compiler/qsc_partial_eval/tests/dynamic_vars.rs
+++ b/compiler/qsc_partial_eval/tests/dynamic_vars.rs
@@ -5,12 +5,12 @@
 
 pub mod test_utils;
 
+use expect_test::expect;
 use indoc::indoc;
-use qsc_rir::rir::{BlockId, CallableId, Instruction, Literal, Operand, Ty, Variable};
-use test_utils::{
-    assert_block_instructions, assert_block_last_instruction, assert_callable,
-    compile_and_partially_evaluate, mresetz_callable, read_result_callable,
-};
+use qsc_rir::rir::CallableId;
+use test_utils::{assert_callable, compile_and_partially_evaluate};
+
+use crate::test_utils::assert_blocks;
 
 #[test]
 fn dynamic_int_from_if_expression_with_single_measurement_comparison_and_classical_blocks() {
@@ -30,52 +30,52 @@ fn dynamic_int_from_if_expression_with_single_measurement_comparison_and_classic
 
     // Verify the callables added to the program.
     let mresetz_callable_id = CallableId(1);
-    assert_callable(&program, mresetz_callable_id, &mresetz_callable());
+    assert_callable(
+        &program,
+        mresetz_callable_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__qis__mresetz__body
+            call_type: Measurement
+            input_type:
+                [0]: Qubit
+                [1]: Result
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
     let read_result_callable_id = CallableId(2);
-    assert_callable(&program, read_result_callable_id, &read_result_callable());
-
-    // Set the IDs of the blocks we want to verify.
-    let initial_block_id = BlockId(0);
-    let continuation_block_id = BlockId(1);
-    let if_block_id = BlockId(2);
-    let else_block_id = BlockId(3);
-
-    // Verify the branch instruction in the initial-block.
-    let condition_var = Variable {
-        variable_id: 1.into(),
-        ty: Ty::Boolean,
-    };
-    let branch_inst = Instruction::Branch(condition_var, if_block_id, else_block_id);
-    assert_block_last_instruction(&program, initial_block_id, &branch_inst);
-
-    // Create the expected variable that will hold the dynamic integer value.
-    let dynamic_int_var = Variable {
-        variable_id: 2.into(),
-        ty: Ty::Integer,
-    };
-
-    // Verify the instructions in the if-block.
-    assert_block_instructions(
+    assert_callable(
         &program,
-        if_block_id,
-        &[
-            Instruction::Store(Operand::Literal(Literal::Integer(0)), dynamic_int_var),
-            Instruction::Jump(continuation_block_id),
-        ],
+        read_result_callable_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__qis__read_result__body
+            call_type: Readout
+            input_type:
+                [0]: Result
+            output_type: Boolean
+            body: <NONE>"#]],
     );
 
-    // Verify the instructions in the else-block.
-    assert_block_instructions(
+    assert_blocks(
         &program,
-        else_block_id,
-        &[
-            Instruction::Store(Operand::Literal(Literal::Integer(1)), dynamic_int_var),
-            Instruction::Jump(continuation_block_id),
-        ],
+        &expect![[r#"
+        Blocks:
+        Block 0:Block:
+            Call id(1), args( Qubit(0), Result(0), )
+            Variable(0, Boolean) = Call id(2), args( Result(0), )
+            Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false)
+            Branch Variable(1, Boolean), 2, 3
+        Block 1:Block:
+            Call id(3), args( Integer(0), Pointer, )
+            Return
+        Block 2:Block:
+            Variable(2, Integer) = Store Integer(0)
+            Jump(1)
+        Block 3:Block:
+            Variable(2, Integer) = Store Integer(1)
+            Jump(1)"#]],
     );
-
-    // Verify the instructions in the continuation-block.
-    assert_block_instructions(&program, continuation_block_id, &[Instruction::Return]);
 }
 
 #[test]
diff --git a/compiler/qsc_partial_eval/tests/intrinsics.rs b/compiler/qsc_partial_eval/tests/intrinsics.rs
index 6dbcf796..4408d768 100644
--- a/compiler/qsc_partial_eval/tests/intrinsics.rs
+++ b/compiler/qsc_partial_eval/tests/intrinsics.rs
@@ -5,14 +5,15 @@
 
 pub mod test_utils;
 
+use expect_test::{expect, Expect};
 use indoc::{formatdoc, indoc};
-use qsc_rir::rir::{
-    BlockId, Callable, CallableId, CallableType, Instruction, Literal, Operand, Ty,
-};
+use qsc_rir::rir::{BlockId, CallableId};
 use test_utils::{assert_block_instructions, assert_callable, compile_and_partially_evaluate};
 
 fn check_call_to_single_qubit_instrinsic_adds_callable_and_generates_instruction(
     intrinsic_name: &str,
+    expected_callable: &Expect,
+    expected_block: &Expect,
 ) {
     let program = compile_and_partially_evaluate(
         formatdoc! {
@@ -30,27 +31,14 @@ fn check_call_to_single_qubit_instrinsic_adds_callable_and_generates_instruction
         .as_str(),
     );
     let op_callable_id = CallableId(1);
-    assert_callable(
-        &program,
-        op_callable_id,
-        &single_qubit_intrinsic_op(intrinsic_name),
-    );
-    assert_block_instructions(
-        &program,
-        BlockId(0),
-        &[
-            Instruction::Call(
-                op_callable_id,
-                vec![Operand::Literal(Literal::Qubit(0))],
-                None,
-            ),
-            Instruction::Return,
-        ],
-    );
+    assert_callable(&program, op_callable_id, expected_callable);
+    assert_block_instructions(&program, BlockId(0), expected_block);
 }
 
 fn check_call_to_single_qubit_rotation_instrinsic_adds_callable_and_generates_instruction(
     intrinsic_name: &str,
+    expected_callable: &Expect,
+    expected_block: &Expect,
 ) {
     let program = compile_and_partially_evaluate(
         formatdoc! {
@@ -68,30 +56,14 @@ fn check_call_to_single_qubit_rotation_instrinsic_adds_callable_and_generates_in
         .as_str(),
     );
     let op_callable_id = CallableId(1);
-    assert_callable(
-        &program,
-        op_callable_id,
-        &single_qubit_rotation_intrinsic_op(intrinsic_name),
-    );
-    assert_block_instructions(
-        &program,
-        BlockId(0),
-        &[
-            Instruction::Call(
-                op_callable_id,
-                vec![
-                    Operand::Literal(Literal::Double(0.0)),
-                    Operand::Literal(Literal::Qubit(0)),
-                ],
-                None,
-            ),
-            Instruction::Return,
-        ],
-    );
+    assert_callable(&program, op_callable_id, expected_callable);
+    assert_block_instructions(&program, BlockId(0), expected_block);
 }
 
 fn check_call_to_two_qubits_rotation_instrinsic_adds_callable_and_generates_instruction(
     intrinsic_name: &str,
+    expected_callable: &Expect,
+    expected_block: &Expect,
 ) {
     let program = compile_and_partially_evaluate(
         formatdoc! {
@@ -109,31 +81,14 @@ fn check_call_to_two_qubits_rotation_instrinsic_adds_callable_and_generates_inst
         .as_str(),
     );
     let op_callable_id = CallableId(1);
-    assert_callable(
-        &program,
-        op_callable_id,
-        &two_qubits_rotation_intrinsic_op(intrinsic_name),
-    );
-    assert_block_instructions(
-        &program,
-        BlockId(0),
-        &[
-            Instruction::Call(
-                op_callable_id,
-                vec![
-                    Operand::Literal(Literal::Double(0.0)),
-                    Operand::Literal(Literal::Qubit(0)),
-                    Operand::Literal(Literal::Qubit(1)),
-                ],
-                None,
-            ),
-            Instruction::Return,
-        ],
-    );
+    assert_callable(&program, op_callable_id, expected_callable);
+    assert_block_instructions(&program, BlockId(0), expected_block);
 }
 
 fn check_call_to_two_qubits_instrinsic_adds_callable_and_generates_instruction(
     intrinsic_name: &str,
+    expected_callable: &Expect,
+    expected_block: &Expect,
 ) {
     let program = compile_and_partially_evaluate(
         formatdoc! {
@@ -151,30 +106,14 @@ fn check_call_to_two_qubits_instrinsic_adds_callable_and_generates_instruction(
         .as_str(),
     );
     let op_callable_id = CallableId(1);
-    assert_callable(
-        &program,
-        op_callable_id,
-        &two_qubits_intrinsic_op(intrinsic_name),
-    );
-    assert_block_instructions(
-        &program,
-        BlockId(0),
-        &[
-            Instruction::Call(
-                op_callable_id,
-                vec![
-                    Operand::Literal(Literal::Qubit(0)),
-                    Operand::Literal(Literal::Qubit(1)),
-                ],
-                None,
-            ),
-            Instruction::Return,
-        ],
-    );
+    assert_callable(&program, op_callable_id, expected_callable);
+    assert_block_instructions(&program, BlockId(0), expected_block);
 }
 
 fn check_call_to_three_qubits_instrinsic_adds_callable_and_generates_instruction(
     intrinsic_name: &str,
+    expected_callable: &Expect,
+    expected_block: &Expect,
 ) {
     let program = compile_and_partially_evaluate(
         formatdoc! {
@@ -192,103 +131,27 @@ fn check_call_to_three_qubits_instrinsic_adds_callable_and_generates_instruction
         .as_str(),
     );
     let op_callable_id = CallableId(1);
-    assert_callable(
-        &program,
-        op_callable_id,
-        &three_qubits_intrinsic_op(intrinsic_name),
-    );
-    assert_block_instructions(
-        &program,
-        BlockId(0),
-        &[
-            Instruction::Call(
-                op_callable_id,
-                vec![
-                    Operand::Literal(Literal::Qubit(0)),
-                    Operand::Literal(Literal::Qubit(1)),
-                    Operand::Literal(Literal::Qubit(2)),
-                ],
-                None,
-            ),
-            Instruction::Return,
-        ],
-    );
-}
-
-fn measurement_intrinsic_op(name: &str) -> Callable {
-    Callable {
-        name: name.to_string(),
-        input_type: vec![Ty::Qubit, Ty::Result],
-        output_type: None,
-        body: None,
-        call_type: CallableType::Measurement,
-    }
-}
-
-fn reset_intrinsic_op() -> Callable {
-    Callable {
-        name: "__quantum__qis__reset__body".to_string(),
-        input_type: vec![Ty::Qubit],
-        output_type: None,
-        body: None,
-        call_type: CallableType::Reset,
-    }
-}
-
-fn single_qubit_intrinsic_op(name: &str) -> Callable {
-    Callable {
-        name: name.to_string(),
-        input_type: vec![Ty::Qubit],
-        output_type: None,
-        body: None,
-        call_type: CallableType::Regular,
-    }
-}
-
-fn single_qubit_rotation_intrinsic_op(name: &str) -> Callable {
-    Callable {
-        name: name.to_string(),
-        input_type: vec![Ty::Double, Ty::Qubit],
-        output_type: None,
-        body: None,
-        call_type: CallableType::Regular,
-    }
-}
-
-fn two_qubits_intrinsic_op(name: &str) -> Callable {
-    Callable {
-        name: name.to_string(),
-        input_type: vec![Ty::Qubit, Ty::Qubit],
-        output_type: None,
-        body: None,
-        call_type: CallableType::Regular,
-    }
-}
-
-fn two_qubits_rotation_intrinsic_op(name: &str) -> Callable {
-    Callable {
-        name: name.to_string(),
-        input_type: vec![Ty::Double, Ty::Qubit, Ty::Qubit],
-        output_type: None,
-        body: None,
-        call_type: CallableType::Regular,
-    }
-}
-
-fn three_qubits_intrinsic_op(name: &str) -> Callable {
-    Callable {
-        name: name.to_string(),
-        input_type: vec![Ty::Qubit, Ty::Qubit, Ty::Qubit],
-        output_type: None,
-        body: None,
-        call_type: CallableType::Regular,
-    }
+    assert_callable(&program, op_callable_id, expected_callable);
+    assert_block_instructions(&program, BlockId(0), expected_block);
 }
 
 #[test]
 fn call_to_intrinsic_h_adds_callable_and_generates_instruction() {
     check_call_to_single_qubit_instrinsic_adds_callable_and_generates_instruction(
         "__quantum__qis__h__body",
+        &expect![[r#"
+            Callable:
+                name: __quantum__qis__h__body
+                call_type: Regular
+                input_type:
+                    [0]: Qubit
+                output_type: <VOID>
+                body: <NONE>"#]],
+        &expect![[r#"
+            Block:
+                Call id(1), args( Qubit(0), )
+                Call id(2), args( Integer(0), Pointer, )
+                Return"#]],
     );
 }
 
@@ -296,6 +159,19 @@ fn call_to_intrinsic_h_adds_callable_and_generates_instruction() {
 fn call_to_intrinsic_s_adds_callable_and_generates_instruction() {
     check_call_to_single_qubit_instrinsic_adds_callable_and_generates_instruction(
         "__quantum__qis__s__body",
+        &expect![[r#"
+            Callable:
+                name: __quantum__qis__s__body
+                call_type: Regular
+                input_type:
+                    [0]: Qubit
+                output_type: <VOID>
+                body: <NONE>"#]],
+        &expect![[r#"
+            Block:
+                Call id(1), args( Qubit(0), )
+                Call id(2), args( Integer(0), Pointer, )
+                Return"#]],
     );
 }
 
@@ -303,6 +179,19 @@ fn call_to_intrinsic_s_adds_callable_and_generates_instruction() {
 fn call_to_intrinsic_adjoint_s_adds_callable_and_generates_instruction() {
     check_call_to_single_qubit_instrinsic_adds_callable_and_generates_instruction(
         "__quantum__qis__s__adj",
+        &expect![[r#"
+            Callable:
+                name: __quantum__qis__s__adj
+                call_type: Regular
+                input_type:
+                    [0]: Qubit
+                output_type: <VOID>
+                body: <NONE>"#]],
+        &expect![[r#"
+            Block:
+                Call id(1), args( Qubit(0), )
+                Call id(2), args( Integer(0), Pointer, )
+                Return"#]],
     );
 }
 
@@ -310,6 +199,19 @@ fn call_to_intrinsic_adjoint_s_adds_callable_and_generates_instruction() {
 fn call_to_intrinsic_t_adds_callable_and_generates_instruction() {
     check_call_to_single_qubit_instrinsic_adds_callable_and_generates_instruction(
         "__quantum__qis__t__body",
+        &expect![[r#"
+            Callable:
+                name: __quantum__qis__t__body
+                call_type: Regular
+                input_type:
+                    [0]: Qubit
+                output_type: <VOID>
+                body: <NONE>"#]],
+        &expect![[r#"
+            Block:
+                Call id(1), args( Qubit(0), )
+                Call id(2), args( Integer(0), Pointer, )
+                Return"#]],
     );
 }
 
@@ -317,6 +219,19 @@ fn call_to_intrinsic_t_adds_callable_and_generates_instruction() {
 fn call_to_intrinsic_adjoint_t_adds_callable_and_generates_instruction() {
     check_call_to_single_qubit_instrinsic_adds_callable_and_generates_instruction(
         "__quantum__qis__t__adj",
+        &expect![[r#"
+            Callable:
+                name: __quantum__qis__t__adj
+                call_type: Regular
+                input_type:
+                    [0]: Qubit
+                output_type: <VOID>
+                body: <NONE>"#]],
+        &expect![[r#"
+            Block:
+                Call id(1), args( Qubit(0), )
+                Call id(2), args( Integer(0), Pointer, )
+                Return"#]],
     );
 }
 
@@ -324,6 +239,19 @@ fn call_to_intrinsic_adjoint_t_adds_callable_and_generates_instruction() {
 fn call_to_intrinsic_x_adds_callable_and_generates_instruction() {
     check_call_to_single_qubit_instrinsic_adds_callable_and_generates_instruction(
         "__quantum__qis__x__body",
+        &expect![[r#"
+            Callable:
+                name: __quantum__qis__x__body
+                call_type: Regular
+                input_type:
+                    [0]: Qubit
+                output_type: <VOID>
+                body: <NONE>"#]],
+        &expect![[r#"
+            Block:
+                Call id(1), args( Qubit(0), )
+                Call id(2), args( Integer(0), Pointer, )
+                Return"#]],
     );
 }
 
@@ -331,6 +259,19 @@ fn call_to_intrinsic_x_adds_callable_and_generates_instruction() {
 fn call_to_intrinsic_y_adds_callable_and_generates_instruction() {
     check_call_to_single_qubit_instrinsic_adds_callable_and_generates_instruction(
         "__quantum__qis__y__body",
+        &expect![[r#"
+            Callable:
+                name: __quantum__qis__y__body
+                call_type: Regular
+                input_type:
+                    [0]: Qubit
+                output_type: <VOID>
+                body: <NONE>"#]],
+        &expect![[r#"
+            Block:
+                Call id(1), args( Qubit(0), )
+                Call id(2), args( Integer(0), Pointer, )
+                Return"#]],
     );
 }
 
@@ -338,6 +279,19 @@ fn call_to_intrinsic_y_adds_callable_and_generates_instruction() {
 fn call_to_intrinsic_z_adds_callable_and_generates_instruction() {
     check_call_to_single_qubit_instrinsic_adds_callable_and_generates_instruction(
         "__quantum__qis__z__body",
+        &expect![[r#"
+            Callable:
+                name: __quantum__qis__z__body
+                call_type: Regular
+                input_type:
+                    [0]: Qubit
+                output_type: <VOID>
+                body: <NONE>"#]],
+        &expect![[r#"
+            Block:
+                Call id(1), args( Qubit(0), )
+                Call id(2), args( Integer(0), Pointer, )
+                Return"#]],
     );
 }
 
@@ -345,6 +299,20 @@ fn call_to_intrinsic_z_adds_callable_and_generates_instruction() {
 fn call_to_intrinsic_swap_adds_callable_and_generates_instruction() {
     check_call_to_two_qubits_instrinsic_adds_callable_and_generates_instruction(
         "__quantum__qis__swap__body",
+        &expect![[r#"
+            Callable:
+                name: __quantum__qis__swap__body
+                call_type: Regular
+                input_type:
+                    [0]: Qubit
+                    [1]: Qubit
+                output_type: <VOID>
+                body: <NONE>"#]],
+        &expect![[r#"
+            Block:
+                Call id(1), args( Qubit(0), Qubit(1), )
+                Call id(2), args( Integer(0), Pointer, )
+                Return"#]],
     );
 }
 
@@ -352,6 +320,20 @@ fn call_to_intrinsic_swap_adds_callable_and_generates_instruction() {
 fn call_to_intrinsic_cx_adds_callable_and_generates_instruction() {
     check_call_to_two_qubits_instrinsic_adds_callable_and_generates_instruction(
         "__quantum__qis__cx__body",
+        &expect![[r#"
+            Callable:
+                name: __quantum__qis__cx__body
+                call_type: Regular
+                input_type:
+                    [0]: Qubit
+                    [1]: Qubit
+                output_type: <VOID>
+                body: <NONE>"#]],
+        &expect![[r#"
+            Block:
+                Call id(1), args( Qubit(0), Qubit(1), )
+                Call id(2), args( Integer(0), Pointer, )
+                Return"#]],
     );
 }
 
@@ -359,6 +341,20 @@ fn call_to_intrinsic_cx_adds_callable_and_generates_instruction() {
 fn call_to_intrinsic_cy_adds_callable_and_generates_instruction() {
     check_call_to_two_qubits_instrinsic_adds_callable_and_generates_instruction(
         "__quantum__qis__cy__body",
+        &expect![[r#"
+            Callable:
+                name: __quantum__qis__cy__body
+                call_type: Regular
+                input_type:
+                    [0]: Qubit
+                    [1]: Qubit
+                output_type: <VOID>
+                body: <NONE>"#]],
+        &expect![[r#"
+            Block:
+                Call id(1), args( Qubit(0), Qubit(1), )
+                Call id(2), args( Integer(0), Pointer, )
+                Return"#]],
     );
 }
 
@@ -366,6 +362,20 @@ fn call_to_intrinsic_cy_adds_callable_and_generates_instruction() {
 fn call_to_intrinsic_cz_adds_callable_and_generates_instruction() {
     check_call_to_two_qubits_instrinsic_adds_callable_and_generates_instruction(
         "__quantum__qis__cz__body",
+        &expect![[r#"
+            Callable:
+                name: __quantum__qis__cz__body
+                call_type: Regular
+                input_type:
+                    [0]: Qubit
+                    [1]: Qubit
+                output_type: <VOID>
+                body: <NONE>"#]],
+        &expect![[r#"
+            Block:
+                Call id(1), args( Qubit(0), Qubit(1), )
+                Call id(2), args( Integer(0), Pointer, )
+                Return"#]],
     );
 }
 
@@ -373,6 +383,21 @@ fn call_to_intrinsic_cz_adds_callable_and_generates_instruction() {
 fn call_to_intrinsic_ccx_adds_callable_and_generates_instruction() {
     check_call_to_three_qubits_instrinsic_adds_callable_and_generates_instruction(
         "__quantum__qis__ccx__body",
+        &expect![[r#"
+            Callable:
+                name: __quantum__qis__ccx__body
+                call_type: Regular
+                input_type:
+                    [0]: Qubit
+                    [1]: Qubit
+                    [2]: Qubit
+                output_type: <VOID>
+                body: <NONE>"#]],
+        &expect![[r#"
+            Block:
+                Call id(1), args( Qubit(0), Qubit(1), Qubit(2), )
+                Call id(2), args( Integer(0), Pointer, )
+                Return"#]],
     );
 }
 
@@ -380,6 +405,20 @@ fn call_to_intrinsic_ccx_adds_callable_and_generates_instruction() {
 fn call_to_intrinsic_rx_adds_callable_and_generates_instruction() {
     check_call_to_single_qubit_rotation_instrinsic_adds_callable_and_generates_instruction(
         "__quantum__qis__rx__body",
+        &expect![[r#"
+            Callable:
+                name: __quantum__qis__rx__body
+                call_type: Regular
+                input_type:
+                    [0]: Double
+                    [1]: Qubit
+                output_type: <VOID>
+                body: <NONE>"#]],
+        &expect![[r#"
+            Block:
+                Call id(1), args( Double(0), Qubit(0), )
+                Call id(2), args( Integer(0), Pointer, )
+                Return"#]],
     );
 }
 
@@ -387,6 +426,21 @@ fn call_to_intrinsic_rx_adds_callable_and_generates_instruction() {
 fn call_to_intrinsic_rxx_adds_callable_and_generates_instruction() {
     check_call_to_two_qubits_rotation_instrinsic_adds_callable_and_generates_instruction(
         "__quantum__qis__rxx__body",
+        &expect![[r#"
+            Callable:
+                name: __quantum__qis__rxx__body
+                call_type: Regular
+                input_type:
+                    [0]: Double
+                    [1]: Qubit
+                    [2]: Qubit
+                output_type: <VOID>
+                body: <NONE>"#]],
+        &expect![[r#"
+            Block:
+                Call id(1), args( Double(0), Qubit(0), Qubit(1), )
+                Call id(2), args( Integer(0), Pointer, )
+                Return"#]],
     );
 }
 
@@ -394,6 +448,20 @@ fn call_to_intrinsic_rxx_adds_callable_and_generates_instruction() {
 fn call_to_intrinsic_ry_adds_callable_and_generates_instruction() {
     check_call_to_single_qubit_rotation_instrinsic_adds_callable_and_generates_instruction(
         "__quantum__qis__ry__body",
+        &expect![[r#"
+            Callable:
+                name: __quantum__qis__ry__body
+                call_type: Regular
+                input_type:
+                    [0]: Double
+                    [1]: Qubit
+                output_type: <VOID>
+                body: <NONE>"#]],
+        &expect![[r#"
+            Block:
+                Call id(1), args( Double(0), Qubit(0), )
+                Call id(2), args( Integer(0), Pointer, )
+                Return"#]],
     );
 }
 
@@ -401,6 +469,21 @@ fn call_to_intrinsic_ry_adds_callable_and_generates_instruction() {
 fn call_to_intrinsic_ryy_adds_callable_and_generates_instruction() {
     check_call_to_two_qubits_rotation_instrinsic_adds_callable_and_generates_instruction(
         "__quantum__qis__ryy__body",
+        &expect![[r#"
+            Callable:
+                name: __quantum__qis__ryy__body
+                call_type: Regular
+                input_type:
+                    [0]: Double
+                    [1]: Qubit
+                    [2]: Qubit
+                output_type: <VOID>
+                body: <NONE>"#]],
+        &expect![[r#"
+            Block:
+                Call id(1), args( Double(0), Qubit(0), Qubit(1), )
+                Call id(2), args( Integer(0), Pointer, )
+                Return"#]],
     );
 }
 
@@ -408,6 +491,20 @@ fn call_to_intrinsic_ryy_adds_callable_and_generates_instruction() {
 fn call_to_intrinsic_rz_adds_callable_and_generates_instruction() {
     check_call_to_single_qubit_rotation_instrinsic_adds_callable_and_generates_instruction(
         "__quantum__qis__rz__body",
+        &expect![[r#"
+            Callable:
+                name: __quantum__qis__rz__body
+                call_type: Regular
+                input_type:
+                    [0]: Double
+                    [1]: Qubit
+                output_type: <VOID>
+                body: <NONE>"#]],
+        &expect![[r#"
+            Block:
+                Call id(1), args( Double(0), Qubit(0), )
+                Call id(2), args( Integer(0), Pointer, )
+                Return"#]],
     );
 }
 
@@ -415,6 +512,21 @@ fn call_to_intrinsic_rz_adds_callable_and_generates_instruction() {
 fn call_to_intrinsic_rzz_adds_callable_and_generates_instruction() {
     check_call_to_two_qubits_rotation_instrinsic_adds_callable_and_generates_instruction(
         "__quantum__qis__rzz__body",
+        &expect![[r#"
+            Callable:
+                name: __quantum__qis__rzz__body
+                call_type: Regular
+                input_type:
+                    [0]: Double
+                    [1]: Qubit
+                    [2]: Qubit
+                output_type: <VOID>
+                body: <NONE>"#]],
+        &expect![[r#"
+            Block:
+                Call id(1), args( Double(0), Qubit(0), Qubit(1), )
+                Call id(2), args( Integer(0), Pointer, )
+                Return"#]],
     );
 }
 
@@ -432,18 +544,26 @@ fn check_partial_eval_for_call_to_reset() {
         "#,
     });
     let op_callable_id = CallableId(1);
-    assert_callable(&program, op_callable_id, &reset_intrinsic_op());
+    assert_callable(
+        &program,
+        op_callable_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__qis__reset__body
+            call_type: Reset
+            input_type:
+                [0]: Qubit
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
     assert_block_instructions(
         &program,
         BlockId(0),
-        &[
-            Instruction::Call(
-                op_callable_id,
-                vec![Operand::Literal(Literal::Qubit(0))],
-                None,
-            ),
-            Instruction::Return,
-        ],
+        &expect![[r#"
+            Block:
+                Call id(1), args( Qubit(0), )
+                Call id(2), args( Integer(0), Pointer, )
+                Return"#]],
     );
 }
 
@@ -464,22 +584,24 @@ fn call_to_intrinsic_m_adds_callable_and_generates_instruction() {
     assert_callable(
         &program,
         op_callable_id,
-        &measurement_intrinsic_op("__quantum__qis__mz__body"),
+        &expect![[r#"
+        Callable:
+            name: __quantum__qis__mz__body
+            call_type: Measurement
+            input_type:
+                [0]: Qubit
+                [1]: Result
+            output_type: <VOID>
+            body: <NONE>"#]],
     );
     assert_block_instructions(
         &program,
         BlockId(0),
-        &[
-            Instruction::Call(
-                op_callable_id,
-                vec![
-                    Operand::Literal(Literal::Qubit(0)),
-                    Operand::Literal(Literal::Result(0)),
-                ],
-                None,
-            ),
-            Instruction::Return,
-        ],
+        &expect![[r#"
+            Block:
+                Call id(1), args( Qubit(0), Result(0), )
+                Call id(2), args( Integer(0), Pointer, )
+                Return"#]],
     );
 }
 
@@ -500,21 +622,23 @@ fn call_to_intrinsic_mresetz_adds_callable_and_generates_instruction() {
     assert_callable(
         &program,
         op_callable_id,
-        &measurement_intrinsic_op("__quantum__qis__mresetz__body"),
+        &expect![[r#"
+        Callable:
+            name: __quantum__qis__mresetz__body
+            call_type: Measurement
+            input_type:
+                [0]: Qubit
+                [1]: Result
+            output_type: <VOID>
+            body: <NONE>"#]],
     );
     assert_block_instructions(
         &program,
         BlockId(0),
-        &[
-            Instruction::Call(
-                op_callable_id,
-                vec![
-                    Operand::Literal(Literal::Qubit(0)),
-                    Operand::Literal(Literal::Result(0)),
-                ],
-                None,
-            ),
-            Instruction::Return,
-        ],
+        &expect![[r#"
+            Block:
+                Call id(1), args( Qubit(0), Result(0), )
+                Call id(2), args( Integer(0), Pointer, )
+                Return"#]],
     );
 }
diff --git a/compiler/qsc_partial_eval/tests/loops.rs b/compiler/qsc_partial_eval/tests/loops.rs
index 24f44372..541e143a 100644
--- a/compiler/qsc_partial_eval/tests/loops.rs
+++ b/compiler/qsc_partial_eval/tests/loops.rs
@@ -5,32 +5,11 @@
 
 pub mod test_utils;
 
+use expect_test::expect;
 use indoc::indoc;
-use qsc_rir::rir::{
-    BlockId, Callable, CallableId, CallableType, Instruction, Literal, Operand, Ty,
-};
+use qsc_rir::rir::{BlockId, CallableId};
 use test_utils::{assert_block_instructions, assert_callable, compile_and_partially_evaluate};
 
-fn single_qubit_intrinsic() -> Callable {
-    Callable {
-        name: "op".to_string(),
-        input_type: vec![Ty::Qubit],
-        output_type: None,
-        body: None,
-        call_type: CallableType::Regular,
-    }
-}
-
-fn single_qubit_rotation_intrinsic() -> Callable {
-    Callable {
-        name: "rotation".to_string(),
-        input_type: vec![Ty::Double, Ty::Qubit],
-        output_type: None,
-        body: None,
-        call_type: CallableType::Regular,
-    }
-}
-
 #[test]
 fn unitary_call_within_a_for_loop() {
     let program = compile_and_partially_evaluate(indoc! {
@@ -49,28 +28,28 @@ fn unitary_call_within_a_for_loop() {
     });
 
     let op_callable_id = CallableId(1);
-    assert_callable(&program, op_callable_id, &single_qubit_intrinsic());
+    assert_callable(
+        &program,
+        op_callable_id,
+        &expect![[r#"
+        Callable:
+            name: op
+            call_type: Regular
+            input_type:
+                [0]: Qubit
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
     assert_block_instructions(
         &program,
         BlockId(0),
-        &[
-            Instruction::Call(
-                op_callable_id,
-                vec![Operand::Literal(Literal::Qubit(0))],
-                None,
-            ),
-            Instruction::Call(
-                op_callable_id,
-                vec![Operand::Literal(Literal::Qubit(0))],
-                None,
-            ),
-            Instruction::Call(
-                op_callable_id,
-                vec![Operand::Literal(Literal::Qubit(0))],
-                None,
-            ),
-            Instruction::Return,
-        ],
+        &expect![[r#"
+            Block:
+                Call id(1), args( Qubit(0), )
+                Call id(1), args( Qubit(0), )
+                Call id(1), args( Qubit(0), )
+                Call id(2), args( Integer(0), Pointer, )
+                Return"#]],
     );
 }
 
@@ -94,28 +73,28 @@ fn unitary_call_within_a_while_loop() {
     });
 
     let rotation_callable_id = CallableId(1);
-    assert_callable(&program, rotation_callable_id, &single_qubit_intrinsic());
+    assert_callable(
+        &program,
+        rotation_callable_id,
+        &expect![[r#"
+        Callable:
+            name: op
+            call_type: Regular
+            input_type:
+                [0]: Qubit
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
     assert_block_instructions(
         &program,
         BlockId(0),
-        &[
-            Instruction::Call(
-                rotation_callable_id,
-                vec![Operand::Literal(Literal::Qubit(0))],
-                None,
-            ),
-            Instruction::Call(
-                rotation_callable_id,
-                vec![Operand::Literal(Literal::Qubit(0))],
-                None,
-            ),
-            Instruction::Call(
-                rotation_callable_id,
-                vec![Operand::Literal(Literal::Qubit(0))],
-                None,
-            ),
-            Instruction::Return,
-        ],
+        &expect![[r#"
+            Block:
+                Call id(1), args( Qubit(0), )
+                Call id(1), args( Qubit(0), )
+                Call id(1), args( Qubit(0), )
+                Call id(2), args( Integer(0), Pointer, )
+                Return"#]],
     );
 }
 
@@ -139,28 +118,28 @@ fn unitary_call_within_a_repeat_until_loop() {
     });
 
     let op_callable_id = CallableId(1);
-    assert_callable(&program, op_callable_id, &single_qubit_intrinsic());
+    assert_callable(
+        &program,
+        op_callable_id,
+        &expect![[r#"
+        Callable:
+            name: op
+            call_type: Regular
+            input_type:
+                [0]: Qubit
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
     assert_block_instructions(
         &program,
         BlockId(0),
-        &[
-            Instruction::Call(
-                op_callable_id,
-                vec![Operand::Literal(Literal::Qubit(0))],
-                None,
-            ),
-            Instruction::Call(
-                op_callable_id,
-                vec![Operand::Literal(Literal::Qubit(0))],
-                None,
-            ),
-            Instruction::Call(
-                op_callable_id,
-                vec![Operand::Literal(Literal::Qubit(0))],
-                None,
-            ),
-            Instruction::Return,
-        ],
+        &expect![[r#"
+            Block:
+                Call id(1), args( Qubit(0), )
+                Call id(1), args( Qubit(0), )
+                Call id(1), args( Qubit(0), )
+                Call id(2), args( Integer(0), Pointer, )
+                Return"#]],
     );
 }
 
@@ -185,38 +164,26 @@ fn rotation_call_within_a_for_loop() {
     assert_callable(
         &program,
         rotation_callable_id,
-        &single_qubit_rotation_intrinsic(),
+        &expect![[r#"
+        Callable:
+            name: rotation
+            call_type: Regular
+            input_type:
+                [0]: Double
+                [1]: Qubit
+            output_type: <VOID>
+            body: <NONE>"#]],
     );
     assert_block_instructions(
         &program,
         BlockId(0),
-        &[
-            Instruction::Call(
-                rotation_callable_id,
-                vec![
-                    Operand::Literal(Literal::Double(0.0)),
-                    Operand::Literal(Literal::Qubit(0)),
-                ],
-                None,
-            ),
-            Instruction::Call(
-                rotation_callable_id,
-                vec![
-                    Operand::Literal(Literal::Double(1.0)),
-                    Operand::Literal(Literal::Qubit(0)),
-                ],
-                None,
-            ),
-            Instruction::Call(
-                rotation_callable_id,
-                vec![
-                    Operand::Literal(Literal::Double(2.0)),
-                    Operand::Literal(Literal::Qubit(0)),
-                ],
-                None,
-            ),
-            Instruction::Return,
-        ],
+        &expect![[r#"
+            Block:
+                Call id(1), args( Double(0), Qubit(0), )
+                Call id(1), args( Double(1), Qubit(0), )
+                Call id(1), args( Double(2), Qubit(0), )
+                Call id(2), args( Integer(0), Pointer, )
+                Return"#]],
     );
 }
 
@@ -241,37 +208,29 @@ fn rotation_call_within_a_while_loop() {
     });
 
     let op_callable_id = CallableId(1);
-    assert_callable(&program, op_callable_id, &single_qubit_rotation_intrinsic());
+    assert_callable(
+        &program,
+        op_callable_id,
+        &expect![[r#"
+        Callable:
+            name: rotation
+            call_type: Regular
+            input_type:
+                [0]: Double
+                [1]: Qubit
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
     assert_block_instructions(
         &program,
         BlockId(0),
-        &[
-            Instruction::Call(
-                op_callable_id,
-                vec![
-                    Operand::Literal(Literal::Double(0.0)),
-                    Operand::Literal(Literal::Qubit(0)),
-                ],
-                None,
-            ),
-            Instruction::Call(
-                op_callable_id,
-                vec![
-                    Operand::Literal(Literal::Double(1.0)),
-                    Operand::Literal(Literal::Qubit(0)),
-                ],
-                None,
-            ),
-            Instruction::Call(
-                op_callable_id,
-                vec![
-                    Operand::Literal(Literal::Double(2.0)),
-                    Operand::Literal(Literal::Qubit(0)),
-                ],
-                None,
-            ),
-            Instruction::Return,
-        ],
+        &expect![[r#"
+            Block:
+                Call id(1), args( Double(0), Qubit(0), )
+                Call id(1), args( Double(1), Qubit(0), )
+                Call id(1), args( Double(2), Qubit(0), )
+                Call id(2), args( Integer(0), Pointer, )
+                Return"#]],
     );
 }
 
@@ -299,37 +258,25 @@ fn rotation_call_within_a_repeat_until_loop() {
     assert_callable(
         &program,
         rotation_callable_id,
-        &single_qubit_rotation_intrinsic(),
+        &expect![[r#"
+        Callable:
+            name: rotation
+            call_type: Regular
+            input_type:
+                [0]: Double
+                [1]: Qubit
+            output_type: <VOID>
+            body: <NONE>"#]],
     );
     assert_block_instructions(
         &program,
         BlockId(0),
-        &[
-            Instruction::Call(
-                rotation_callable_id,
-                vec![
-                    Operand::Literal(Literal::Double(0.0)),
-                    Operand::Literal(Literal::Qubit(0)),
-                ],
-                None,
-            ),
-            Instruction::Call(
-                rotation_callable_id,
-                vec![
-                    Operand::Literal(Literal::Double(1.0)),
-                    Operand::Literal(Literal::Qubit(0)),
-                ],
-                None,
-            ),
-            Instruction::Call(
-                rotation_callable_id,
-                vec![
-                    Operand::Literal(Literal::Double(2.0)),
-                    Operand::Literal(Literal::Qubit(0)),
-                ],
-                None,
-            ),
-            Instruction::Return,
-        ],
+        &expect![[r#"
+            Block:
+                Call id(1), args( Double(0), Qubit(0), )
+                Call id(1), args( Double(1), Qubit(0), )
+                Call id(1), args( Double(2), Qubit(0), )
+                Call id(2), args( Integer(0), Pointer, )
+                Return"#]],
     );
 }
diff --git a/compiler/qsc_partial_eval/tests/misc.rs b/compiler/qsc_partial_eval/tests/misc.rs
index da2b4a7b..77940e2a 100644
--- a/compiler/qsc_partial_eval/tests/misc.rs
+++ b/compiler/qsc_partial_eval/tests/misc.rs
@@ -5,22 +5,11 @@
 
 pub mod test_utils;
 
+use expect_test::expect;
 use indoc::indoc;
-use qsc_rir::rir::{
-    BlockId, Callable, CallableId, CallableType, Instruction, Literal, Operand, Ty,
-};
+use qsc_rir::rir::{BlockId, CallableId};
 use test_utils::{assert_block_instructions, assert_callable, compile_and_partially_evaluate};
 
-fn single_qubit_intrinsic_op() -> Callable {
-    Callable {
-        name: "op".to_string(),
-        input_type: vec![Ty::Qubit],
-        output_type: None,
-        body: None,
-        call_type: CallableType::Regular,
-    }
-}
-
 #[test]
 fn unitary_call_within_an_if_with_classical_condition_within_a_for_loop() {
     let program = compile_and_partially_evaluate(indoc! {
@@ -41,28 +30,28 @@ fn unitary_call_within_an_if_with_classical_condition_within_a_for_loop() {
     });
 
     let op_callable_id = CallableId(1);
-    assert_callable(&program, op_callable_id, &single_qubit_intrinsic_op());
+    assert_callable(
+        &program,
+        op_callable_id,
+        &expect![[r#"
+        Callable:
+            name: op
+            call_type: Regular
+            input_type:
+                [0]: Qubit
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
     assert_block_instructions(
         &program,
         BlockId(0),
-        &[
-            Instruction::Call(
-                op_callable_id,
-                vec![Operand::Literal(Literal::Qubit(0))],
-                None,
-            ),
-            Instruction::Call(
-                op_callable_id,
-                vec![Operand::Literal(Literal::Qubit(0))],
-                None,
-            ),
-            Instruction::Call(
-                op_callable_id,
-                vec![Operand::Literal(Literal::Qubit(0))],
-                None,
-            ),
-            Instruction::Return,
-        ],
+        &expect![[r#"
+            Block:
+                Call id(1), args( Qubit(0), )
+                Call id(1), args( Qubit(0), )
+                Call id(1), args( Qubit(0), )
+                Call id(2), args( Integer(0), Pointer, )
+                Return"#]],
     );
 }
 
@@ -88,28 +77,28 @@ fn unitary_call_within_an_if_with_classical_condition_within_a_while_loop() {
     });
 
     let op_callable_id = CallableId(1);
-    assert_callable(&program, op_callable_id, &single_qubit_intrinsic_op());
+    assert_callable(
+        &program,
+        op_callable_id,
+        &expect![[r#"
+        Callable:
+            name: op
+            call_type: Regular
+            input_type:
+                [0]: Qubit
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
     assert_block_instructions(
         &program,
         BlockId(0),
-        &[
-            Instruction::Call(
-                op_callable_id,
-                vec![Operand::Literal(Literal::Qubit(0))],
-                None,
-            ),
-            Instruction::Call(
-                op_callable_id,
-                vec![Operand::Literal(Literal::Qubit(0))],
-                None,
-            ),
-            Instruction::Call(
-                op_callable_id,
-                vec![Operand::Literal(Literal::Qubit(0))],
-                None,
-            ),
-            Instruction::Return,
-        ],
+        &expect![[r#"
+            Block:
+                Call id(1), args( Qubit(0), )
+                Call id(1), args( Qubit(0), )
+                Call id(1), args( Qubit(0), )
+                Call id(2), args( Integer(0), Pointer, )
+                Return"#]],
     );
 }
 
@@ -135,27 +124,27 @@ fn unitary_call_within_an_if_with_classical_condition_within_a_repeat_until_loop
     });
 
     let op_callable_id = CallableId(1);
-    assert_callable(&program, op_callable_id, &single_qubit_intrinsic_op());
+    assert_callable(
+        &program,
+        op_callable_id,
+        &expect![[r#"
+        Callable:
+            name: op
+            call_type: Regular
+            input_type:
+                [0]: Qubit
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
     assert_block_instructions(
         &program,
         BlockId(0),
-        &[
-            Instruction::Call(
-                op_callable_id,
-                vec![Operand::Literal(Literal::Qubit(0))],
-                None,
-            ),
-            Instruction::Call(
-                op_callable_id,
-                vec![Operand::Literal(Literal::Qubit(0))],
-                None,
-            ),
-            Instruction::Call(
-                op_callable_id,
-                vec![Operand::Literal(Literal::Qubit(0))],
-                None,
-            ),
-            Instruction::Return,
-        ],
+        &expect![[r#"
+            Block:
+                Call id(1), args( Qubit(0), )
+                Call id(1), args( Qubit(0), )
+                Call id(1), args( Qubit(0), )
+                Call id(2), args( Integer(0), Pointer, )
+                Return"#]],
     );
 }
diff --git a/compiler/qsc_partial_eval/tests/output_recording.rs b/compiler/qsc_partial_eval/tests/output_recording.rs
new file mode 100644
index 00000000..3c9cd3c6
--- /dev/null
+++ b/compiler/qsc_partial_eval/tests/output_recording.rs
@@ -0,0 +1,526 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#![allow(clippy::needless_raw_string_hashes)]
+
+use expect_test::expect;
+use indoc::indoc;
+use test_utils::compile_and_partially_evaluate;
+
+pub mod test_utils;
+
+#[test]
+fn output_recording_for_tuple_of_different_types() {
+    let program = compile_and_partially_evaluate(indoc! {
+        r#"
+        namespace Test {
+            @EntryPoint()
+            operation Main() : (Result, Bool) {
+                use q = Qubit();
+                let r = QIR.Intrinsic.__quantum__qis__mresetz__body(q);
+                (r, r == Zero)
+            }
+        }
+        "#,
+    });
+
+    expect![[r#"
+        Program:
+            entry: 0
+            callables:
+                Callable 0: Callable:
+                    name: main
+                    call_type: Regular
+                    input_type: <VOID>
+                    output_type: <VOID>
+                    body: 0
+                Callable 1: Callable:
+                    name: __quantum__qis__mresetz__body
+                    call_type: Measurement
+                    input_type:
+                        [0]: Qubit
+                        [1]: Result
+                    output_type: <VOID>
+                    body: <NONE>
+                Callable 2: Callable:
+                    name: __quantum__qis__read_result__body
+                    call_type: Readout
+                    input_type:
+                        [0]: Result
+                    output_type: Boolean
+                    body: <NONE>
+                Callable 3: Callable:
+                    name: __quantum__rt__tuple_record_output
+                    call_type: OutputRecording
+                    input_type:
+                        [0]: Integer
+                        [1]: Pointer
+                    output_type: <VOID>
+                    body: <NONE>
+                Callable 4: Callable:
+                    name: __quantum__rt__result_record_output
+                    call_type: OutputRecording
+                    input_type:
+                        [0]: Result
+                        [1]: Pointer
+                    output_type: <VOID>
+                    body: <NONE>
+                Callable 5: Callable:
+                    name: __quantum__rt__bool_record_output
+                    call_type: OutputRecording
+                    input_type:
+                        [0]: Boolean
+                        [1]: Pointer
+                    output_type: <VOID>
+                    body: <NONE>
+            blocks:
+                Block 0: Block:
+                    Call id(1), args( Qubit(0), Result(0), )
+                    Variable(0, Boolean) = Call id(2), args( Result(0), )
+                    Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false)
+                    Call id(3), args( Integer(2), Pointer, )
+                    Call id(4), args( Result(0), Pointer, )
+                    Call id(5), args( Variable(1, Boolean), Pointer, )
+                    Return
+            config: Config:
+                remap_qubits_on_reuse: false
+                defer_measurements: false
+            num_qubits: 1
+            num_results: 1"#]]
+    .assert_eq(&program.to_string());
+}
+
+#[test]
+fn output_recording_for_nested_tuples() {
+    let program = compile_and_partially_evaluate(indoc! {
+        r#"
+        namespace Test {
+            @EntryPoint()
+            operation Main() : (Result, (Bool, Result), (Bool,)) {
+                use q = Qubit();
+                let r = QIR.Intrinsic.__quantum__qis__mresetz__body(q);
+                (r, (r == Zero, r), (r == One,))
+            }
+        }
+        "#,
+    });
+
+    expect![[r#"
+        Program:
+            entry: 0
+            callables:
+                Callable 0: Callable:
+                    name: main
+                    call_type: Regular
+                    input_type: <VOID>
+                    output_type: <VOID>
+                    body: 0
+                Callable 1: Callable:
+                    name: __quantum__qis__mresetz__body
+                    call_type: Measurement
+                    input_type:
+                        [0]: Qubit
+                        [1]: Result
+                    output_type: <VOID>
+                    body: <NONE>
+                Callable 2: Callable:
+                    name: __quantum__qis__read_result__body
+                    call_type: Readout
+                    input_type:
+                        [0]: Result
+                    output_type: Boolean
+                    body: <NONE>
+                Callable 3: Callable:
+                    name: __quantum__rt__tuple_record_output
+                    call_type: OutputRecording
+                    input_type:
+                        [0]: Integer
+                        [1]: Pointer
+                    output_type: <VOID>
+                    body: <NONE>
+                Callable 4: Callable:
+                    name: __quantum__rt__result_record_output
+                    call_type: OutputRecording
+                    input_type:
+                        [0]: Result
+                        [1]: Pointer
+                    output_type: <VOID>
+                    body: <NONE>
+                Callable 5: Callable:
+                    name: __quantum__rt__bool_record_output
+                    call_type: OutputRecording
+                    input_type:
+                        [0]: Boolean
+                        [1]: Pointer
+                    output_type: <VOID>
+                    body: <NONE>
+            blocks:
+                Block 0: Block:
+                    Call id(1), args( Qubit(0), Result(0), )
+                    Variable(0, Boolean) = Call id(2), args( Result(0), )
+                    Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false)
+                    Variable(2, Boolean) = Call id(2), args( Result(0), )
+                    Variable(3, Boolean) = Icmp Eq, Variable(2, Boolean), Bool(true)
+                    Call id(3), args( Integer(3), Pointer, )
+                    Call id(4), args( Result(0), Pointer, )
+                    Call id(3), args( Integer(2), Pointer, )
+                    Call id(5), args( Variable(1, Boolean), Pointer, )
+                    Call id(4), args( Result(0), Pointer, )
+                    Call id(3), args( Integer(1), Pointer, )
+                    Call id(5), args( Variable(3, Boolean), Pointer, )
+                    Return
+            config: Config:
+                remap_qubits_on_reuse: false
+                defer_measurements: false
+            num_qubits: 1
+            num_results: 1"#]]
+    .assert_eq(&program.to_string());
+}
+
+#[test]
+fn output_recording_for_tuple_of_arrays() {
+    // This program would not actually pass RCA checks as it shows up as using a dynamically sized array.
+    // However, the output recording should still be correct if/when we support this kind of return in the future.
+    let program = compile_and_partially_evaluate(indoc! {
+        r#"
+        namespace Test {
+            @EntryPoint()
+            operation Main() : (Result, Bool[]) {
+                use q = Qubit();
+                let r = QIR.Intrinsic.__quantum__qis__mresetz__body(q);
+                (r, [r == Zero, r == One])
+            }
+        }
+        "#,
+    });
+
+    expect![[r#"
+        Program:
+            entry: 0
+            callables:
+                Callable 0: Callable:
+                    name: main
+                    call_type: Regular
+                    input_type: <VOID>
+                    output_type: <VOID>
+                    body: 0
+                Callable 1: Callable:
+                    name: __quantum__qis__mresetz__body
+                    call_type: Measurement
+                    input_type:
+                        [0]: Qubit
+                        [1]: Result
+                    output_type: <VOID>
+                    body: <NONE>
+                Callable 2: Callable:
+                    name: __quantum__qis__read_result__body
+                    call_type: Readout
+                    input_type:
+                        [0]: Result
+                    output_type: Boolean
+                    body: <NONE>
+                Callable 3: Callable:
+                    name: __quantum__rt__tuple_record_output
+                    call_type: OutputRecording
+                    input_type:
+                        [0]: Integer
+                        [1]: Pointer
+                    output_type: <VOID>
+                    body: <NONE>
+                Callable 4: Callable:
+                    name: __quantum__rt__result_record_output
+                    call_type: OutputRecording
+                    input_type:
+                        [0]: Result
+                        [1]: Pointer
+                    output_type: <VOID>
+                    body: <NONE>
+                Callable 5: Callable:
+                    name: __quantum__rt__array_record_output
+                    call_type: OutputRecording
+                    input_type:
+                        [0]: Integer
+                        [1]: Pointer
+                    output_type: <VOID>
+                    body: <NONE>
+                Callable 6: Callable:
+                    name: __quantum__rt__bool_record_output
+                    call_type: OutputRecording
+                    input_type:
+                        [0]: Boolean
+                        [1]: Pointer
+                    output_type: <VOID>
+                    body: <NONE>
+            blocks:
+                Block 0: Block:
+                    Call id(1), args( Qubit(0), Result(0), )
+                    Variable(0, Boolean) = Call id(2), args( Result(0), )
+                    Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false)
+                    Variable(2, Boolean) = Call id(2), args( Result(0), )
+                    Variable(3, Boolean) = Icmp Eq, Variable(2, Boolean), Bool(true)
+                    Call id(3), args( Integer(2), Pointer, )
+                    Call id(4), args( Result(0), Pointer, )
+                    Call id(5), args( Integer(2), Pointer, )
+                    Call id(6), args( Variable(1, Boolean), Pointer, )
+                    Call id(6), args( Variable(3, Boolean), Pointer, )
+                    Return
+            config: Config:
+                remap_qubits_on_reuse: false
+                defer_measurements: false
+            num_qubits: 1
+            num_results: 1"#]]
+    .assert_eq(&program.to_string());
+}
+
+#[test]
+fn output_recording_for_array_of_tuples() {
+    let program = compile_and_partially_evaluate(indoc! {
+        r#"
+        namespace Test {
+            @EntryPoint()
+            operation Main() : (Result, Bool)[] {
+                use q = Qubit();
+                let r = QIR.Intrinsic.__quantum__qis__mresetz__body(q);
+                [(r, r == Zero), (r, r == One)]
+            }
+        }
+        "#,
+    });
+
+    expect![[r#"
+        Program:
+            entry: 0
+            callables:
+                Callable 0: Callable:
+                    name: main
+                    call_type: Regular
+                    input_type: <VOID>
+                    output_type: <VOID>
+                    body: 0
+                Callable 1: Callable:
+                    name: __quantum__qis__mresetz__body
+                    call_type: Measurement
+                    input_type:
+                        [0]: Qubit
+                        [1]: Result
+                    output_type: <VOID>
+                    body: <NONE>
+                Callable 2: Callable:
+                    name: __quantum__qis__read_result__body
+                    call_type: Readout
+                    input_type:
+                        [0]: Result
+                    output_type: Boolean
+                    body: <NONE>
+                Callable 3: Callable:
+                    name: __quantum__rt__array_record_output
+                    call_type: OutputRecording
+                    input_type:
+                        [0]: Integer
+                        [1]: Pointer
+                    output_type: <VOID>
+                    body: <NONE>
+                Callable 4: Callable:
+                    name: __quantum__rt__tuple_record_output
+                    call_type: OutputRecording
+                    input_type:
+                        [0]: Integer
+                        [1]: Pointer
+                    output_type: <VOID>
+                    body: <NONE>
+                Callable 5: Callable:
+                    name: __quantum__rt__result_record_output
+                    call_type: OutputRecording
+                    input_type:
+                        [0]: Result
+                        [1]: Pointer
+                    output_type: <VOID>
+                    body: <NONE>
+                Callable 6: Callable:
+                    name: __quantum__rt__bool_record_output
+                    call_type: OutputRecording
+                    input_type:
+                        [0]: Boolean
+                        [1]: Pointer
+                    output_type: <VOID>
+                    body: <NONE>
+            blocks:
+                Block 0: Block:
+                    Call id(1), args( Qubit(0), Result(0), )
+                    Variable(0, Boolean) = Call id(2), args( Result(0), )
+                    Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false)
+                    Variable(2, Boolean) = Call id(2), args( Result(0), )
+                    Variable(3, Boolean) = Icmp Eq, Variable(2, Boolean), Bool(true)
+                    Call id(3), args( Integer(2), Pointer, )
+                    Call id(4), args( Integer(2), Pointer, )
+                    Call id(5), args( Result(0), Pointer, )
+                    Call id(6), args( Variable(1, Boolean), Pointer, )
+                    Call id(4), args( Integer(2), Pointer, )
+                    Call id(5), args( Result(0), Pointer, )
+                    Call id(6), args( Variable(3, Boolean), Pointer, )
+                    Return
+            config: Config:
+                remap_qubits_on_reuse: false
+                defer_measurements: false
+            num_qubits: 1
+            num_results: 1"#]]
+    .assert_eq(&program.to_string());
+}
+
+#[test]
+fn output_recording_for_literal_bool() {
+    let program = compile_and_partially_evaluate(indoc! {
+        r#"
+        namespace Test {
+            @EntryPoint()
+            operation Main() : Bool {
+                true
+            }
+        }
+        "#,
+    });
+
+    expect![[r#"
+        Program:
+            entry: 0
+            callables:
+                Callable 0: Callable:
+                    name: main
+                    call_type: Regular
+                    input_type: <VOID>
+                    output_type: <VOID>
+                    body: 0
+                Callable 1: Callable:
+                    name: __quantum__rt__bool_record_output
+                    call_type: OutputRecording
+                    input_type:
+                        [0]: Boolean
+                        [1]: Pointer
+                    output_type: <VOID>
+                    body: <NONE>
+            blocks:
+                Block 0: Block:
+                    Call id(1), args( Bool(true), Pointer, )
+                    Return
+            config: Config:
+                remap_qubits_on_reuse: false
+                defer_measurements: false
+            num_qubits: 0
+            num_results: 0"#]]
+    .assert_eq(&program.to_string());
+}
+
+#[test]
+fn output_recording_for_literal_int() {
+    let program = compile_and_partially_evaluate(indoc! {
+        r#"
+        namespace Test {
+            @EntryPoint()
+            operation Main() : Int {
+                42
+            }
+        }
+        "#,
+    });
+
+    expect![[r#"
+        Program:
+            entry: 0
+            callables:
+                Callable 0: Callable:
+                    name: main
+                    call_type: Regular
+                    input_type: <VOID>
+                    output_type: <VOID>
+                    body: 0
+                Callable 1: Callable:
+                    name: __quantum__rt__integer_record_output
+                    call_type: OutputRecording
+                    input_type:
+                        [0]: Integer
+                        [1]: Pointer
+                    output_type: <VOID>
+                    body: <NONE>
+            blocks:
+                Block 0: Block:
+                    Call id(1), args( Integer(42), Pointer, )
+                    Return
+            config: Config:
+                remap_qubits_on_reuse: false
+                defer_measurements: false
+            num_qubits: 0
+            num_results: 0"#]]
+    .assert_eq(&program.to_string());
+}
+
+#[test]
+fn output_recording_for_mix_of_literal_and_variable() {
+    let program = compile_and_partially_evaluate(indoc! {
+        r#"
+        namespace Test {
+            @EntryPoint()
+            operation Main() : (Result, Bool) {
+                use q = Qubit();
+                let r = QIR.Intrinsic.__quantum__qis__mresetz__body(q);
+                (r, true)
+            }
+        }
+        "#,
+    });
+
+    expect![[r#"
+        Program:
+            entry: 0
+            callables:
+                Callable 0: Callable:
+                    name: main
+                    call_type: Regular
+                    input_type: <VOID>
+                    output_type: <VOID>
+                    body: 0
+                Callable 1: Callable:
+                    name: __quantum__qis__mresetz__body
+                    call_type: Measurement
+                    input_type:
+                        [0]: Qubit
+                        [1]: Result
+                    output_type: <VOID>
+                    body: <NONE>
+                Callable 2: Callable:
+                    name: __quantum__rt__tuple_record_output
+                    call_type: OutputRecording
+                    input_type:
+                        [0]: Integer
+                        [1]: Pointer
+                    output_type: <VOID>
+                    body: <NONE>
+                Callable 3: Callable:
+                    name: __quantum__rt__result_record_output
+                    call_type: OutputRecording
+                    input_type:
+                        [0]: Result
+                        [1]: Pointer
+                    output_type: <VOID>
+                    body: <NONE>
+                Callable 4: Callable:
+                    name: __quantum__rt__bool_record_output
+                    call_type: OutputRecording
+                    input_type:
+                        [0]: Boolean
+                        [1]: Pointer
+                    output_type: <VOID>
+                    body: <NONE>
+            blocks:
+                Block 0: Block:
+                    Call id(1), args( Qubit(0), Result(0), )
+                    Call id(2), args( Integer(2), Pointer, )
+                    Call id(3), args( Result(0), Pointer, )
+                    Call id(4), args( Bool(true), Pointer, )
+                    Return
+            config: Config:
+                remap_qubits_on_reuse: false
+                defer_measurements: false
+            num_qubits: 1
+            num_results: 1"#]]
+    .assert_eq(&program.to_string());
+}
diff --git a/compiler/qsc_partial_eval/tests/qubits.rs b/compiler/qsc_partial_eval/tests/qubits.rs
index db2c9e9e..bfaf2081 100644
--- a/compiler/qsc_partial_eval/tests/qubits.rs
+++ b/compiler/qsc_partial_eval/tests/qubits.rs
@@ -5,22 +5,11 @@
 
 pub mod test_utils;
 
+use expect_test::expect;
 use indoc::indoc;
-use qsc_rir::rir::{
-    BlockId, Callable, CallableId, CallableType, Instruction, Literal, Operand, Ty,
-};
+use qsc_rir::rir::{BlockId, CallableId};
 use test_utils::{assert_block_instructions, assert_callable, compile_and_partially_evaluate};
 
-fn single_qubit_intrinsic_op() -> Callable {
-    Callable {
-        name: "op".to_string(),
-        input_type: vec![Ty::Qubit],
-        output_type: None,
-        body: None,
-        call_type: CallableType::Regular,
-    }
-}
-
 #[test]
 fn qubit_ids_are_correct_for_allocate_use_release_one_qubit() {
     let program = compile_and_partially_evaluate(indoc! {
@@ -36,22 +25,31 @@ fn qubit_ids_are_correct_for_allocate_use_release_one_qubit() {
         }
         "#,
     });
-    let op_callable_id = CallableId(1);
-    assert_callable(&program, op_callable_id, &single_qubit_intrinsic_op());
-    assert_block_instructions(
-        &program,
-        BlockId(0),
-        &[
-            Instruction::Call(
-                op_callable_id,
-                vec![Operand::Literal(Literal::Qubit(0))],
-                None,
-            ),
-            Instruction::Return,
-        ],
-    );
-    assert_eq!(program.num_qubits, 1);
-    assert_eq!(program.num_results, 0);
+    expect![[r#"
+        Callable:
+            name: op
+            call_type: Regular
+            input_type:
+                [0]: Qubit
+            output_type: <VOID>
+            body: <NONE>"#]]
+    .assert_eq(&program.get_callable(CallableId(1)).to_string());
+    expect![[r#"
+        Callable:
+            name: __quantum__rt__tuple_record_output
+            call_type: OutputRecording
+            input_type:
+                [0]: Integer
+                [1]: Pointer
+            output_type: <VOID>
+            body: <NONE>"#]]
+    .assert_eq(&program.get_callable(CallableId(2)).to_string());
+    expect![[r#"
+        Block:
+            Call id(1), args( Qubit(0), )
+            Call id(2), args( Integer(0), Pointer, )
+            Return"#]]
+    .assert_eq(&program.get_block(BlockId(0)).to_string());
 }
 
 #[test]
@@ -76,28 +74,42 @@ fn qubit_ids_are_correct_for_allocate_use_release_multiple_qubits() {
         "#,
     });
     let op_callable_id = CallableId(1);
-    assert_callable(&program, op_callable_id, &single_qubit_intrinsic_op());
+    assert_callable(
+        &program,
+        op_callable_id,
+        &expect![[r#"
+        Callable:
+            name: op
+            call_type: Regular
+            input_type:
+                [0]: Qubit
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
+    let tuple_callable_id = CallableId(2);
+    assert_callable(
+        &program,
+        tuple_callable_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__rt__tuple_record_output
+            call_type: OutputRecording
+            input_type:
+                [0]: Integer
+                [1]: Pointer
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
     assert_block_instructions(
         &program,
         BlockId(0),
-        &[
-            Instruction::Call(
-                op_callable_id,
-                vec![Operand::Literal(Literal::Qubit(0))],
-                None,
-            ),
-            Instruction::Call(
-                op_callable_id,
-                vec![Operand::Literal(Literal::Qubit(1))],
-                None,
-            ),
-            Instruction::Call(
-                op_callable_id,
-                vec![Operand::Literal(Literal::Qubit(2))],
-                None,
-            ),
-            Instruction::Return,
-        ],
+        &expect![[r#"
+            Block:
+                Call id(1), args( Qubit(0), )
+                Call id(1), args( Qubit(1), )
+                Call id(1), args( Qubit(2), )
+                Call id(2), args( Integer(0), Pointer, )
+                Return"#]],
     );
     assert_eq!(program.num_qubits, 3);
     assert_eq!(program.num_results, 0);
@@ -125,28 +137,42 @@ fn qubit_ids_are_correct_for_allocate_use_release_one_qubit_multiple_times() {
         "#,
     });
     let op_callable_id = CallableId(1);
-    assert_callable(&program, op_callable_id, &single_qubit_intrinsic_op());
+    assert_callable(
+        &program,
+        op_callable_id,
+        &expect![[r#"
+        Callable:
+            name: op
+            call_type: Regular
+            input_type:
+                [0]: Qubit
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
+    let tuple_callable_id = CallableId(2);
+    assert_callable(
+        &program,
+        tuple_callable_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__rt__tuple_record_output
+            call_type: OutputRecording
+            input_type:
+                [0]: Integer
+                [1]: Pointer
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
     assert_block_instructions(
         &program,
         BlockId(0),
-        &[
-            Instruction::Call(
-                op_callable_id,
-                vec![Operand::Literal(Literal::Qubit(0))],
-                None,
-            ),
-            Instruction::Call(
-                op_callable_id,
-                vec![Operand::Literal(Literal::Qubit(0))],
-                None,
-            ),
-            Instruction::Call(
-                op_callable_id,
-                vec![Operand::Literal(Literal::Qubit(0))],
-                None,
-            ),
-            Instruction::Return,
-        ],
+        &expect![[r#"
+            Block:
+                Call id(1), args( Qubit(0), )
+                Call id(1), args( Qubit(0), )
+                Call id(1), args( Qubit(0), )
+                Call id(2), args( Integer(0), Pointer, )
+                Return"#]],
     );
     assert_eq!(program.num_qubits, 1);
     assert_eq!(program.num_results, 0);
@@ -180,38 +206,44 @@ fn qubit_ids_are_correct_for_allocate_use_release_multiple_qubits_interleaved()
         "#,
     });
     let op_callable_id = CallableId(1);
-    assert_callable(&program, op_callable_id, &single_qubit_intrinsic_op());
+    assert_callable(
+        &program,
+        op_callable_id,
+        &expect![[r#"
+        Callable:
+            name: op
+            call_type: Regular
+            input_type:
+                [0]: Qubit
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
+    let tuple_callable_id = CallableId(2);
+    assert_callable(
+        &program,
+        tuple_callable_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__rt__tuple_record_output
+            call_type: OutputRecording
+            input_type:
+                [0]: Integer
+                [1]: Pointer
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
     assert_block_instructions(
         &program,
         BlockId(0),
-        &[
-            Instruction::Call(
-                op_callable_id,
-                vec![Operand::Literal(Literal::Qubit(0))],
-                None,
-            ),
-            Instruction::Call(
-                op_callable_id,
-                vec![Operand::Literal(Literal::Qubit(1))],
-                None,
-            ),
-            Instruction::Call(
-                op_callable_id,
-                vec![Operand::Literal(Literal::Qubit(2))],
-                None,
-            ),
-            Instruction::Call(
-                op_callable_id,
-                vec![Operand::Literal(Literal::Qubit(2))],
-                None,
-            ),
-            Instruction::Call(
-                op_callable_id,
-                vec![Operand::Literal(Literal::Qubit(3))],
-                None,
-            ),
-            Instruction::Return,
-        ],
+        &expect![[r#"
+            Block:
+                Call id(1), args( Qubit(0), )
+                Call id(1), args( Qubit(1), )
+                Call id(1), args( Qubit(2), )
+                Call id(1), args( Qubit(2), )
+                Call id(1), args( Qubit(3), )
+                Call id(2), args( Integer(0), Pointer, )
+                Return"#]],
     );
     assert_eq!(program.num_qubits, 4);
     assert_eq!(program.num_results, 0);
diff --git a/compiler/qsc_partial_eval/tests/results.rs b/compiler/qsc_partial_eval/tests/results.rs
index 64c3adf5..c6ef1c73 100644
--- a/compiler/qsc_partial_eval/tests/results.rs
+++ b/compiler/qsc_partial_eval/tests/results.rs
@@ -5,72 +5,60 @@
 
 pub mod test_utils;
 
+use expect_test::expect;
 use indoc::indoc;
-use qsc_rir::rir::{
-    BlockId, Callable, CallableId, CallableType, ConditionCode, Instruction, Literal, Operand, Ty,
-    Variable, VariableId,
-};
+use qsc_rir::rir::{BlockId, CallableId};
 use test_utils::{assert_block_instructions, assert_callable, compile_and_partially_evaluate};
 
-fn m_intrinsic_op() -> Callable {
-    Callable {
-        name: "__quantum__qis__mz__body".to_string(),
-        input_type: vec![Ty::Qubit, Ty::Result],
-        output_type: None,
-        body: None,
-        call_type: CallableType::Measurement,
-    }
-}
-
-fn mresetz_intrinsic_op() -> Callable {
-    Callable {
-        name: "__quantum__qis__mresetz__body".to_string(),
-        input_type: vec![Ty::Qubit, Ty::Result],
-        output_type: None,
-        body: None,
-        call_type: CallableType::Measurement,
-    }
-}
-
-fn read_reasult_intrinsic_op() -> Callable {
-    Callable {
-        name: "__quantum__rt__read_result__body".to_string(),
-        input_type: vec![Ty::Result],
-        output_type: Some(Ty::Boolean),
-        body: None,
-        call_type: CallableType::Readout,
-    }
-}
-
 #[test]
 fn result_ids_are_correct_for_measuring_and_resetting_one_qubit() {
     let program = compile_and_partially_evaluate(indoc! {
         r#"
         namespace Test {
             @EntryPoint()
-            operation Main() : Unit {
+            operation Main() : Result {
                 use q = Qubit();
-                QIR.Intrinsic.__quantum__qis__mresetz__body(q);
+                QIR.Intrinsic.__quantum__qis__mresetz__body(q)
             }
         }
         "#,
     });
     let op_callable_id = CallableId(1);
-    assert_callable(&program, op_callable_id, &mresetz_intrinsic_op());
+    let result_record_id = CallableId(2);
+    assert_callable(
+        &program,
+        op_callable_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__qis__mresetz__body
+            call_type: Measurement
+            input_type:
+                [0]: Qubit
+                [1]: Result
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
+    assert_callable(
+        &program,
+        result_record_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__rt__result_record_output
+            call_type: OutputRecording
+            input_type:
+                [0]: Result
+                [1]: Pointer
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
     assert_block_instructions(
         &program,
         BlockId(0),
-        &[
-            Instruction::Call(
-                op_callable_id,
-                vec![
-                    Operand::Literal(Literal::Qubit(0)),
-                    Operand::Literal(Literal::Result(0)),
-                ],
-                None,
-            ),
-            Instruction::Return,
-        ],
+        &expect![[r#"
+            Block:
+                Call id(1), args( Qubit(0), Result(0), )
+                Call id(2), args( Result(0), Pointer, )
+                Return"#]],
     );
     assert_eq!(program.num_qubits, 1);
     assert_eq!(program.num_results, 1);
@@ -82,29 +70,49 @@ fn result_ids_are_correct_for_measuring_one_qubit() {
         r#"
         namespace Test {
             @EntryPoint()
-            operation Main() : Unit {
+            operation Main() : Result {
                 use q = Qubit();
-                QIR.Intrinsic.__quantum__qis__m__body(q);
+                QIR.Intrinsic.__quantum__qis__m__body(q)
             }
         }
         "#,
     });
     let op_callable_id = CallableId(1);
-    assert_callable(&program, op_callable_id, &m_intrinsic_op());
+    let result_record_id = CallableId(2);
+    assert_callable(
+        &program,
+        op_callable_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__qis__mz__body
+            call_type: Measurement
+            input_type:
+                [0]: Qubit
+                [1]: Result
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
+    assert_callable(
+        &program,
+        result_record_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__rt__result_record_output
+            call_type: OutputRecording
+            input_type:
+                [0]: Result
+                [1]: Pointer
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
     assert_block_instructions(
         &program,
         BlockId(0),
-        &[
-            Instruction::Call(
-                op_callable_id,
-                vec![
-                    Operand::Literal(Literal::Qubit(0)),
-                    Operand::Literal(Literal::Result(0)),
-                ],
-                None,
-            ),
-            Instruction::Return,
-        ],
+        &expect![[r#"
+            Block:
+                Call id(1), args( Qubit(0), Result(0), )
+                Call id(2), args( Result(0), Pointer, )
+                Return"#]],
     );
     assert_eq!(program.num_qubits, 1);
     assert_eq!(program.num_results, 1);
@@ -116,47 +124,143 @@ fn result_ids_are_correct_for_measuring_one_qubit_multiple_times() {
         r#"
         namespace Test {
             @EntryPoint()
-            operation Main() : Unit {
+            operation Main() : (Result, Result, Result) {
                 use q = Qubit();
-                QIR.Intrinsic.__quantum__qis__m__body(q);
-                QIR.Intrinsic.__quantum__qis__m__body(q);
-                QIR.Intrinsic.__quantum__qis__m__body(q);
+                (QIR.Intrinsic.__quantum__qis__m__body(q),
+                QIR.Intrinsic.__quantum__qis__m__body(q),
+                QIR.Intrinsic.__quantum__qis__m__body(q))
             }
         }
         "#,
     });
     let op_callable_id = CallableId(1);
-    assert_callable(&program, op_callable_id, &m_intrinsic_op());
+    let tuple_record_id = CallableId(2);
+    let result_record_id = CallableId(3);
+    assert_callable(
+        &program,
+        op_callable_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__qis__mz__body
+            call_type: Measurement
+            input_type:
+                [0]: Qubit
+                [1]: Result
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
+    assert_callable(
+        &program,
+        tuple_record_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__rt__tuple_record_output
+            call_type: OutputRecording
+            input_type:
+                [0]: Integer
+                [1]: Pointer
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
+    assert_callable(
+        &program,
+        result_record_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__rt__result_record_output
+            call_type: OutputRecording
+            input_type:
+                [0]: Result
+                [1]: Pointer
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
     assert_block_instructions(
         &program,
         BlockId(0),
-        &[
-            Instruction::Call(
-                op_callable_id,
-                vec![
-                    Operand::Literal(Literal::Qubit(0)),
-                    Operand::Literal(Literal::Result(0)),
-                ],
-                None,
-            ),
-            Instruction::Call(
-                op_callable_id,
-                vec![
-                    Operand::Literal(Literal::Qubit(0)),
-                    Operand::Literal(Literal::Result(1)),
-                ],
-                None,
-            ),
-            Instruction::Call(
-                op_callable_id,
-                vec![
-                    Operand::Literal(Literal::Qubit(0)),
-                    Operand::Literal(Literal::Result(2)),
-                ],
-                None,
-            ),
-            Instruction::Return,
-        ],
+        &expect![[r#"
+            Block:
+                Call id(1), args( Qubit(0), Result(0), )
+                Call id(1), args( Qubit(0), Result(1), )
+                Call id(1), args( Qubit(0), Result(2), )
+                Call id(2), args( Integer(3), Pointer, )
+                Call id(3), args( Result(0), Pointer, )
+                Call id(3), args( Result(1), Pointer, )
+                Call id(3), args( Result(2), Pointer, )
+                Return"#]],
+    );
+}
+
+#[test]
+fn result_ids_are_correct_for_measuring_one_qubit_multiple_times_into_array() {
+    let program = compile_and_partially_evaluate(indoc! {
+        r#"
+        namespace Test {
+            @EntryPoint()
+            operation Main() : Result[] {
+                use q = Qubit();
+                [QIR.Intrinsic.__quantum__qis__m__body(q),
+                QIR.Intrinsic.__quantum__qis__m__body(q),
+                QIR.Intrinsic.__quantum__qis__m__body(q)]
+            }
+        }
+        "#,
+    });
+    let op_callable_id = CallableId(1);
+    let array_record_id = CallableId(2);
+    let result_record_id = CallableId(3);
+    assert_callable(
+        &program,
+        op_callable_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__qis__mz__body
+            call_type: Measurement
+            input_type:
+                [0]: Qubit
+                [1]: Result
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
+    assert_callable(
+        &program,
+        array_record_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__rt__array_record_output
+            call_type: OutputRecording
+            input_type:
+                [0]: Integer
+                [1]: Pointer
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
+    assert_callable(
+        &program,
+        result_record_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__rt__result_record_output
+            call_type: OutputRecording
+            input_type:
+                [0]: Result
+                [1]: Pointer
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
+    assert_block_instructions(
+        &program,
+        BlockId(0),
+        &expect![[r#"
+            Block:
+                Call id(1), args( Qubit(0), Result(0), )
+                Call id(1), args( Qubit(0), Result(1), )
+                Call id(1), args( Qubit(0), Result(2), )
+                Call id(2), args( Integer(3), Pointer, )
+                Call id(3), args( Result(0), Pointer, )
+                Call id(3), args( Result(1), Pointer, )
+                Call id(3), args( Result(2), Pointer, )
+                Return"#]],
     );
     assert_eq!(program.num_qubits, 1);
     assert_eq!(program.num_results, 3);
@@ -168,47 +272,70 @@ fn result_ids_are_correct_for_measuring_multiple_qubits() {
         r#"
         namespace Test {
             @EntryPoint()
-            operation Main() : Unit {
+            operation Main() : (Result, Result, Result) {
                 use (q0, q1, q2) = (Qubit(), Qubit(), Qubit());
-                QIR.Intrinsic.__quantum__qis__m__body(q0);
-                QIR.Intrinsic.__quantum__qis__m__body(q1);
-                QIR.Intrinsic.__quantum__qis__m__body(q2);
+                (QIR.Intrinsic.__quantum__qis__m__body(q0),
+                QIR.Intrinsic.__quantum__qis__m__body(q1),
+                QIR.Intrinsic.__quantum__qis__m__body(q2))
             }
         }
         "#,
     });
     let op_callable_id = CallableId(1);
-    assert_callable(&program, op_callable_id, &m_intrinsic_op());
+    let tuple_record_id = CallableId(2);
+    let result_record_id = CallableId(3);
+    assert_callable(
+        &program,
+        op_callable_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__qis__mz__body
+            call_type: Measurement
+            input_type:
+                [0]: Qubit
+                [1]: Result
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
+    assert_callable(
+        &program,
+        tuple_record_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__rt__tuple_record_output
+            call_type: OutputRecording
+            input_type:
+                [0]: Integer
+                [1]: Pointer
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
+    assert_callable(
+        &program,
+        result_record_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__rt__result_record_output
+            call_type: OutputRecording
+            input_type:
+                [0]: Result
+                [1]: Pointer
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
     assert_block_instructions(
         &program,
         BlockId(0),
-        &[
-            Instruction::Call(
-                op_callable_id,
-                vec![
-                    Operand::Literal(Literal::Qubit(0)),
-                    Operand::Literal(Literal::Result(0)),
-                ],
-                None,
-            ),
-            Instruction::Call(
-                op_callable_id,
-                vec![
-                    Operand::Literal(Literal::Qubit(1)),
-                    Operand::Literal(Literal::Result(1)),
-                ],
-                None,
-            ),
-            Instruction::Call(
-                op_callable_id,
-                vec![
-                    Operand::Literal(Literal::Qubit(2)),
-                    Operand::Literal(Literal::Result(2)),
-                ],
-                None,
-            ),
-            Instruction::Return,
-        ],
+        &expect![[r#"
+            Block:
+                Call id(1), args( Qubit(0), Result(0), )
+                Call id(1), args( Qubit(1), Result(1), )
+                Call id(1), args( Qubit(2), Result(2), )
+                Call id(2), args( Integer(3), Pointer, )
+                Call id(3), args( Result(0), Pointer, )
+                Call id(3), args( Result(1), Pointer, )
+                Call id(3), args( Result(2), Pointer, )
+                Return"#]],
     );
     assert_eq!(program.num_qubits, 3);
     assert_eq!(program.num_results, 3);
@@ -220,72 +347,68 @@ fn comparing_measurement_results_for_equality_adds_read_result_and_comparison_in
         r#"
         namespace Test {
             @EntryPoint()
-            operation Main() : Unit {
+            operation Main() : Bool {
                 use (q0, q1) = (Qubit(), Qubit());
                 let r0 = QIR.Intrinsic.__quantum__qis__m__body(q0);
                 let r1 = QIR.Intrinsic.__quantum__qis__m__body(q1);
-                let b = r0 == r1;
+                r0 == r1
             }
         }
         "#,
     });
     let measurement_callable_id = CallableId(1);
-    assert_callable(&program, measurement_callable_id, &m_intrinsic_op());
+    assert_callable(
+        &program,
+        measurement_callable_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__qis__mz__body
+            call_type: Measurement
+            input_type:
+                [0]: Qubit
+                [1]: Result
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
     let readout_callable_id = CallableId(2);
-    assert_callable(&program, readout_callable_id, &read_reasult_intrinsic_op());
+    assert_callable(
+        &program,
+        readout_callable_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__qis__read_result__body
+            call_type: Readout
+            input_type:
+                [0]: Result
+            output_type: Boolean
+            body: <NONE>"#]],
+    );
+    let bool_record_id = CallableId(3);
+    assert_callable(
+        &program,
+        bool_record_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__rt__bool_record_output
+            call_type: OutputRecording
+            input_type:
+                [0]: Boolean
+                [1]: Pointer
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
     assert_block_instructions(
         &program,
         BlockId(0),
-        &vec![
-            Instruction::Call(
-                measurement_callable_id,
-                vec![
-                    Operand::Literal(Literal::Qubit(0)),
-                    Operand::Literal(Literal::Result(0)),
-                ],
-                None,
-            ),
-            Instruction::Call(
-                measurement_callable_id,
-                vec![
-                    Operand::Literal(Literal::Qubit(1)),
-                    Operand::Literal(Literal::Result(1)),
-                ],
-                None,
-            ),
-            Instruction::Call(
-                readout_callable_id,
-                vec![Operand::Literal(Literal::Result(0))],
-                Some(Variable {
-                    variable_id: VariableId(0),
-                    ty: Ty::Boolean,
-                }),
-            ),
-            Instruction::Call(
-                readout_callable_id,
-                vec![Operand::Literal(Literal::Result(1))],
-                Some(Variable {
-                    variable_id: VariableId(1),
-                    ty: Ty::Boolean,
-                }),
-            ),
-            Instruction::Icmp(
-                ConditionCode::Eq,
-                Operand::Variable(Variable {
-                    variable_id: VariableId(0),
-                    ty: Ty::Boolean,
-                }),
-                Operand::Variable(Variable {
-                    variable_id: VariableId(1),
-                    ty: Ty::Boolean,
-                }),
-                Variable {
-                    variable_id: VariableId(2),
-                    ty: Ty::Boolean,
-                },
-            ),
-            Instruction::Return,
-        ],
+        &expect![[r#"
+            Block:
+                Call id(1), args( Qubit(0), Result(0), )
+                Call id(1), args( Qubit(1), Result(1), )
+                Variable(0, Boolean) = Call id(2), args( Result(0), )
+                Variable(1, Boolean) = Call id(2), args( Result(1), )
+                Variable(2, Boolean) = Icmp Eq, Variable(0, Boolean), Variable(1, Boolean)
+                Call id(3), args( Variable(2, Boolean), Pointer, )
+                Return"#]],
     );
     assert_eq!(program.num_qubits, 2);
     assert_eq!(program.num_results, 2);
@@ -297,72 +420,68 @@ fn comparing_measurement_results_for_inequality_adds_read_result_and_comparison_
         r#"
         namespace Test {
             @EntryPoint()
-            operation Main() : Unit {
+            operation Main() : Bool {
                 use (q0, q1) = (Qubit(), Qubit());
                 let r0 = QIR.Intrinsic.__quantum__qis__m__body(q0);
                 let r1 = QIR.Intrinsic.__quantum__qis__m__body(q1);
-                let b = r0 != r1;
+                r0 != r1
             }
         }
         "#,
     });
     let measurement_callable_id = CallableId(1);
-    assert_callable(&program, measurement_callable_id, &m_intrinsic_op());
+    assert_callable(
+        &program,
+        measurement_callable_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__qis__mz__body
+            call_type: Measurement
+            input_type:
+                [0]: Qubit
+                [1]: Result
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
     let readout_callable_id = CallableId(2);
-    assert_callable(&program, readout_callable_id, &read_reasult_intrinsic_op());
+    assert_callable(
+        &program,
+        readout_callable_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__qis__read_result__body
+            call_type: Readout
+            input_type:
+                [0]: Result
+            output_type: Boolean
+            body: <NONE>"#]],
+    );
+    let bool_record_id = CallableId(3);
+    assert_callable(
+        &program,
+        bool_record_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__rt__bool_record_output
+            call_type: OutputRecording
+            input_type:
+                [0]: Boolean
+                [1]: Pointer
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
     assert_block_instructions(
         &program,
         BlockId(0),
-        &vec![
-            Instruction::Call(
-                measurement_callable_id,
-                vec![
-                    Operand::Literal(Literal::Qubit(0)),
-                    Operand::Literal(Literal::Result(0)),
-                ],
-                None,
-            ),
-            Instruction::Call(
-                measurement_callable_id,
-                vec![
-                    Operand::Literal(Literal::Qubit(1)),
-                    Operand::Literal(Literal::Result(1)),
-                ],
-                None,
-            ),
-            Instruction::Call(
-                readout_callable_id,
-                vec![Operand::Literal(Literal::Result(0))],
-                Some(Variable {
-                    variable_id: VariableId(0),
-                    ty: Ty::Boolean,
-                }),
-            ),
-            Instruction::Call(
-                readout_callable_id,
-                vec![Operand::Literal(Literal::Result(1))],
-                Some(Variable {
-                    variable_id: VariableId(1),
-                    ty: Ty::Boolean,
-                }),
-            ),
-            Instruction::Icmp(
-                ConditionCode::Ne,
-                Operand::Variable(Variable {
-                    variable_id: VariableId(0),
-                    ty: Ty::Boolean,
-                }),
-                Operand::Variable(Variable {
-                    variable_id: VariableId(1),
-                    ty: Ty::Boolean,
-                }),
-                Variable {
-                    variable_id: VariableId(2),
-                    ty: Ty::Boolean,
-                },
-            ),
-            Instruction::Return,
-        ],
+        &expect![[r#"
+            Block:
+                Call id(1), args( Qubit(0), Result(0), )
+                Call id(1), args( Qubit(1), Result(1), )
+                Variable(0, Boolean) = Call id(2), args( Result(0), )
+                Variable(1, Boolean) = Call id(2), args( Result(1), )
+                Variable(2, Boolean) = Icmp Ne, Variable(0, Boolean), Variable(1, Boolean)
+                Call id(3), args( Variable(2, Boolean), Pointer, )
+                Return"#]],
     );
     assert_eq!(program.num_qubits, 2);
     assert_eq!(program.num_results, 2);
@@ -375,52 +494,65 @@ fn comparing_measurement_result_against_result_literal_for_equality_adds_read_re
         r#"
         namespace Test {
             @EntryPoint()
-            operation Main() : Unit {
+            operation Main() : Bool {
                 use q = Qubit();
                 let r = QIR.Intrinsic.__quantum__qis__m__body(q);
-                let b = r == One;
+                r == One
             }
         }
         "#,
     });
     let measurement_callable_id = CallableId(1);
-    assert_callable(&program, measurement_callable_id, &m_intrinsic_op());
+    assert_callable(
+        &program,
+        measurement_callable_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__qis__mz__body
+            call_type: Measurement
+            input_type:
+                [0]: Qubit
+                [1]: Result
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
     let readout_callable_id = CallableId(2);
-    assert_callable(&program, readout_callable_id, &read_reasult_intrinsic_op());
+    assert_callable(
+        &program,
+        readout_callable_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__qis__read_result__body
+            call_type: Readout
+            input_type:
+                [0]: Result
+            output_type: Boolean
+            body: <NONE>"#]],
+    );
+    let bool_record_id = CallableId(3);
+    assert_callable(
+        &program,
+        bool_record_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__rt__bool_record_output
+            call_type: OutputRecording
+            input_type:
+                [0]: Boolean
+                [1]: Pointer
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
     assert_block_instructions(
         &program,
         BlockId(0),
-        &[
-            Instruction::Call(
-                measurement_callable_id,
-                vec![
-                    Operand::Literal(Literal::Qubit(0)),
-                    Operand::Literal(Literal::Result(0)),
-                ],
-                None,
-            ),
-            Instruction::Call(
-                readout_callable_id,
-                vec![Operand::Literal(Literal::Result(0))],
-                Some(Variable {
-                    variable_id: VariableId(0),
-                    ty: Ty::Boolean,
-                }),
-            ),
-            Instruction::Icmp(
-                ConditionCode::Eq,
-                Operand::Variable(Variable {
-                    variable_id: VariableId(0),
-                    ty: Ty::Boolean,
-                }),
-                Operand::Literal(Literal::Bool(true)),
-                Variable {
-                    variable_id: VariableId(1),
-                    ty: Ty::Boolean,
-                },
-            ),
-            Instruction::Return,
-        ],
+        &expect![[r#"
+            Block:
+                Call id(1), args( Qubit(0), Result(0), )
+                Variable(0, Boolean) = Call id(2), args( Result(0), )
+                Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(true)
+                Call id(3), args( Variable(1, Boolean), Pointer, )
+                Return"#]],
     );
     assert_eq!(program.num_qubits, 1);
     assert_eq!(program.num_results, 1);
@@ -433,52 +565,65 @@ fn comparing_measurement_result_against_result_literal_for_inequality_adds_read_
         r#"
         namespace Test {
             @EntryPoint()
-            operation Main() : Unit {
+            operation Main() : Bool {
                 use q = Qubit();
                 let r = QIR.Intrinsic.__quantum__qis__m__body(q);
-                let b = r != Zero;
+                r != Zero
             }
         }
         "#,
     });
     let measurement_callable_id = CallableId(1);
-    assert_callable(&program, measurement_callable_id, &m_intrinsic_op());
+    assert_callable(
+        &program,
+        measurement_callable_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__qis__mz__body
+            call_type: Measurement
+            input_type:
+                [0]: Qubit
+                [1]: Result
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
     let readout_callable_id = CallableId(2);
-    assert_callable(&program, readout_callable_id, &read_reasult_intrinsic_op());
+    assert_callable(
+        &program,
+        readout_callable_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__qis__read_result__body
+            call_type: Readout
+            input_type:
+                [0]: Result
+            output_type: Boolean
+            body: <NONE>"#]],
+    );
+    let bool_record_id = CallableId(3);
+    assert_callable(
+        &program,
+        bool_record_id,
+        &expect![[r#"
+        Callable:
+            name: __quantum__rt__bool_record_output
+            call_type: OutputRecording
+            input_type:
+                [0]: Boolean
+                [1]: Pointer
+            output_type: <VOID>
+            body: <NONE>"#]],
+    );
     assert_block_instructions(
         &program,
         BlockId(0),
-        &[
-            Instruction::Call(
-                measurement_callable_id,
-                vec![
-                    Operand::Literal(Literal::Qubit(0)),
-                    Operand::Literal(Literal::Result(0)),
-                ],
-                None,
-            ),
-            Instruction::Call(
-                readout_callable_id,
-                vec![Operand::Literal(Literal::Result(0))],
-                Some(Variable {
-                    variable_id: VariableId(0),
-                    ty: Ty::Boolean,
-                }),
-            ),
-            Instruction::Icmp(
-                ConditionCode::Ne,
-                Operand::Variable(Variable {
-                    variable_id: VariableId(0),
-                    ty: Ty::Boolean,
-                }),
-                Operand::Literal(Literal::Bool(false)),
-                Variable {
-                    variable_id: VariableId(1),
-                    ty: Ty::Boolean,
-                },
-            ),
-            Instruction::Return,
-        ],
+        &expect![[r#"
+            Block:
+                Call id(1), args( Qubit(0), Result(0), )
+                Variable(0, Boolean) = Call id(2), args( Result(0), )
+                Variable(1, Boolean) = Icmp Ne, Variable(0, Boolean), Bool(false)
+                Call id(3), args( Variable(1, Boolean), Pointer, )
+                Return"#]],
     );
     assert_eq!(program.num_qubits, 1);
     assert_eq!(program.num_results, 1);
diff --git a/compiler/qsc_partial_eval/tests/test_utils.rs b/compiler/qsc_partial_eval/tests/test_utils.rs
index 8141a210..2552d808 100644
--- a/compiler/qsc_partial_eval/tests/test_utils.rs
+++ b/compiler/qsc_partial_eval/tests/test_utils.rs
@@ -1,6 +1,7 @@
 // Copyright (c) Microsoft Corporation.
 // Licensed under the MIT License.
 
+use expect_test::Expect;
 use qsc::{incremental::Compiler, PackageType};
 use qsc_data_structures::language_features::LanguageFeatures;
 use qsc_fir::fir::PackageStore;
@@ -8,40 +9,26 @@ use qsc_frontend::compile::{PackageStore as HirPackageStore, SourceMap, TargetCa
 use qsc_lowerer::{map_hir_package_to_fir, Lowerer};
 use qsc_partial_eval::{partially_evaluate, ProgramEntry};
 use qsc_rca::{Analyzer, PackageStoreComputeProperties};
-use qsc_rir::rir::{BlockId, Callable, CallableId, CallableType, Instruction, Program, Ty};
+use qsc_rir::rir::{BlockId, CallableId, Program};
 
-pub fn assert_block_last_instruction(
-    program: &Program,
-    block_id: BlockId,
-    expected_inst: &Instruction,
-) {
-    let block = program.blocks.get(block_id).expect("block does not exist");
-    let actual_inst = block.0.last().expect("block does not have instructions");
-    assert_eq!(expected_inst, actual_inst);
+pub fn assert_block_instructions(program: &Program, block_id: BlockId, expected_insts: &Expect) {
+    let block = program.get_block(block_id);
+    expected_insts.assert_eq(&block.to_string());
 }
 
-pub fn assert_block_instructions(
-    program: &Program,
-    block_id: BlockId,
-    expected_insts: &[Instruction],
-) {
-    let block = program.blocks.get(block_id).expect("block does not exist");
-    assert_eq!(
-        block.0.len(),
-        expected_insts.len(),
-        "expected number of instructions is different than actual number of instructions"
-    );
-    for (expected_inst, actual_inst) in expected_insts.iter().zip(block.0.iter()) {
-        assert_eq!(expected_inst, actual_inst);
-    }
+pub fn assert_blocks(program: &Program, expected_blocks: &Expect) {
+    let all_blocks = program
+        .blocks
+        .iter()
+        .fold("Blocks:".to_string(), |acc, (id, block)| {
+            acc + &format!("\nBlock {}:", id.0) + &block.to_string()
+        });
+    expected_blocks.assert_eq(&all_blocks);
 }
 
-pub fn assert_callable(program: &Program, callable_id: CallableId, expected_callable: &Callable) {
-    let actual_callable = program
-        .callables
-        .get(callable_id)
-        .expect("callable does not exist ");
-    assert_eq!(expected_callable, actual_callable);
+pub fn assert_callable(program: &Program, callable_id: CallableId, expected_callable: &Expect) {
+    let actual_callable = program.get_callable(callable_id);
+    expected_callable.assert_eq(&actual_callable.to_string());
 }
 
 #[must_use]
@@ -58,28 +45,6 @@ pub fn compile_and_partially_evaluate(source: &str) -> Program {
     }
 }
 
-#[must_use]
-pub fn mresetz_callable() -> Callable {
-    Callable {
-        name: "__quantum__qis__mresetz__body".to_string(),
-        input_type: vec![Ty::Qubit, Ty::Result],
-        output_type: None,
-        body: None,
-        call_type: CallableType::Measurement,
-    }
-}
-
-#[must_use]
-pub fn read_result_callable() -> Callable {
-    Callable {
-        name: "__quantum__rt__read_result__body".to_string(),
-        input_type: vec![Ty::Result],
-        output_type: Some(Ty::Boolean),
-        body: None,
-        call_type: CallableType::Readout,
-    }
-}
-
 struct CompilationContext {
     fir_store: PackageStore,
     compute_properties: PackageStoreComputeProperties,
diff --git a/pip/tests/test_interpreter.py b/pip/tests/test_interpreter.py
index af76a540..bab27dcf 100644
--- a/pip/tests/test_interpreter.py
+++ b/pip/tests/test_interpreter.py
@@ -321,7 +321,7 @@ def test_adaptive_qir_can_be_generated() -> None:
             open Microsoft.Quantum.Math;
             open QIR.Intrinsic;
             @EntryPoint()
-            operation Main() : Unit {
+            operation Main() : Result {
                 use q = Qubit();
                 let pi_over_two = 4.0 / 2.0;
                 __quantum__qis__rz__body(pi_over_two, q);
@@ -329,6 +329,7 @@ def test_adaptive_qir_can_be_generated() -> None:
                 __quantum__qis__rz__body(some_angle, q);
                 set some_angle = ArcCos(-1.0) / PI();
                 __quantum__qis__rz__body(some_angle, q);
+                __quantum__qis__mresetz__body(q)
             }
         }
         """
@@ -345,12 +346,18 @@ def test_adaptive_qir_can_be_generated() -> None:
           call void @__quantum__qis__rz__body(double 2.0, %Qubit* inttoptr (i64 0 to %Qubit*))
           call void @__quantum__qis__rz__body(double 0.0, %Qubit* inttoptr (i64 0 to %Qubit*))
           call void @__quantum__qis__rz__body(double 1.0, %Qubit* inttoptr (i64 0 to %Qubit*))
+          call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
+          call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null)
           ret void
         }
 
         declare void @__quantum__qis__rz__body(double, %Qubit*)
 
-        attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="adaptive_profile" "required_num_qubits"="1" "required_num_results"="0" }
+        declare void @__quantum__qis__mresetz__body(%Qubit*, %Result*) #1
+
+        declare void @__quantum__rt__result_record_output(%Result*, i8*)
+
+        attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="adaptive_profile" "required_num_qubits"="1" "required_num_results"="1" }
         attributes #1 = { "irreversible" }
 
         ; module flags