Repository: microsoft/qsharp
Pull request #2241 (2025-03-19 05:45:29)

Added copy button to code blocks in copilot
This adds a button to copy to clipboard to the top right of code blocks, e.g.

<img width="473" alt="image" src="https://github.com/user-attachments/assets/72c7be4a-56d5-4d7b-8cc2-fc9a34ad3689" />



Patch:
diff --git a/compiler/qsc/src/interpret.rs b/compiler/qsc/src/interpret.rs
index ce9f1977..829c073e 100644
--- a/compiler/qsc/src/interpret.rs
+++ b/compiler/qsc/src/interpret.rs
@@ -759,7 +759,6 @@ impl Interpreter {
             sim.chained.finish()
         } else {
             let mut sim = CircuitBuilder::new(CircuitConfig {
-                base_profile: self.capabilities.is_empty(),
                 max_operations: CircuitConfig::DEFAULT_MAX_OPERATIONS,
             });
 
@@ -1004,14 +1003,6 @@ fn sim_circuit_backend() -> BackendChain<SparseSim, CircuitBuilder> {
     BackendChain::new(
         SparseSim::new(),
         CircuitBuilder::new(CircuitConfig {
-            // When using in conjunction with the simulator,
-            // the circuit builder should *not* perform base profile
-            // decompositions, in order to match the simulator's behavior.
-            //
-            // Note that conditional compilation (e.g. @Config(Base) attributes)
-            // will still respect the selected profile. This also
-            // matches the behavior of the simulator.
-            base_profile: false,
             max_operations: CircuitConfig::DEFAULT_MAX_OPERATIONS,
         }),
     )
diff --git a/compiler/qsc_circuit/src/builder.rs b/compiler/qsc_circuit/src/builder.rs
index 9359a408..7dce08b6 100644
--- a/compiler/qsc_circuit/src/builder.rs
+++ b/compiler/qsc_circuit/src/builder.rs
@@ -56,48 +56,34 @@ impl Backend for Builder {
     }
 
     fn m(&mut self, q: usize) -> Self::ResultType {
-        if self.config.base_profile {
-            // defer the measurement and reset the qubit
-            self.remapper.mreset(q)
-        } else {
-            let mapped_q = self.map(q);
-            // In the Circuit schema, result id is per-qubit
-            let res_id = self.num_measurements_for_qubit(mapped_q);
-            let id = self.remapper.m(q);
+        let mapped_q = self.map(q);
+        // In the Circuit schema, result id is per-qubit
+        let res_id = self.num_measurements_for_qubit(mapped_q);
+        let id = self.remapper.m(q);
 
-            self.push_gate(measurement_gate(mapped_q.0, res_id));
-            id
-        }
+        self.push_gate(measurement_gate(mapped_q.0, res_id));
+        id
     }
 
     fn mresetz(&mut self, q: usize) -> Self::ResultType {
-        if self.config.base_profile {
-            // defer the measurement
-            self.remapper.mreset(q)
-        } else {
-            let mapped_q = self.map(q);
-            // In the Circuit schema, result id is per-qubit
-            let res_id = self.num_measurements_for_qubit(mapped_q);
-            // We don't actually need the Remapper since we're not
-            // remapping any qubits, but it's handy for keeping track of measurements
-            let id = self.remapper.m(q);
-
-            // Ideally MResetZ would be atomic but we don't currently have
-            // a way to visually represent that. So decompose it into
-            // a measurement and a reset gate.
-            self.push_gate(measurement_gate(mapped_q.0, res_id));
-            self.push_gate(gate(KET_ZERO, [mapped_q]));
-            id
-        }
+        let mapped_q = self.map(q);
+        // In the Circuit schema, result id is per-qubit
+        let res_id = self.num_measurements_for_qubit(mapped_q);
+        // We don't actually need the Remapper since we're not
+        // remapping any qubits, but it's handy for keeping track of measurements
+        let id = self.remapper.m(q);
+
+        // Ideally MResetZ would be atomic but we don't currently have
+        // a way to visually represent that. So decompose it into
+        // a measurement and a reset gate.
+        self.push_gate(measurement_gate(mapped_q.0, res_id));
+        self.push_gate(gate(KET_ZERO, [mapped_q]));
+        id
     }
 
     fn reset(&mut self, q: usize) {
-        if self.config.base_profile {
-            self.remapper.reset(q);
-        } else {
-            let mapped_q = self.map(q);
-            self.push_gate(gate(KET_ZERO, [mapped_q]));
-        }
+        let mapped_q = self.map(q);
+        self.push_gate(gate(KET_ZERO, [mapped_q]));
     }
 
     fn rx(&mut self, theta: f64, q: usize) {
@@ -267,18 +253,6 @@ impl Builder {
     }
 
     fn finish_circuit(&self, mut circuit: Circuit) -> Circuit {
-        // add deferred measurements
-        if self.config.base_profile {
-            for (qubit, _) in &self.remapper.qubit_measurement_counts {
-                if self.max_ops_exceeded || circuit.operations.len() >= self.config.max_operations {
-                    break;
-                }
-
-                // guaranteed one measurement per qubit, so result is always 0
-                circuit.operations.push(measurement_gate(qubit.0, 0));
-            }
-        }
-
         // add qubit declarations
         for i in 0..self.remapper.num_qubits() {
             let num_measurements = self.num_measurements_for_qubit(WireId(i));
@@ -408,16 +382,6 @@ impl Remapper {
         id
     }
 
-    fn mreset(&mut self, q: usize) -> usize {
-        let id = self.m(q);
-        self.reset(q);
-        id
-    }
-
-    fn reset(&mut self, q: usize) {
-        self.qubit_map.remove(q);
-    }
-
     fn qubit_allocate(&mut self) -> usize {
         let id = self.next_qubit_id;
         self.next_qubit_id += 1;
diff --git a/compiler/qsc_circuit/src/circuit.rs b/compiler/qsc_circuit/src/circuit.rs
index da101293..33507087 100644
--- a/compiler/qsc_circuit/src/circuit.rs
+++ b/compiler/qsc_circuit/src/circuit.rs
@@ -79,8 +79,6 @@ pub struct Qubit {
 
 #[derive(Clone, Debug, Copy, Default)]
 pub struct Config {
-    /// Perform Base Profile decompositions
-    pub base_profile: bool,
     /// Maximum number of operations the builder will add to the circuit
     pub max_operations: usize,
 }
diff --git a/library/std/src/Std/Intrinsic.qs b/library/std/src/Std/Intrinsic.qs
index 949587b6..44a5dd56 100644
--- a/library/std/src/Std/Intrinsic.qs
+++ b/library/std/src/Std/Intrinsic.qs
@@ -265,38 +265,6 @@ operation I(target : Qubit) : Unit is Adj + Ctl {
 /// ```qsharp
 /// Measure([PauliZ], [qubit]);
 /// ```
-@Config(QubitReset)
-operation M(qubit : Qubit) : Result {
-    __quantum__qis__m__body(qubit)
-}
-
-/// # Summary
-/// Performs a measurement of a single qubit in the
-/// Pauli _Z_ basis.
-///
-/// # Input
-/// ## qubit
-/// Qubit to be measured.
-///
-/// # Output
-/// `Zero` if the +1 eigenvalue is observed, and `One` if
-/// the -1 eigenvalue is observed.
-///
-/// # Remarks
-/// The output result is given by
-/// the distribution
-/// $$
-/// \begin{align}
-///     \Pr(\texttt{Zero} | \ket{\psi}) =
-///         \braket{\psi | 0} \braket{0 | \psi}.
-/// \end{align}
-/// $$
-///
-/// Equivalent to:
-/// ```qsharp
-/// Measure([PauliZ], [qubit]);
-/// ```
-@Config(not QubitReset)
 operation M(qubit : Qubit) : Result {
     Measure([PauliZ], [qubit])
 }
@@ -326,7 +294,6 @@ operation M(qubit : Qubit) : Result {
 /// $N$ is the `Length(bases)`.
 /// That is, measurement returns a `Result` $d$ such that the eigenvalue of the
 /// observed measurement effect is $(-1)^d$.
-@Config(QubitReset)
 operation Measure(bases : Pauli[], qubits : Qubit[]) : Result {
     if Length(bases) != Length(qubits) {
         fail "Arrays 'bases' and 'qubits' must be of the same length.";
@@ -350,50 +317,6 @@ operation Measure(bases : Pauli[], qubits : Qubit[]) : Result {
     }
 }
 
-/// # Summary
-/// Performs a joint measurement of one or more qubits in the
-/// specified Pauli bases.
-///
-/// If the basis array and qubit array are different lengths, then the
-/// operation will fail.
-///
-/// # Input
-/// ## bases
-/// Array of single-qubit Pauli values indicating the tensor product
-/// factors on each qubit.
-/// ## qubits
-/// Register of qubits to be measured.
-///
-/// # Output
-/// `Zero` if the +1 eigenvalue is observed, and `One` if
-/// the -1 eigenvalue is observed.
-///
-/// # Remarks
-/// The probability of getting `Zero` is
-/// $\bra{\psi} \frac{I + P_0 \otimes \ldots \otimes P_{N-1}}{2} \ket{\psi}$
-/// where $P_i$ is the $i$-th element of `bases`, and where
-/// $N$ is the `Length(bases)`.
-/// That is, measurement returns a `Result` $d$ such that the eigenvalue of the
-/// observed measurement effect is $(-1)^d$.
-@Config(not QubitReset)
-operation Measure(bases : Pauli[], qubits : Qubit[]) : Result {
-    if Length(bases) != Length(qubits) {
-        fail "Arrays 'bases' and 'qubits' must be of the same length.";
-    }
-    // Because Base Profile does not allow qubit reuse, we always allocate a new qubit
-    // and use entanglement to measure the state while collapsing the original target(s) and
-    // leaving it available for later operations.
-    use aux = Qubit();
-    within {
-        H(aux);
-    } apply {
-        for i in 0..Length(bases) - 1 {
-            EntangleForJointMeasure(bases[i], aux, qubits[i]);
-        }
-    }
-    __quantum__qis__mresetz__body(aux)
-}
-
 /// # Summary
 /// Applies a rotation about the given Pauli axis.
 ///
diff --git a/package-lock.json b/package-lock.json
index a4629e98..c82213c5 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -34,6 +34,7 @@
         "github-markdown-css": "^5.3.0",
         "globals": "^15.9.0",
         "highlight.js": "^11.10.0",
+        "highlightjs-copy": "^1.0.6",
         "markdown-it": "^14.1.0",
         "mocha": "^10.8.2",
         "modern-normalize": "^2.0.0",
@@ -4074,6 +4075,13 @@
         "node": ">=12.0.0"
       }
     },
+    "node_modules/highlightjs-copy": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/highlightjs-copy/-/highlightjs-copy-1.0.6.tgz",
+      "integrity": "sha512-UaHIlJ4rkk5R4OVDnpgxevIuYdHggN5sPgs3E/2FKLxypvzAQVTOZl66hm8cEnhrEoLHTGkQymLtfJ/efyv24Q==",
+      "dev": true,
+      "license": "ISC"
+    },
     "node_modules/http-assert": {
       "version": "1.5.0",
       "resolved": "https://registry.npmjs.org/http-assert/-/http-assert-1.5.0.tgz",
diff --git a/package.json b/package.json
index 64ce3de7..88973096 100644
--- a/package.json
+++ b/package.json
@@ -39,6 +39,7 @@
     "github-markdown-css": "^5.3.0",
     "globals": "^15.9.0",
     "highlight.js": "^11.10.0",
+    "highlightjs-copy": "^1.0.6",
     "markdown-it": "^14.1.0",
     "mocha": "^10.8.2",
     "modern-normalize": "^2.0.0",
diff --git a/vscode/src/copilot/webview/copilot.css b/vscode/src/copilot/webview/copilot.css
index 803e13b9..52c6a074 100644
--- a/vscode/src/copilot/webview/copilot.css
+++ b/vscode/src/copilot/webview/copilot.css
@@ -166,3 +166,8 @@ pre code {
 .histogram-container {
   width: 100%;
 }
+
+/* If not specified it defaults to the 'pre code' default monospace font  */
+.hljs-copy-button {
+  font-family: system-ui;
+}
diff --git a/vscode/src/copilot/webview/copilot.tsx b/vscode/src/copilot/webview/copilot.tsx
index ad045ff7..b5bd317d 100644
--- a/vscode/src/copilot/webview/copilot.tsx
+++ b/vscode/src/copilot/webview/copilot.tsx
@@ -17,6 +17,8 @@ import "./copilot.css";
 // Set up the Markdown renderer with KaTeX support
 import mk from "@vscode/markdown-it-katex";
 import hljs from "highlight.js/lib/core";
+import CopyButtonPlugin from "highlightjs-copy";
+import "highlightjs-copy/styles/highlightjs-copy.css";
 import python from "highlight.js/lib/languages/python";
 import markdownIt from "markdown-it";
 import { useEffect, useRef } from "preact/hooks";
@@ -36,18 +38,8 @@ const vscodeApi: WebviewApi<ChatElement[]> = acquireVsCodeApi();
 // to bloat the code
 hljs.registerLanguage("python", python);
 hljs.registerLanguage("qsharp", hlsjQsharp);
-const md = markdownIt("commonmark", {
-  highlight(str, lang) {
-    if (lang && hljs.getLanguage(lang)) {
-      try {
-        return hljs.highlight(str, { language: lang }).value;
-      } catch (__) {
-        console.error("Failed to highlight code block", __);
-      }
-    }
-    return "";
-  },
-});
+hljs.addPlugin(new CopyButtonPlugin());
+const md = markdownIt("commonmark");
 md.use(mk as any, {
   enableMathBlockInHtml: true,
   enableMathInlineInHtml: true,
@@ -248,10 +240,21 @@ function UserMessage(props: { content: string }) {
  * An assistant message in the chat history.
  */
 function AssistantMessage(props: { content: string }) {
+  // Highlight.js needs to be called on the code blocks after they are present in the
+  // DOM for the highlighjs-copy plugin to work (as it needs to add buttons to the container).
+  const ref = useRef<HTMLDivElement>(null);
+  useEffect(() => {
+    ref.current?.querySelectorAll("pre code").forEach((block) => {
+      hljs.highlightElement(block as HTMLElement);
+    });
+  }, [props.content]);
+
   return (
     <div className="left-message-row">
       <div className="assistant-message">
-        <Markdown markdown={props.content}></Markdown>
+        <div ref={ref}>
+          <Markdown markdown={props.content}></Markdown>
+        </div>
         <div className="content-reminder">
           AI generated content may be incorrect.
         </div>
diff --git a/vscode/src/copilot/webview/types.d.ts b/vscode/src/copilot/webview/types.d.ts
new file mode 100644
index 00000000..eb9a87e4
--- /dev/null
+++ b/vscode/src/copilot/webview/types.d.ts
@@ -0,0 +1,5 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+// This module has no types available, so we declare it as any.
+declare module "highlightjs-copy";


Test patch:
diff --git a/compiler/qsc/src/interpret/circuit_tests.rs b/compiler/qsc/src/interpret/circuit_tests.rs
index 53bb19d4..0baba2e5 100644
--- a/compiler/qsc/src/interpret/circuit_tests.rs
+++ b/compiler/qsc/src/interpret/circuit_tests.rs
@@ -202,11 +202,10 @@ fn m_base_profile() {
         .circuit(CircuitEntryPoint::EntryPoint, false)
         .expect("circuit generation should succeed");
 
-    expect![[r"
-        q_0    ── H ──── Z ────────────────
-        q_1    ── H ──── ● ──── H ──── M ──
-                                       ╘═══
-    "]]
+    expect![[r#"
+        q_0    ── H ──── M ──
+                         ╘═══
+    "#]]
     .assert_eq(&circ.to_string());
 }
 
@@ -287,10 +286,10 @@ fn mresetz_base_profile() {
         .circuit(CircuitEntryPoint::EntryPoint, false)
         .expect("circuit generation should succeed");
 
-    expect![[r"
-        q_0    ── H ──── M ──
-                         ╘═══
-    "]]
+    expect![[r#"
+        q_0    ── H ──── M ──── |0〉 ──
+                         ╘════════════
+    "#]]
     .assert_eq(&circ.to_string());
 }
 
@@ -597,14 +596,12 @@ fn operation_with_qubits_base_profile() {
         .circuit(CircuitEntryPoint::Operation("Test.Test".into()), false)
         .expect("circuit generation should succeed");
 
-    expect![[r"
-        q_0    ── H ──── ● ──── Z ──────────────────────────────
-        q_1    ───────── X ─────┼──────────── Z ────────────────
-        q_2    ── H ─────────── ● ──── H ─────┼───── M ─────────
-                                              │      ╘══════════
-        q_3    ── H ───────────────────────── ● ──── H ──── M ──
-                                                            ╘═══
-    "]]
+    expect![[r#"
+        q_0    ── H ──── ● ──── M ──
+                         │      ╘═══
+        q_1    ───────── X ──── M ──
+                                ╘═══
+    "#]]
     .assert_eq(&circ.to_string());
 }
 
@@ -1067,33 +1064,22 @@ mod debugger_stepping {
             Profile::Base,
         );
 
-        // Surprising but expected: Reset gates would *not* normally
-        // be generated in Base Profile, but they are here, since
-        // when running in tandem with the simulator, the resulting
-        // circuit is intended to match the calls into the simulator.
-        //
-        // Note the circuit still looks different than what would be
-        // generated in Unrestricted Profile for the same code,
-        // due to conditional compilation in the standard library.
-        expect![["
+        expect![[r#"
             step:
             step:
             q_0
             step:
             q_0    ── H ──
             step:
-            q_0    ── H ──── Z ─────────────────────────
-            q_1    ── H ──── ● ──── H ──── M ──── |0〉 ──
-                                           ╘════════════
+            q_0    ── H ──── M ──
+                             ╘═══
             step:
-            q_0    ── H ──── Z ──── |0〉 ──────────────────
-            q_1    ── H ──── ● ───── H ───── M ──── |0〉 ──
-                                             ╘════════════
+            q_0    ── H ──── M ──── |0〉 ──
+                             ╘════════════
             step:
-            q_0    ── H ──── Z ──── |0〉 ──────────────────
-            q_1    ── H ──── ● ───── H ───── M ──── |0〉 ──
-                                             ╘════════════
-        "]]
+            q_0    ── H ──── M ──── |0〉 ──
+                             ╘════════════
+        "#]]
         .assert_eq(&circs);
     }
 
diff --git a/compiler/qsc/src/interpret/tests.rs b/compiler/qsc/src/interpret/tests.rs
index 86fa3771..99942ba5 100644
--- a/compiler/qsc/src/interpret/tests.rs
+++ b/compiler/qsc/src/interpret/tests.rs
@@ -884,21 +884,17 @@ mod given_interpreter {
 
                 define void @ENTRYPOINT__main() #0 {
                 block_0:
-                  call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 1 to %Qubit*))
-                  call void @__quantum__qis__cz__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Qubit* inttoptr (i64 0 to %Qubit*))
-                  call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 1 to %Qubit*))
-                  call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
+                  call void @__quantum__qis__cx__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Qubit* inttoptr (i64 1 to %Qubit*))
+                  call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
                   call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null)
                   ret void
                 }
 
-                declare void @__quantum__qis__h__body(%Qubit*)
-
-                declare void @__quantum__qis__cz__body(%Qubit*, %Qubit*)
+                declare void @__quantum__qis__m__body(%Qubit*, %Result*) #1
 
                 declare void @__quantum__rt__result_record_output(%Result*, i8*)
 
-                declare void @__quantum__qis__m__body(%Qubit*, %Result*) #1
+                declare void @__quantum__qis__cx__body(%Qubit*, %Qubit*)
 
                 attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="base_profile" "required_num_qubits"="2" "required_num_results"="1" }
                 attributes #1 = { "irreversible" }
@@ -1083,21 +1079,17 @@ mod given_interpreter {
 
                 define void @ENTRYPOINT__main() #0 {
                 block_0:
-                  call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 1 to %Qubit*))
-                  call void @__quantum__qis__cz__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Qubit* inttoptr (i64 0 to %Qubit*))
-                  call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 1 to %Qubit*))
-                  call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
+                  call void @__quantum__qis__cx__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Qubit* inttoptr (i64 1 to %Qubit*))
+                  call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
                   call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null)
                   ret void
                 }
 
-                declare void @__quantum__qis__h__body(%Qubit*)
-
-                declare void @__quantum__qis__cz__body(%Qubit*, %Qubit*)
+                declare void @__quantum__qis__m__body(%Qubit*, %Result*) #1
 
                 declare void @__quantum__rt__result_record_output(%Result*, i8*)
 
-                declare void @__quantum__qis__m__body(%Qubit*, %Result*) #1
+                declare void @__quantum__qis__cx__body(%Qubit*, %Qubit*)
 
                 attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="base_profile" "required_num_qubits"="2" "required_num_results"="1" }
                 attributes #1 = { "irreversible" }
@@ -1131,21 +1123,17 @@ mod given_interpreter {
 
                 define void @ENTRYPOINT__main() #0 {
                 block_0:
-                  call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 1 to %Qubit*))
-                  call void @__quantum__qis__cz__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Qubit* inttoptr (i64 0 to %Qubit*))
-                  call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 1 to %Qubit*))
-                  call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
+                  call void @__quantum__qis__cx__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Qubit* inttoptr (i64 1 to %Qubit*))
+                  call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
                   call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null)
                   ret void
                 }
 
-                declare void @__quantum__qis__h__body(%Qubit*)
-
-                declare void @__quantum__qis__cz__body(%Qubit*, %Qubit*)
+                declare void @__quantum__qis__m__body(%Qubit*, %Result*) #1
 
                 declare void @__quantum__rt__result_record_output(%Result*, i8*)
 
-                declare void @__quantum__qis__m__body(%Qubit*, %Result*) #1
+                declare void @__quantum__qis__cx__body(%Qubit*, %Qubit*)
 
                 attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="base_profile" "required_num_qubits"="2" "required_num_results"="1" }
                 attributes #1 = { "irreversible" }
@@ -1211,21 +1199,17 @@ mod given_interpreter {
 
                 define void @ENTRYPOINT__main() #0 {
                 block_0:
-                  call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 1 to %Qubit*))
-                  call void @__quantum__qis__cz__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Qubit* inttoptr (i64 0 to %Qubit*))
-                  call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 1 to %Qubit*))
-                  call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
+                  call void @__quantum__qis__cx__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Qubit* inttoptr (i64 1 to %Qubit*))
+                  call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
                   call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null)
                   ret void
                 }
 
