Skip to content

Commit 70abcef

Browse files
authored
Merge branch 'main' into ch-reorg.qir.codegen
2 parents 1b93cbe + 1ac1fab commit 70abcef

File tree

2 files changed

+104
-1
lines changed

2 files changed

+104
-1
lines changed

lib/Optimizer/Transforms/LoopAnalysis.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,14 @@ static bool isaConstantOf(Value v, std::int64_t hasVal) {
7373
return false;
7474
}
7575

76+
static bool isNegativeConstant(Value v) {
77+
v = peelCastOps(v);
78+
if (auto c = v.getDefiningOp<arith::ConstantOp>())
79+
if (auto ia = dyn_cast<IntegerAttr>(c.getValue()))
80+
return ia.getInt() < 0;
81+
return false;
82+
}
83+
7684
static bool isClosedIntervalForm(arith::CmpIPredicate p) {
7785
return p == arith::CmpIPredicate::ule || p == arith::CmpIPredicate::sle;
7886
}
@@ -274,7 +282,7 @@ bool opt::isaMonotonicLoop(Operation *op, bool allowEarlyExit,
274282

275283
bool opt::isaInvariantLoop(const LoopComponents &c, bool allowClosedInterval) {
276284
if (isaConstantOf(c.initialValue, 0) && isaConstantOf(c.stepValue, 1) &&
277-
isa<arith::AddIOp>(c.stepOp)) {
285+
isa<arith::AddIOp>(c.stepOp) && !isNegativeConstant(c.compareValue)) {
278286
auto cmp = cast<arith::CmpIOp>(c.compareOp);
279287
return validCountedLoopIntervalForm(cmp, allowClosedInterval);
280288
}

test/Quake/loop_normalize.qke

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// ========================================================================== //
2+
// Copyright (c) 2022 - 2025 NVIDIA Corporation & Affiliates. //
3+
// All rights reserved. //
4+
// //
5+
// This source code and the accompanying materials are made available under //
6+
// the terms of the Apache License 2.0 which accompanies this distribution. //
7+
// ========================================================================== //
8+
9+
// RUN: cudaq-opt -cc-loop-normalize %s | FileCheck %s
10+
11+
module {
12+
func.func @test_positive_boundaries() {
13+
%c0_i64 = arith.constant 0 : i64
14+
%c1_i64 = arith.constant 1 : i64
15+
%0 = quake.alloca !quake.veq<0>
16+
%1 = cc.loop while ((%arg0 = %c1_i64) -> (i64)) {
17+
%2 = arith.cmpi ult, %arg0, %c0_i64 : i64
18+
cc.condition %2(%arg0 : i64)
19+
} do {
20+
^bb0(%arg0: i64):
21+
%2 = arith.subi %arg0, %c1_i64 : i64
22+
%3 = quake.extract_ref %0[%2] : (!quake.veq<0>, i64) -> !quake.ref
23+
quake.x %3 : (!quake.ref) -> ()
24+
cc.continue %arg0 : i64
25+
} step {
26+
^bb0(%arg0: i64):
27+
%2 = arith.addi %arg0, %c1_i64 : i64
28+
cc.continue %2 : i64
29+
}
30+
return
31+
}
32+
33+
// CHECK-LABEL: func.func @test_positive_boundaries() {
34+
// CHECK: %[[VAL_0:.*]] = arith.constant 0 : i64
35+
// CHECK: %[[VAL_1:.*]] = arith.constant 1 : i64
36+
// CHECK: %[[VAL_2:.*]] = quake.alloca !quake.veq<0>
37+
// CHECK: %[[VAL_3:.*]] = cc.loop while ((%arg0 = %[[VAL_0]]) -> (i64)) {
38+
// CHECK: %[[VAL_4:.*]] = arith.cmpi ne, %arg0, %[[VAL_0]] : i64
39+
// CHECK: cc.condition %[[VAL_4]](%arg0 : i64)
40+
// CHECK: } do {
41+
// CHECK: ^bb0(%arg0: i64):
42+
// CHECK: %[[VAL_4:.*]] = quake.extract_ref %[[VAL_2]][%arg0] : (!quake.veq<0>, i64) -> !quake.ref
43+
// CHECK: quake.x %[[VAL_4]] : (!quake.ref) -> ()
44+
// CHECK: cc.continue %arg0 : i64
45+
// CHECK: } step {
46+
// CHECK: ^bb0(%arg0: i64):
47+
// CHECK: %[[VAL_4:.*]] = arith.addi %arg0, %[[VAL_1]] : i64
48+
// CHECK: cc.continue %[[VAL_4]] : i64
49+
// CHECK: } {normalized}
50+
// CHECK: return
51+
// CHECK: }
52+
53+
func.func @test_negative_boundaries() {
54+
%c-1_i32 = arith.constant -1 : i32
55+
%c1_i32 = arith.constant 1 : i32
56+
%c0_i32 = arith.constant 0 : i32
57+
%0 = quake.alloca !quake.veq<0>
58+
%1 = cc.loop while ((%arg0 = %c0_i32) -> (i32)) {
59+
%2 = arith.cmpi slt, %arg0, %c-1_i32 : i32
60+
cc.condition %2(%arg0 : i32)
61+
} do {
62+
^bb0(%arg0: i32):
63+
%2 = cc.cast signed %arg0 : (i32) -> i64
64+
%3 = quake.extract_ref %0[%2] : (!quake.veq<0>, i64) -> !quake.ref
65+
quake.x %3 : (!quake.ref) -> ()
66+
cc.continue %arg0 : i32
67+
} step {
68+
^bb0(%arg0: i32):
69+
%2 = arith.addi %arg0, %c1_i32 : i32
70+
cc.continue %2 : i32
71+
}
72+
return
73+
}
74+
75+
// CHECK-LABEL: func.func @test_negative_boundaries() {
76+
// CHECK: %[[VAL_0:.*]] = arith.constant 0 : i32
77+
// CHECK: %[[VAL_1:.*]] = arith.constant 1 : i32
78+
// CHECK: %[[VAL_2:.*]] = quake.alloca !quake.veq<0>
79+
// CHECK: %[[VAL_3:.*]] = cc.loop while ((%arg0 = %[[VAL_0]]) -> (i32)) {
80+
// CHECK: %[[VAL_4:.*]] = arith.cmpi ne, %arg0, %[[VAL_0]] : i32
81+
// CHECK: cc.condition %[[VAL_4]](%arg0 : i32)
82+
// CHECK: } do {
83+
// CHECK: ^bb0(%arg0: i32):
84+
// CHECK: %[[VAL_4:.*]] = cc.cast signed %arg0 : (i32) -> i64
85+
// CHECK: %[[VAL_5:.*]] = quake.extract_ref %[[VAL_2]][%[[VAL_4]]] : (!quake.veq<0>, i64) -> !quake.ref
86+
// CHECK: quake.x %[[VAL_5]] : (!quake.ref) -> ()
87+
// CHECK: cc.continue %arg0 : i32
88+
// CHECK: } step {
89+
// CHECK: ^bb0(%arg0: i32):
90+
// CHECK: %[[VAL_4:.*]] = arith.addi %arg0, %[[VAL_1]] : i32
91+
// CHECK: cc.continue %[[VAL_4]] : i32
92+
// CHECK: } {normalized}
93+
// CHECK: return
94+
// CHECK: }
95+
}

0 commit comments

Comments
 (0)