Repository: microsoft/qsharp
Pull request #2085 (2024-12-31 00:55:31)

Simplify `Relabel` logic
This simplifies the relabeling logic to collapse the four match cases down into one for easier readibility. It avoids trying to optimize special cases for qubits that may not have been mapped and treats all labels as having an intial mapping to themselves.

Based on feedback from @DmitryVasilevsky in https://github.com/microsoft/qsharp/pull/2082#discussion_r1899442453


Patch:
diff --git a/Cargo.lock b/Cargo.lock
index 493fc42b..8f495d01 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -44,15 +44,6 @@ dependencies = [
  "mimalloc-sys",
 ]
 
-[[package]]
-name = "always-assert"
-version = "0.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4436e0292ab1bb631b42973c61205e704475fe8126af845c8d923c0996328127"
-dependencies = [
- "log",
-]
-
 [[package]]
 name = "anes"
 version = "0.1.6"
@@ -378,21 +369,6 @@ dependencies = [
  "itertools",
 ]
 
-[[package]]
-name = "crossbeam-channel"
-version = "0.5.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2"
-dependencies = [
- "crossbeam-utils",
-]
-
-[[package]]
-name = "crossbeam-utils"
-version = "0.8.20"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
-
 [[package]]
 name = "crunchy"
 version = "0.2.2"
@@ -727,12 +703,6 @@ dependencies = [
  "libc",
 ]
 
-[[package]]
-name = "jod-thread"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8b23360e99b8717f20aaa4598f5a6541efbe30630039fbc7706cf954a87947ae"
-
 [[package]]
 name = "js-sys"
 version = "0.3.70"
@@ -866,15 +836,6 @@ dependencies = [
  "adler",
 ]
 
-[[package]]
-name = "miow"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "52ffbca2f655e33c08be35d87278e5b18b89550a37dbd598c20db92f6a471123"
-dependencies = [
- "windows-sys 0.42.0",
-]
-
 [[package]]
 name = "nalgebra"
 version = "0.33.0"
@@ -997,9 +958,9 @@ checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9"
 
 [[package]]
 name = "oq3_lexer"