-                declare void @__quantum__qis__h__body(%Qubit*)
-
-                declare void @__quantum__qis__cz__body(%Qubit*, %Qubit*)
+                declare void @__quantum__qis__m__body(%Qubit*, %Result*) #1
 
                 declare void @__quantum__rt__result_record_output(%Result*, i8*)
 
-                declare void @__quantum__qis__m__body(%Qubit*, %Result*) #1
+                declare void @__quantum__qis__cx__body(%Qubit*, %Qubit*)
 
                 attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="base_profile" "required_num_qubits"="2" "required_num_results"="1" }
                 attributes #1 = { "irreversible" }
@@ -1271,21 +1255,17 @@ mod given_interpreter {
 
                 define void @ENTRYPOINT__main() #0 {
                 block_0:
-                  call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 1 to %Qubit*))
-                  call void @__quantum__qis__cz__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Qubit* inttoptr (i64 0 to %Qubit*))
-                  call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 1 to %Qubit*))
-                  call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
+                  call void @__quantum__qis__cx__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Qubit* inttoptr (i64 1 to %Qubit*))
+                  call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
                   call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null)
                   ret void
                 }
 
-                declare void @__quantum__qis__h__body(%Qubit*)
-
-                declare void @__quantum__qis__cz__body(%Qubit*, %Qubit*)
+                declare void @__quantum__qis__m__body(%Qubit*, %Result*) #1
 
                 declare void @__quantum__rt__result_record_output(%Result*, i8*)
 
