Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
293 changes: 260 additions & 33 deletions cudaq/lib/Optimizer/Transforms/MemToReg.cpp

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions cudaq/test/AST-Quake/unroll_particular_wire_loops.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,13 +136,13 @@ __qpu__ bool keeps_measurement_data_loop() {
// CHECK-NOT: quake.concat
// CHECK-NOT: quake.extract_ref
// CHECK: %[[LOOP:.*]]:2 = cc.loop while
// CHECK-SAME: (i1, i32)
// CHECK-SAME: (i32, i1)
// CHECK: %[[PTR:.*]] = cc.compute_ptr %[[HANDLES]]{{\[}}%{{.*}}] : (!cc.ptr<!cc.array<!cc.measure_handle x 3>>, i64) -> !cc.ptr<!cc.measure_handle>
// CHECK: %[[HANDLE:.*]] = cc.load %[[PTR]] : !cc.ptr<!cc.measure_handle>
// CHECK: quake.discriminate %[[HANDLE]] : (!cc.measure_handle) -> i1
// CHECK: cc.continue
// CHECK: quake.return_wire %[[W0]] : !quake.wire
// CHECK: quake.return_wire %[[W1]] : !quake.wire
// CHECK: quake.return_wire %[[W2]] : !quake.wire
// CHECK: return %[[LOOP]]#0 : i1
// CHECK: return %[[LOOP]]#1 : i1
// clang-format on
41 changes: 41 additions & 0 deletions cudaq/test/Transforms/loop_peeling.qke
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
// ========================================================================== //

// RUN: cudaq-opt --cc-loop-peeling %s | FileCheck %s
// RUN: cudaq-opt --memtoreg %s | FileCheck --check-prefix=CHECK-MEMTOREG %s

func.func @peel_do_while() {
%c1_i32 = arith.constant 1 : i32
Expand Down Expand Up @@ -90,6 +91,28 @@ func.func @peel_do_while() {
// CHECK: return
// CHECK: }

// This regression-tests a `cc.loop do { } while { }` (post_condition=true,
// so `do` is the entry region, not `while`) where the linear-type-argument
// canonicalization used to physically permute a block's arguments before
// updating the data-flow bookkeeping that still referenced them, crashing on
// the dangling reference. See MemToReg.cpp's canonicalizeArgumentOrder.
// CHECK-MEMTOREG-LABEL: func.func @peel_do_while() {
// CHECK-MEMTOREG: %[[LOOP_0:.*]]:2 = cc.loop do ((%{{.*}} = %{{.*}}, %{{.*}} = %{{.*}}) -> (i32, i1)) {
// CHECK-MEMTOREG: cc.continue %{{.*}}, %{{.*}} : i32, i1
// CHECK-MEMTOREG: } while {
// CHECK-MEMTOREG: ^bb0(%[[ARG0:.*]]: i32, %[[ARG1:.*]]: i1):
// CHECK-MEMTOREG: %[[CMPI_0:.*]] = arith.cmpi eq, %[[ARG1]], %{{.*}} : i1
// CHECK-MEMTOREG: %[[IF_0:.*]] = cc.if(%[[CMPI_0]]) -> i1 {
// CHECK-MEMTOREG: cc.continue %{{.*}} : i1
// CHECK-MEMTOREG: } else {
// CHECK-MEMTOREG: %[[CMPI_1:.*]] = arith.cmpi ult, %[[ARG0]], %{{.*}} : i32
// CHECK-MEMTOREG: cc.continue %[[CMPI_1]] : i1
// CHECK-MEMTOREG: }
// CHECK-MEMTOREG: cc.condition %[[IF_0]](%[[ARG0]], %[[ARG1]] : i32, i1)
// CHECK-MEMTOREG: }
// CHECK-MEMTOREG: return
// CHECK-MEMTOREG: }

func.func @peel_do_while_with_args() {
%c10_i32 = arith.constant 10 : i32
%c0_i32 = arith.constant 0 : i32
Expand Down Expand Up @@ -157,3 +180,21 @@ func.func @peel_do_while_with_args() {
// CHECK: return
// CHECK: }

// CHECK-MEMTOREG-LABEL: func.func @peel_do_while_with_args() {
// CHECK-MEMTOREG: %[[LOOP_1:.*]]:2 = cc.loop do ((%{{.*}} = %{{.*}}, %{{.*}} = %{{.*}}) -> (i32, i1)) {
// CHECK-MEMTOREG: cc.continue %{{.*}}, %{{.*}} : i32, i1
// CHECK-MEMTOREG: } while {
// CHECK-MEMTOREG: ^bb0(%[[ARG2:.*]]: i32, %[[ARG3:.*]]: i1):
// CHECK-MEMTOREG: %[[CMPI_2:.*]] = arith.cmpi eq, %[[ARG3]], %{{.*}} : i1
// CHECK-MEMTOREG: %[[IF_1:.*]] = cc.if(%[[CMPI_2]]) -> i1 {
// CHECK-MEMTOREG: cc.continue %{{.*}} : i1
// CHECK-MEMTOREG: } else {
// CHECK-MEMTOREG: %[[CMPI_3:.*]] = arith.cmpi ult, %[[ARG2]], %{{.*}} : i32
// CHECK-MEMTOREG: cc.continue %[[CMPI_3]] : i1
// CHECK-MEMTOREG: }
// CHECK-MEMTOREG: cc.condition %[[IF_1]](%[[ARG2]], %[[ARG3]] : i32, i1)
// CHECK-MEMTOREG: }
// CHECK-MEMTOREG: quake.dealloc %{{.*}} : !quake.veq<10>
// CHECK-MEMTOREG: return
// CHECK-MEMTOREG: }

46 changes: 46 additions & 0 deletions cudaq/test/Transforms/memtoreg-10.qke
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// ========================================================================== //
// Copyright (c) 2026 NVIDIA Corporation & Affiliates. //
// All rights reserved. //
// //
// This source code and the accompanying materials are made available under //
// the terms of the Apache License 2.0 which accompanies this distribution. //
// ========================================================================== //

// RUN: cudaq-opt --canonicalize --memtoreg --canonicalize %s | FileCheck %s

// Regression for a verifier error where the cc.if's appended results and its
// regions' cc.continue operands disagreed on slot order. cc.if carries the
// LinearTypeArgs trait, so only the wire can become a region block argument;
// the promoted i32 is results-only. The live-out order (which fixes the result
// list) and the canonicalized block argument order (which fixed the terminator
// operands) must therefore be one and the same order.
func.func @if_mixed_promotion(%c: i1, %k: i32) {
%q = quake.alloca !quake.ref
%m = cc.alloca i32
cc.if (%c) {
%v = cc.load %m : !cc.ptr<i32>
cc.store %k, %m : !cc.ptr<i32>
quake.x %q : (!quake.ref) -> ()
}
quake.y %q : (!quake.ref) -> ()
%f = cc.load %m : !cc.ptr<i32>
quake.log_output %f : (i32) -> () {compilerGenerated}
quake.dealloc %q : !quake.ref
return
}

// CHECK-LABEL: func.func @if_mixed_promotion(
// CHECK-SAME: %[[COND:.*]]: i1, %[[K:.*]]: i32) {
// CHECK: %[[NULL_0:.*]] = quake.null_wire
// CHECK: %[[UNDEF_0:.*]] = cc.undef i32
// CHECK: %[[IF_0:.*]]:2 = cc.if(%[[COND]]) ((%[[ARG:.*]] = %[[NULL_0]])) -> (!quake.wire, i32) {
// CHECK: %[[X_0:.*]] = quake.x %[[ARG]] : (!quake.wire) -> !quake.wire
// CHECK: cc.continue %[[X_0]], %[[K]] : !quake.wire, i32
// CHECK: } else {
// CHECK: cc.continue %[[ARG]], %[[UNDEF_0]] : !quake.wire, i32
// CHECK: }
// CHECK: %[[Y_0:.*]] = quake.y %[[IF_0]]#0 : (!quake.wire) -> !quake.wire
// CHECK: quake.log_output %[[IF_0]]#1 : (i32) -> () {compilerGenerated}
// CHECK: quake.sink %[[Y_0]] : !quake.wire
// CHECK: return
// CHECK: }
20 changes: 10 additions & 10 deletions cudaq/test/Transforms/memtoreg-2.qke
Original file line number Diff line number Diff line change
Expand Up @@ -771,19 +771,19 @@ func.func @simple_loop() {
// CHECK: %[[VAL_2:.*]] = arith.constant 42 : i64
// CHECK: %[[VAL_3:.*]] = quake.null_wire
// CHECK: %[[VAL_4:.*]] = cc.undef i64
// CHECK: %[[VAL_5:.*]]:2 = cc.loop while ((%[[VAL_6:.*]] = %[[VAL_3]], %[[VAL_7:.*]] = %[[VAL_0]]) -> (!quake.wire, i64)) {
// CHECK: %[[VAL_8:.*]] = arith.cmpi ult, %[[VAL_7]], %[[VAL_2]] : i64
// CHECK: cc.condition %[[VAL_8]](%[[VAL_6]], %[[VAL_7]] : !quake.wire, i64)
// CHECK: %[[VAL_5:.*]]:2 = cc.loop while ((%[[VAL_6:.*]] = %[[VAL_0]], %[[VAL_7:.*]] = %[[VAL_3]]) -> (i64, !quake.wire)) {
// CHECK: %[[VAL_8:.*]] = arith.cmpi ult, %[[VAL_6]], %[[VAL_2]] : i64
// CHECK: cc.condition %[[VAL_8]](%[[VAL_6]], %[[VAL_7]] : i64, !quake.wire)
// CHECK: } do {
// CHECK: ^bb0(%[[VAL_9:.*]]: !quake.wire, %[[VAL_10:.*]]: i64):
// CHECK: %[[VAL_11:.*]] = quake.x %[[VAL_9]] : (!quake.wire) -> !quake.wire
// CHECK: cc.continue %[[VAL_11]], %[[VAL_10]] : !quake.wire, i64
// CHECK: ^bb0(%[[VAL_9:.*]]: i64, %[[VAL_10:.*]]: !quake.wire):
// CHECK: %[[VAL_11:.*]] = quake.x %[[VAL_10]] : (!quake.wire) -> !quake.wire
// CHECK: cc.continue %[[VAL_9]], %[[VAL_11]] : i64, !quake.wire
// CHECK: } step {
// CHECK: ^bb0(%[[VAL_12:.*]]: !quake.wire, %[[VAL_13:.*]]: i64):
// CHECK: %[[VAL_14:.*]] = arith.addi %[[VAL_13]], %[[VAL_1]] : i64
// CHECK: cc.continue %[[VAL_12]], %[[VAL_14]] : !quake.wire, i64
// CHECK: ^bb0(%[[VAL_12:.*]]: i64, %[[VAL_13:.*]]: !quake.wire):
// CHECK: %[[VAL_14:.*]] = arith.addi %[[VAL_12]], %[[VAL_1]] : i64
// CHECK: cc.continue %[[VAL_14]], %[[VAL_13]] : i64, !quake.wire
// CHECK: }
// CHECK: %[[VAL_15:.*]] = quake.z %[[VAL_16:.*]]#0 : (!quake.wire) -> !quake.wire
// CHECK: %[[VAL_15:.*]] = quake.z %[[VAL_16:.*]]#1 : (!quake.wire) -> !quake.wire
// CHECK: quake.sink %[[VAL_15]] : !quake.wire
// CHECK: return
// CHECK: }
Expand Down
Loading
Loading