-version = "0.6.0"
+version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0de2f0f9d48042c12f82b2550808378718627e108fc3f6adf63e02e5293541a3"
+checksum = "a27bbc91e3e9d6193a44aac8f5d62c1507c41669af71a4e7e0ef66fd6470e960"
 dependencies = [
  "unicode-properties",
  "unicode-xid",
@@ -1007,9 +968,9 @@ dependencies = [
 
 [[package]]
 name = "oq3_parser"
-version = "0.6.0"
+version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e69b215426a4a2a023fd62cca4436c633ba0ab39ee260aca875ac60321b3704b"
+checksum = "9a72022fcb414e8a0912920a1cf46417b6aa95f19d4b38778df7450f8a3c17fa"
 dependencies = [
  "drop_bomb",
  "oq3_lexer",
@@ -1018,9 +979,9 @@ dependencies = [
 
 [[package]]
 name = "oq3_semantics"
-version = "0.6.0"
+version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3e15e9cee54e92fb1b3aaa42556b0bd76c8c1c10912a7d6798f43dfc3afdcb0d"
+checksum = "b72dffd869f3548190c705828d030fbb7fca94e519dcfa6a489227e5c3ffd777"
 dependencies = [
  "boolenum",
  "hashbrown 0.12.3",
@@ -1031,9 +992,9 @@ dependencies = [
 
 [[package]]
 name = "oq3_source_file"
-version = "0.6.0"
+version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4f65243cc4807c600c544a21db6c17544c53aa2bc034b3eccf388251cc6530e7"
+checksum = "ff8c03f1f92c7a8f0b5249664b526169ceb8f925cb314ff93d3b27d8a4afb78c"
 dependencies = [
  "ariadne",
  "oq3_syntax",
@@ -1041,9 +1002,9 @@ dependencies = [
 
 [[package]]
 name = "oq3_syntax"
-version = "0.6.0"
+version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a8c3d637a7db9ddb3811719db8a466bd4960ea668df4b2d14043a1b0038465b0"
+checksum = "42c754ce1d9da28d6c0334c212d64b521288fe8c7cf16e9727d45dcf661ff084"
 dependencies = [
  "cov-mark",
  "either",
@@ -1052,7 +1013,6 @@ dependencies = [
  "once_cell",
  "oq3_lexer",
  "oq3_parser",
- "ra_ap_stdx",
  "rowan",
  "rustc-hash",
  "rustversion",
@@ -1652,20 +1612,6 @@ version = "0.0.188"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "92d33758724f997689f84146e5401e28d875a061804f861f113696f44f5232aa"
 
-[[package]]
-name = "ra_ap_stdx"
-version = "0.0.188"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2e80fb2ff88b31fa35cde89ae13ea7c9ada97c7a2c778dcafef530a267658000"
-dependencies = [
- "always-assert",
- "crossbeam-channel",
- "jod-thread",
- "libc",
- "miow",
- "winapi",
-]
-
 [[package]]
 name = "rand"
 version = "0.8.5"
@@ -1765,12 +1711,13 @@ dependencies = [
 
 [[package]]
 name = "rowan"
-version = "0.15.16"
+version = "0.15.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0a542b0253fa46e632d27a1dc5cf7b930de4df8659dc6e720b647fc72147ae3d"
+checksum = "32a58fa8a7ccff2aec4f39cc45bf5f985cec7125ab271cf681c279fd00192b49"
 dependencies = [
  "countme",
  "hashbrown 0.14.5",
+ "memoffset",
  "rustc-hash",
  "text-size",
 ]
@@ -2070,9 +2017,9 @@ dependencies = [
 
 [[package]]
 name = "triomphe"
-version = "0.1.13"
+version = "0.1.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6631e42e10b40c0690bf92f404ebcfe6e1fdb480391d15f17cc8e96eeed5369"
+checksum = "859eb650cfee7434994602c3a68b25d77ad9e68c8a6cd491616ef86661382eb3"
 
 [[package]]
 name = "typenum"
@@ -2231,22 +2178,6 @@ dependencies = [
  "safe_arch",
 ]
 
-[[package]]
-name = "winapi"
-version = "0.3.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
-dependencies = [
- "winapi-i686-pc-windows-gnu",
- "winapi-x86_64-pc-windows-gnu",
-]
-
-[[package]]
-name = "winapi-i686-pc-windows-gnu"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
-
 [[package]]
 name = "winapi-util"
 version = "0.1.9"
@@ -2256,27 +2187,6 @@ dependencies = [
  "windows-sys 0.59.0",
 ]
 
-[[package]]
-name = "winapi-x86_64-pc-windows-gnu"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
-
-[[package]]
-name = "windows-sys"
-version = "0.42.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
-dependencies = [
- "windows_aarch64_gnullvm 0.42.2",
- "windows_aarch64_msvc 0.42.2",
- "windows_i686_gnu 0.42.2",
- "windows_i686_msvc 0.42.2",
- "windows_x86_64_gnu 0.42.2",
- "windows_x86_64_gnullvm 0.42.2",
- "windows_x86_64_msvc 0.42.2",
-]
-
 [[package]]
 name = "windows-sys"
 version = "0.45.0"
diff --git a/Cargo.toml b/Cargo.toml
index 57aafe9f..12235954 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -62,11 +62,11 @@ ndarray = "0.15.4"
 num-bigint = "0.4"
 num-complex = "0.4"
 num-traits = "0.2"
-oq3_source_file = "0.6.0"
-oq3_syntax = "0.6.0"
-oq3_parser = "0.6.0"
-oq3_lexer = "0.6.0"
-oq3_semantics = "0.6.0"
+oq3_source_file = "0.7.0"
+oq3_syntax = "0.7.0"
+oq3_parser = "0.7.0"
+oq3_lexer = "0.7.0"
+oq3_semantics = "0.7.0"
 probability = "0.20"
 indenter = "0.3"
 regex-lite = "0.1"
diff --git a/compiler/qsc_eval/src/intrinsic.rs b/compiler/qsc_eval/src/intrinsic.rs
index 4d2b2e5e..df910c50 100644
--- a/compiler/qsc_eval/src/intrinsic.rs
+++ b/compiler/qsc_eval/src/intrinsic.rs
@@ -377,56 +377,30 @@ pub fn qubit_relabel(
         return Err(Error::RelabelingMismatch(arg_span));
     }
 
-    let mut map = FxHashMap::default();
-    map.reserve(left.len());
+    // Start with a mapping of each qubit to itself.
+    let mut mappings: FxHashMap<usize, usize> =
+        left.iter().copied().zip(left.iter().copied()).collect();
     for (l, r) in left.into_iter().zip(right.into_iter()) {
+        // Trivial case where the qubit is already mapped to itself in the relabel, which can be short circuited.
         if l == r {
             continue;
         }
-        match (map.contains_key(&l), map.contains_key(&r)) {
-            (false, false) => {
-                // Neither qubit has been relabeled yet.
-                swap(l, r);
-                map.insert(l, r);
-                map.insert(r, l);
-            }
-            (false, true) => {
-                // The right qubit has been relabeled, so we need to swap the left qubit with the
-                // new label for the right qubit.
-                let label = *map
-                    .keys()
-                    .find(|k| map[*k] == r)
-                    .expect("mapped qubit should be present as both key and value");
-                swap(l, label);
-                map.insert(l, r);
-                map.insert(label, l);
-            }
-            (true, false) => {
-                // The left qubit has been relabeled, so we swap the qubits as normal but
-                // remember the new mapping of the right qubit.
-                let mapped = *map.get(&l).expect("mapped qubit should be present");
-                swap(l, r);
-                map.insert(l, r);
-                map.insert(r, mapped);
-            }
-            (true, true) => {
-                // Both qubits have been relabeled, so we need to swap new label for the right qubit with
-                // the left qubit and remember the new mapping of both qubits.
-                // This is effectively a combination of the second and third cases above.
-                let label_r = *map
-                    .keys()
-                    .find(|k| map[*k] == r)
-                    .expect("mapped qubit should be present as both key and value");
-                let mapped_l = *map.get(&l).expect("mapped qubit should be present");
-                let mapped_r = *map.get(&r).expect("mapped qubit should be present");
 
-                // This swap is only necessary if the labels don't already point to each other.
-                if mapped_l != r && mapped_r != l {
-                    swap(label_r, l);
-                    map.insert(label_r, mapped_l);
-                    map.insert(l, mapped_r);
-                }
-            }
+        // Check what each label currently maps to.
+        let mapped_l = *mappings.get(&l).expect("mapped qubit should be present");
+        let mapped_r = *mappings.get(&r).expect("mapped qubit should be present");
+
+        // We only need to swap if the label is not pointing to the correct qubit.
+        if mapped_l != r && mapped_r != l {
+            // Do a reverse lookup to find which label is currently mapped to the desired right qubit.
+            // This tells us which label to use in the swap, which we will use in the update of the mappings too.
+            let label_r = *mappings
+                .keys()
+                .find(|k| mappings[*k] == r)
+                .expect("mapped qubit should be present as both key and value");
+            swap(l, label_r);
+            mappings.insert(label_r, mapped_l);
+            mappings.insert(l, mapped_r);
         }
     }
 
diff --git a/compiler/qsc_partial_eval/src/evaluation_context.rs b/compiler/qsc_partial_eval/src/evaluation_context.rs
index a0468580..b124634d 100644
--- a/compiler/qsc_partial_eval/src/evaluation_context.rs
+++ b/compiler/qsc_partial_eval/src/evaluation_context.rs
@@ -96,12 +96,10 @@ pub struct Scope {
     pub args_value_kind: Vec<ValueKind>,
     /// The classical environment of the callable, which holds values corresponding to local variables.
     pub env: Env,
-    // Consider optimizing `hybrid_vars` and `mutable_vars` by removing them and enlightening the evaluator on how to
-    // properly handle `Value::Var`, which could be either `static` or `dynamic`.
     /// Map that holds the values of local variables.
     hybrid_vars: FxHashMap<LocalVarId, Value>,
-    /// Maps variable IDs to mutable variables, which contain their current kind.
-    mutable_vars: FxHashMap<VariableId, MutableKind>,
+    /// Maps variable IDs to static literal values, if any.
+    static_vars: FxHashMap<VariableId, Literal>,
     /// Number of currently active blocks (starting from where this scope was created).
     active_block_count: usize,
 }
@@ -161,18 +159,37 @@ impl Scope {
             env,
             active_block_count: 1,
             hybrid_vars,
-            mutable_vars: FxHashMap::default(),
+            static_vars: FxHashMap::default(),
         }
     }
 
-    /// Gets a mutable variable.
-    pub fn find_mutable_kind(&self, var_id: VariableId) -> Option<&MutableKind> {
-        self.mutable_vars.get(&var_id)
+    /// Gets the static literal value for the given variable.
+    pub fn get_static_value(&self, var_id: VariableId) -> Option<&Literal> {
+        self.static_vars.get(&var_id)
     }
 
-    /// Gets a mutable mutable variable.
-    pub fn find_mutable_var_mut(&mut self, var_id: VariableId) -> Option<&mut MutableKind> {
-        self.mutable_vars.get_mut(&var_id)
+    /// Removes the static literal value for the given variable.
+    pub fn remove_static_value(&mut self, var_id: VariableId) {
+        self.static_vars.remove(&var_id);
+    }
+
+    /// Clones the static literal value mappings, which allows callers to cache the mappings across branches.
+    pub fn clone_static_var_mappings(&self) -> FxHashMap<VariableId, Literal> {
+        self.static_vars.clone()
+    }
+
+    /// Sets the static literal value mappings to the given mapping, overwriting any existing mappings.
+    pub fn set_static_var_mappings(&mut self, static_vars: FxHashMap<VariableId, Literal>) {
+        self.static_vars = static_vars;
+    }
+
+    /// Keeps only the static literal value mappings that are also present in the provided other mapping.
+    pub fn keep_matching_static_var_mappings(
+        &mut self,
+        other_mappings: &FxHashMap<VariableId, Literal>,
+    ) {
+        self.static_vars
+            .retain(|var_id, lit| Some(&*lit) == other_mappings.get(var_id));
     }
 
     /// Gets the value of a hybrid local variable.
@@ -197,11 +214,8 @@ impl Scope {
     }
 
     // Insert a variable into the mutable variables map.
-    pub fn insert_mutable_var(&mut self, var_id: VariableId, mutable_kind: MutableKind) {
-        let Entry::Vacant(vacant) = self.mutable_vars.entry(var_id) else {
-            panic!("mutable variable should not already exist");
-        };
-        vacant.insert(mutable_kind);
+    pub fn insert_static_var_mapping(&mut self, var_id: VariableId, literal: Literal) {
+        self.static_vars.insert(var_id, literal);
     }
 
     /// Determines whether we are currently evaluating a branch within the scope.
@@ -317,9 +331,3 @@ fn map_eval_value_to_value_kind(value: &Value) -> ValueKind {
         | Value::String(_) => ValueKind::Element(RuntimeKind::Static),
     }
 }
-
-#[derive(Clone, Copy, Debug)]
-pub enum MutableKind {
-    Static(Literal),
-    Dynamic,
-}
diff --git a/compiler/qsc_partial_eval/src/lib.rs b/compiler/qsc_partial_eval/src/lib.rs
index d6f57688..3fa2fd73 100644
--- a/compiler/qsc_partial_eval/src/lib.rs
+++ b/compiler/qsc_partial_eval/src/lib.rs
@@ -13,7 +13,7 @@ mod management;
 
 use core::panic;
 use evaluation_context::{
-    Arg, BlockNode, BranchControlFlow, EvalControlFlow, EvaluationContext, MutableKind, Scope,
+    Arg, BlockNode, BranchControlFlow, EvalControlFlow, EvaluationContext, Scope,
 };
 use management::{QuantumIntrinsicsChecker, ResourceManager};
 use miette::Diagnostic;
@@ -51,7 +51,7 @@ use qsc_rir::{
     builder,
     rir::{
         self, Callable, CallableId, CallableType, ConditionCode, Instruction, Literal, Operand,
-        Program,
+        Program, VariableId,
     },
 };
 use rustc_hash::FxHashMap;
@@ -204,8 +204,19 @@ impl<'a> PartialEvaluator<'a> {
     fn bind_value_to_ident(&mut self, mutability: Mutability, ident: &Ident, value: Value) {
         // We do slightly different things depending on the mutability of the identifier.
         match mutability {
-            Mutability::Immutable => self.bind_value_to_immutable_ident(ident, value),
             Mutability::Mutable => self.bind_value_to_mutable_ident(ident, value),
+            Mutability::Immutable => {
+                let current_scope = self.eval_context.get_current_scope();
+                if matches!(value, Value::Var(var) if current_scope.get_static_value(var.id.into()).is_none())
+                {
+                    // An immutable identifier is being bound to a dynamic value, so treat the identifier as mutable.
+                    // This allows it to represent a point-in-time copy of the mutable value during evaluation.
+                    self.bind_value_to_mutable_ident(ident, value);
+                } else {
+                    // The value is static, so bind it to the classical map.
+                    self.bind_value_to_immutable_ident(ident, value);
+                }
+            }
         };
     }
 
@@ -226,11 +237,13 @@ impl<'a> PartialEvaluator<'a> {
         }
 
         // Always bind the value to the hybrid map but do it differently depending of the value type.
-        if let Some((var_id, mutable_kind)) = self.try_create_mutable_variable(ident.id, &value) {
-            // Keep track of whether the mutable variable is static or dynamic.
-            self.eval_context
-                .get_current_scope_mut()
-                .insert_mutable_var(var_id, mutable_kind);
+        if let Some((var_id, literal)) = self.try_create_mutable_variable(ident.id, &value) {
+            // If the variable maps to a know static literal, track that mapping.
+            if let Some(literal) = literal {
+                self.eval_context
+                    .get_current_scope_mut()
+                    .insert_static_var_mapping(var_id, literal);
+            }
         } else {
             self.bind_value_in_hybrid_map(ident, value);
         }
@@ -1510,6 +1523,8 @@ impl<'a> PartialEvaluator<'a> {
         };
 
         // Evaluate the body expression.
+        // First, we cache the current static variable mappings so that we can restore them later.
+        let cached_mappings = self.clone_current_static_var_map();
         let if_true_branch_control_flow =
             self.eval_expr_if_branch(body_expr_id, continuation_block_node_id, maybe_if_expr_var)?;
         let if_true_block_id = match if_true_branch_control_flow {
@@ -1519,16 +1534,28 @@ impl<'a> PartialEvaluator<'a> {
 
         // Evaluate the otherwise expression (if any), and determine the block to branch to if the condition is false.
         let if_false_block_id = if let Some(otherwise_expr_id) = otherwise_expr_id {
+            // Cache the mappings after the true block so we can compare afterwards.
+            let post_if_true_mappings = self.clone_current_static_var_map();
+            // Restore the cached mappings from before evaluating the true block.
+            self.overwrite_current_static_var_map(cached_mappings);
             let if_false_branch_control_flow = self.eval_expr_if_branch(
                 otherwise_expr_id,
                 continuation_block_node_id,
                 maybe_if_expr_var,
             )?;
+            // Only keep the static mappings that are the same in both blocks; when they are different,
+            // the variable is no longer static across the if expression.
+            self.keep_matching_static_var_mappings(&post_if_true_mappings);
             match if_false_branch_control_flow {
                 BranchControlFlow::Block(block_id) => block_id,
                 BranchControlFlow::Return(value) => return Ok(EvalControlFlow::Return(value)),
             }
         } else {
+            // Only keep the static mappings that are the same after the true block as before; when they are different,
+            // the variable is no longer static across the if expression.
+            self.keep_matching_static_var_mappings(&cached_mappings);
+
+            // Since there is no otherwise block, we branch to the continuation block.
             continuation_block_node_id
         };
 
@@ -1814,9 +1841,7 @@ impl<'a> PartialEvaluator<'a> {
                 // the variable if it is static at this moment.
                 if let Value::Var(var) = bound_value {
                     let current_scope = self.eval_context.get_current_scope();
-                    if let Some(MutableKind::Static(literal)) =
-                        current_scope.find_mutable_kind(var.id.into())
-                    {
+                    if let Some(literal) = current_scope.get_static_value(var.id.into()) {
                         map_rir_literal_to_eval_value(*literal)
                     } else {
                         bound_value.clone()
@@ -2229,7 +2254,7 @@ impl<'a> PartialEvaluator<'a> {
         &mut self,
         local_var_id: LocalVarId,
         value: &Value,
-    ) -> Option<(rir::VariableId, MutableKind)> {
+    ) -> Option<(rir::VariableId, Option<Literal>)> {
         // Check if we can create a mutable variable for this value.
         let var_ty = try_get_eval_var_type(value)?;
 
@@ -2249,13 +2274,13 @@ impl<'a> PartialEvaluator<'a> {
         let store_ins = Instruction::Store(value_operand, rir_var);
         self.get_current_rir_block_mut().0.push(store_ins);
 
-        // Create a mutable variable.
-        let mutable_kind = match value_operand {
-            Operand::Literal(literal) => MutableKind::Static(literal),
-            Operand::Variable(_) => MutableKind::Dynamic,
+        // Create a mutable variable, mapping it to the static value if any.
+        let static_value = match value_operand {
+            Operand::Literal(literal) => Some(literal),
+            Operand::Variable(_) => None,
         };
 
-        Some((var_id, mutable_kind))
+        Some((var_id, static_value))
     }
 
     fn get_or_insert_callable(&mut self, callable: Callable) -> CallableId {
@@ -2625,14 +2650,16 @@ impl<'a> PartialEvaluator<'a> {
 
             // If this is a mutable variable, make sure to update whether it is static or dynamic.
             let current_scope = self.eval_context.get_current_scope_mut();
-            if matches!(rhs_operand, Operand::Variable(_))
-                || current_scope.is_currently_evaluating_branch()
-            {
-                if let Some(mutable_kind) = current_scope.find_mutable_var_mut(rir_var.variable_id)
-                {
-                    *mutable_kind = MutableKind::Dynamic;
+            match rhs_operand {
+                Operand::Literal(literal) => {
+                    // The variable maps to a static literal here, so track that literal value.
+                    current_scope.insert_static_var_mapping(rir_var.variable_id, literal);
                 }
-            }
+                Operand::Variable(_) => {
+                    // The variable is not known to be some literal value, so remove the static mapping.
+                    current_scope.remove_static_value(rir_var.variable_id);
+                }
+            };
         } else {
             // Verify that we are not updating a value that does not have a backing variable from a dynamic branch
             // because it is unsupported.
@@ -2918,6 +2945,27 @@ impl<'a> PartialEvaluator<'a> {
             _ => panic!("{value} cannot be mapped to a RIR operand"),
         }
     }
+
+    fn clone_current_static_var_map(&self) -> FxHashMap<VariableId, Literal> {
+        self.eval_context
+            .get_current_scope()
+            .clone_static_var_mappings()
+    }
+
+    fn overwrite_current_static_var_map(&mut self, static_vars: FxHashMap<VariableId, Literal>) {
+        self.eval_context
+            .get_current_scope_mut()
+            .set_static_var_mappings(static_vars);
+    }
+
+    fn keep_matching_static_var_mappings(
+        &mut self,
+        other_mappings: &FxHashMap<VariableId, Literal>,
+    ) {
+        self.eval_context
+            .get_current_scope_mut()
+            .keep_matching_static_var_mappings(other_mappings);
+    }
 }
 
 fn eval_un_op_with_literals(un_op: UnOp, value: Value) -> Value {
diff --git a/compiler/qsc_rir/src/passes/ssa_transform.rs b/compiler/qsc_rir/src/passes/ssa_transform.rs
index 040adad6..463943e9 100644
--- a/compiler/qsc_rir/src/passes/ssa_transform.rs
+++ b/compiler/qsc_rir/src/passes/ssa_transform.rs
@@ -172,7 +172,10 @@ fn map_variable_use_in_block(block: &mut Block, var_map: &mut FxHashMap<Variable
         match &mut instr {
             // Track the new value of the variable and omit the store instruction.
             Instruction::Store(operand, var) => {
-                var_map.insert(var.variable_id, *operand);
+                // Note this uses the mapped operand to make sure this variable points to whatever root literal or variable
+                // this operand corresponds to at this point in the block. This makes the new variable respect a point-in-time
+                // copy of the operand.
+                var_map.insert(var.variable_id, operand.mapped(var_map));
                 continue;
             }
 
@@ -181,7 +184,11 @@ fn map_variable_use_in_block(block: &mut Block, var_map: &mut FxHashMap<Variable
                 *args = args
                     .iter()
                     .map(|arg| match arg {
-                        Operand::Variable(var) => var.map_to_operand(var_map),
+                        Operand::Variable(var) => {
+                            // If the variable is not in the map, it is not something whose value has been updated via store in this block,
+                            // so just fallback to use the `arg` value directly.
+                            *var_map.get(&var.variable_id).unwrap_or(arg)
+                        }
                         Operand::Literal(_) => *arg,
                     })
                     .collect();
diff --git a/katas/content/nonlocal_games/examples/GHZGameDemo.qs b/katas/content/nonlocal_games/examples/GHZGameDemo.qs
new file mode 100644
index 00000000..3858ee24
--- /dev/null
+++ b/katas/content/nonlocal_games/examples/GHZGameDemo.qs
@@ -0,0 +1,82 @@
+namespace Quantum.Kata.GHZGame {
+    open Microsoft.Quantum.Random;
+    open Microsoft.Quantum.Convert;
+
+    function WinCondition (rst : Bool[], abc : Bool[]) : Bool {
+        return (rst[0] or rst[1] or rst[2]) == (abc[0] != abc[1] != abc[2]);
+    }
+
+    function AliceClassical (r : Bool) : Bool {
+        return true;
+    }
+
+    function BobClassical (s : Bool) : Bool {
+        return true;
+    }
+
+    function CharlieClassical (t : Bool) : Bool {
+        return true;
+    }
+
+    operation CreateEntangledTriple (qs : Qubit[]) : Unit is Adj {
+        X(qs[0]);
+        X(qs[1]);
+        H(qs[0]);
+        H(qs[1]);
+        Controlled Z([qs[0]], qs[1]);
+        ApplyControlledOnBitString([false, true], X, [qs[0], qs[1]], qs[2]);
+        ApplyControlledOnBitString([true, false], X, [qs[0], qs[1]], qs[2]);
+    }
+
+    operation AliceQuantum (bit : Bool, qubit : Qubit) : Bool {
+        if bit {
+            return MResetX(qubit) == One;
+        }
+        return MResetZ(qubit) == One;
+    }
+
+    operation BobQuantum (bit : Bool, qubit : Qubit) : Bool {
+        if bit {
+            return MResetX(qubit) == One;
+        }
+        return MResetZ(qubit) == One;
+    }
+
+    operation CharlieQuantum (bit : Bool, qubit : Qubit) : Bool {
+        if bit {
+            return MResetX(qubit) == One;
+        }
+        return MResetZ(qubit) == One;
+    }
+
+    operation getRandomRefereeBits () : Bool[] {
+        let bits = [[false, false, false],
+                    [true, true, false],
+                    [false, true, true],
+                    [true, false, true]];
+        return bits[DrawRandomInt(0, 3)];
+    }
+
+    @EntryPoint()
+    operation GHZ_GameDemo () : Unit {
+        use (aliceQubit, bobQubit, charlieQubit) = (Qubit(), Qubit(), Qubit());
+        mutable classicalWins = 0;
+        mutable quantumWins = 0;
+        let iterations = 1000;
+        for _ in 1 .. iterations {
+            CreateEntangledTriple([aliceQubit, bobQubit, charlieQubit]);
+            let inputs = getRandomRefereeBits();
+            let coutputs = [AliceClassical(inputs[0]), BobClassical(inputs[1]), CharlieClassical(inputs[2])];
+            if WinCondition(inputs, coutputs) {
+                set classicalWins += 1;
+            }
+            let qoutputs = [AliceQuantum(inputs[0], aliceQubit), BobQuantum(inputs[1], bobQubit), CharlieQuantum(inputs[2], charlieQubit)];
+            if WinCondition(inputs, qoutputs) {
+                set quantumWins += 1;
+            }
+            ResetAll([aliceQubit, bobQubit, charlieQubit]);
+        }
+        Message($"Percentage of classical wins is {100.0*IntAsDouble(classicalWins)/IntAsDouble(iterations)}%");
+        Message($"Percentage of quantum wins is {100.0*IntAsDouble(quantumWins)/IntAsDouble(iterations)}%");
+    }
+}
diff --git a/katas/content/nonlocal_games/ghz_create_entangled_triple/Placeholder.qs b/katas/content/nonlocal_games/ghz_create_entangled_triple/Placeholder.qs
new file mode 100644
index 00000000..fc35a3eb
--- /dev/null
+++ b/katas/content/nonlocal_games/ghz_create_entangled_triple/Placeholder.qs
@@ -0,0 +1,5 @@
+namespace Kata {
+    operation CreateEntangledTriple (qs : Qubit[]) : Unit {
+        // Implement your solution here...
+    }
+}
diff --git a/katas/content/nonlocal_games/ghz_create_entangled_triple/Solution.qs b/katas/content/nonlocal_games/ghz_create_entangled_triple/Solution.qs
new file mode 100644
index 00000000..77314a66
--- /dev/null
+++ b/katas/content/nonlocal_games/ghz_create_entangled_triple/Solution.qs
@@ -0,0 +1,11 @@
+namespace Kata {
+    operation CreateEntangledTriple (qs : Qubit[]) : Unit is Adj {
+        X(qs[0]);
+        X(qs[1]);
+        H(qs[0]);
+        H(qs[1]);
+        Controlled Z([qs[0]], qs[1]);
+        ApplyControlledOnBitString([false, true], X, [qs[0], qs[1]], qs[2]);
+        ApplyControlledOnBitString([true, false], X, [qs[0], qs[1]], qs[2]);
+    }
+}
diff --git a/katas/content/nonlocal_games/ghz_create_entangled_triple/Verification.qs b/katas/content/nonlocal_games/ghz_create_entangled_triple/Verification.qs
new file mode 100644
index 00000000..039384cd
--- /dev/null
+++ b/katas/content/nonlocal_games/ghz_create_entangled_triple/Verification.qs
@@ -0,0 +1,19 @@
+namespace Kata.Verification {
+    open Microsoft.Quantum.Diagnostics;
+    open Microsoft.Quantum.Katas;
+
+    operation CreateEntangledTriple_Reference (qs : Qubit[]) : Unit is Adj {
+        X(qs[0]);
+        X(qs[1]);
+        H(qs[0]);
+        H(qs[1]);
+        Controlled Z([qs[0]], qs[1]);
+        ApplyControlledOnBitString([false, true], X, [qs[0], qs[1]], qs[2]);
+        ApplyControlledOnBitString([true, false], X, [qs[0], qs[1]], qs[2]);
+    }
+
+    @EntryPoint()
+    operation CheckSolution() : Bool {
+        CheckOperationsEquivalenceOnZeroStateWithFeedback(Kata.CreateEntangledTriple, CreateEntangledTriple_Reference, 3)
+    }
+}
diff --git a/katas/content/nonlocal_games/ghz_create_entangled_triple/index.md b/katas/content/nonlocal_games/ghz_create_entangled_triple/index.md
new file mode 100644
index 00000000..4566d06d
--- /dev/null
+++ b/katas/content/nonlocal_games/ghz_create_entangled_triple/index.md
@@ -0,0 +1,12 @@
+In the quantum version of the game, the players still can not communicate during the game, but they are allowed to share
+qubits from an entangled triple before the start of the game.
+
+**Input:**
+An array of three qubits in the $\ket{000}$ state.
+
+**Goal:**
+Create the entangled state $\ket{\Phi} = \frac{1}{2} \big(\ket{000} - \ket{011} - \ket{101} - \ket{110} \big)$ on these qubits.
+
+>This state is equivalent to the three-qubit [GHZ state](https://en.wikipedia.org/wiki/Greenberger%E2%80%93Horne%E2%80%93Zeilinger_state)
+>$$\frac{1}{\sqrt{2}} \big(\ket{000} + \ket{111} \big)$$
+>up to local unitary operations. Please refer to the follow-up GHZ Quantum Strategy discussion for details.
diff --git a/katas/content/nonlocal_games/ghz_create_entangled_triple/solution.md b/katas/content/nonlocal_games/ghz_create_entangled_triple/solution.md
new file mode 100644
index 00000000..674cac56
--- /dev/null
+++ b/katas/content/nonlocal_games/ghz_create_entangled_triple/solution.md
@@ -0,0 +1,13 @@
+1. Apply an X gate to the first and the second qubits to get the $\ket{110}$ state.
+2. Appy an H gate to the first and the second qubits to get the following state:
+$$\frac12 \big( \ket{000} - \ket{010} - \ket{100} + \ket{110} \big)$$
+3. Flip the sign of the last term using a controlled Z gate with the first qubit as control and the second qubit as target (or vice versa):
+$$\frac12 \big( \ket{000} - \ket{010} - \ket{100} -{\color{blue}\ket{110}} \big)$$
+4. Now we have the right signs for each term, and the first and the last terms match those of the state we're preparing, so we just need to adjust the two middle terms.
+To do this, we can use [ControlledOnBitString](https://learn.microsoft.com/qsharp/api/qsharp-lang/microsoft.quantum.canon/applycontrolledonbitstring) operation to flip the state of the last qubit if the first two qubits are in $\ket{01}$ or in $\ket{10}$ states, which gives us:
+$$\frac{1}{2} \big(\ket{000} - {\color{blue}\ket{011}} - {\color{blue}\ket{101}} - \ket{110} \big)$$
+
+@[solution]({
+    "id": "nonlocal_games__ghz_create_entangled_triple_solution",
+    "codePath": "Solution.qs"
+})
diff --git a/katas/content/nonlocal_games/ghz_quantum_strategy/Placeholder.qs b/katas/content/nonlocal_games/ghz_quantum_strategy/Placeholder.qs
new file mode 100644
index 00000000..051a08d5
--- /dev/null
+++ b/katas/content/nonlocal_games/ghz_quantum_strategy/Placeholder.qs
@@ -0,0 +1,19 @@
+namespace Kata {
+    operation AliceQuantum (bit : Bool, qubit : Qubit) : Bool {
+        // Implement your solution here...
+
+        return false;
+    }
+
+    operation BobQuantum (bit : Bool, qubit : Qubit) : Bool {
+        // Implement your solution here...
+
+        return false;
+    }
+
+    operation CharlieQuantum (bit : Bool, qubit : Qubit) : Bool {
+        // Implement your solution here...
+
+        return false;
+    }
+}
diff --git a/katas/content/nonlocal_games/ghz_quantum_strategy/Solution.qs b/katas/content/nonlocal_games/ghz_quantum_strategy/Solution.qs
new file mode 100644
index 00000000..6904f2ad
--- /dev/null
+++ b/katas/content/nonlocal_games/ghz_quantum_strategy/Solution.qs
@@ -0,0 +1,23 @@
+namespace Kata {
+    operation AliceQuantum (bit : Bool, qubit : Qubit) : Bool {
+        if bit {
+            return MResetX(qubit) == One;
+        }
+        return MResetZ(qubit) == One;
+    }
+
+    operation BobQuantum (bit : Bool, qubit : Qubit) : Bool {
+        if bit {
+            return MResetX(qubit) == One;
+        }
+        return MResetZ(qubit) == One;
+    }
+
+    // alternative implementation
+    operation CharlieQuantum (bit : Bool, qubit : Qubit) : Bool {
+        if bit {
+            H(qubit);
+        }    
+        return M(qubit) == One;
+    }
+}
diff --git a/katas/content/nonlocal_games/ghz_quantum_strategy/Verification.qs b/katas/content/nonlocal_games/ghz_quantum_strategy/Verification.qs
new file mode 100644
index 00000000..3b7c2d80
--- /dev/null
+++ b/katas/content/nonlocal_games/ghz_quantum_strategy/Verification.qs
@@ -0,0 +1,59 @@
+namespace Kata.Verification {
+
+    function WinCondition_Reference (rst : Bool[], abc : Bool[]) : Bool {
+        return (rst[0] or rst[1] or rst[2]) == (abc[0] != abc[1] != abc[2]);
+    }
+
+    function RefereeBits () : Bool[][] {
+        return [[false, false, false],
+                [true, true, false],
+                [false, true, true],
+                [true, false, true]];
+    }
+
+    operation CreateEntangledTriple_Reference (qs : Qubit[]) : Unit is Adj {
+        X(qs[0]);
+        X(qs[1]);
+        H(qs[0]);
+        H(qs[1]);
+        Controlled Z([qs[0]], qs[1]);
+        ApplyControlledOnBitString([false, true], X, [qs[0], qs[1]], qs[2]);
+        ApplyControlledOnBitString([true, false], X, [qs[0], qs[1]], qs[2]);
+    }
+
+    operation PlayQuantumGHZ_Reference (strategies : ((Bool, Qubit) => Bool)[], inputs : Bool[], qubits : Qubit[]) : Bool[] {
+        let r = inputs[0];
+        let s = inputs[1];
+        let t = inputs[2];
+        let a = strategies[0](r, qubits[0]);
+        let b = strategies[1](s, qubits[1]);
+        let c = strategies[2](t, qubits[2]);
+        return [a, b, c];
+    }
+
+    @EntryPoint()
+    operation CheckSolution () : Bool {
+        use qs = Qubit[3];
+        let inputs = RefereeBits();
+        let strategies = [Kata.AliceQuantum, Kata.BobQuantum, Kata.CharlieQuantum];
+
+        let iterations = 1000;
+        mutable wins = 0;
+        for _ in 1 .. iterations {
+            for bits in inputs {
+                CreateEntangledTriple_Reference(qs);
+                let abc = PlayQuantumGHZ_Reference(strategies, bits, qs);
+                if WinCondition_Reference(bits, abc) {
+                    set wins = wins + 1;
+                }
+		ResetAll(qs);
+            }
+        }
+        if wins < iterations*Length(inputs) {
+            Message($"Players' quantum strategies get {wins} wins out of {iterations*Length(inputs)} runs, which is not optimal");
+            return false;
+        }
+        Message("Correct!");
+        true
+    }
+}
diff --git a/katas/content/nonlocal_games/ghz_quantum_strategy/index.md b/katas/content/nonlocal_games/ghz_quantum_strategy/index.md
new file mode 100644
index 00000000..c604c790
--- /dev/null
+++ b/katas/content/nonlocal_games/ghz_quantum_strategy/index.md
@@ -0,0 +1,11 @@
+In this task, you should implement three functions, one for each player's quantum strategy.
+Note that they are covered by one test, so you must implement all of them to pass the test.
+
+**Inputs:**
+
+1. The input bit for one of each of the players (R, S and T respectively),
+2. That player's qubit of the entangled triple shared between the players.
+
+**Goal:**
+Measure the qubit in the Z basis if the bit is 0 (FALSE), or the X basis if the bit is 1 (TRUE), and return the result.
+The state of the qubit after the operation does not matter.
diff --git a/katas/content/nonlocal_games/ghz_quantum_strategy/solution.md b/katas/content/nonlocal_games/ghz_quantum_strategy/solution.md
new file mode 100644
index 00000000..861d9f78
--- /dev/null
+++ b/katas/content/nonlocal_games/ghz_quantum_strategy/solution.md
@@ -0,0 +1,12 @@
+In Q#, you can perform measurements in a specific basis using either the
+[Measure operation](https://learn.microsoft.com/qsharp/api/qsharp-lang/microsoft.quantum.intrinsic/measure)
+or convenient shorthands for measure-and-reset-to-$\ket{0}$ sequence of operations
+[MResetZ](https://learn.microsoft.com/qsharp/api/qsharp-lang/microsoft.quantum.measurement/mresetz) and
+[MResetX](https://learn.microsoft.com/qsharp/api/qsharp-lang/microsoft.quantum.measurement/mresetx).
+
+Alternatively, you can recall that measuring the qubit in the X basis is equivalent to applying an H gate to it and measuring it in the Z basis.
+
+@[solution]({
+    "id": "nonlocal_games__ghz_quantum_strategy_solution",
+    "codePath": "Solution.qs"
+})
diff --git a/katas/content/nonlocal_games/index.md b/katas/content/nonlocal_games/index.md
index 2eb25e8a..1d683bb1 100644
--- a/katas/content/nonlocal_games/index.md
+++ b/katas/content/nonlocal_games/index.md
@@ -64,7 +64,7 @@ Then, let's proceed with quantum strategies for Alice and Bob.
 })
 
 @[section]({
-    "id": "nonlocal_games__discussion",
+    "id": "nonlocal_games__chsh_discussion",
     "title": "Discussion: Probability of Victory for Quantum Strategy"
 })
 
@@ -226,6 +226,146 @@ Then, let's proceed with quantum strategy and game implementation.
     "path": "./ghz_classical_game/"
 })
 
+@[exercise]({
+    "id": "nonlocal_games__ghz_create_entangled_state",
+    "title": "Create Entangled Triple",
+    "path": "./ghz_create_entangled_triple/"
+})
+
+@[exercise]({
+    "id": "nonlocal_games__ghz_quantum_strategy",
+    "title": "Quantum Strategy",
+    "path": "./ghz_quantum_strategy/"
+})
+
+@[section]({
+    "id": "nonlocal_games__ghz_discussion",
+    "title": "Discussion: Why the GHZ Quantum Strategy has a 100% Win Rate"
+})
+---------------------------------------------------------------
+Recall the formula for the win condition:
+1. The sum of the answer bits must be even if the question bits are (0,0,0)
+2. The sum of the answer bits must be odd if the question bits are (1,1,0), (1,0,1) or (0,1,1).
+
+> As a reminder, the probability "wavefunction" for three qubits is given by the following vector of length 8:
+> $$\begin{bmatrix}
+\psi_{000}\\
+\psi_{001}\\
+\psi_{010}\\
+\psi_{011}\\
+\psi_{100}\\
+\psi_{101}\\
+\psi_{110}\\
+\psi_{111}
+\end{bmatrix}$$
+> $|\psi_{ijk}|^2$ gives the probability of observing the corresponding basis state $\ket{ijk}$ upon measuring the qubit trio.
+
+Now, the entangled state $\ket{\Phi}$ that Alice, Bob and Charlie have agreed to use is represented as
+
+$$\begin{bmatrix}
++1/2\\
+ 0\\
+ 0\\
+-1/2\\
+ 0\\
+-1/2\\
+-1/2\\
+ 0
+\end{bmatrix}$$
+
+Let's first consider the case in which **all three players got the 0 bit**.
+
+When the players make their measurements, they will collectively get one of the basis states of the original state - 000, 011, 101 or 110.
+This means they'll report back zero \"1\" bits between them (with $25\%$ probability) or two \"1\" bits between them (with $75\%$ probability),
+either way satisfying the win condition for the team.
+
+Now, suppose **Alice gets a 0 bit and the others get 1**.
+
+Alice, looking at the 0, takes a Z basis measurement as before, while Bob and Charlie each take X basis measurements.
+(An X basis measurement is also equivalent to performing a Hadamard transform followed by a standard Z basis measurement,
+as the X basis is the $\ket{+}$ / $\ket{-}$, and a Hadamard transform rotates the $\ket{0}$ / $\ket{1}$ basis to $\ket{+}$ / $\ket{-}$.)
+So Bob and Charlie apply a Hadamard transform to their qubits, which corresponds to the following transformation applied to the whole system state:
+
+$$I \otimes H \otimes H = \begin{bmatrix}
+1/2 & 1/2 & 1/2 & 1/2 & 0 & 0 & 0 & 0\\
+1/2 & -1/2 & 1/2 & -1/2 & 0 & 0 & 0 & 0\\
+1/2 & 1/2 & -1/2 & -1/2 & 0 & 0 & 0 & 0\\
+1/2 & -1/2 & -1/2 & 1/2 & 0 & 0 & 0 & 0\\
+0 & 0 & 0 & 0 & 1/2 & 1/2 & 1/2 & 1/2\\
+0 & 0 & 0 & 0 & 1/2 & -1/2 & 1/2 & -1/2\\
+0 & 0 & 0 & 0 & 1/2 & 1/2 & -1/2 & -1/2\\
+0 & 0 & 0 & 0 & 1/2 & -1/2 & -1/2 & 1/2
+\end{bmatrix}$$
+
+When applied to the original entangled state, all the amplitude shifts to the states corresponding to $\ket{001}$, $\ket{010}$, $\ket{100}$, and $\ket{111}$.
+The precise configuration of the new entangled state is
+
+$$\begin{bmatrix}
+ 0\\
+ 1/2\\
+ 1/2\\
+ 0\\
+-1/2\\
+ 0\\
+ 0\\
+ 1/2
+\end{bmatrix}$$
+
+Now the players perform their measurements, and an odd number of them will see \"1\" (thanks to the new entangled state), again satisfying the win condition.
+Similarly, if **Alice and Charlie get \"1\" bits and Bob a \"0\"**, Alice and Charlie will apply Hadamard transforms to their qubits to give the tensor product
+
+$$ H \otimes I \otimes H = \begin{bmatrix}
+1/2 & 1/2  & 0   & 0    & 1/2  & 1/2  & 0    & 0\\
+1/2 & -1/2 & 0   & 0    & 1/2  & -1/2 & 0    & 0\\
+0   & 0    & 1/2 & 1/2  & 0    & 0    & 1/2  & 1/2\\
+0   & 0    & 1/2 & -1/2 & 0    & 0    & 1/2  & -1/2\\
+1/2 & 1/2  & 0   & 0    & -1/2 & -1/2 & 0    & 0\\
+1/2 & -1/2 & 0   & 0    & -1/2 & 1/2  & 0    & 0\\
+0   & 0    & 1/2 & 1/2  & 0    & 0    & -1/2 & -1/2\\
+0   & 0    & 1/2 & -1/2 & 0    & 0    & -1/2 & 1/2
+\end{bmatrix}$$
+
+The resulting state vector before the measurement will be the same as in the previous case, except that the $\ket{010}$ state
+ends up with the negative amplitude instead of $\ket{100}$. Again the players report back an odd number of true bits between them and the team wins.
+
+Finally if Charlie got the \"0\" bit and Alice and Bob both got \"1\", the latter two will apply Hadamard transform for the tensor product
+
+$$ H \otimes H \otimes I = \begin{bmatrix}
+1/2 & 0 & 1/2 & 0 & 1/2 & 0 & 1/2 & 0\\
+0 & 1/2 & 0 & 1/2 & 0 & 1/2 & 0 & 1/2\\
+1/2 & 0 & -1/2 & 0 & 1/2 & 0 & -1/2 & 0\\
+0 & 1/2 & 0 & -1/2 & 0 & 1/2 & 0 & -1/2\\
+1/2 & 0 & 1/2 & 0 & -1/2 & 0 & -1/2 & 0\\
+0 & 1/2 & 0 & 1/2 & 0 & -1/2 & 0 & -1/2\\
+1/2 & 0 & -1/2 & 0 & -1/2 & 0 & 1/2 & 0\\
+0 & 1/2 & 0 & -1/2 & 0 & -1/2 & 0 & 1/2
+\end{bmatrix}$$
+
+Operating with this on the original entangled state yields $(\ket{100} + \ket{010} - \ket{001} + \ket{111})/2$ and 
+once more the team will report back an odd number of true bits between them and win.
+
+@[section]({
+    "id": "nonlocal_games__ghz_e2e",
+    "title": "Running GHZ Game End to End"
+})
+
+Putting together the building blocks we've implemented into a strategy is very simple:
+
+1. Allocate three qubits and prepare our entangled state on them (using `CreateEntangledTriple`).
+2. Send one of the qubits to each of the players (this step is \"virtual\", not directly reflected in Q# code, other than making sure that the strategies each act on their qubit only).
+3. Have the players perform their measurements on their respective qubits using corresponding elements of the `strategies` array.
+4. Reset qubits to $\ket{0}$ before they are released.
+5. Return their measurement results.
+
+In the example below you can compare winning percentage of classical and quantum games.
+
+>You may play with the code and check if there is a difference in results when
+>1. The referee picks non-random bits. How can the referee minimize player's win probability?
+>2. Players get the [GHZ state](https://en.wikipedia.org/wiki/Greenberger%E2%80%93Horne%E2%80%93Zeilinger_state).
+> How to change the quantum strategies to get $100\%$ win rate?
+
+@[example]({"id": "nonlocal_games__ghz_e2edemo", "codePath": "./examples/GHZGameDemo.qs"})
+
 @[section]({
     "id": "nonlocal_games__conclusion",
     "title": "Conclusion"
diff --git a/library/std/src/Std/Intrinsic.qs b/library/std/src/Std/Intrinsic.qs
index 67465050..949587b6 100644
--- a/library/std/src/Std/Intrinsic.qs
+++ b/library/std/src/Std/Intrinsic.qs
@@ -143,14 +143,14 @@ operation CNOT(control : Qubit, target : Qubit) : Unit is Adj + Ctl {
 operation Exp(paulis : Pauli[], theta : Double, qubits : Qubit[]) : Unit is Adj + Ctl {
     body ... {
         Fact(Length(paulis) == Length(qubits), "Arrays 'pauli' and 'qubits' must have the same length");
-        let (newPaulis, newQubits) = RemovePauliI(paulis, qubits);
+        let (paulis, qubits) = RemovePauliI(paulis, qubits);
         let angle = -2.0 * theta;
-        let len = Length(newPaulis);
+        let len = Length(paulis);
 
         if len == 0 {
             ApplyGlobalPhase(theta);
         } elif len == 1 {
-            R(newPaulis[0], angle, qubits[0]);
+            R(paulis[0], angle, qubits[0]);
         } elif len == 2 {
             within {
                 MapPauli(qubits[1], paulis[0], paulis[1]);
diff --git a/package-lock.json b/package-lock.json
index 0d916bc0..e8246476 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -29,7 +29,7 @@
         "@vscode/test-web": "^0.0.61",
         "chai": "^4.3.10",
         "esbuild": "^0.23.1",
-        "eslint": "^9.1.0",
+        "eslint": "^9.17.0",
         "events": "^3.3.0",
         "github-markdown-css": "^5.3.0",
         "globals": "^15.9.0",
@@ -41,7 +41,7 @@
         "prettier": "^3.3.3",
         "punycode": "^2.3.1",
         "typescript": "^5.5.4",
-        "typescript-eslint": "^8.3.0",
+        "typescript-eslint": "^8.19.1",
         "url": "^0.11.3",
         "user-agent-data-types": "^0.4.2",
         "vscode-uri": "^3.0.8"
@@ -632,18 +632,66 @@
       }
     },
     "node_modules/@eslint-community/regexpp": {
-      "version": "4.10.0",
-      "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz",
-      "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==",
+      "version": "4.12.1",
+      "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz",
+      "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==",
       "dev": true,
       "engines": {
         "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
       }
     },
+    "node_modules/@eslint/config-array": {
+      "version": "0.19.1",
+      "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.1.tgz",
+      "integrity": "sha512-fo6Mtm5mWyKjA/Chy1BYTdn5mGJoDNjC7C64ug20ADsRDGrA85bN3uK3MaKbeRkRuuIEAR5N33Jr1pbm411/PA==",
+      "dev": true,
+      "dependencies": {
+        "@eslint/object-schema": "^2.1.5",
+        "debug": "^4.3.1",
+        "minimatch": "^3.1.2"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      }
+    },
+    "node_modules/@eslint/config-array/node_modules/brace-expansion": {
+      "version": "1.1.11",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+      "dev": true,
+      "dependencies": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "node_modules/@eslint/config-array/node_modules/minimatch": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+      "dev": true,
+      "dependencies": {
+        "brace-expansion": "^1.1.7"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/@eslint/core": {
+      "version": "0.9.1",
+      "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.9.1.tgz",
+      "integrity": "sha512-GuUdqkyyzQI5RMIWkHhvTWLCyLo1jNK3vzkSyaExH5kHPDHcuL2VOpHjmMY+y3+NC69qAKToBqldTBgYeLSr9Q==",
+      "dev": true,
+      "dependencies": {
+        "@types/json-schema": "^7.0.15"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      }
+    },
     "node_modules/@eslint/eslintrc": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz",
-      "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==",
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.2.0.tgz",
+      "integrity": "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==",
       "dev": true,
       "dependencies": {
         "ajv": "^6.12.4",
@@ -720,49 +768,68 @@
       }
     },
     "node_modules/@eslint/js": {
-      "version": "9.9.1",
-      "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.9.1.tgz",
-      "integrity": "sha512-xIDQRsfg5hNBqHz04H1R3scSVwmI+KUbqjsQKHKQ1DAUSaUjYPReZZmS/5PNiKu1fUvzDd6H7DEDKACSEhu+TQ==",
+      "version": "9.17.0",
+      "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.17.0.tgz",
+      "integrity": "sha512-Sxc4hqcs1kTu0iID3kcZDW3JHq2a77HO9P8CP6YEA/FpH3Ll8UXE2r/86Rz9YJLKme39S9vU5OWNjC6Xl0Cr3w==",
       "dev": true,
       "engines": {
         "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
       }
     },
-    "node_modules/@humanwhocodes/config-array": {
-      "version": "0.13.0",
-      "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz",
-      "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==",
-      "deprecated": "Use @eslint/config-array instead",
+    "node_modules/@eslint/object-schema": {
+      "version": "2.1.5",
+      "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.5.tgz",
+      "integrity": "sha512-o0bhxnL89h5Bae5T318nFoFzGy+YE5i/gGkoPAgkmTVdRKTiv3p8JHevPiPaMwoloKfEiiaHlawCqaZMqRm+XQ==",
+      "dev": true,
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      }
+    },
+    "node_modules/@eslint/plugin-kit": {
+      "version": "0.2.4",
+      "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.4.tgz",
+      "integrity": "sha512-zSkKow6H5Kdm0ZUQUB2kV5JIXqoG0+uH5YADhaEHswm664N9Db8dXSi0nMJpacpMf+MyyglF1vnZohpEg5yUtg==",
       "dev": true,
       "dependencies": {
-        "@humanwhocodes/object-schema": "^2.0.3",
-        "debug": "^4.3.1",
-        "minimatch": "^3.0.5"
+        "levn": "^0.4.1"
       },
       "engines": {
-        "node": ">=10.10.0"
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
       }
     },
-    "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": {
-      "version": "1.1.11",
-      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
-      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+    "node_modules/@humanfs/core": {
+      "version": "0.19.1",
+      "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
+      "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==",
       "dev": true,
-      "dependencies": {
-        "balanced-match": "^1.0.0",
-        "concat-map": "0.0.1"
+      "engines": {
+        "node": ">=18.18.0"
       }
     },
-    "node_modules/@humanwhocodes/config-array/node_modules/minimatch": {
-      "version": "3.1.2",
-      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
-      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+    "node_modules/@humanfs/node": {
+      "version": "0.16.6",
+      "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz",
+      "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==",
       "dev": true,
       "dependencies": {
-        "brace-expansion": "^1.1.7"
+        "@humanfs/core": "^0.19.1",
+        "@humanwhocodes/retry": "^0.3.0"
       },
       "engines": {
-        "node": "*"
+        "node": ">=18.18.0"
+      }
+    },
+    "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": {
+      "version": "0.3.1",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz",
+      "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==",
+      "dev": true,
+      "engines": {
+        "node": ">=18.18"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/nzakas"
       }
     },
     "node_modules/@humanwhocodes/module-importer": {
@@ -778,17 +845,10 @@
         "url": "https://github.com/sponsors/nzakas"
       }
     },
-    "node_modules/@humanwhocodes/object-schema": {
-      "version": "2.0.3",
-      "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz",
-      "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==",
-      "deprecated": "Use @eslint/object-schema instead",
-      "dev": true
-    },
     "node_modules/@humanwhocodes/retry": {
-      "version": "0.2.4",
-      "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.2.4.tgz",
-      "integrity": "sha512-Ttl/jHpxfS3st5sxwICYfk4pOH0WrLI1SpW283GgQL7sCWU7EHIOhX4b4fkIxr3tkfzwg8+FNojtzsIEE7Ecgg==",
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.1.tgz",
+      "integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==",
       "dev": true,
       "engines": {
         "node": ">=18.18"
@@ -1862,6 +1922,12 @@
       "integrity": "sha512-Wj71sXE4Q4AkGdG9Tvq1u/fquNz9EdG4LIJMwVVII7ashjD/8cf8fyIfJAjRr6YcsXnSE8cOGQPq1gqeR8z+3w==",
       "dev": true
     },
+    "node_modules/@types/estree": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
+      "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==",
+      "dev": true
+    },
     "node_modules/@types/jquery": {
       "version": "3.5.29",
       "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.29.tgz",
@@ -1871,6 +1937,12 @@
         "@types/sizzle": "*"
       }
     },
+    "node_modules/@types/json-schema": {
+      "version": "7.0.15",
+      "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
+      "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
+      "dev": true
+    },
     "node_modules/@types/linkify-it": {
       "version": "5.0.0",
       "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz",
@@ -1945,20 +2017,20 @@
       "dev": true
     },
     "node_modules/@typescript-eslint/eslint-plugin": {
-      "version": "8.3.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.3.0.tgz",
-      "integrity": "sha512-FLAIn63G5KH+adZosDYiutqkOkYEx0nvcwNNfJAf+c7Ae/H35qWwTYvPZUKFj5AS+WfHG/WJJfWnDnyNUlp8UA==",
+      "version": "8.19.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.19.1.tgz",
+      "integrity": "sha512-tJzcVyvvb9h/PB96g30MpxACd9IrunT7GF9wfA9/0TJ1LxGOJx1TdPzSbBBnNED7K9Ka8ybJsnEpiXPktolTLg==",
       "dev": true,
       "dependencies": {
         "@eslint-community/regexpp": "^4.10.0",
-        "@typescript-eslint/scope-manager": "8.3.0",
-        "@typescript-eslint/type-utils": "8.3.0",
-        "@typescript-eslint/utils": "8.3.0",
-        "@typescript-eslint/visitor-keys": "8.3.0",
+        "@typescript-eslint/scope-manager": "8.19.1",
+        "@typescript-eslint/type-utils": "8.19.1",
+        "@typescript-eslint/utils": "8.19.1",
+        "@typescript-eslint/visitor-keys": "8.19.1",
         "graphemer": "^1.4.0",
         "ignore": "^5.3.1",
         "natural-compare": "^1.4.0",
-        "ts-api-utils": "^1.3.0"
+        "ts-api-utils": "^2.0.0"
       },
       "engines": {
         "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -1969,24 +2041,20 @@
       },
       "peerDependencies": {
         "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0",
-        "eslint": "^8.57.0 || ^9.0.0"
-      },
-      "peerDependenciesMeta": {
-        "typescript": {
-          "optional": true
-        }
+        "eslint": "^8.57.0 || ^9.0.0",
+        "typescript": ">=4.8.4 <5.8.0"
       }
     },
     "node_modules/@typescript-eslint/parser": {
-      "version": "8.3.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.3.0.tgz",
-      "integrity": "sha512-h53RhVyLu6AtpUzVCYLPhZGL5jzTD9fZL+SYf/+hYOx2bDkyQXztXSc4tbvKYHzfMXExMLiL9CWqJmVz6+78IQ==",
+      "version": "8.19.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.19.1.tgz",
+      "integrity": "sha512-67gbfv8rAwawjYx3fYArwldTQKoYfezNUT4D5ioWetr/xCrxXxvleo3uuiFuKfejipvq+og7mjz3b0G2bVyUCw==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/scope-manager": "8.3.0",
-        "@typescript-eslint/types": "8.3.0",
-        "@typescript-eslint/typescript-estree": "8.3.0",
-        "@typescript-eslint/visitor-keys": "8.3.0",
+        "@typescript-eslint/scope-manager": "8.19.1",
+        "@typescript-eslint/types": "8.19.1",
+        "@typescript-eslint/typescript-estree": "8.19.1",
+        "@typescript-eslint/visitor-keys": "8.19.1",
         "debug": "^4.3.4"
       },
       "engines": {
@@ -1997,22 +2065,18 @@
         "url": "https://opencollective.com/typescript-eslint"
       },
       "peerDependencies": {
-        "eslint": "^8.57.0 || ^9.0.0"
-      },
-      "peerDependenciesMeta": {
-        "typescript": {
-          "optional": true
-        }
+        "eslint": "^8.57.0 || ^9.0.0",
+        "typescript": ">=4.8.4 <5.8.0"
       }
     },
     "node_modules/@typescript-eslint/scope-manager": {
-      "version": "8.3.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.3.0.tgz",
-      "integrity": "sha512-mz2X8WcN2nVu5Hodku+IR8GgCOl4C0G/Z1ruaWN4dgec64kDBabuXyPAr+/RgJtumv8EEkqIzf3X2U5DUKB2eg==",
+      "version": "8.19.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.19.1.tgz",
+      "integrity": "sha512-60L9KIuN/xgmsINzonOcMDSB8p82h95hoBfSBtXuO4jlR1R9L1xSkmVZKgCPVfavDlXihh4ARNjXhh1gGnLC7Q==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/types": "8.3.0",
-        "@typescript-eslint/visitor-keys": "8.3.0"
+        "@typescript-eslint/types": "8.19.1",
+        "@typescript-eslint/visitor-keys": "8.19.1"
       },
       "engines": {
         "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -2023,15 +2087,15 @@
       }
     },
     "node_modules/@typescript-eslint/type-utils": {
-      "version": "8.3.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.3.0.tgz",
-      "integrity": "sha512-wrV6qh//nLbfXZQoj32EXKmwHf4b7L+xXLrP3FZ0GOUU72gSvLjeWUl5J5Ue5IwRxIV1TfF73j/eaBapxx99Lg==",
+      "version": "8.19.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.19.1.tgz",
+      "integrity": "sha512-Rp7k9lhDKBMRJB/nM9Ksp1zs4796wVNyihG9/TU9R6KCJDNkQbc2EOKjrBtLYh3396ZdpXLtr/MkaSEmNMtykw==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/typescript-estree": "8.3.0",
-        "@typescript-eslint/utils": "8.3.0",
+        "@typescript-eslint/typescript-estree": "8.19.1",
+        "@typescript-eslint/utils": "8.19.1",
         "debug": "^4.3.4",
-        "ts-api-utils": "^1.3.0"
+        "ts-api-utils": "^2.0.0"
       },
       "engines": {
         "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -2040,16 +2104,15 @@
         "type": "opencollective",
         "url": "https://opencollective.com/typescript-eslint"
       },
-      "peerDependenciesMeta": {
-        "typescript": {
-          "optional": true
-        }
+      "peerDependencies": {
+        "eslint": "^8.57.0 || ^9.0.0",
+        "typescript": ">=4.8.4 <5.8.0"
       }
     },
     "node_modules/@typescript-eslint/types": {
-      "version": "8.3.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.3.0.tgz",
-      "integrity": "sha512-y6sSEeK+facMaAyixM36dQ5NVXTnKWunfD1Ft4xraYqxP0lC0POJmIaL/mw72CUMqjY9qfyVfXafMeaUj0noWw==",
+      "version": "8.19.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.19.1.tgz",
+      "integrity": "sha512-JBVHMLj7B1K1v1051ZaMMgLW4Q/jre5qGK0Ew6UgXz1Rqh+/xPzV1aW581OM00X6iOfyr1be+QyW8LOUf19BbA==",
       "dev": true,
       "engines": {
         "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -2060,19 +2123,19 @@
       }
     },
     "node_modules/@typescript-eslint/typescript-estree": {
-      "version": "8.3.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.3.0.tgz",
-      "integrity": "sha512-Mq7FTHl0R36EmWlCJWojIC1qn/ZWo2YiWYc1XVtasJ7FIgjo0MVv9rZWXEE7IK2CGrtwe1dVOxWwqXUdNgfRCA==",
+      "version": "8.19.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.19.1.tgz",
+      "integrity": "sha512-jk/TZwSMJlxlNnqhy0Eod1PNEvCkpY6MXOXE/WLlblZ6ibb32i2We4uByoKPv1d0OD2xebDv4hbs3fm11SMw8Q==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/types": "8.3.0",
-        "@typescript-eslint/visitor-keys": "8.3.0",
+        "@typescript-eslint/types": "8.19.1",
+        "@typescript-eslint/visitor-keys": "8.19.1",
         "debug": "^4.3.4",
         "fast-glob": "^3.3.2",
         "is-glob": "^4.0.3",
         "minimatch": "^9.0.4",
         "semver": "^7.6.0",
-        "ts-api-utils": "^1.3.0"
+        "ts-api-utils": "^2.0.0"
       },
       "engines": {
         "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -2081,22 +2144,20 @@
         "type": "opencollective",
         "url": "https://opencollective.com/typescript-eslint"
       },
-      "peerDependenciesMeta": {
-        "typescript": {
-          "optional": true
-        }
+      "peerDependencies": {
+        "typescript": ">=4.8.4 <5.8.0"
       }
     },
     "node_modules/@typescript-eslint/utils": {
-      "version": "8.3.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.3.0.tgz",
-      "integrity": "sha512-F77WwqxIi/qGkIGOGXNBLV7nykwfjLsdauRB/DOFPdv6LTF3BHHkBpq81/b5iMPSF055oO2BiivDJV4ChvNtXA==",
+      "version": "8.19.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.19.1.tgz",
+      "integrity": "sha512-IxG5gLO0Ne+KaUc8iW1A+XuKLd63o4wlbI1Zp692n1xojCl/THvgIKXJXBZixTh5dd5+yTJ/VXH7GJaaw21qXA==",
       "dev": true,
       "dependencies": {
         "@eslint-community/eslint-utils": "^4.4.0",
-        "@typescript-eslint/scope-manager": "8.3.0",
-        "@typescript-eslint/types": "8.3.0",
-        "@typescript-eslint/typescript-estree": "8.3.0"
+        "@typescript-eslint/scope-manager": "8.19.1",
+        "@typescript-eslint/types": "8.19.1",
+        "@typescript-eslint/typescript-estree": "8.19.1"
       },
       "engines": {
         "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -2106,17 +2167,18 @@
         "url": "https://opencollective.com/typescript-eslint"
       },
       "peerDependencies": {
-        "eslint": "^8.57.0 || ^9.0.0"
+        "eslint": "^8.57.0 || ^9.0.0",
+        "typescript": ">=4.8.4 <5.8.0"
       }
     },
     "node_modules/@typescript-eslint/visitor-keys": {
-      "version": "8.3.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.3.0.tgz",
-      "integrity": "sha512-RmZwrTbQ9QveF15m/Cl28n0LXD6ea2CjkhH5rQ55ewz3H24w+AMCJHPVYaZ8/0HoG8Z3cLLFFycRXxeO2tz9FA==",
+      "version": "8.19.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.19.1.tgz",
+      "integrity": "sha512-fzmjU8CHK853V/avYZAvuVut3ZTfwN5YtMaoi+X9Y9MA9keaWNHC3zEQ9zvyX/7Hj+5JkNyK1l7TOR2hevHB6Q==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/types": "8.3.0",
-        "eslint-visitor-keys": "^3.4.3"
+        "@typescript-eslint/types": "8.19.1",
+        "eslint-visitor-keys": "^4.2.0"
       },
       "engines": {
         "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -2126,6 +2188,18 @@
         "url": "https://opencollective.com/typescript-eslint"
       }
     },
+    "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz",
+      "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==",
+      "dev": true,
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
     "node_modules/@vscode/debugadapter": {
       "version": "1.65.0",
       "resolved": "https://registry.npmjs.org/@vscode/debugadapter/-/debugadapter-1.65.0.tgz",
@@ -2249,9 +2323,9 @@
       }
     },
     "node_modules/acorn": {
-      "version": "8.12.1",
-      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz",
-      "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==",
+      "version": "8.14.0",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz",
+      "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==",
       "dev": true,
       "bin": {
         "acorn": "bin/acorn"
@@ -3199,28 +3273,32 @@
       }
     },
     "node_modules/eslint": {
-      "version": "9.1.0",
-      "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.1.0.tgz",
-      "integrity": "sha512-1TCBecGFQtItia2o39P7Z4BK1X7ByNPxAiWJvwiyTGcOwYnTiiASgMpNA6a+beu8cFPhEDWvPf6mIlYUJv6sgA==",
+      "version": "9.17.0",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.17.0.tgz",
+      "integrity": "sha512-evtlNcpJg+cZLcnVKwsai8fExnqjGPicK7gnUtlNuzu+Fv9bI0aLpND5T44VLQtoMEnI57LoXO9XAkIXwohKrA==",
       "dev": true,
       "dependencies": {
         "@eslint-community/eslint-utils": "^4.2.0",
-        "@eslint-community/regexpp": "^4.6.1",
-        "@eslint/eslintrc": "^3.0.2",
-        "@eslint/js": "9.1.1",
-        "@humanwhocodes/config-array": "^0.13.0",
+        "@eslint-community/regexpp": "^4.12.1",
+        "@eslint/config-array": "^0.19.0",
+        "@eslint/core": "^0.9.0",
+        "@eslint/eslintrc": "^3.2.0",
+        "@eslint/js": "9.17.0",
+        "@eslint/plugin-kit": "^0.2.3",
+        "@humanfs/node": "^0.16.6",
         "@humanwhocodes/module-importer": "^1.0.1",
-        "@humanwhocodes/retry": "^0.2.3",
-        "@nodelib/fs.walk": "^1.2.8",
+        "@humanwhocodes/retry": "^0.4.1",
+        "@types/estree": "^1.0.6",
+        "@types/json-schema": "^7.0.15",
         "ajv": "^6.12.4",
         "chalk": "^4.0.0",
-        "cross-spawn": "^7.0.2",
+        "cross-spawn": "^7.0.6",
         "debug": "^4.3.2",
         "escape-string-regexp": "^4.0.0",
-        "eslint-scope": "^8.0.1",
-        "eslint-visitor-keys": "^4.0.0",
-        "espree": "^10.0.1",
-        "esquery": "^1.4.2",
+        "eslint-scope": "^8.2.0",
+        "eslint-visitor-keys": "^4.2.0",
+        "espree": "^10.3.0",
+        "esquery": "^1.5.0",
         "esutils": "^2.0.2",
         "fast-deep-equal": "^3.1.3",
         "file-entry-cache": "^8.0.0",
@@ -3229,15 +3307,11 @@
         "ignore": "^5.2.0",
         "imurmurhash": "^0.1.4",
         "is-glob": "^4.0.0",
-        "is-path-inside": "^3.0.3",
         "json-stable-stringify-without-jsonify": "^1.0.1",
-        "levn": "^0.4.1",
         "lodash.merge": "^4.6.2",
         "minimatch": "^3.1.2",
         "natural-compare": "^1.4.0",
-        "optionator": "^0.9.3",
-        "strip-ansi": "^6.0.1",
-        "text-table": "^0.2.0"
+        "optionator": "^0.9.3"
       },
       "bin": {
         "eslint": "bin/eslint.js"
@@ -3246,13 +3320,21 @@
         "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
       },
       "funding": {
-        "url": "https://opencollective.com/eslint"
+        "url": "https://eslint.org/donate"
+      },
+      "peerDependencies": {
+        "jiti": "*"
+      },
+      "peerDependenciesMeta": {
+        "jiti": {
+          "optional": true
+        }
       }
     },
     "node_modules/eslint-scope": {
-      "version": "8.0.2",
-      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.2.tgz",
-      "integrity": "sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA==",
+      "version": "8.2.0",
+      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz",
+      "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==",
       "dev": true,
       "dependencies": {
         "esrecurse": "^4.3.0",
@@ -3277,15 +3359,6 @@
         "url": "https://opencollective.com/eslint"
       }
     },
-    "node_modules/eslint/node_modules/@eslint/js": {
-      "version": "9.1.1",
-      "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.1.1.tgz",
-      "integrity": "sha512-5WoDz3Y19Bg2BnErkZTp0en+c/i9PvgFS7MBe1+m60HjFr0hrphlAGp4yzI7pxpt4xShln4ZyYp4neJm8hmOkQ==",
-      "dev": true,
-      "engines": {
-        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
-      }
-    },
     "node_modules/eslint/node_modules/ajv": {
       "version": "6.12.6",
       "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
@@ -3313,9 +3386,9 @@
       }
     },
     "node_modules/eslint/node_modules/eslint-visitor-keys": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz",
-      "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==",
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz",
+      "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==",
       "dev": true,
       "engines": {
         "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -3343,14 +3416,14 @@
       }
     },
     "node_modules/espree": {
-      "version": "10.1.0",
-      "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz",
-      "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==",
+      "version": "10.3.0",
+      "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz",
+      "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==",
       "dev": true,
       "dependencies": {
-        "acorn": "^8.12.0",
+        "acorn": "^8.14.0",
         "acorn-jsx": "^5.3.2",
-        "eslint-visitor-keys": "^4.0.0"
+        "eslint-visitor-keys": "^4.2.0"
       },
       "engines": {
         "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -3360,9 +3433,9 @@
       }
     },
     "node_modules/espree/node_modules/eslint-visitor-keys": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz",
-      "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==",
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz",
+      "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==",
       "dev": true,
       "engines": {
         "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -3435,16 +3508,16 @@
       "dev": true
     },
     "node_modules/fast-glob": {
-      "version": "3.3.2",
-      "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
-      "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
+      "version": "3.3.3",
+      "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
+      "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
       "dev": true,
       "dependencies": {
         "@nodelib/fs.stat": "^2.0.2",
         "@nodelib/fs.walk": "^1.2.3",
         "glob-parent": "^5.1.2",
         "merge2": "^1.3.0",
-        "micromatch": "^4.0.4"
+        "micromatch": "^4.0.8"
       },
       "engines": {
         "node": ">=8.6.0"
@@ -3475,9 +3548,9 @@
       "dev": true
     },
     "node_modules/fastq": {
-      "version": "1.17.1",
-      "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
-      "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==",
+      "version": "1.18.0",
+      "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.18.0.tgz",
+      "integrity": "sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw==",
       "dev": true,
       "dependencies": {
         "reusify": "^1.0.4"
@@ -4083,15 +4156,6 @@
         "node": ">=0.12.0"
       }
     },
-    "node_modules/is-path-inside": {
-      "version": "3.0.3",
-      "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
-      "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
-      "dev": true,
-      "engines": {
-        "node": ">=8"
-      }
-    },
     "node_modules/is-plain-obj": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
@@ -5794,12 +5858,6 @@
         "b4a": "^1.6.4"
       }
     },
-    "node_modules/text-table": {
-      "version": "0.2.0",
-      "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
-      "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
-      "dev": true
-    },
     "node_modules/through2": {
       "version": "2.0.5",
       "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz",
@@ -5832,15 +5890,15 @@
       }
     },
     "node_modules/ts-api-utils": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz",
-      "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==",
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.0.tgz",
+      "integrity": "sha512-xCt/TOAc+EOHS1XPnijD3/yzpH6qg2xppZO1YDqGoVsNXfQfzHpOdNuXwrwOU8u4ITXJyDCTyt8w5g1sZv9ynQ==",
       "dev": true,
       "engines": {
-        "node": ">=16"
+        "node": ">=18.12"
       },
       "peerDependencies": {
-        "typescript": ">=4.2.0"
+        "typescript": ">=4.8.4"
       }
     },
     "node_modules/tslib": {
@@ -5906,14 +5964,14 @@
       }
     },
     "node_modules/typescript-eslint": {
-      "version": "8.3.0",
-      "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.3.0.tgz",
-      "integrity": "sha512-EvWjwWLwwKDIJuBjk2I6UkV8KEQcwZ0VM10nR1rIunRDIP67QJTZAHBXTX0HW/oI1H10YESF8yWie8fRQxjvFA==",
+      "version": "8.19.1",
+      "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.19.1.tgz",
+      "integrity": "sha512-LKPUQpdEMVOeKluHi8md7rwLcoXHhwvWp3x+sJkMuq3gGm9yaYJtPo8sRZSblMFJ5pcOGCAak/scKf1mvZDlQw==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/eslint-plugin": "8.3.0",
-        "@typescript-eslint/parser": "8.3.0",
-        "@typescript-eslint/utils": "8.3.0"
+        "@typescript-eslint/eslint-plugin": "8.19.1",
+        "@typescript-eslint/parser": "8.19.1",
+        "@typescript-eslint/utils": "8.19.1"
       },
       "engines": {
         "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -5922,10 +5980,9 @@
         "type": "opencollective",
         "url": "https://opencollective.com/typescript-eslint"
       },
-      "peerDependenciesMeta": {
-        "typescript": {
-          "optional": true
-        }
+      "peerDependencies": {
+        "eslint": "^8.57.0 || ^9.0.0",
+        "typescript": ">=4.8.4 <5.8.0"
       }
     },
     "node_modules/uc.micro": {
diff --git a/package.json b/package.json
index 7a413bb4..59bd26d4 100644
--- a/package.json
+++ b/package.json
@@ -34,7 +34,7 @@
     "@vscode/test-web": "^0.0.61",
     "chai": "^4.3.10",
     "esbuild": "^0.23.1",
-    "eslint": "^9.1.0",
+    "eslint": "^9.17.0",
     "events": "^3.3.0",
     "github-markdown-css": "^5.3.0",
     "globals": "^15.9.0",
@@ -46,7 +46,7 @@
     "prettier": "^3.3.3",
     "punycode": "^2.3.1",
     "typescript": "^5.5.4",
-    "typescript-eslint": "^8.3.0",
+    "typescript-eslint": "^8.19.1",
     "url": "^0.11.3",
     "user-agent-data-types": "^0.4.2",
     "vscode-uri": "^3.0.8"
diff --git a/vscode/syntaxes/qsharp.tmLanguage.json b/vscode/syntaxes/qsharp.tmLanguage.json
index 051efa23..d9c390c2 100644
--- a/vscode/syntaxes/qsharp.tmLanguage.json
+++ b/vscode/syntaxes/qsharp.tmLanguage.json
@@ -6,6 +6,9 @@
     {
       "include": "#comments"
     },
+    {
+      "include": "#functions"
+    },
     {
       "include": "#keywords"
     },
@@ -20,6 +23,9 @@
     },
     {
       "include": "#strings"
+    },
+    {
+      "include": "#variables"
     }
   ],
   "repository": {
@@ -35,6 +41,103 @@
         }
       ]
     },
+    "functions": {
+      "patterns": [
+        {
+          "comment": "function definition",
+          "name": "meta.function.definition.qsharp",
+          "begin": "\\b(function)\\s+([A-Za-z0-9_]+)(\\()",
+          "beginCaptures": {
+            "1": {
+              "name": "keyword.other.qsharp"
+            },
+            "2": {
+              "name": "entity.name.function.qsharp"
+            },
+            "3": {
+              "name": "punctuation.brackets.round.qsharp"
+            }
+          },
+          "end": "\\)",
+          "endCaptures": {
+            "0": {
+              "name": "punctuation.brackets.round.qsharp"
+            }
+          },
+          "patterns": [
+            {
+              "include": "#comments"
+            },
+            {
+              "include": "#functions"
+            },
+            {
+              "include": "#keywords"
+            },
+            {
+              "include": "#operators"
+            },
+            {
+              "include": "#types"
+            },
+            {
+              "include": "#constants"
+            },
+            {
+              "include": "#strings"
+            },
+            {
+              "include": "#variables"
+            }
+          ]
+        },
+        {
+          "comment": "function calls",
+          "name": "meta.function.call.qsharp",
+          "begin": "\\b(?<!@)([A-Za-z0-9_]+)(\\()",
+          "beginCaptures": {
+            "1": {
+              "name": "entity.name.function.qsharp"
+            },
+            "2": {
+              "name": "punctuation.brackets.round.qsharp"
+            }
+          },
+          "end": "\\)",
+          "endCaptures": {
+            "0": {
+              "name": "punctuation.brackets.round.qsharp"
+            }
+          },
+          "patterns": [
+            {
+              "include": "#comments"
+            },
+            {
+              "include": "#functions"
+            },
+            {
+              "include": "#keywords"
+            },
+            {
+              "include": "#operators"
+            },
+            {
+              "include": "#types"
+            },
+            {
+              "include": "#constants"
+            },
+            {
+              "include": "#strings"
+            },
+            {
+              "include": "#variables"
+            }
+          ]
+        }
+      ]
+    },
     "keywords": {
       "patterns": [
         {
@@ -72,6 +175,11 @@
         {
           "name": "constant.other.result.qsharp",
           "match": "\\b(One|Zero)\\b"
+        },
+        {
+          "comment": "integers and decimals",
+          "name": "constant.numeric.qsharp",
+          "match": "\\b[\\d_]*\\.?[\\d_]\\b"
         }
       ]
     },
@@ -89,6 +197,14 @@
           ]
         }
       ]
+    },
+    "variables": {
+      "patterns": [
+        {
+          "name": "variable.other.qsharp",
+          "match": "\\b(?<!@)[A-Za-z0-9_]+\\b"
+        }
+      ]
     }
   },
   "scopeName": "source.qsharp"


Test patch:
diff --git a/compiler/qsc/src/codegen/tests.rs b/compiler/qsc/src/codegen/tests.rs
index 6c82359c..2379b926 100644
--- a/compiler/qsc/src/codegen/tests.rs
+++ b/compiler/qsc/src/codegen/tests.rs
@@ -1230,8 +1230,8 @@ mod adaptive_ri_profile {
             block_2:
               br label %block_3
             block_3:
-              %var_3 = phi i64 [0, %block_1], [1, %block_2]
-              call void @__quantum__rt__int_record_output(i64 %var_3, i8* null)
+              %var_4 = phi i64 [0, %block_1], [1, %block_2]
+              call void @__quantum__rt__int_record_output(i64 %var_4, i8* null)
               ret void
             }
 
diff --git a/compiler/qsc_partial_eval/src/tests/assigns.rs b/compiler/qsc_partial_eval/src/tests/assigns.rs
index 3a0e8e2a..321cb4da 100644
--- a/compiler/qsc_partial_eval/src/tests/assigns.rs
+++ b/compiler/qsc_partial_eval/src/tests/assigns.rs
@@ -191,7 +191,8 @@ fn assigning_dynamic_bool_updates_value_and_adds_store_instructions() {
                 Variable(1, Boolean) = Call id(2), args( Result(0), )
                 Variable(2, Boolean) = Store Variable(1, Boolean)
                 Variable(0, Boolean) = Store Variable(2, Boolean)
-                Call id(3), args( Variable(0, Boolean), Pointer, )
+                Variable(3, Boolean) = Store Variable(0, Boolean)
+                Call id(3), args( Variable(3, Boolean), Pointer, )
                 Return"#]],
     );
 }
@@ -301,7 +302,8 @@ fn assigning_dynamic_int_updates_value_and_adds_store_instructions() {
                 Branch Variable(2, Boolean), 2, 3
             Block 1:Block:
                 Variable(0, Integer) = Store Variable(3, Integer)
-                Call id(3), args( Variable(0, Integer), Pointer, )
+                Variable(4, Integer) = Store Variable(0, Integer)
+                Call id(3), args( Variable(4, Integer), Pointer, )
                 Return
             Block 2:Block:
                 Variable(3, Integer) = Store Integer(1)
@@ -379,7 +381,8 @@ fn assigning_classical_bool_within_dynamic_if_expression_adds_store_instruction(
                 Variable(2, Boolean) = Store Variable(1, Boolean)
                 Branch Variable(2, Boolean), 2, 1
             Block 1:Block:
-                Call id(3), args( Variable(0, Boolean), Pointer, )
+                Variable(3, Boolean) = Store Variable(0, Boolean)
+                Call id(3), args( Variable(3, Boolean), Pointer, )
                 Return
             Block 2:Block:
                 Variable(0, Boolean) = Store Bool(true)
@@ -456,7 +459,8 @@ fn assigning_classical_int_within_dynamic_if_else_expression_adds_store_instruct
                 Variable(2, Boolean) = Icmp Eq, Variable(1, Boolean), Bool(false)
                 Branch Variable(2, Boolean), 2, 3
             Block 1:Block:
-                Call id(3), args( Variable(0, Integer), Pointer, )
+                Variable(3, Integer) = Store Variable(0, Integer)
+                Call id(3), args( Variable(3, Integer), Pointer, )
                 Return
             Block 2:Block:
                 Variable(0, Integer) = Store Integer(1)
@@ -1210,9 +1214,11 @@ fn logical_and_assign_with_lhs_classical_true_is_optimized_as_store() {
                 Call id(1), args( Qubit(0), Result(0), )
                 Variable(0, Boolean) = Call id(2), args( Result(0), )
                 Variable(1, Boolean) = Store Variable(0, Boolean)
-                Variable(2, Boolean) = Store Bool(true)
                 Variable(2, Boolean) = Store Variable(1, Boolean)
-                Call id(3), args( Variable(2, Boolean), Pointer, )
+                Variable(3, Boolean) = Store Bool(true)
+                Variable(3, Boolean) = Store Variable(2, Boolean)
+                Variable(4, Boolean) = Store Variable(3, Boolean)
+                Call id(3), args( Variable(4, Boolean), Pointer, )
                 Return"#]],
     );
 }
@@ -1282,8 +1288,9 @@ fn logical_and_assign_with_lhs_classical_false_short_circuits_evaluation() {
                 Call id(1), args( Qubit(0), Result(0), )
                 Variable(0, Boolean) = Call id(2), args( Result(0), )
                 Variable(1, Boolean) = Store Variable(0, Boolean)
-                Variable(2, Boolean) = Store Bool(false)
-                Variable(2, Boolean) = Store Bool(false)
+                Variable(2, Boolean) = Store Variable(1, Boolean)
+                Variable(3, Boolean) = Store Bool(false)
+                Variable(3, Boolean) = Store Bool(false)
                 Call id(3), args( Bool(false), Pointer, )
                 Return"#]],
     );
@@ -1358,7 +1365,8 @@ fn logical_and_assign_with_dynamic_lhs_and_dynamic_rhs_short_circuits_when_rhs_i
                 Branch Variable(2, Boolean), 2, 1
             Block 1:Block:
                 Variable(2, Boolean) = Store Variable(3, Boolean)
-                Call id(3), args( Variable(2, Boolean), Pointer, )
+                Variable(6, Boolean) = Store Variable(2, Boolean)
+                Call id(3), args( Variable(6, Boolean), Pointer, )
                 Return
             Block 2:Block:
                 Call id(1), args( Qubit(0), Result(1), )
@@ -1434,8 +1442,9 @@ fn logical_or_assign_with_lhs_classical_true_short_circuits_evaluation() {
                 Call id(1), args( Qubit(0), Result(0), )
                 Variable(0, Boolean) = Call id(2), args( Result(0), )
                 Variable(1, Boolean) = Store Variable(0, Boolean)
-                Variable(2, Boolean) = Store Bool(true)
-                Variable(2, Boolean) = Store Bool(true)
+                Variable(2, Boolean) = Store Variable(1, Boolean)
+                Variable(3, Boolean) = Store Bool(true)
+                Variable(3, Boolean) = Store Bool(true)
                 Call id(3), args( Bool(true), Pointer, )
                 Return"#]],
     );
@@ -1506,9 +1515,11 @@ fn logical_or_assign_with_lhs_classical_false_is_optimized_as_store() {
                 Call id(1), args( Qubit(0), Result(0), )
                 Variable(0, Boolean) = Call id(2), args( Result(0), )
                 Variable(1, Boolean) = Store Variable(0, Boolean)
-                Variable(2, Boolean) = Store Bool(false)
                 Variable(2, Boolean) = Store Variable(1, Boolean)
-                Call id(3), args( Variable(2, Boolean), Pointer, )
+                Variable(3, Boolean) = Store Bool(false)
+                Variable(3, Boolean) = Store Variable(2, Boolean)
+                Variable(4, Boolean) = Store Variable(3, Boolean)
+                Call id(3), args( Variable(4, Boolean), Pointer, )
                 Return"#]],
     );
 }
@@ -1582,7 +1593,8 @@ fn logical_or_assign_with_dynamic_lhs_and_dynamic_rhs_short_circuits_when_rhs_is
                 Branch Variable(2, Boolean), 1, 2
             Block 1:Block:
                 Variable(2, Boolean) = Store Variable(3, Boolean)
-                Call id(3), args( Variable(2, Boolean), Pointer, )
+                Variable(6, Boolean) = Store Variable(2, Boolean)
+                Call id(3), args( Variable(6, Boolean), Pointer, )
                 Return
             Block 2:Block:
                 Call id(1), args( Qubit(0), Result(1), )
@@ -1662,7 +1674,8 @@ fn integer_assign_add_with_lhs_classical_integer_and_rhs_dynamic_integer() {
             Block 1:Block:
                 Variable(4, Integer) = Add Integer(0), Variable(3, Integer)
                 Variable(0, Integer) = Store Variable(4, Integer)
-                Call id(3), args( Variable(0, Integer), Pointer, )
+                Variable(5, Integer) = Store Variable(0, Integer)
+                Call id(3), args( Variable(5, Integer), Pointer, )
                 Return
             Block 2:Block:
                 Variable(3, Integer) = Store Integer(0)
@@ -1732,24 +1745,25 @@ fn integer_assign_sub_with_lhs_dynamic_integer_and_rhs_classical_integer() {
     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, 3
-        Block 1:Block:
-            Variable(3, Integer) = Store Variable(2, Integer)
-            Variable(4, Integer) = Sub Variable(3, Integer), Integer(1)
-            Variable(3, Integer) = Store Variable(4, Integer)
-            Call id(3), args( Variable(3, Integer), Pointer, )
-            Return
-        Block 2:Block:
-            Variable(2, Integer) = Store Integer(0)
-            Jump(1)
-        Block 3:Block:
-            Variable(2, Integer) = Store Integer(1)
-            Jump(1)"#]],
+            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:
+                Variable(3, Integer) = Store Variable(2, Integer)
+                Variable(4, Integer) = Sub Variable(3, Integer), Integer(1)
+                Variable(3, Integer) = Store Variable(4, Integer)
+                Variable(5, Integer) = Store Variable(3, Integer)
+                Call id(3), args( Variable(5, Integer), Pointer, )
+                Return
+            Block 2:Block:
+                Variable(2, Integer) = Store Integer(0)
+                Jump(1)
+            Block 3:Block:
+                Variable(2, Integer) = Store Integer(1)
+                Jump(1)"#]],
     );
 }
 
@@ -1812,35 +1826,36 @@ fn integer_assign_mul_with_lhs_dynamic_integer_and_rhs_dynamic_integer() {
     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, 3
-        Block 1:Block:
-            Variable(3, Integer) = Store Variable(2, Integer)
-            Call id(1), args( Qubit(0), Result(1), )
-            Variable(4, Boolean) = Call id(2), args( Result(1), )
-            Variable(5, Boolean) = Icmp Eq, Variable(4, Boolean), Bool(false)
-            Branch Variable(5, Boolean), 5, 6
-        Block 2:Block:
-            Variable(2, Integer) = Store Integer(0)
-            Jump(1)
-        Block 3:Block:
-            Variable(2, Integer) = Store Integer(1)
-            Jump(1)
-        Block 4:Block:
-            Variable(7, Integer) = Mul Variable(3, Integer), Variable(6, Integer)
-            Variable(3, Integer) = Store Variable(7, Integer)
-            Call id(3), args( Variable(3, Integer), Pointer, )
-            Return
-        Block 5:Block:
-            Variable(6, Integer) = Store Integer(1)
-            Jump(4)
-        Block 6:Block:
-            Variable(6, Integer) = Store Integer(0)
-            Jump(4)"#]],
+            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:
+                Variable(3, Integer) = Store Variable(2, Integer)
+                Call id(1), args( Qubit(0), Result(1), )
+                Variable(4, Boolean) = Call id(2), args( Result(1), )
+                Variable(5, Boolean) = Icmp Eq, Variable(4, Boolean), Bool(false)
+                Branch Variable(5, Boolean), 5, 6
+            Block 2:Block:
+                Variable(2, Integer) = Store Integer(0)
+                Jump(1)
+            Block 3:Block:
+                Variable(2, Integer) = Store Integer(1)
+                Jump(1)
+            Block 4:Block:
+                Variable(7, Integer) = Mul Variable(3, Integer), Variable(6, Integer)
+                Variable(3, Integer) = Store Variable(7, Integer)
+                Variable(8, Integer) = Store Variable(3, Integer)
+                Call id(3), args( Variable(8, Integer), Pointer, )
+                Return
+            Block 5:Block:
+                Variable(6, Integer) = Store Integer(1)
+                Jump(4)
+            Block 6:Block:
+                Variable(6, Integer) = Store Integer(0)
+                Jump(4)"#]],
     );
 }
 
@@ -1913,7 +1928,8 @@ fn integer_assign_div_with_lhs_classical_integer_and_rhs_dynamic_integer() {
             Block 1:Block:
                 Variable(4, Integer) = Sdiv Integer(0), Variable(3, Integer)
                 Variable(0, Integer) = Store Variable(4, Integer)
-                Call id(3), args( Variable(0, Integer), Pointer, )
+                Variable(5, Integer) = Store Variable(0, Integer)
+                Call id(3), args( Variable(5, Integer), Pointer, )
                 Return
             Block 2:Block:
                 Variable(3, Integer) = Store Integer(0)
@@ -1983,24 +1999,25 @@ fn integer_assign_mod_with_lhs_dynamic_integer_and_rhs_classical_integer() {
     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, 3
-        Block 1:Block:
-            Variable(3, Integer) = Store Variable(2, Integer)
-            Variable(4, Integer) = Srem Variable(3, Integer), Integer(1)
-            Variable(3, Integer) = Store Variable(4, Integer)
-            Call id(3), args( Variable(3, Integer), Pointer, )
-            Return
-        Block 2:Block:
-            Variable(2, Integer) = Store Integer(0)
-            Jump(1)
-        Block 3:Block:
-            Variable(2, Integer) = Store Integer(1)
-            Jump(1)"#]],
+            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:
+                Variable(3, Integer) = Store Variable(2, Integer)
+                Variable(4, Integer) = Srem Variable(3, Integer), Integer(1)
+                Variable(3, Integer) = Store Variable(4, Integer)
+                Variable(5, Integer) = Store Variable(3, Integer)
+                Call id(3), args( Variable(5, Integer), Pointer, )
+                Return
+            Block 2:Block:
+                Variable(2, Integer) = Store Integer(0)
+                Jump(1)
+            Block 3:Block:
+                Variable(2, Integer) = Store Integer(1)
+                Jump(1)"#]],
     );
 }
 
@@ -2119,7 +2136,8 @@ fn integer_assign_exp_with_lhs_dynamic_integer_and_rhs_classical_zero_integer()
                 Variable(3, Integer) = Store Variable(2, Integer)
                 Variable(4, Integer) = Store Integer(1)
                 Variable(3, Integer) = Store Variable(4, Integer)
-                Call id(3), args( Variable(3, Integer), Pointer, )
+                Variable(5, Integer) = Store Variable(3, Integer)
+                Call id(3), args( Variable(5, Integer), Pointer, )
                 Return
             Block 2:Block:
                 Variable(2, Integer) = Store Integer(0)
@@ -2202,7 +2220,8 @@ fn integer_assign_exp_with_lhs_dynamic_integer_and_rhs_classical_positive_intege
                 Variable(6, Integer) = Mul Variable(5, Integer), Variable(3, Integer)
                 Variable(7, Integer) = Mul Variable(6, Integer), Variable(3, Integer)
                 Variable(3, Integer) = Store Variable(7, Integer)
-                Call id(3), args( Variable(3, Integer), Pointer, )
+                Variable(8, Integer) = Store Variable(3, Integer)
+                Call id(3), args( Variable(8, Integer), Pointer, )
                 Return
             Block 2:Block:
                 Variable(2, Integer) = Store Integer(0)
@@ -2316,7 +2335,8 @@ fn integer_assign_bitwise_and_with_lhs_dynamic_integer_and_rhs_dynamic_integer()
             Block 4:Block:
                 Variable(7, Integer) = BitwiseAnd Variable(3, Integer), Variable(6, Integer)
                 Variable(3, Integer) = Store Variable(7, Integer)
-                Call id(3), args( Variable(3, Integer), Pointer, )
+                Variable(8, Integer) = Store Variable(3, Integer)
+                Call id(3), args( Variable(8, Integer), Pointer, )
                 Return
             Block 5:Block:
                 Variable(6, Integer) = Store Integer(1)
@@ -2396,7 +2416,8 @@ fn integer_assign_bitwise_or_with_lhs_classical_integer_and_rhs_dynamic_integer(
             Block 1:Block:
                 Variable(4, Integer) = BitwiseOr Integer(0), Variable(3, Integer)
                 Variable(0, Integer) = Store Variable(4, Integer)
-                Call id(3), args( Variable(0, Integer), Pointer, )
+                Variable(5, Integer) = Store Variable(0, Integer)
+                Call id(3), args( Variable(5, Integer), Pointer, )
                 Return
             Block 2:Block:
                 Variable(3, Integer) = Store Integer(0)
@@ -2466,24 +2487,25 @@ fn integer_bitwise_xor_with_lhs_dynamic_integer_and_rhs_classical_integer() {
     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, 3
-        Block 1:Block:
-            Variable(3, Integer) = Store Variable(2, Integer)
-            Variable(4, Integer) = BitwiseXor Variable(3, Integer), Integer(1)
-            Variable(3, Integer) = Store Variable(4, Integer)
-            Call id(3), args( Variable(3, Integer), Pointer, )
-            Return
-        Block 2:Block:
-            Variable(2, Integer) = Store Integer(0)
-            Jump(1)
-        Block 3:Block:
-            Variable(2, Integer) = Store Integer(1)
-            Jump(1)"#]],
+            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:
+                Variable(3, Integer) = Store Variable(2, Integer)
+                Variable(4, Integer) = BitwiseXor Variable(3, Integer), Integer(1)
+                Variable(3, Integer) = Store Variable(4, Integer)
+                Variable(5, Integer) = Store Variable(3, Integer)
+                Call id(3), args( Variable(5, Integer), Pointer, )
+                Return
+            Block 2:Block:
+                Variable(2, Integer) = Store Integer(0)
+                Jump(1)
+            Block 3:Block:
+                Variable(2, Integer) = Store Integer(1)
+                Jump(1)"#]],
     );
 }
 
@@ -2567,7 +2589,8 @@ fn integer_assign_bitwise_left_shift_with_lhs_dynamic_integer_and_rhs_dynamic_in
             Block 4:Block:
                 Variable(7, Integer) = Shl Variable(3, Integer), Variable(6, Integer)
                 Variable(3, Integer) = Store Variable(7, Integer)
-                Call id(3), args( Variable(3, Integer), Pointer, )
+                Variable(8, Integer) = Store Variable(3, Integer)
+                Call id(3), args( Variable(8, Integer), Pointer, )
                 Return
             Block 5:Block:
                 Variable(6, Integer) = Store Integer(1)
@@ -2647,7 +2670,8 @@ fn integer_assign_bitwise_right_shift_with_lhs_classical_integer_and_rhs_dynamic
             Block 1:Block:
                 Variable(4, Integer) = Ashr Integer(0), Variable(3, Integer)
                 Variable(0, Integer) = Store Variable(4, Integer)
-                Call id(3), args( Variable(0, Integer), Pointer, )
+                Variable(5, Integer) = Store Variable(0, Integer)
+                Call id(3), args( Variable(5, Integer), Pointer, )
                 Return
             Block 2:Block:
                 Variable(3, Integer) = Store Integer(0)
diff --git a/compiler/qsc_partial_eval/src/tests/bindings.rs b/compiler/qsc_partial_eval/src/tests/bindings.rs
index a669d879..8c255384 100644
--- a/compiler/qsc_partial_eval/src/tests/bindings.rs
+++ b/compiler/qsc_partial_eval/src/tests/bindings.rs
@@ -175,7 +175,9 @@ fn immutable_bool_binding_does_not_generate_store_instruction() {
                 Call id(1), args( Qubit(0), Result(0), )
                 Variable(0, Boolean) = Call id(2), args( Result(0), )
                 Variable(1, Boolean) = Store Variable(0, Boolean)
-                Call id(3), args( Variable(1, Boolean), Pointer, )
+                Variable(2, Boolean) = Store Variable(1, Boolean)
+                Variable(3, Boolean) = Store Variable(2, Boolean)
+                Call id(3), args( Variable(3, Boolean), Pointer, )
                 Return"#]],
     );
 }
@@ -242,7 +244,8 @@ fn mutable_bool_binding_generates_store_instruction() {
                 Variable(0, Boolean) = Call id(2), args( Result(0), )
                 Variable(1, Boolean) = Store Variable(0, Boolean)
                 Variable(2, Boolean) = Store Variable(1, Boolean)
-                Call id(3), args( Variable(2, Boolean), Pointer, )
+                Variable(3, Boolean) = Store Variable(2, Boolean)
+                Call id(3), args( Variable(3, Boolean), Pointer, )
                 Return"#]],
     );
 }
@@ -310,7 +313,9 @@ fn immutable_int_binding_does_not_generate_store_instruction() {
                 Variable(1, Boolean) = Store Variable(0, Boolean)
                 Branch Variable(1, Boolean), 2, 3
             Block 1:Block:
-                Call id(3), args( Variable(2, Integer), Pointer, )
+                Variable(3, Integer) = Store Variable(2, Integer)
+                Variable(4, Integer) = Store Variable(3, Integer)
+                Call id(3), args( Variable(4, Integer), Pointer, )
                 Return
             Block 2:Block:
                 Variable(2, Integer) = Store Integer(0)
@@ -385,7 +390,8 @@ fn mutable_int_binding_does_generate_store_instruction() {
                 Branch Variable(1, Boolean), 2, 3
             Block 1:Block:
                 Variable(3, Integer) = Store Variable(2, Integer)
-                Call id(3), args( Variable(3, Integer), Pointer, )
+                Variable(4, Integer) = Store Variable(3, Integer)
+                Call id(3), args( Variable(4, Integer), Pointer, )
                 Return
             Block 2:Block:
                 Variable(2, Integer) = Store Integer(0)
@@ -462,22 +468,23 @@ fn mutable_variable_in_outer_scope_set_to_mutable_from_inner_scope() {
     assert_blocks(
         &program,
         &expect![[r#"
-        Blocks:
-        Block 0:Block:
-            Variable(0, Integer) = Store Integer(0)
-            Call id(1), args( Qubit(0), Result(0), )
-            Variable(1, Boolean) = Call id(2), args( Result(0), )
-            Variable(2, Boolean) = Store Variable(1, Boolean)
-            Branch Variable(2, Boolean), 2, 3
-        Block 1:Block:
-            Call id(3), args( Variable(0, Integer), Pointer, )
-            Return
-        Block 2:Block:
-            Variable(3, Integer) = Store Integer(1)
-            Variable(0, Integer) = Store Integer(1)
-            Jump(1)
-        Block 3:Block:
-            Variable(0, Integer) = Store Integer(2)
-            Jump(1)"#]],
+            Blocks:
+            Block 0:Block:
+                Variable(0, Integer) = Store Integer(0)
+                Call id(1), args( Qubit(0), Result(0), )
+                Variable(1, Boolean) = Call id(2), args( Result(0), )
+                Variable(2, Boolean) = Store Variable(1, Boolean)
+                Branch Variable(2, Boolean), 2, 3
+            Block 1:Block:
+                Variable(4, Integer) = Store Variable(0, Integer)
+                Call id(3), args( Variable(4, Integer), Pointer, )
+                Return
+            Block 2:Block:
+                Variable(3, Integer) = Store Integer(1)
+                Variable(0, Integer) = Store Integer(1)
+                Jump(1)
+            Block 3:Block:
+                Variable(0, Integer) = Store Integer(2)
+                Jump(1)"#]],
     );
 }
diff --git a/compiler/qsc_partial_eval/src/tests/calls.rs b/compiler/qsc_partial_eval/src/tests/calls.rs
index f614c712..6607eaf5 100644
--- a/compiler/qsc_partial_eval/src/tests/calls.rs
+++ b/compiler/qsc_partial_eval/src/tests/calls.rs
@@ -553,7 +553,8 @@ fn call_to_operation_that_returns_dynamic_bool() {
                 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( Variable(1, Boolean), Pointer, )
+                Variable(2, Boolean) = Store Variable(1, Boolean)
+                Call id(3), args( Variable(2, Boolean), Pointer, )
                 Return"#]],
     );
 }
diff --git a/compiler/qsc_partial_eval/src/tests/dynamic_vars.rs b/compiler/qsc_partial_eval/src/tests/dynamic_vars.rs
index d0b580f8..f278746b 100644
--- a/compiler/qsc_partial_eval/src/tests/dynamic_vars.rs
+++ b/compiler/qsc_partial_eval/src/tests/dynamic_vars.rs
@@ -55,21 +55,22 @@ fn dynamic_int_from_if_expression_with_single_measurement_comparison_and_classic
     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, 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)"#]],
+            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:
+                Variable(3, Integer) = Store Variable(2, Integer)
+                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)"#]],
     );
 }
 
@@ -150,25 +151,513 @@ fn dynamic_int_from_if_expression_with_single_measurement_comparison_and_non_cla
                 output_type: <VOID>
                 body: <NONE>"#]],
     );
+    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, 3
+            Block 1:Block:
+                Variable(3, Integer) = Store Variable(2, Integer)
+                Call id(5), args( Integer(0), Pointer, )
+                Return
+            Block 2:Block:
+                Call id(3), args( Qubit(1), )
+                Variable(2, Integer) = Store Integer(0)
+                Jump(1)
+            Block 3:Block:
+                Call id(4), args( Qubit(1), )
+                Variable(2, Integer) = Store Integer(1)
+                Jump(1)"#]],
+    );
+}
+
+#[test]
+fn dynamic_var_across_if_else_static_in_both_branches_constant_folded() {
+    let program = get_rir_program(indoc! {
+        r#"
+        namespace Test {
+            @EntryPoint()
+            operation Main() : Unit {
+                mutable value = 0;
+                use q = Qubit();
+                let cond = MResetZ(q);
+                if cond == Zero {
+                    value -= 1;
+                } else {
+                    value += 1;
+                }
+            }
+        }
+        "#,
+    });
+
+    assert_blocks(
+        &program,
+        &expect![[r#"
+        Blocks:
+        Block 0:Block:
+            Variable(0, Integer) = Store Integer(0)
+            Call id(1), args( Qubit(0), Result(0), )
+            Variable(1, Boolean) = Call id(2), args( Result(0), )
+            Variable(2, Boolean) = Icmp Eq, Variable(1, Boolean), Bool(false)
+            Branch Variable(2, Boolean), 2, 3
+        Block 1:Block:
+            Call id(3), args( Integer(0), Pointer, )
+            Return
+        Block 2:Block:
+            Variable(0, Integer) = Store Integer(-1)
+            Jump(1)
+        Block 3:Block:
+            Variable(0, Integer) = Store Integer(1)
+            Jump(1)"#]],
+    );
+}
+
+#[test]
+fn dynamic_var_across_if_else_in_loop_constant_folded_in_first_iteration() {
+    let program = get_rir_program(indoc! {
+        r#"
+        namespace Test {
+            @EntryPoint()
+            operation Main() : Unit {
+                mutable value = 0;
+                use q = Qubit();
+                let cond = MResetZ(q);
+                for _ in 0..1 {
+                    if cond == Zero {
+                        value -= 1;
+                    } else {
+                        value += 1;
+                    }
+                }
+            }
+        }
+        "#,
+    });
+
+    assert_blocks(
+        &program,
+        &expect![[r#"
+        Blocks:
+        Block 0:Block:
+            Variable(0, Integer) = Store Integer(0)
+            Call id(1), args( Qubit(0), Result(0), )
+            Variable(1, Integer) = Store Integer(0)
+            Variable(2, Boolean) = Call id(2), args( Result(0), )
+            Variable(3, Boolean) = Icmp Eq, Variable(2, Boolean), Bool(false)
+            Branch Variable(3, Boolean), 2, 3
+        Block 1:Block:
+            Variable(1, Integer) = Store Integer(1)
+            Variable(4, Boolean) = Call id(2), args( Result(0), )
+            Variable(5, Boolean) = Icmp Eq, Variable(4, Boolean), Bool(false)
+            Branch Variable(5, Boolean), 5, 6
+        Block 2:Block:
+            Variable(0, Integer) = Store Integer(-1)
+            Jump(1)
+        Block 3:Block:
+            Variable(0, Integer) = Store Integer(1)
+            Jump(1)
+        Block 4:Block:
+            Variable(1, Integer) = Store Integer(2)
+            Call id(3), args( Integer(0), Pointer, )
+            Return
+        Block 5:Block:
+            Variable(6, Integer) = Sub Variable(0, Integer), Integer(1)
+            Variable(0, Integer) = Store Variable(6, Integer)
+            Jump(4)
+        Block 6:Block:
+            Variable(7, Integer) = Add Variable(0, Integer), Integer(1)
+            Variable(0, Integer) = Store Variable(7, Integer)
+            Jump(4)"#]],
+    );
+}
+
+#[test]
+fn dynamic_var_within_if_else_in_loop_constant_folded_in_every_iteration() {
+    let program = get_rir_program(indoc! {
+        r#"
+        namespace Test {
+            @EntryPoint()
+            operation Main() : Unit {
+                use q = Qubit();
+                let cond = MResetZ(q);
+                for _ in 0..1 {
+                    mutable value = 0;
+                    if cond == Zero {
+                        value -= 1;
+                    } else {
+                        value += 1;
+                    }
+                }
+            }
+        }
+        "#,
+    });
+
+    assert_blocks(
+        &program,
+        &expect![[r#"
+            Blocks:
+            Block 0:Block:
+                Call id(1), args( Qubit(0), Result(0), )
+                Variable(0, Integer) = Store Integer(0)
+                Variable(1, Integer) = Store Integer(0)
+                Variable(2, Boolean) = Call id(2), args( Result(0), )
+                Variable(3, Boolean) = Icmp Eq, Variable(2, Boolean), Bool(false)
+                Branch Variable(3, Boolean), 2, 3
+            Block 1:Block:
+                Variable(0, Integer) = Store Integer(1)
+                Variable(4, Integer) = Store Integer(0)
+                Variable(5, Boolean) = Call id(2), args( Result(0), )
+                Variable(6, Boolean) = Icmp Eq, Variable(5, Boolean), Bool(false)
+                Branch Variable(6, Boolean), 5, 6
+            Block 2:Block:
+                Variable(1, Integer) = Store Integer(-1)
+                Jump(1)
+            Block 3:Block:
+                Variable(1, Integer) = Store Integer(1)
+                Jump(1)
+            Block 4:Block:
+                Variable(0, Integer) = Store Integer(2)
+                Call id(3), args( Integer(0), Pointer, )
+                Return
+            Block 5:Block:
+                Variable(4, Integer) = Store Integer(-1)
+                Jump(4)
+            Block 6:Block:
+                Variable(4, Integer) = Store Integer(1)
+                Jump(4)"#]],
+    );
+}
+
+#[test]
+fn dynamic_var_updated_twice_in_same_branch_constant_folded() {
+    let program = get_rir_program(indoc! {
+        r#"
+        namespace Test {
+            @EntryPoint()
+            operation Main() : Unit {
+                mutable value = 0;
+                use q = Qubit();
+                let cond = MResetZ(q);
+                if cond == Zero {
+                    value -= 1;
+                    value += 3;
+                } else {
+                    value += 1;
+                    value -= 3;
+                }
+            }
+        }
+        "#,
+    });
+
+    assert_blocks(
+        &program,
+        &expect![[r#"
+            Blocks:
+            Block 0:Block:
+                Variable(0, Integer) = Store Integer(0)
+                Call id(1), args( Qubit(0), Result(0), )
+                Variable(1, Boolean) = Call id(2), args( Result(0), )
+                Variable(2, Boolean) = Icmp Eq, Variable(1, Boolean), Bool(false)
+                Branch Variable(2, Boolean), 2, 3
+            Block 1:Block:
+                Call id(3), args( Integer(0), Pointer, )
+                Return
+            Block 2:Block:
+                Variable(0, Integer) = Store Integer(-1)
+                Variable(0, Integer) = Store Integer(2)
+                Jump(1)
+            Block 3:Block:
+                Variable(0, Integer) = Store Integer(1)
+                Variable(0, Integer) = Store Integer(-2)
+                Jump(1)"#]],
+    );
+}
+
+#[test]
+fn dynamic_var_updated_to_same_value_in_different_branches_constant_folded_after_if() {
+    let program = get_rir_program(indoc! {
+        r#"
+        namespace Test {
+            @EntryPoint()
+            operation Main() : Unit {
+                mutable value = 0;
+                use q = Qubit();
+                let cond = MResetZ(q);
+                if cond == Zero {
+                    value -= 1;
+                    value += 2;
+                } else {
+                    value += 1;
+                    value /= 1;
+                }
+                value += 1;
+            }
+        }
+        "#,
+    });
+
     assert_blocks(
         &program,
         &expect![[r#"
         Blocks:
         Block 0:Block:
+            Variable(0, Integer) = Store Integer(0)
             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
+            Variable(1, Boolean) = Call id(2), args( Result(0), )
+            Variable(2, Boolean) = Icmp Eq, Variable(1, Boolean), Bool(false)
+            Branch Variable(2, Boolean), 2, 3
         Block 1:Block:
-            Call id(5), args( Integer(0), Pointer, )
+            Variable(0, Integer) = Store Integer(2)
+            Call id(3), args( Integer(0), Pointer, )
             Return
         Block 2:Block:
-            Call id(3), args( Qubit(1), )
-            Variable(2, Integer) = Store Integer(0)
+            Variable(0, Integer) = Store Integer(-1)
+            Variable(0, Integer) = Store Integer(1)
             Jump(1)
         Block 3:Block:
-            Call id(4), args( Qubit(1), )
-            Variable(2, Integer) = Store Integer(1)
+            Variable(0, Integer) = Store Integer(1)
+            Variable(0, Integer) = Store Integer(1)
             Jump(1)"#]],
     );
 }
+
+#[test]
+fn dynamic_var_updated_in_nested_branches_constant_folded_when_value_matches_across_all_branches() {
+    let program = get_rir_program(indoc! {
+        r#"
+        namespace Test {
+            @EntryPoint()
+            operation Main() : Int {
+                mutable value = 0;
+                use q = Qubit();
+                let cond = MResetZ(q);
+                if cond == Zero {
+                    value -= 1;
+                    if cond == Zero {
+                        value += 2;
+                    } else {
+                        value -= 2;
+                        value /= 3;
+                        value *= -1;
+                }
+                } else {
+                    value += 1;
+                    if cond == Zero {
+                        value += 2;
+                        value /= 3;
+                    } else {
+                        value -= 2;
+                        value *= -1;
+                    }
+                }
+                return value;
+            }
+        }
+        "#,
+    });
+
+    assert_blocks(
+        &program,
+        &expect![[r#"
+            Blocks:
+            Block 0:Block:
+                Variable(0, Integer) = Store Integer(0)
+                Call id(1), args( Qubit(0), Result(0), )
+                Variable(1, Boolean) = Call id(2), args( Result(0), )
+                Variable(2, Boolean) = Icmp Eq, Variable(1, Boolean), Bool(false)
+                Branch Variable(2, Boolean), 2, 6
+            Block 1:Block:
+                Call id(3), args( Integer(1), Pointer, )
+                Return
+            Block 2:Block:
+                Variable(0, Integer) = Store Integer(-1)
+                Variable(3, Boolean) = Call id(2), args( Result(0), )
+                Variable(4, Boolean) = Icmp Eq, Variable(3, Boolean), Bool(false)
+                Branch Variable(4, Boolean), 4, 5
+            Block 3:Block:
+                Jump(1)
+            Block 4:Block:
+                Variable(0, Integer) = Store Integer(1)
+                Jump(3)
+            Block 5:Block:
+                Variable(0, Integer) = Store Integer(-3)
+                Variable(0, Integer) = Store Integer(-1)
+                Variable(0, Integer) = Store Integer(1)
+                Jump(3)
+            Block 6:Block:
+                Variable(0, Integer) = Store Integer(1)
+                Variable(5, Boolean) = Call id(2), args( Result(0), )
+                Variable(6, Boolean) = Icmp Eq, Variable(5, Boolean), Bool(false)
+                Branch Variable(6, Boolean), 8, 9
+            Block 7:Block:
+                Jump(1)
+            Block 8:Block:
+                Variable(0, Integer) = Store Integer(3)
+                Variable(0, Integer) = Store Integer(1)
+                Jump(7)
+            Block 9:Block:
+                Variable(0, Integer) = Store Integer(-1)
+                Variable(0, Integer) = Store Integer(1)
+                Jump(7)"#]],
+    );
+}
+
+#[test]
+fn dynamic_var_set_to_static_after_dynamism_still_constant_folded() {
+    let program = get_rir_program(indoc! {
+        r#"
+        namespace Test {
+            @EntryPoint()
+            operation Main() : Unit {
+                mutable value = 0;
+                use q = Qubit();
+                let cond = MResetZ(q);
+                if cond == Zero {
+                    value -= 1;
+                }
+                value *= 2;
+                value = 3;
+                value += 1;
+            }
+        }
+        "#,
+    });
+
+    assert_blocks(
+        &program,
+        &expect![[r#"
+            Blocks:
+            Block 0:Block:
+                Variable(0, Integer) = Store Integer(0)
+                Call id(1), args( Qubit(0), Result(0), )
+                Variable(1, Boolean) = Call id(2), args( Result(0), )
+                Variable(2, Boolean) = Icmp Eq, Variable(1, Boolean), Bool(false)
+                Branch Variable(2, Boolean), 2, 1
+            Block 1:Block:
+                Variable(3, Integer) = Mul Variable(0, Integer), Integer(2)
+                Variable(0, Integer) = Store Variable(3, Integer)
+                Variable(0, Integer) = Store Integer(3)
+                Variable(0, Integer) = Store Integer(4)
+                Call id(3), args( Integer(0), Pointer, )
+                Return
+            Block 2:Block:
+                Variable(0, Integer) = Store Integer(-1)
+                Jump(1)"#]],
+    );
+}
+
+#[test]
+fn dynamic_var_updated_in_loop_constant_folded_when_every_iteration_results_in_same_value() {
+    let program = get_rir_program(indoc! {
+        r#"
+        namespace Test {
+            @EntryPoint()
+            operation Main() : Int {
+                mutable value = 0;
+                use q = Qubit();
+                let cond = MResetZ(q);
+                for _ in 0..1 {
+                    if cond == Zero {
+                        value -= 1;
+                        value ^= 2;
+                    } else {
+                        value += 1;
+                    }
+                    value -= 1;
+                }
+                return value
+            }
+        }
+        "#,
+    });
+
+    assert_blocks(
+        &program,
+        &expect![[r#"
+            Blocks:
+            Block 0:Block:
+                Variable(0, Integer) = Store Integer(0)
+                Call id(1), args( Qubit(0), Result(0), )
+                Variable(1, Integer) = Store Integer(0)
+                Variable(2, Boolean) = Call id(2), args( Result(0), )
+                Variable(3, Boolean) = Icmp Eq, Variable(2, Boolean), Bool(false)
+                Branch Variable(3, Boolean), 2, 3
+            Block 1:Block:
+                Variable(0, Integer) = Store Integer(0)
+                Variable(1, Integer) = Store Integer(1)
+                Variable(4, Boolean) = Call id(2), args( Result(0), )
+                Variable(5, Boolean) = Icmp Eq, Variable(4, Boolean), Bool(false)
+                Branch Variable(5, Boolean), 5, 6
+            Block 2:Block:
+                Variable(0, Integer) = Store Integer(-1)
+                Variable(0, Integer) = Store Integer(1)
+                Jump(1)
+            Block 3:Block:
+                Variable(0, Integer) = Store Integer(1)
+                Jump(1)
+            Block 4:Block:
+                Variable(0, Integer) = Store Integer(0)
+                Variable(1, Integer) = Store Integer(2)
+                Call id(3), args( Integer(0), Pointer, )
+                Return
+            Block 5:Block:
+                Variable(0, Integer) = Store Integer(-1)
+                Variable(0, Integer) = Store Integer(1)
+                Jump(4)
+            Block 6:Block:
+                Variable(0, Integer) = Store Integer(1)
+                Jump(4)"#]],
+    );
+}
+
+#[test]
+fn immutable_bind_of_dynamic_var_should_be_point_in_time_copy() {
+    let program = get_rir_program(indoc! {
+        r#"
+        namespace Test {
+            @EntryPoint()
+            operation Main() : (Int, Int) {
+                mutable value = 0;
+                use q = Qubit();
+                let cond = MResetZ(q);
+                if cond == Zero {
+                    value -= 1;
+                }
+                let copy = value;
+                value += 1;
+                (copy, value)
+            }
+        }
+        "#,
+    });
+
+    assert_blocks(
+        &program,
+        &expect![[r#"
+            Blocks:
+            Block 0:Block:
+                Variable(0, Integer) = Store Integer(0)
+                Call id(1), args( Qubit(0), Result(0), )
+                Variable(1, Boolean) = Call id(2), args( Result(0), )
+                Variable(2, Boolean) = Icmp Eq, Variable(1, Boolean), Bool(false)
+                Branch Variable(2, Boolean), 2, 1
+            Block 1:Block:
+                Variable(3, Integer) = Store Variable(0, Integer)
+                Variable(4, Integer) = Add Variable(0, Integer), Integer(1)
+                Variable(0, Integer) = Store Variable(4, Integer)
+                Call id(3), args( Integer(2), Pointer, )
+                Call id(4), args( Variable(3, Integer), Pointer, )
+                Call id(4), args( Variable(0, Integer), Pointer, )
+                Return
+            Block 2:Block:
+                Variable(0, Integer) = Store Integer(-1)
+                Jump(1)"#]],
+    );
+}
diff --git a/compiler/qsc_partial_eval/src/tests/intrinsics.rs b/compiler/qsc_partial_eval/src/tests/intrinsics.rs
index bd82f142..4a237968 100644
--- a/compiler/qsc_partial_eval/src/tests/intrinsics.rs
+++ b/compiler/qsc_partial_eval/src/tests/intrinsics.rs
@@ -767,6 +767,7 @@ fn call_to_intrinsic_begin_estimate_caching_with_dynamic_values_yields_true() {
                 Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false)
                 Branch Variable(1, Boolean), 2, 3
             Block 1:Block:
+                Variable(3, Integer) = Store Variable(2, Integer)
                 Call id(3), args( Qubit(0), )
                 Call id(4), args( Integer(0), Pointer, )
                 Return
diff --git a/compiler/qsc_partial_eval/src/tests/misc.rs b/compiler/qsc_partial_eval/src/tests/misc.rs
index 30f90947..a493abed 100644
--- a/compiler/qsc_partial_eval/src/tests/misc.rs
+++ b/compiler/qsc_partial_eval/src/tests/misc.rs
@@ -206,7 +206,8 @@ fn boolean_assign_and_update_with_classical_value_within_an_if_with_dynamic_cond
                 Variable(2, Boolean) = Store Variable(1, Boolean)
                 Branch Variable(2, Boolean), 2, 1
             Block 1:Block:
-                Call id(3), args( Variable(0, Boolean), Pointer, )
+                Variable(3, Boolean) = Store Variable(0, Boolean)
+                Call id(3), args( Variable(3, Boolean), Pointer, )
                 Return
             Block 2:Block:
                 Variable(0, Boolean) = Store Bool(false)
@@ -242,7 +243,8 @@ fn integer_assign_and_update_with_classical_value_within_an_if_with_dynamic_cond
                 Variable(2, Boolean) = Store Variable(1, Boolean)
                 Branch Variable(2, Boolean), 2, 1
             Block 1:Block:
-                Call id(3), args( Variable(0, Integer), Pointer, )
+                Variable(3, Integer) = Store Variable(0, Integer)
+                Call id(3), args( Variable(3, Integer), Pointer, )
                 Return
             Block 2:Block:
                 Variable(0, Integer) = Store Integer(5)
@@ -313,31 +315,32 @@ fn integer_assign_with_hybrid_value_within_an_if_with_dynamic_condition() {
     assert_blocks(
         &program,
         &expect![[r#"
-        Blocks:
-        Block 0:Block:
-            Variable(0, Integer) = Store Integer(0)
-            Variable(1, Integer) = Store Integer(0)
-            Call id(1), args( Qubit(0), Result(0), )
-            Variable(2, Boolean) = Call id(2), args( Result(0), )
-            Variable(3, Boolean) = Store Variable(2, Boolean)
-            Branch Variable(3, Boolean), 2, 1
-        Block 1:Block:
-            Variable(1, Integer) = Store Integer(1)
-            Call id(1), args( Qubit(0), Result(1), )
-            Variable(4, Boolean) = Call id(2), args( Result(1), )
-            Variable(5, Boolean) = Store Variable(4, Boolean)
-            Branch Variable(5, Boolean), 4, 3
-        Block 2:Block:
-            Variable(0, Integer) = Store Integer(1)
-            Jump(1)
-        Block 3:Block:
-            Variable(1, Integer) = Store Integer(2)
-            Call id(3), args( Variable(0, Integer), Pointer, )
-            Return
-        Block 4:Block:
-            Variable(6, Integer) = BitwiseOr Variable(0, Integer), Integer(2)
-            Variable(0, Integer) = Store Variable(6, Integer)
-            Jump(3)"#]],
+            Blocks:
+            Block 0:Block:
+                Variable(0, Integer) = Store Integer(0)
+                Variable(1, Integer) = Store Integer(0)
+                Call id(1), args( Qubit(0), Result(0), )
+                Variable(2, Boolean) = Call id(2), args( Result(0), )
+                Variable(3, Boolean) = Store Variable(2, Boolean)
+                Branch Variable(3, Boolean), 2, 1
+            Block 1:Block:
+                Variable(1, Integer) = Store Integer(1)
+                Call id(1), args( Qubit(0), Result(1), )
+                Variable(4, Boolean) = Call id(2), args( Result(1), )
+                Variable(5, Boolean) = Store Variable(4, Boolean)
+                Branch Variable(5, Boolean), 4, 3
+            Block 2:Block:
+                Variable(0, Integer) = Store Integer(1)
+                Jump(1)
+            Block 3:Block:
+                Variable(1, Integer) = Store Integer(2)
+                Variable(7, Integer) = Store Variable(0, Integer)
+                Call id(3), args( Variable(7, Integer), Pointer, )
+                Return
+            Block 4:Block:
+                Variable(6, Integer) = BitwiseOr Variable(0, Integer), Integer(2)
+                Variable(0, Integer) = Store Variable(6, Integer)
+                Jump(3)"#]],
     );
 }
 
@@ -372,7 +375,8 @@ fn large_loop_with_inner_if_completes_eval_and_transform() {
         &expect![[r#"
             Block:
                 Variable(1, Integer) = Store Integer(100)
-                Call id(3), args( Variable(0, Integer), Pointer, )
+                Variable(400, Integer) = Store Variable(0, Integer)
+                Call id(3), args( Variable(400, Integer), Pointer, )
                 Return"#]],
     );
 }
diff --git a/compiler/qsc_partial_eval/src/tests/operators.rs b/compiler/qsc_partial_eval/src/tests/operators.rs
index f3f5e5e7..20eb1a3b 100644
--- a/compiler/qsc_partial_eval/src/tests/operators.rs
+++ b/compiler/qsc_partial_eval/src/tests/operators.rs
@@ -72,7 +72,9 @@ fn leading_positive_unary_operator_does_not_generate_rir_instruction() {
                 Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false)
                 Branch Variable(1, Boolean), 2, 3
             Block 1:Block:
-                Call id(3), args( Variable(2, Integer), Pointer, )
+                Variable(3, Integer) = Store Variable(2, Integer)
+                Variable(4, Integer) = Store Variable(3, Integer)
+                Call id(3), args( Variable(4, Integer), Pointer, )
                 Return
             Block 2:Block:
                 Variable(2, Integer) = Store Integer(0)
@@ -146,8 +148,10 @@ fn leading_negative_unary_operator_generates_rir_instruction() {
                 Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false)
                 Branch Variable(1, Boolean), 2, 3
             Block 1:Block:
-                Variable(3, Integer) = Mul Integer(-1), Variable(2, Integer)
-                Call id(3), args( Variable(3, Integer), Pointer, )
+                Variable(3, Integer) = Store Variable(2, Integer)
+                Variable(4, Integer) = Mul Integer(-1), Variable(3, Integer)
+                Variable(5, Integer) = Store Variable(4, Integer)
+                Call id(3), args( Variable(5, Integer), Pointer, )
                 Return
             Block 2:Block:
                 Variable(2, Integer) = Store Integer(0)
@@ -221,8 +225,10 @@ fn bitwise_not_unary_operator_generates_rir_instruction() {
                 Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false)
                 Branch Variable(1, Boolean), 2, 3
             Block 1:Block:
-                Variable(3, Integer) = BitwiseNot Variable(2, Integer)
-                Call id(3), args( Variable(3, Integer), Pointer, )
+                Variable(3, Integer) = Store Variable(2, Integer)
+                Variable(4, Integer) = BitwiseNot Variable(3, Integer)
+                Variable(5, Integer) = Store Variable(4, Integer)
+                Call id(3), args( Variable(5, Integer), Pointer, )
                 Return
             Block 2:Block:
                 Variable(2, Integer) = Store Integer(0)
@@ -294,8 +300,10 @@ fn logical_not_unary_operator_generates_logical_not_rir_instruction() {
                 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) = LogicalNot Variable(1, Boolean)
-                Call id(3), args( Variable(2, Boolean), Pointer, )
+                Variable(2, Boolean) = Store Variable(1, Boolean)
+                Variable(3, Boolean) = LogicalNot Variable(2, Boolean)
+                Variable(4, Boolean) = Store Variable(3, Boolean)
+                Call id(3), args( Variable(4, Boolean), Pointer, )
                 Return"#]],
     );
 }
@@ -366,7 +374,8 @@ fn comparing_measurement_results_for_equality_adds_read_result_and_comparison_in
                 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, )
+                Variable(3, Boolean) = Store Variable(2, Boolean)
+                Call id(3), args( Variable(3, Boolean), Pointer, )
                 Return"#]],
     );
     assert_eq!(program.num_qubits, 2);
@@ -439,7 +448,8 @@ fn comparing_measurement_results_for_inequality_adds_read_result_and_comparison_
                 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, )
+                Variable(3, Boolean) = Store Variable(2, Boolean)
+                Call id(3), args( Variable(3, Boolean), Pointer, )
                 Return"#]],
     );
     assert_eq!(program.num_qubits, 2);
@@ -510,7 +520,8 @@ fn comparing_measurement_result_against_result_literal_for_equality_adds_read_re
                 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( Variable(1, Boolean), Pointer, )
+                Variable(2, Boolean) = Store Variable(1, Boolean)
+                Call id(3), args( Variable(2, Boolean), Pointer, )
                 Return"#]],
     );
     assert_eq!(program.num_qubits, 1);
@@ -581,7 +592,8 @@ fn comparing_measurement_result_against_result_literal_for_inequality_adds_read_
                 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(true)
-                Call id(3), args( Variable(1, Boolean), Pointer, )
+                Variable(2, Boolean) = Store Variable(1, Boolean)
+                Call id(3), args( Variable(2, Boolean), Pointer, )
                 Return"#]],
     );
     assert_eq!(program.num_qubits, 1);
@@ -651,8 +663,10 @@ fn comparing_lhs_classical_boolean_against_rhs_dynamic_boolean_for_equality() {
                 Call id(1), args( Qubit(0), Result(0), )
                 Variable(0, Boolean) = Call id(2), args( Result(0), )
                 Variable(1, Boolean) = Store Variable(0, Boolean)
-                Variable(2, Boolean) = Icmp Eq, Bool(false), Variable(1, Boolean)
-                Call id(3), args( Variable(2, Boolean), Pointer, )
+                Variable(2, Boolean) = Store Variable(1, Boolean)
+                Variable(3, Boolean) = Icmp Eq, Bool(false), Variable(2, Boolean)
+                Variable(4, Boolean) = Store Variable(3, Boolean)
+                Call id(3), args( Variable(4, Boolean), Pointer, )
                 Return"#]],
     );
 }
@@ -715,16 +729,17 @@ fn comparing_lhs_dynamic_boolean_against_rhs_dynamic_boolean_for_equality() {
         &program,
         BlockId(0),
         &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(false)
-            Call id(1), args( Qubit(0), Result(1), )
-            Variable(2, Boolean) = Call id(2), args( Result(1), )
-            Variable(3, Boolean) = Icmp Eq, Variable(2, Boolean), Bool(false)
-            Variable(4, Boolean) = Icmp Eq, Variable(1, Boolean), Variable(3, Boolean)
-            Call id(3), args( Variable(4, Boolean), Pointer, )
-            Return"#]],
+            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(1), args( Qubit(0), Result(1), )
+                Variable(2, Boolean) = Call id(2), args( Result(1), )
+                Variable(3, Boolean) = Icmp Eq, Variable(2, Boolean), Bool(false)
+                Variable(4, Boolean) = Icmp Eq, Variable(1, Boolean), Variable(3, Boolean)
+                Variable(5, Boolean) = Store Variable(4, Boolean)
+                Call id(3), args( Variable(5, Boolean), Pointer, )
+                Return"#]],
     );
 }
 
@@ -791,8 +806,10 @@ fn comparing_lhs_classical_boolean_against_rhs_dynamic_boolean_for_inequality()
                 Call id(1), args( Qubit(0), Result(0), )
                 Variable(0, Boolean) = Call id(2), args( Result(0), )
                 Variable(1, Boolean) = Store Variable(0, Boolean)
-                Variable(2, Boolean) = Icmp Ne, Bool(true), Variable(1, Boolean)
-                Call id(3), args( Variable(2, Boolean), Pointer, )
+                Variable(2, Boolean) = Store Variable(1, Boolean)
+                Variable(3, Boolean) = Icmp Ne, Bool(true), Variable(2, Boolean)
+                Variable(4, Boolean) = Store Variable(3, Boolean)
+                Call id(3), args( Variable(4, Boolean), Pointer, )
                 Return"#]],
     );
 }
@@ -855,16 +872,17 @@ fn comparing_lhs_dynamic_boolean_against_rhs_dynamic_boolean_for_inequality() {
         &program,
         BlockId(0),
         &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(false)
-            Call id(1), args( Qubit(0), Result(1), )
-            Variable(2, Boolean) = Call id(2), args( Result(1), )
-            Variable(3, Boolean) = Icmp Eq, Variable(2, Boolean), Bool(false)
-            Variable(4, Boolean) = Icmp Ne, Variable(1, Boolean), Variable(3, Boolean)
-            Call id(3), args( Variable(4, Boolean), Pointer, )
-            Return"#]],
+            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(1), args( Qubit(0), Result(1), )
+                Variable(2, Boolean) = Call id(2), args( Result(1), )
+                Variable(3, Boolean) = Icmp Eq, Variable(2, Boolean), Bool(false)
+                Variable(4, Boolean) = Icmp Ne, Variable(1, Boolean), Variable(3, Boolean)
+                Variable(5, Boolean) = Store Variable(4, Boolean)
+                Call id(3), args( Variable(5, Boolean), Pointer, )
+                Return"#]],
     );
 }
 
@@ -931,7 +949,9 @@ fn logical_and_with_lhs_classical_true_is_optimized_as_store() {
                 Call id(1), args( Qubit(0), Result(0), )
                 Variable(0, Boolean) = Call id(2), args( Result(0), )
                 Variable(1, Boolean) = Store Variable(0, Boolean)
-                Call id(3), args( Variable(1, Boolean), Pointer, )
+                Variable(2, Boolean) = Store Variable(1, Boolean)
+                Variable(3, Boolean) = Store Variable(2, Boolean)
+                Call id(3), args( Variable(3, Boolean), Pointer, )
                 Return"#]],
     );
 }
@@ -999,6 +1019,7 @@ fn logical_and_with_lhs_classical_false_short_circuits_evaluation() {
                 Call id(1), args( Qubit(0), Result(0), )
                 Variable(0, Boolean) = Call id(2), args( Result(0), )
                 Variable(1, Boolean) = Store Variable(0, Boolean)
+                Variable(2, Boolean) = Store Variable(1, Boolean)
                 Call id(3), args( Bool(false), Pointer, )
                 Return"#]],
     );
@@ -1069,7 +1090,8 @@ fn logical_and_with_dynamic_lhs_and_dynamic_rhs_short_circuits_when_lhs_is_false
                 Variable(2, Boolean) = Store Bool(false)
                 Branch Variable(1, Boolean), 2, 1
             Block 1:Block:
-                Call id(3), args( Variable(2, Boolean), Pointer, )
+                Variable(5, Boolean) = Store Variable(2, Boolean)
+                Call id(3), args( Variable(5, Boolean), Pointer, )
                 Return
             Block 2:Block:
                 Call id(1), args( Qubit(0), Result(1), )
@@ -1143,6 +1165,7 @@ fn logical_or_with_lhs_classical_true_short_circuits_evaluation() {
                 Call id(1), args( Qubit(0), Result(0), )
                 Variable(0, Boolean) = Call id(2), args( Result(0), )
                 Variable(1, Boolean) = Store Variable(0, Boolean)
+                Variable(2, Boolean) = Store Variable(1, Boolean)
                 Call id(3), args( Bool(true), Pointer, )
                 Return"#]],
     );
@@ -1211,7 +1234,9 @@ fn logical_or_with_lhs_classical_false_is_optimized_as_store() {
                 Call id(1), args( Qubit(0), Result(0), )
                 Variable(0, Boolean) = Call id(2), args( Result(0), )
                 Variable(1, Boolean) = Store Variable(0, Boolean)
-                Call id(3), args( Variable(1, Boolean), Pointer, )
+                Variable(2, Boolean) = Store Variable(1, Boolean)
+                Variable(3, Boolean) = Store Variable(2, Boolean)
+                Call id(3), args( Variable(3, Boolean), Pointer, )
                 Return"#]],
     );
 }
@@ -1281,7 +1306,8 @@ fn logical_or_with_dynamic_lhs_and_dynamic_rhs_short_circuits_when_rhs_is_true()
                 Variable(2, Boolean) = Store Bool(true)
                 Branch Variable(1, Boolean), 1, 2
             Block 1:Block:
-                Call id(3), args( Variable(2, Boolean), Pointer, )
+                Variable(5, Boolean) = Store Variable(2, Boolean)
+                Call id(3), args( Variable(5, Boolean), Pointer, )
                 Return
             Block 2:Block:
                 Call id(1), args( Qubit(0), Result(1), )
@@ -1366,7 +1392,8 @@ fn logical_and_and_sequence_with_dynamic_operands() {
                 Variable(2, Boolean) = Store Variable(4, Boolean)
                 Jump(1)
             Block 3:Block:
-                Call id(3), args( Variable(5, Boolean), Pointer, )
+                Variable(8, Boolean) = Store Variable(5, Boolean)
+                Call id(3), args( Variable(8, Boolean), Pointer, )
                 Return
             Block 4:Block:
                 Call id(1), args( Qubit(2), Result(2), )
@@ -1451,7 +1478,8 @@ fn logical_and_or_sequence_with_dynamic_operands() {
                 Variable(2, Boolean) = Store Variable(4, Boolean)
                 Jump(1)
             Block 3:Block:
-                Call id(3), args( Variable(5, Boolean), Pointer, )
+                Variable(8, Boolean) = Store Variable(5, Boolean)
+                Call id(3), args( Variable(8, Boolean), Pointer, )
                 Return
             Block 4:Block:
                 Call id(1), args( Qubit(2), Result(2), )
@@ -1527,7 +1555,8 @@ fn logical_or_and_sequence_with_dynamic_operands() {
                 Variable(2, Boolean) = Store Bool(true)
                 Branch Variable(1, Boolean), 1, 2
             Block 1:Block:
-                Call id(3), args( Variable(2, Boolean), Pointer, )
+                Variable(8, Boolean) = Store Variable(2, Boolean)
+                Call id(3), args( Variable(8, Boolean), Pointer, )
                 Return
             Block 2:Block:
                 Call id(1), args( Qubit(1), Result(1), )
@@ -1621,7 +1650,8 @@ fn logical_or_or_sequence_with_dynamic_operands() {
                 Variable(2, Boolean) = Store Variable(4, Boolean)
                 Jump(1)
             Block 3:Block:
-                Call id(3), args( Variable(5, Boolean), Pointer, )
+                Variable(8, Boolean) = Store Variable(5, Boolean)
+                Call id(3), args( Variable(8, Boolean), Pointer, )
                 Return
             Block 4:Block:
                 Call id(1), args( Qubit(2), Result(2), )
@@ -1697,8 +1727,10 @@ fn integer_add_with_lhs_classical_integer_and_rhs_dynamic_integer() {
                 Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false)
                 Branch Variable(1, Boolean), 2, 3
             Block 1:Block:
-                Variable(3, Integer) = Add Integer(1), Variable(2, Integer)
-                Call id(3), args( Variable(3, Integer), Pointer, )
+                Variable(3, Integer) = Store Variable(2, Integer)
+                Variable(4, Integer) = Add Integer(1), Variable(3, Integer)
+                Variable(5, Integer) = Store Variable(4, Integer)
+                Call id(3), args( Variable(5, Integer), Pointer, )
                 Return
             Block 2:Block:
                 Variable(2, Integer) = Store Integer(0)
@@ -1774,8 +1806,10 @@ fn integer_sub_with_lhs_dynamic_integer_and_rhs_classical_integer() {
                 Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false)
                 Branch Variable(1, Boolean), 2, 3
             Block 1:Block:
-                Variable(3, Integer) = Sub Variable(2, Integer), Integer(1)
-                Call id(3), args( Variable(3, Integer), Pointer, )
+                Variable(3, Integer) = Store Variable(2, Integer)
+                Variable(4, Integer) = Sub Variable(3, Integer), Integer(1)
+                Variable(5, Integer) = Store Variable(4, Integer)
+                Call id(3), args( Variable(5, Integer), Pointer, )
                 Return
             Block 2:Block:
                 Variable(2, Integer) = Store Integer(0)
@@ -1852,10 +1886,11 @@ fn integer_mul_with_lhs_dynamic_integer_and_rhs_dynamic_integer() {
                 Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false)
                 Branch Variable(1, Boolean), 2, 3
             Block 1:Block:
+                Variable(3, Integer) = Store Variable(2, Integer)
                 Call id(1), args( Qubit(0), Result(1), )
-                Variable(3, Boolean) = Call id(2), args( Result(1), )
-                Variable(4, Boolean) = Icmp Eq, Variable(3, Boolean), Bool(false)
-                Branch Variable(4, Boolean), 5, 6
+                Variable(4, Boolean) = Call id(2), args( Result(1), )
+                Variable(5, Boolean) = Icmp Eq, Variable(4, Boolean), Bool(false)
+                Branch Variable(5, Boolean), 5, 6
             Block 2:Block:
                 Variable(2, Integer) = Store Integer(0)
                 Jump(1)
@@ -1863,14 +1898,16 @@ fn integer_mul_with_lhs_dynamic_integer_and_rhs_dynamic_integer() {
                 Variable(2, Integer) = Store Integer(1)
                 Jump(1)
             Block 4:Block:
-                Variable(6, Integer) = Mul Variable(2, Integer), Variable(5, Integer)
-                Call id(3), args( Variable(6, Integer), Pointer, )
+                Variable(7, Integer) = Store Variable(6, Integer)
+                Variable(8, Integer) = Mul Variable(3, Integer), Variable(7, Integer)
+                Variable(9, Integer) = Store Variable(8, Integer)
+                Call id(3), args( Variable(9, Integer), Pointer, )
                 Return
             Block 5:Block:
-                Variable(5, Integer) = Store Integer(1)
+                Variable(6, Integer) = Store Integer(1)
                 Jump(4)
             Block 6:Block:
-                Variable(5, Integer) = Store Integer(0)
+                Variable(6, Integer) = Store Integer(0)
                 Jump(4)"#]],
     );
 }
@@ -1940,8 +1977,10 @@ fn integer_div_with_lhs_classical_integer_and_rhs_dynamic_integer() {
                 Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false)
                 Branch Variable(1, Boolean), 2, 3
             Block 1:Block:
-                Variable(3, Integer) = Sdiv Integer(1), Variable(2, Integer)
-                Call id(3), args( Variable(3, Integer), Pointer, )
+                Variable(3, Integer) = Store Variable(2, Integer)
+                Variable(4, Integer) = Sdiv Integer(1), Variable(3, Integer)
+                Variable(5, Integer) = Store Variable(4, Integer)
+                Call id(3), args( Variable(5, Integer), Pointer, )
                 Return
             Block 2:Block:
                 Variable(2, Integer) = Store Integer(0)
@@ -2039,8 +2078,10 @@ fn integer_mod_with_lhs_dynamic_integer_and_rhs_classical_integer() {
                 Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false)
                 Branch Variable(1, Boolean), 2, 3
             Block 1:Block:
-                Variable(3, Integer) = Srem Variable(2, Integer), Integer(1)
-                Call id(3), args( Variable(3, Integer), Pointer, )
+                Variable(3, Integer) = Store Variable(2, Integer)
+                Variable(4, Integer) = Srem Variable(3, Integer), Integer(1)
+                Variable(5, Integer) = Store Variable(4, Integer)
+                Call id(3), args( Variable(5, Integer), Pointer, )
                 Return
             Block 2:Block:
                 Variable(2, Integer) = Store Integer(0)
@@ -2161,8 +2202,10 @@ fn integer_exponentiation_with_lhs_dynamic_integer_and_rhs_classical_zero_intege
                 Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false)
                 Branch Variable(1, Boolean), 2, 3
             Block 1:Block:
-                Variable(3, Integer) = Store Integer(1)
-                Call id(3), args( Variable(3, Integer), Pointer, )
+                Variable(3, Integer) = Store Variable(2, Integer)
+                Variable(4, Integer) = Store Integer(1)
+                Variable(5, Integer) = Store Variable(4, Integer)
+                Call id(3), args( Variable(5, Integer), Pointer, )
                 Return
             Block 2:Block:
                 Variable(2, Integer) = Store Integer(0)
@@ -2238,11 +2281,13 @@ fn integer_exponentiation_with_lhs_dynamic_integer_and_rhs_classical_positive_in
                 Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false)
                 Branch Variable(1, Boolean), 2, 3
             Block 1:Block:
-                Variable(3, Integer) = Store Integer(1)
-                Variable(4, Integer) = Mul Variable(3, Integer), Variable(2, Integer)
-                Variable(5, Integer) = Mul Variable(4, Integer), Variable(2, Integer)
-                Variable(6, Integer) = Mul Variable(5, Integer), Variable(2, Integer)
-                Call id(3), args( Variable(6, Integer), Pointer, )
+                Variable(3, Integer) = Store Variable(2, Integer)
+                Variable(4, Integer) = Store Integer(1)
+                Variable(5, Integer) = Mul Variable(4, Integer), Variable(3, Integer)
+                Variable(6, Integer) = Mul Variable(5, Integer), Variable(3, Integer)
+                Variable(7, Integer) = Mul Variable(6, Integer), Variable(3, Integer)
+                Variable(8, Integer) = Store Variable(7, Integer)
+                Call id(3), args( Variable(8, Integer), Pointer, )
                 Return
             Block 2:Block:
                 Variable(2, Integer) = Store Integer(0)
@@ -2342,10 +2387,11 @@ fn integer_bitwise_and_with_lhs_dynamic_integer_and_rhs_dynamic_integer() {
                 Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false)
                 Branch Variable(1, Boolean), 2, 3
             Block 1:Block:
+                Variable(3, Integer) = Store Variable(2, Integer)
                 Call id(1), args( Qubit(0), Result(1), )
-                Variable(3, Boolean) = Call id(2), args( Result(1), )
-                Variable(4, Boolean) = Icmp Eq, Variable(3, Boolean), Bool(false)
-                Branch Variable(4, Boolean), 5, 6
+                Variable(4, Boolean) = Call id(2), args( Result(1), )
+                Variable(5, Boolean) = Icmp Eq, Variable(4, Boolean), Bool(false)
+                Branch Variable(5, Boolean), 5, 6
             Block 2:Block:
                 Variable(2, Integer) = Store Integer(0)
                 Jump(1)
@@ -2353,14 +2399,16 @@ fn integer_bitwise_and_with_lhs_dynamic_integer_and_rhs_dynamic_integer() {
                 Variable(2, Integer) = Store Integer(1)
                 Jump(1)
             Block 4:Block:
-                Variable(6, Integer) = BitwiseAnd Variable(2, Integer), Variable(5, Integer)
-                Call id(3), args( Variable(6, Integer), Pointer, )
+                Variable(7, Integer) = Store Variable(6, Integer)
+                Variable(8, Integer) = BitwiseAnd Variable(3, Integer), Variable(7, Integer)
+                Variable(9, Integer) = Store Variable(8, Integer)
+                Call id(3), args( Variable(9, Integer), Pointer, )
                 Return
             Block 5:Block:
-                Variable(5, Integer) = Store Integer(1)
+                Variable(6, Integer) = Store Integer(1)
                 Jump(4)
             Block 6:Block:
-                Variable(5, Integer) = Store Integer(0)
+                Variable(6, Integer) = Store Integer(0)
                 Jump(4)"#]],
     );
 }
@@ -2430,8 +2478,10 @@ fn integer_bitwise_or_with_lhs_classical_integer_and_rhs_dynamic_integer() {
                 Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false)
                 Branch Variable(1, Boolean), 2, 3
             Block 1:Block:
-                Variable(3, Integer) = BitwiseOr Integer(1), Variable(2, Integer)
-                Call id(3), args( Variable(3, Integer), Pointer, )
+                Variable(3, Integer) = Store Variable(2, Integer)
+                Variable(4, Integer) = BitwiseOr Integer(1), Variable(3, Integer)
+                Variable(5, Integer) = Store Variable(4, Integer)
+                Call id(3), args( Variable(5, Integer), Pointer, )
                 Return
             Block 2:Block:
                 Variable(2, Integer) = Store Integer(0)
@@ -2507,8 +2557,10 @@ fn integer_bitwise_xor_with_lhs_dynamic_integer_and_rhs_classical_integer() {
                 Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false)
                 Branch Variable(1, Boolean), 2, 3
             Block 1:Block:
-                Variable(3, Integer) = BitwiseXor Variable(2, Integer), Integer(1)
-                Call id(3), args( Variable(3, Integer), Pointer, )
+                Variable(3, Integer) = Store Variable(2, Integer)
+                Variable(4, Integer) = BitwiseXor Variable(3, Integer), Integer(1)
+                Variable(5, Integer) = Store Variable(4, Integer)
+                Call id(3), args( Variable(5, Integer), Pointer, )
                 Return
             Block 2:Block:
                 Variable(2, Integer) = Store Integer(0)
@@ -2585,10 +2637,11 @@ fn integer_bitwise_left_shif_with_lhs_dynamic_integer_and_rhs_dynamic_integer()
                 Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false)
                 Branch Variable(1, Boolean), 2, 3
             Block 1:Block:
+                Variable(3, Integer) = Store Variable(2, Integer)
                 Call id(1), args( Qubit(0), Result(1), )
-                Variable(3, Boolean) = Call id(2), args( Result(1), )
-                Variable(4, Boolean) = Icmp Eq, Variable(3, Boolean), Bool(false)
-                Branch Variable(4, Boolean), 5, 6
+                Variable(4, Boolean) = Call id(2), args( Result(1), )
+                Variable(5, Boolean) = Icmp Eq, Variable(4, Boolean), Bool(false)
+                Branch Variable(5, Boolean), 5, 6
             Block 2:Block:
                 Variable(2, Integer) = Store Integer(0)
                 Jump(1)
@@ -2596,14 +2649,16 @@ fn integer_bitwise_left_shif_with_lhs_dynamic_integer_and_rhs_dynamic_integer()
                 Variable(2, Integer) = Store Integer(1)
                 Jump(1)
             Block 4:Block:
-                Variable(6, Integer) = Shl Variable(2, Integer), Variable(5, Integer)
-                Call id(3), args( Variable(6, Integer), Pointer, )
+                Variable(7, Integer) = Store Variable(6, Integer)
+                Variable(8, Integer) = Shl Variable(3, Integer), Variable(7, Integer)
+                Variable(9, Integer) = Store Variable(8, Integer)
+                Call id(3), args( Variable(9, Integer), Pointer, )
                 Return
             Block 5:Block:
-                Variable(5, Integer) = Store Integer(1)
+                Variable(6, Integer) = Store Integer(1)
                 Jump(4)
             Block 6:Block:
-                Variable(5, Integer) = Store Integer(0)
+                Variable(6, Integer) = Store Integer(0)
                 Jump(4)"#]],
     );
 }
@@ -2673,8 +2728,10 @@ fn integer_bitwise_right_shift_with_lhs_classical_integer_and_rhs_dynamic_intege
                 Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false)
                 Branch Variable(1, Boolean), 2, 3
             Block 1:Block:
-                Variable(3, Integer) = Ashr Integer(1), Variable(2, Integer)
-                Call id(3), args( Variable(3, Integer), Pointer, )
+                Variable(3, Integer) = Store Variable(2, Integer)
+                Variable(4, Integer) = Ashr Integer(1), Variable(3, Integer)
+                Variable(5, Integer) = Store Variable(4, Integer)
+                Call id(3), args( Variable(5, Integer), Pointer, )
                 Return
             Block 2:Block:
                 Variable(2, Integer) = Store Integer(0)
@@ -2750,8 +2807,10 @@ fn integer_equality_comparison_with_lhs_dynamic_integer_and_rhs_classical_intege
                 Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false)
                 Branch Variable(1, Boolean), 2, 3
             Block 1:Block:
-                Variable(3, Boolean) = Icmp Eq, Variable(2, Integer), Integer(1)
-                Call id(3), args( Variable(3, Boolean), Pointer, )
+                Variable(3, Integer) = Store Variable(2, Integer)
+                Variable(4, Boolean) = Icmp Eq, Variable(3, Integer), Integer(1)
+                Variable(5, Boolean) = Store Variable(4, Boolean)
+                Call id(3), args( Variable(5, Boolean), Pointer, )
                 Return
             Block 2:Block:
                 Variable(2, Integer) = Store Integer(0)
@@ -2828,10 +2887,11 @@ fn integer_inequality_comparison_with_lhs_dynamic_integer_and_rhs_dynamic_intege
                 Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false)
                 Branch Variable(1, Boolean), 2, 3
             Block 1:Block:
+                Variable(3, Integer) = Store Variable(2, Integer)
                 Call id(1), args( Qubit(0), Result(1), )
-                Variable(3, Boolean) = Call id(2), args( Result(1), )
-                Variable(4, Boolean) = Icmp Eq, Variable(3, Boolean), Bool(false)
-                Branch Variable(4, Boolean), 5, 6
+                Variable(4, Boolean) = Call id(2), args( Result(1), )
+                Variable(5, Boolean) = Icmp Eq, Variable(4, Boolean), Bool(false)
+                Branch Variable(5, Boolean), 5, 6
             Block 2:Block:
                 Variable(2, Integer) = Store Integer(0)
                 Jump(1)
@@ -2839,14 +2899,16 @@ fn integer_inequality_comparison_with_lhs_dynamic_integer_and_rhs_dynamic_intege
                 Variable(2, Integer) = Store Integer(1)
                 Jump(1)
             Block 4:Block:
-                Variable(6, Boolean) = Icmp Ne, Variable(2, Integer), Variable(5, Integer)
-                Call id(3), args( Variable(6, Boolean), Pointer, )
+                Variable(7, Integer) = Store Variable(6, Integer)
+                Variable(8, Boolean) = Icmp Ne, Variable(3, Integer), Variable(7, Integer)
+                Variable(9, Boolean) = Store Variable(8, Boolean)
+                Call id(3), args( Variable(9, Boolean), Pointer, )
                 Return
             Block 5:Block:
-                Variable(5, Integer) = Store Integer(1)
+                Variable(6, Integer) = Store Integer(1)
                 Jump(4)
             Block 6:Block:
-                Variable(5, Integer) = Store Integer(0)
+                Variable(6, Integer) = Store Integer(0)
                 Jump(4)"#]],
     );
 }
@@ -2916,8 +2978,10 @@ fn integer_greater_than_comparison_with_lhs_classical_integer_and_rhs_dynamic_in
                 Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false)
                 Branch Variable(1, Boolean), 2, 3
             Block 1:Block:
-                Variable(3, Boolean) = Icmp Sgt, Integer(1), Variable(2, Integer)
-                Call id(3), args( Variable(3, Boolean), Pointer, )
+                Variable(3, Integer) = Store Variable(2, Integer)
+                Variable(4, Boolean) = Icmp Sgt, Integer(1), Variable(3, Integer)
+                Variable(5, Boolean) = Store Variable(4, Boolean)
+                Call id(3), args( Variable(5, Boolean), Pointer, )
                 Return
             Block 2:Block:
                 Variable(2, Integer) = Store Integer(0)
@@ -2993,8 +3057,10 @@ fn integer_greater_or_equal_than_comparison_with_lhs_dynamic_integer_and_rhs_cla
                 Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false)
                 Branch Variable(1, Boolean), 2, 3
             Block 1:Block:
-                Variable(3, Boolean) = Icmp Sge, Variable(2, Integer), Integer(1)
-                Call id(3), args( Variable(3, Boolean), Pointer, )
+                Variable(3, Integer) = Store Variable(2, Integer)
+                Variable(4, Boolean) = Icmp Sge, Variable(3, Integer), Integer(1)
+                Variable(5, Boolean) = Store Variable(4, Boolean)
+                Call id(3), args( Variable(5, Boolean), Pointer, )
                 Return
             Block 2:Block:
                 Variable(2, Integer) = Store Integer(0)
@@ -3071,10 +3137,11 @@ fn integer_less_than_comparison_with_lhs_dynamic_integer_and_rhs_dynamic_integer
                 Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false)
                 Branch Variable(1, Boolean), 2, 3
             Block 1:Block:
+                Variable(3, Integer) = Store Variable(2, Integer)
                 Call id(1), args( Qubit(0), Result(1), )
-                Variable(3, Boolean) = Call id(2), args( Result(1), )
-                Variable(4, Boolean) = Icmp Eq, Variable(3, Boolean), Bool(false)
-                Branch Variable(4, Boolean), 5, 6
+                Variable(4, Boolean) = Call id(2), args( Result(1), )
+                Variable(5, Boolean) = Icmp Eq, Variable(4, Boolean), Bool(false)
+                Branch Variable(5, Boolean), 5, 6
             Block 2:Block:
                 Variable(2, Integer) = Store Integer(0)
                 Jump(1)
@@ -3082,14 +3149,16 @@ fn integer_less_than_comparison_with_lhs_dynamic_integer_and_rhs_dynamic_integer
                 Variable(2, Integer) = Store Integer(1)
                 Jump(1)
             Block 4:Block:
-                Variable(6, Boolean) = Icmp Slt, Variable(2, Integer), Variable(5, Integer)
-                Call id(3), args( Variable(6, Boolean), Pointer, )
+                Variable(7, Integer) = Store Variable(6, Integer)
+                Variable(8, Boolean) = Icmp Slt, Variable(3, Integer), Variable(7, Integer)
+                Variable(9, Boolean) = Store Variable(8, Boolean)
+                Call id(3), args( Variable(9, Boolean), Pointer, )
                 Return
             Block 5:Block:
-                Variable(5, Integer) = Store Integer(1)
+                Variable(6, Integer) = Store Integer(1)
                 Jump(4)
             Block 6:Block:
-                Variable(5, Integer) = Store Integer(0)
+                Variable(6, Integer) = Store Integer(0)
                 Jump(4)"#]],
     );
 }
@@ -3159,8 +3228,10 @@ fn integer_less_or_equal_than_comparison_with_lhs_classical_integer_and_rhs_dyna
                 Variable(1, Boolean) = Icmp Eq, Variable(0, Boolean), Bool(false)
                 Branch Variable(1, Boolean), 2, 3
             Block 1:Block:
-                Variable(3, Boolean) = Icmp Sle, Integer(1), Variable(2, Integer)
-                Call id(3), args( Variable(3, Boolean), Pointer, )
+                Variable(3, Integer) = Store Variable(2, Integer)
+                Variable(4, Boolean) = Icmp Sle, Integer(1), Variable(3, Integer)
+                Variable(5, Boolean) = Store Variable(4, Boolean)
+                Call id(3), args( Variable(5, Boolean), Pointer, )
                 Return
             Block 2:Block:
                 Variable(2, Integer) = Store Integer(0)
diff --git a/compiler/qsc_rir/src/passes/ssa_transform/tests.rs b/compiler/qsc_rir/src/passes/ssa_transform/tests.rs
index f6e9c158..46fd6ba2 100644
--- a/compiler/qsc_rir/src/passes/ssa_transform/tests.rs
+++ b/compiler/qsc_rir/src/passes/ssa_transform/tests.rs
@@ -2493,3 +2493,156 @@ fn ssa_transform_maps_store_with_variable_from_store_in_conditional_to_phi_node(
             num_qubits: 0
             num_results: 0"#]].assert_eq(&program.to_string());
 }
+
+#[test]
+fn ssa_transform_allows_point_in_time_copy_of_dynamic_variable() {
+    let mut program = new_program();
+    program.callables.insert(
+        CallableId(1),
+        Callable {
+            name: "dynamic_bool".to_string(),
+            input_type: Vec::new(),
+            output_type: Some(Ty::Boolean),
+            body: None,
+            call_type: CallableType::Regular,
+        },
+    );
+
+    program.blocks.insert(
+        BlockId(0),
+        Block(vec![
+            Instruction::Call(
+                CallableId(1),
+                Vec::new(),
+                Some(Variable {
+                    variable_id: VariableId(0),
+                    ty: Ty::Boolean,
+                }),
+            ),
+            Instruction::Store(
+                Operand::Variable(Variable {
+                    variable_id: VariableId(0),
+                    ty: Ty::Boolean,
+                }),
+                Variable {
+                    variable_id: VariableId(1),
+                    ty: Ty::Boolean,
+                },
+            ),
+            Instruction::Store(
+                Operand::Variable(Variable {
+                    variable_id: VariableId(1),
+                    ty: Ty::Boolean,
+                }),
+                Variable {
+                    variable_id: VariableId(2),
+                    ty: Ty::Boolean,
+                },
+            ),
+            Instruction::LogicalNot(
+                Operand::Variable(Variable {
+                    variable_id: VariableId(1),
+                    ty: Ty::Boolean,
+                }),
+                Variable {
+                    variable_id: VariableId(3),
+                    ty: Ty::Boolean,
+                },
+            ),
+            Instruction::Store(
+                Operand::Variable(Variable {
+                    variable_id: VariableId(3),
+                    ty: Ty::Boolean,
+                }),
+                Variable {
+                    variable_id: VariableId(1),
+                    ty: Ty::Boolean,
+                },
+            ),
+            Instruction::LogicalNot(
+                Operand::Variable(Variable {
+                    variable_id: VariableId(2),
+                    ty: Ty::Boolean,
+                }),
+                Variable {
+                    variable_id: VariableId(4),
+                    ty: Ty::Boolean,
+                },
+            ),
+            Instruction::LogicalNot(
+                Operand::Variable(Variable {
+                    variable_id: VariableId(1),
+                    ty: Ty::Boolean,
+                }),
+                Variable {
+                    variable_id: VariableId(5),
+                    ty: Ty::Boolean,
+                },
+            ),
+            Instruction::Return,
+        ]),
+    );
+
+    // Before
+    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: dynamic_bool
+                    call_type: Regular
+                    input_type: <VOID>
+                    output_type: Boolean
+                    body: <NONE>
+            blocks:
+                Block 0: Block:
+                    Variable(0, Boolean) = Call id(1), args( )
+                    Variable(1, Boolean) = Store Variable(0, Boolean)
+                    Variable(2, Boolean) = Store Variable(1, Boolean)
+                    Variable(3, Boolean) = LogicalNot Variable(1, Boolean)
+                    Variable(1, Boolean) = Store Variable(3, Boolean)
+                    Variable(4, Boolean) = LogicalNot Variable(2, Boolean)
+                    Variable(5, Boolean) = LogicalNot Variable(1, Boolean)
+                    Return
+            config: Config:
+                capabilities: Base
+            num_qubits: 0
+            num_results: 0"#]]
+    .assert_eq(&program.to_string());
+
+    // After
+    transform_program(&mut program);
+    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: dynamic_bool
+                    call_type: Regular
+                    input_type: <VOID>
+                    output_type: Boolean
+                    body: <NONE>
+            blocks:
+                Block 0: Block:
+                    Variable(0, Boolean) = Call id(1), args( )
+                    Variable(3, Boolean) = LogicalNot Variable(0, Boolean)
+                    Variable(4, Boolean) = LogicalNot Variable(0, Boolean)
+                    Variable(5, Boolean) = LogicalNot Variable(3, Boolean)
+                    Return
+            config: Config:
+                capabilities: TargetCapabilityFlags(Adaptive | IntegerComputations | FloatingPointComputations | BackwardsBranching | HigherLevelConstructs | QubitReset)
+            num_qubits: 0
+            num_results: 0"#]].assert_eq(&program.to_string());
+}
diff --git a/library/src/tests/intrinsic.rs b/library/src/tests/intrinsic.rs
index f58223c8..df9224cb 100644
--- a/library/src/tests/intrinsic.rs
+++ b/library/src/tests/intrinsic.rs
@@ -3009,6 +3009,39 @@ fn test_exp() {
     .assert_eq(&dump);
 }
 
+#[test]
+fn test_exp_mixed_paulis() {
+    let dump = test_expression(
+        indoc! {r#"
+        {
+            open Std.Math;
+            open Std.Diagnostics;
+            use qs = Qubit[3];
+            for q in qs {
+                H(q);
+            }
+            Exp([PauliX, PauliI, PauliY], PI() / 7.0, qs);
+            DumpMachine();
+            ResetAll(qs);
+        }
+        "#},
+        &Value::unit(),
+    );
+
+    expect![[r#"
+        STATE:
+        |000⟩: 0.4719+0.0000𝑖
+        |001⟩: 0.1651+0.0000𝑖
+        |010⟩: 0.4719+0.0000𝑖
+        |011⟩: 0.1651+0.0000𝑖
+        |100⟩: 0.4719+0.0000𝑖
+        |101⟩: 0.1651+0.0000𝑖
+        |110⟩: 0.4719+0.0000𝑖
+        |111⟩: 0.1651+0.0000𝑖
+    "#]]
+    .assert_eq(&dump);
+}
+
 #[test]
 fn test_apply_unitary_with_h_matrix() {
     let dump = test_expression(
diff --git a/pip/tests-integration/resources/output/Adaptive_RI/SuperdenseCoding.ll b/pip/tests-integration/resources/output/Adaptive_RI/SuperdenseCoding.ll
index 03607bf2..8af7bfa2 100644
--- a/pip/tests-integration/resources/output/Adaptive_RI/SuperdenseCoding.ll
+++ b/pip/tests-integration/resources/output/Adaptive_RI/SuperdenseCoding.ll
@@ -10,13 +10,13 @@ block_0:
   %var_0 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 0 to %Result*))
   call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 2 to %Qubit*))
   call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 2 to %Qubit*), %Result* inttoptr (i64 1 to %Result*))
-  %var_2 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 1 to %Result*))
+  %var_4 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 1 to %Result*))
   br i1 %var_0, label %block_1, label %block_2
 block_1:
   call void @__quantum__qis__z__body(%Qubit* inttoptr (i64 0 to %Qubit*))
   br label %block_2
 block_2:
-  br i1 %var_2, label %block_3, label %block_4
+  br i1 %var_4, label %block_3, label %block_4
 block_3:
   call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 0 to %Qubit*))
   br label %block_4