-                declare void @__quantum__qis__m__body(%Qubit*, %Result*) #1
+                declare void @__quantum__qis__cx__body(%Qubit*, %Qubit*)
 
                 attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="base_profile" "required_num_qubits"="2" "required_num_results"="1" }
                 attributes #1 = { "irreversible" }
diff --git a/compiler/qsc_circuit/src/builder/tests.rs b/compiler/qsc_circuit/src/builder/tests.rs
index 52636374..03f1bf09 100644
--- a/compiler/qsc_circuit/src/builder/tests.rs
+++ b/compiler/qsc_circuit/src/builder/tests.rs
@@ -6,10 +6,7 @@ use expect_test::expect;
 
 #[test]
 fn exceed_max_operations() {
-    let mut builder = Builder::new(Config {
-        base_profile: false,
-        max_operations: 2,
-    });
+    let mut builder = Builder::new(Config { max_operations: 2 });
 
     let q = builder.qubit_allocate();
 
@@ -31,10 +28,7 @@ fn exceed_max_operations() {
 
 #[test]
 fn exceed_max_operations_deferred_measurements() {
-    let mut builder = Builder::new(Config {
-        base_profile: true, // deferred measurements
-        max_operations: 2,
-    });
+    let mut builder = Builder::new(Config { max_operations: 2 });
 
     let q = builder.qubit_allocate();
 
@@ -48,11 +42,10 @@ fn exceed_max_operations_deferred_measurements() {
 
     // The current behavior is to silently truncate the circuit
     // if it exceeds the maximum allowed number of operations.
-    // The measurement will be dropped.
+    // The second X will be dropped.
     expect![[r#"
-        q_0    ── X ──
-
-        q_1    ── X ──
+        q_0    ── X ──── M ──
+                         ╘═══
     "#]]
     .assert_eq(&circuit.to_string());
 }
diff --git a/pip/tests-integration/test_base_qir.py b/pip/tests-integration/test_base_qir.py
index fd06879f..13d4649a 100644
--- a/pip/tests-integration/test_base_qir.py
+++ b/pip/tests-integration/test_base_qir.py
@@ -32,22 +32,23 @@ def test_compile_qir_input_data() -> None:
     qir = operation._repr_qir_()
     assert isinstance(qir, bytes)
     module = Module.from_ir(Context(), qir.decode(), "module")
-    assert len(module.functions) == 5
+    assert len(module.functions) == 3
     assert module.functions[0].name == "ENTRYPOINT__main"
     func = module.functions[0]
     assert len(func.basic_blocks) == 1
-    assert len(func.basic_blocks[0].instructions) == 6
+    assert len(func.basic_blocks[0].instructions) == 3
     call_m = func.basic_blocks[0].instructions[0]
     assert isinstance(call_m, Call)
-    assert call_m.callee.name == "__quantum__qis__h__body"
-    assert len(call_m.args) == 1
-    assert qubit_id(call_m.args[0]) == 1
-    record_res = func.basic_blocks[0].instructions[4]
+    assert call_m.callee.name == "__quantum__qis__m__body"
+    assert len(call_m.args) == 2
+    assert qubit_id(call_m.args[0]) == 0
+    assert result_id(call_m.args[1]) == 0
+    record_res = func.basic_blocks[0].instructions[1]
     assert isinstance(record_res, Call)
     assert len(record_res.args) == 2
     assert record_res.callee.name == "__quantum__rt__result_record_output"
     assert result_id(record_res.args[0]) == 0
-    assert func.basic_blocks[0].instructions[5].opcode == Opcode.RET
+    assert func.basic_blocks[0].instructions[2].opcode == Opcode.RET
 
 
 @pytest.mark.skipif(not PYQIR_AVAILABLE, reason=SKIP_REASON)
@@ -87,7 +88,7 @@ def test_compile_qir_all_gates() -> None:
     assert module.functions[0].name == "ENTRYPOINT__main"
     func = module.functions[0]
     assert len(func.basic_blocks) == 1
-    assert len(func.basic_blocks[0].instructions) == 28
+    assert len(func.basic_blocks[0].instructions) == 26
 
     def check_call(i: int, name: str, num_args: int) -> None:
         call = func.basic_blocks[0].instructions[i]
@@ -114,14 +115,12 @@ def test_compile_qir_all_gates() -> None:
     check_call(16, "__quantum__qis__y__body", 1)
     check_call(17, "__quantum__qis__z__body", 1)
     check_call(18, "__quantum__qis__swap__body", 2)
-    check_call(19, "__quantum__qis__h__body", 1)
-    check_call(20, "__quantum__qis__cz__body", 2)
-    check_call(21, "__quantum__qis__h__body", 1)
-    check_call(22, "__quantum__qis__m__body", 2)
-    check_call(23, "__quantum__qis__m__body", 2)
-    check_call(24, "__quantum__rt__tuple_record_output", 2)
-    check_call(25, "__quantum__rt__result_record_output", 2)
-    check_call(26, "__quantum__rt__result_record_output", 2)
+    check_call(19, "__quantum__qis__cx__body", 2)
+    check_call(20, "__quantum__qis__m__body", 2)
+    check_call(21, "__quantum__qis__m__body", 2)
+    check_call(22, "__quantum__rt__tuple_record_output", 2)
+    check_call(23, "__quantum__rt__result_record_output", 2)
+    check_call(24, "__quantum__rt__result_record_output", 2)
 
     assert required_num_qubits(module.functions[0]) == 5
     assert required_num_results(module.functions[0]) == 2