@@ -26,22 +26,22 @@ block_4:
   call void @__quantum__qis__cx__body(%Qubit* inttoptr (i64 2 to %Qubit*), %Qubit* inttoptr (i64 1 to %Qubit*))
   call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 2 to %Qubit*))
   call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 2 to %Qubit*), %Result* inttoptr (i64 2 to %Result*))
-  %var_5 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 2 to %Result*))
+  %var_9 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 2 to %Result*))
   call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 2 to %Qubit*))
   call void @__quantum__qis__cz__body(%Qubit* inttoptr (i64 2 to %Qubit*), %Qubit* inttoptr (i64 0 to %Qubit*))
   call void @__quantum__qis__cz__body(%Qubit* inttoptr (i64 2 to %Qubit*), %Qubit* inttoptr (i64 1 to %Qubit*))
   call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 2 to %Qubit*))
   call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 2 to %Qubit*), %Result* inttoptr (i64 3 to %Result*))
-  %var_8 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 3 to %Result*))
+  %var_13 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 3 to %Result*))
   call void @__quantum__qis__reset__body(%Qubit* inttoptr (i64 0 to %Qubit*))
   call void @__quantum__qis__reset__body(%Qubit* inttoptr (i64 1 to %Qubit*))
   call void @__quantum__rt__tuple_record_output(i64 2, i8* null)
   call void @__quantum__rt__tuple_record_output(i64 2, i8* null)
   call void @__quantum__rt__bool_record_output(i1 %var_0, i8* null)
-  call void @__quantum__rt__bool_record_output(i1 %var_2, i8* null)
+  call void @__quantum__rt__bool_record_output(i1 %var_4, i8* null)
   call void @__quantum__rt__tuple_record_output(i64 2, i8* null)
-  call void @__quantum__rt__bool_record_output(i1 %var_5, i8* null)
-  call void @__quantum__rt__bool_record_output(i1 %var_8, i8* null)
+  call void @__quantum__rt__bool_record_output(i1 %var_9, i8* null)
+  call void @__quantum__rt__bool_record_output(i1 %var_13, i8* null)
   ret void
 }
 
diff --git a/pip/tests-integration/resources/output/Adaptive_RI/ThreeQubitRepetitionCode.ll b/pip/tests-integration/resources/output/Adaptive_RI/ThreeQubitRepetitionCode.ll
index 2d136271..79aea49e 100644
--- a/pip/tests-integration/resources/output/Adaptive_RI/ThreeQubitRepetitionCode.ll
+++ b/pip/tests-integration/resources/output/Adaptive_RI/ThreeQubitRepetitionCode.ll
@@ -47,15 +47,15 @@ block_6:
 block_7:
   br label %block_9
 block_8:
-  %var_81 = phi i1 [true, %block_5], [false, %block_6]
+  %var_87 = phi i1 [true, %block_5], [false, %block_6]
   br label %block_9
 block_9:
-  %var_82 = phi i1 [true, %block_7], [%var_81, %block_8]
-  br i1 %var_82, label %block_10, label %block_11
+  %var_88 = phi i1 [true, %block_7], [%var_87, %block_8]
+  br i1 %var_88, label %block_10, label %block_11
 block_10:
   br label %block_11
 block_11:
-  %var_83 = phi i64 [0, %block_9], [1, %block_10]
+  %var_89 = phi i64 [0, %block_9], [1, %block_10]
   call void @__quantum__qis__rx__body(double 1.5707963267948966, %Qubit* inttoptr (i64 0 to %Qubit*))
   call void @__quantum__qis__rx__body(double 1.5707963267948966, %Qubit* inttoptr (i64 1 to %Qubit*))
   call void @__quantum__qis__rx__body(double 1.5707963267948966, %Qubit* inttoptr (i64 2 to %Qubit*))
@@ -74,14 +74,14 @@ block_11:
   call void @__quantum__qis__cx__body(%Qubit* inttoptr (i64 2 to %Qubit*), %Qubit* inttoptr (i64 4 to %Qubit*))
   call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 3 to %Qubit*), %Result* inttoptr (i64 2 to %Result*))
   call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 4 to %Qubit*), %Result* inttoptr (i64 3 to %Result*))
-  %var_25 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 2 to %Result*))
-  br i1 %var_25, label %block_12, label %block_13
+  %var_26 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 2 to %Result*))
+  br i1 %var_26, label %block_12, label %block_13
 block_12:
-  %var_27 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 3 to %Result*))
-  br i1 %var_27, label %block_14, label %block_15
+  %var_28 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 3 to %Result*))
+  br i1 %var_28, label %block_14, label %block_15
 block_13:
-  %var_29 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 3 to %Result*))
-  br i1 %var_29, label %block_16, label %block_17
+  %var_30 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 3 to %Result*))
+  br i1 %var_30, label %block_16, label %block_17
 block_14:
   call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 1 to %Qubit*))
   br label %block_18
@@ -96,16 +96,16 @@ block_17:
 block_18:
   br label %block_20
 block_19:
-  %var_84 = phi i1 [true, %block_16], [false, %block_17]
+  %var_90 = phi i1 [true, %block_16], [false, %block_17]
   br label %block_20
 block_20:
-  %var_85 = phi i1 [true, %block_18], [%var_84, %block_19]
-  br i1 %var_85, label %block_21, label %block_22
+  %var_91 = phi i1 [true, %block_18], [%var_90, %block_19]
+  br i1 %var_91, label %block_21, label %block_22
 block_21:
-  %var_31 = add i64 %var_83, 1
+  %var_33 = add i64 %var_89, 1
   br label %block_22
 block_22:
-  %var_86 = phi i64 [%var_83, %block_20], [%var_31, %block_21]
+  %var_92 = phi i64 [%var_89, %block_20], [%var_33, %block_21]
   call void @__quantum__qis__rx__body(double 1.5707963267948966, %Qubit* inttoptr (i64 0 to %Qubit*))
   call void @__quantum__qis__rx__body(double 1.5707963267948966, %Qubit* inttoptr (i64 1 to %Qubit*))
   call void @__quantum__qis__rx__body(double 1.5707963267948966, %Qubit* inttoptr (i64 2 to %Qubit*))
@@ -124,14 +124,14 @@ block_22:
   call void @__quantum__qis__cx__body(%Qubit* inttoptr (i64 2 to %Qubit*), %Qubit* inttoptr (i64 4 to %Qubit*))
   call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 3 to %Qubit*), %Result* inttoptr (i64 4 to %Result*))
   call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 4 to %Qubit*), %Result* inttoptr (i64 5 to %Result*))
-  %var_40 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 4 to %Result*))
-  br i1 %var_40, label %block_23, label %block_24
+  %var_42 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 4 to %Result*))
+  br i1 %var_42, label %block_23, label %block_24
 block_23:
-  %var_42 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 5 to %Result*))
-  br i1 %var_42, label %block_25, label %block_26
-block_24:
   %var_44 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 5 to %Result*))
-  br i1 %var_44, label %block_27, label %block_28
+  br i1 %var_44, label %block_25, label %block_26
+block_24:
+  %var_46 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 5 to %Result*))
+  br i1 %var_46, label %block_27, label %block_28
 block_25:
   call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 1 to %Qubit*))
   br label %block_29
@@ -146,16 +146,16 @@ block_28:
 block_29:
   br label %block_31
 block_30:
-  %var_87 = phi i1 [true, %block_27], [false, %block_28]
+  %var_93 = phi i1 [true, %block_27], [false, %block_28]
   br label %block_31
 block_31:
-  %var_88 = phi i1 [true, %block_29], [%var_87, %block_30]
-  br i1 %var_88, label %block_32, label %block_33
+  %var_94 = phi i1 [true, %block_29], [%var_93, %block_30]
+  br i1 %var_94, label %block_32, label %block_33
 block_32:
-  %var_46 = add i64 %var_86, 1
+  %var_49 = add i64 %var_92, 1
   br label %block_33
 block_33:
-  %var_89 = phi i64 [%var_86, %block_31], [%var_46, %block_32]
+  %var_95 = phi i64 [%var_92, %block_31], [%var_49, %block_32]
   call void @__quantum__qis__rx__body(double 1.5707963267948966, %Qubit* inttoptr (i64 0 to %Qubit*))
   call void @__quantum__qis__rx__body(double 1.5707963267948966, %Qubit* inttoptr (i64 1 to %Qubit*))
   call void @__quantum__qis__rx__body(double 1.5707963267948966, %Qubit* inttoptr (i64 2 to %Qubit*))
@@ -174,14 +174,14 @@ block_33:
   call void @__quantum__qis__cx__body(%Qubit* inttoptr (i64 2 to %Qubit*), %Qubit* inttoptr (i64 4 to %Qubit*))
   call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 3 to %Qubit*), %Result* inttoptr (i64 6 to %Result*))
   call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 4 to %Qubit*), %Result* inttoptr (i64 7 to %Result*))
-  %var_55 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 6 to %Result*))
-  br i1 %var_55, label %block_34, label %block_35
+  %var_58 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 6 to %Result*))
+  br i1 %var_58, label %block_34, label %block_35
 block_34:
-  %var_57 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 7 to %Result*))
-  br i1 %var_57, label %block_36, label %block_37
+  %var_60 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 7 to %Result*))
+  br i1 %var_60, label %block_36, label %block_37
 block_35:
-  %var_59 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 7 to %Result*))
-  br i1 %var_59, label %block_38, label %block_39
+  %var_62 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 7 to %Result*))
+  br i1 %var_62, label %block_38, label %block_39
 block_36:
   call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 1 to %Qubit*))
   br label %block_40
@@ -196,16 +196,16 @@ block_39:
 block_40:
   br label %block_42
 block_41:
-  %var_90 = phi i1 [true, %block_38], [false, %block_39]
+  %var_96 = phi i1 [true, %block_38], [false, %block_39]
   br label %block_42
 block_42:
-  %var_91 = phi i1 [true, %block_40], [%var_90, %block_41]
-  br i1 %var_91, label %block_43, label %block_44
+  %var_97 = phi i1 [true, %block_40], [%var_96, %block_41]
+  br i1 %var_97, label %block_43, label %block_44
 block_43:
-  %var_61 = add i64 %var_89, 1
+  %var_65 = add i64 %var_95, 1
   br label %block_44
 block_44:
-  %var_92 = phi i64 [%var_89, %block_42], [%var_61, %block_43]
+  %var_98 = phi i64 [%var_95, %block_42], [%var_65, %block_43]
   call void @__quantum__qis__rx__body(double 1.5707963267948966, %Qubit* inttoptr (i64 0 to %Qubit*))
   call void @__quantum__qis__rx__body(double 1.5707963267948966, %Qubit* inttoptr (i64 1 to %Qubit*))
   call void @__quantum__qis__rx__body(double 1.5707963267948966, %Qubit* inttoptr (i64 2 to %Qubit*))
@@ -224,14 +224,14 @@ block_44:
   call void @__quantum__qis__cx__body(%Qubit* inttoptr (i64 2 to %Qubit*), %Qubit* inttoptr (i64 4 to %Qubit*))
   call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 3 to %Qubit*), %Result* inttoptr (i64 8 to %Result*))
   call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 4 to %Qubit*), %Result* inttoptr (i64 9 to %Result*))
-  %var_70 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 8 to %Result*))
-  br i1 %var_70, label %block_45, label %block_46
+  %var_74 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 8 to %Result*))
+  br i1 %var_74, label %block_45, label %block_46
 block_45:
-  %var_72 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 9 to %Result*))
-  br i1 %var_72, label %block_47, label %block_48
+  %var_76 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 9 to %Result*))
+  br i1 %var_76, label %block_47, label %block_48
 block_46:
-  %var_74 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 9 to %Result*))
-  br i1 %var_74, label %block_49, label %block_50
+  %var_78 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 9 to %Result*))
+  br i1 %var_78, label %block_49, label %block_50
 block_47:
   call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 1 to %Qubit*))
   br label %block_51
@@ -246,26 +246,26 @@ block_50:
 block_51:
   br label %block_53
 block_52:
-  %var_93 = phi i1 [true, %block_49], [false, %block_50]
+  %var_99 = phi i1 [true, %block_49], [false, %block_50]
   br label %block_53
 block_53:
-  %var_94 = phi i1 [true, %block_51], [%var_93, %block_52]
-  br i1 %var_94, label %block_54, label %block_55
+  %var_100 = phi i1 [true, %block_51], [%var_99, %block_52]
+  br i1 %var_100, label %block_54, label %block_55
 block_54:
-  %var_76 = add i64 %var_92, 1
+  %var_81 = add i64 %var_98, 1
   br label %block_55
 block_55:
-  %var_95 = phi i64 [%var_92, %block_53], [%var_76, %block_54]
+  %var_101 = phi i64 [%var_98, %block_53], [%var_81, %block_54]
   call void @__quantum__qis__cx__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Qubit* inttoptr (i64 2 to %Qubit*))
   call void @__quantum__qis__cx__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Qubit* inttoptr (i64 1 to %Qubit*))
   call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 0 to %Qubit*))
   call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 10 to %Result*))
-  %var_77 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 10 to %Result*))
+  %var_82 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 10 to %Result*))
   call void @__quantum__qis__reset__body(%Qubit* inttoptr (i64 1 to %Qubit*))
   call void @__quantum__qis__reset__body(%Qubit* inttoptr (i64 2 to %Qubit*))
   call void @__quantum__rt__tuple_record_output(i64 2, i8* null)
-  call void @__quantum__rt__bool_record_output(i1 %var_77, i8* null)
-  call void @__quantum__rt__int_record_output(i64 %var_95, i8* null)
+  call void @__quantum__rt__bool_record_output(i1 %var_82, i8* null)
+  call void @__quantum__rt__int_record_output(i64 %var_101, i8* null)
   ret void
 }