Skip to content

Commit dae59b0

Browse files
sitio-coutolanza
authored andcommitted
[CIR][IR] Refactor while loops
Creates a separate C/C++ operation for while loops, while keeping the LoopOpInterface to generically handle loops. This simplifies the IR generation and printing/parsing of while loops. ghstack-source-id: 29a6d7530263a4f96dbe6ce3052875831126005d Pull Request resolved: llvm/clangir#408
1 parent ed157b1 commit dae59b0

File tree

11 files changed

+91
-150
lines changed

11 files changed

+91
-150
lines changed

clang/include/clang/CIR/Dialect/IR/CIROps.td

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -442,7 +442,7 @@ def StoreOp : CIR_Op<"store", [
442442

443443
def ReturnOp : CIR_Op<"return", [ParentOneOf<["FuncOp", "ScopeOp", "IfOp",
444444
"SwitchOp", "DoWhileOp",
445-
"LoopOp"]>,
445+
"WhileOp", "LoopOp"]>,
446446
Terminator]> {
447447
let summary = "Return from function";
448448
let description = [{
@@ -635,7 +635,7 @@ def ConditionOp : CIR_Op<"condition", [
635635
//===----------------------------------------------------------------------===//
636636

637637
def YieldOp : CIR_Op<"yield", [ReturnLike, Terminator,
638-
ParentOneOf<["IfOp", "ScopeOp", "SwitchOp", "LoopOp", "AwaitOp",
638+
ParentOneOf<["IfOp", "ScopeOp", "SwitchOp", "WhileOp", "LoopOp", "AwaitOp",
639639
"TernaryOp", "GlobalOp", "DoWhileOp"]>]> {
640640
let summary = "Represents the default branching behaviour of a region";
641641
let description = [{
@@ -1164,12 +1164,11 @@ def BrCondOp : CIR_Op<"brcond",
11641164
//===----------------------------------------------------------------------===//
11651165

11661166
def LoopOpKind_For : I32EnumAttrCase<"For", 1, "for">;
1167-
def LoopOpKind_While : I32EnumAttrCase<"While", 2, "while">;
11681167

11691168
def LoopOpKind : I32EnumAttr<
11701169
"LoopOpKind",
11711170
"Loop kind",
1172-
[LoopOpKind_For, LoopOpKind_While]> {
1171+
[LoopOpKind_For]> {
11731172
let cppNamespace = "::mlir::cir";
11741173
}
11751174

@@ -1251,8 +1250,8 @@ def LoopOp : CIR_Op<"loop",
12511250
switch(getKind()) {
12521251
case LoopOpKind::For:
12531252
return llvm::SmallVector<Region *, 3>{&getCond(), &getBody(), &getStep()};
1254-
case LoopOpKind::While:
1255-
return llvm::SmallVector<Region *, 2>{&getCond(), &getBody()};
1253+
// case LoopOpKind::While:
1254+
// return llvm::SmallVector<Region *, 2>{&getCond(), &getBody()};
12561255
// case LoopOpKind::DoWhile:
12571256
// return llvm::SmallVector<Region *, 2>{&getBody(), &getCond()};
12581257
}
@@ -1261,7 +1260,7 @@ def LoopOp : CIR_Op<"loop",
12611260
}
12621261

12631262
//===----------------------------------------------------------------------===//
1264-
// DoWhileOp
1263+
// While & DoWhileOp
12651264
//===----------------------------------------------------------------------===//
12661265

12671266
class WhileOpBase<string mnemonic> : CIR_Op<mnemonic, [
@@ -1287,6 +1286,31 @@ class WhileOpBase<string mnemonic> : CIR_Op<mnemonic, [
12871286
];
12881287
}
12891288

1289+
def WhileOp : WhileOpBase<"while"> {
1290+
let regions = (region SizedRegion<1>:$cond, MinSizedRegion<1>:$body);
1291+
let assemblyFormat = "$cond `do` $body attr-dict";
1292+
1293+
let description = [{
1294+
Represents a C/C++ while loop. It consists of two regions:
1295+
1296+
- `cond`: single block region with the loop's condition. Should be
1297+
terminated with a `cir.condition` operation.
1298+
- `body`: contains the loop body and an arbitrary number of blocks.
1299+
1300+
Example:
1301+
1302+
```mlir
1303+
cir.while {
1304+
cir.break
1305+
^bb2:
1306+
cir.yield
1307+
} do {
1308+
cir.condition %cond : cir.bool
1309+
}
1310+
```
1311+
}];
1312+
}
1313+
12901314
def DoWhileOp : WhileOpBase<"do"> {
12911315
let regions = (region MinSizedRegion<1>:$body, SizedRegion<1>:$cond);
12921316
let assemblyFormat = " $body `while` $cond attr-dict";
@@ -2660,7 +2684,7 @@ def AllocException : CIR_Op<"alloc_exception", [
26602684

26612685
def ThrowOp : CIR_Op<"throw", [
26622686
ParentOneOf<["FuncOp", "ScopeOp", "IfOp", "SwitchOp",
2663-
"DoWhileOp", "LoopOp"]>,
2687+
"DoWhileOp", "WhileOp", "LoopOp"]>,
26642688
Terminator]> {
26652689
let summary = "(Re)Throws an exception";
26662690
let description = [{

clang/lib/CIR/CodeGen/CIRGenBuilder.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,14 @@ class CIRGenBuilderTy : public CIRBaseBuilderTy {
607607
return create<mlir::cir::DoWhileOp>(loc, condBuilder, bodyBuilder);
608608
}
609609

610+
/// Create a while operation.
611+
mlir::cir::WhileOp createWhile(
612+
mlir::Location loc,
613+
llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> condBuilder,
614+
llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> bodyBuilder) {
615+
return create<mlir::cir::WhileOp>(loc, condBuilder, bodyBuilder);
616+
}
617+
610618
mlir::cir::MemCpyOp createMemCpy(mlir::Location loc, mlir::Value dst,
611619
mlir::Value src, mlir::Value len) {
612620
return create<mlir::cir::MemCpyOp>(loc, dst, src, len);

clang/lib/CIR/CodeGen/CIRGenStmt.cpp

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "mlir/IR/Value.h"
1717
#include "clang/AST/CharUnits.h"
1818
#include "clang/AST/Stmt.h"
19+
#include "clang/CIR/Dialect/IR/CIRDialect.h"
1920
#include "clang/CIR/Dialect/IR/CIRTypes.h"
2021
#include "llvm/Support/ErrorHandling.h"
2122

@@ -877,7 +878,7 @@ mlir::LogicalResult CIRGenFunction::buildDoStmt(const DoStmt &S) {
877878
}
878879

879880
mlir::LogicalResult CIRGenFunction::buildWhileStmt(const WhileStmt &S) {
880-
mlir::cir::LoopOp loopOp;
881+
mlir::cir::WhileOp whileOp;
881882

882883
// TODO: pass in array of attributes.
883884
auto whileStmtBuilder = [&]() -> mlir::LogicalResult {
@@ -889,8 +890,8 @@ mlir::LogicalResult CIRGenFunction::buildWhileStmt(const WhileStmt &S) {
889890
// sure we handle all cases.
890891
assert(!UnimplementedFeature::requiresCleanups());
891892

892-
loopOp = builder.create<LoopOp>(
893-
getLoc(S.getSourceRange()), mlir::cir::LoopOpKind::While,
893+
whileOp = builder.createWhile(
894+
getLoc(S.getSourceRange()),
894895
/*condBuilder=*/
895896
[&](mlir::OpBuilder &b, mlir::Location loc) {
896897
assert(!UnimplementedFeature::createProfileWeightsForLoop());
@@ -911,10 +912,6 @@ mlir::LogicalResult CIRGenFunction::buildWhileStmt(const WhileStmt &S) {
911912
if (buildStmt(S.getBody(), /*useCurrentScope=*/true).failed())
912913
loopRes = mlir::failure();
913914
buildStopPoint(&S);
914-
},
915-
/*stepBuilder=*/
916-
[&](mlir::OpBuilder &b, mlir::Location loc) {
917-
builder.createYield(loc);
918915
});
919916
return loopRes;
920917
};
@@ -931,7 +928,7 @@ mlir::LogicalResult CIRGenFunction::buildWhileStmt(const WhileStmt &S) {
931928
if (res.failed())
932929
return res;
933930

934-
terminateBody(builder, loopOp.getBody(), getLoc(S.getEndLoc()));
931+
terminateBody(builder, whileOp.getBody(), getLoc(S.getEndLoc()));
935932
return mlir::success();
936933
}
937934

clang/lib/CIR/Dialect/IR/CIRDialect.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1288,6 +1288,14 @@ ::llvm::SmallVector<Region *> DoWhileOp::getLoopRegions() {
12881288
return {&getBody()};
12891289
}
12901290

1291+
void WhileOp::getSuccessorRegions(
1292+
::mlir::RegionBranchPoint point,
1293+
::llvm::SmallVectorImpl<::mlir::RegionSuccessor> &regions) {
1294+
LoopOpInterface::getLoopOpSuccessorRegions(*this, point, regions);
1295+
}
1296+
1297+
::llvm::SmallVector<Region *> WhileOp::getLoopRegions() { return {&getBody()}; }
1298+
12911299
//===----------------------------------------------------------------------===//
12921300
// GlobalOp
12931301
//===----------------------------------------------------------------------===//

clang/test/CIR/CodeGen/loop.cpp

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,10 @@ void l2(bool cond) {
5353

5454
// CHECK: cir.func @_Z2l2b
5555
// CHECK: cir.scope {
56-
// CHECK-NEXT: cir.loop while(cond : {
56+
// CHECK-NEXT: cir.while {
5757
// CHECK-NEXT: %3 = cir.load %0 : cir.ptr <!cir.bool>, !cir.bool
5858
// CHECK-NEXT: cir.condition(%3)
59-
// CHECK-NEXT: }, step : {
60-
// CHECK-NEXT: cir.yield
61-
// CHECK-NEXT: }) {
59+
// CHECK-NEXT: } do {
6260
// CHECK-NEXT: %3 = cir.load %1 : cir.ptr <!s32i>, !s32i
6361
// CHECK-NEXT: %4 = cir.const(#cir.int<1> : !s32i) : !s32i
6462
// CHECK-NEXT: %5 = cir.binop(add, %3, %4) : !s32i
@@ -67,12 +65,10 @@ void l2(bool cond) {
6765
// CHECK-NEXT: }
6866
// CHECK-NEXT: }
6967
// CHECK-NEXT: cir.scope {
70-
// CHECK-NEXT: cir.loop while(cond : {
68+
// CHECK-NEXT: cir.while {
7169
// CHECK-NEXT: %[[#TRUE:]] = cir.const(#true) : !cir.bool
7270
// CHECK-NEXT: cir.condition(%[[#TRUE]])
73-
// CHECK-NEXT: }, step : {
74-
// CHECK-NEXT: cir.yield
75-
// CHECK-NEXT: }) {
71+
// CHECK-NEXT: } do {
7672
// CHECK-NEXT: %3 = cir.load %1 : cir.ptr <!s32i>, !s32i
7773
// CHECK-NEXT: %4 = cir.const(#cir.int<1> : !s32i) : !s32i
7874
// CHECK-NEXT: %5 = cir.binop(add, %3, %4) : !s32i
@@ -81,13 +77,11 @@ void l2(bool cond) {
8177
// CHECK-NEXT: }
8278
// CHECK-NEXT: }
8379
// CHECK-NEXT: cir.scope {
84-
// CHECK-NEXT: cir.loop while(cond : {
80+
// CHECK-NEXT: cir.while {
8581
// CHECK-NEXT: %3 = cir.const(#cir.int<1> : !s32i) : !s32i
8682
// CHECK-NEXT: %4 = cir.cast(int_to_bool, %3 : !s32i), !cir.bool
8783
// CHECK-NEXT: cir.condition(%4)
88-
// CHECK-NEXT: }, step : {
89-
// CHECK-NEXT: cir.yield
90-
// CHECK-NEXT: }) {
84+
// CHECK-NEXT: } do {
9185
// CHECK-NEXT: %3 = cir.load %1 : cir.ptr <!s32i>, !s32i
9286
// CHECK-NEXT: %4 = cir.const(#cir.int<1> : !s32i) : !s32i
9387
// CHECK-NEXT: %5 = cir.binop(add, %3, %4) : !s32i
@@ -159,12 +153,10 @@ void l4() {
159153
}
160154

161155
// CHECK: cir.func @_Z2l4v
162-
// CHECK: cir.loop while(cond : {
156+
// CHECK: cir.while {
163157
// CHECK-NEXT: %[[#TRUE:]] = cir.const(#true) : !cir.bool
164158
// CHECK-NEXT: cir.condition(%[[#TRUE]])
165-
// CHECK-NEXT: }, step : {
166-
// CHECK-NEXT: cir.yield
167-
// CHECK-NEXT: }) {
159+
// CHECK-NEXT: } do {
168160
// CHECK-NEXT: %4 = cir.load %0 : cir.ptr <!s32i>, !s32i
169161
// CHECK-NEXT: %5 = cir.const(#cir.int<1> : !s32i) : !s32i
170162
// CHECK-NEXT: %6 = cir.binop(add, %4, %5) : !s32i
@@ -204,12 +196,10 @@ void l6() {
204196

205197
// CHECK: cir.func @_Z2l6v()
206198
// CHECK-NEXT: cir.scope {
207-
// CHECK-NEXT: cir.loop while(cond : {
199+
// CHECK-NEXT: cir.while {
208200
// CHECK-NEXT: %[[#TRUE:]] = cir.const(#true) : !cir.bool
209201
// CHECK-NEXT: cir.condition(%[[#TRUE]])
210-
// CHECK-NEXT: }, step : {
211-
// CHECK-NEXT: cir.yield
212-
// CHECK-NEXT: }) {
202+
// CHECK-NEXT: } do {
213203
// CHECK-NEXT: cir.return
214204
// CHECK-NEXT: }
215205
// CHECK-NEXT: }

clang/test/CIR/IR/invalid.cir

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -306,11 +306,9 @@ cir.func @cast24(%p : !u32i) {
306306
#true = #cir.bool<true> : !cir.bool
307307
cir.func @b0() {
308308
cir.scope {
309-
cir.loop while(cond : { // expected-error {{expected condition region to terminate with 'cir.condition'}}
309+
cir.while { // expected-error {{expected condition region to terminate with 'cir.condition'}}
310310
cir.yield
311-
}, step : {
312-
cir.yield
313-
}) {
311+
} do {
314312
cir.br ^bb1
315313
^bb1:
316314
cir.return

clang/test/CIR/IR/loop.cir

Lines changed: 0 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -34,29 +34,6 @@ cir.func @l0() {
3434
cir.yield
3535
}
3636
}
37-
cir.scope {
38-
%2 = cir.alloca !u32i, cir.ptr <!u32i>, ["i", init] {alignment = 4 : i64}
39-
%3 = cir.const(#cir.int<0> : !u32i) : !u32i
40-
cir.store %3, %2 : !u32i, cir.ptr <!u32i>
41-
cir.loop while(cond : {
42-
%4 = cir.load %2 : cir.ptr <!u32i>, !u32i
43-
%5 = cir.const(#cir.int<10> : !u32i) : !u32i
44-
%6 = cir.cmp(lt, %4, %5) : !u32i, !cir.bool
45-
cir.condition(%6)
46-
}, step : {
47-
cir.yield
48-
}) {
49-
%4 = cir.load %0 : cir.ptr <!u32i>, !u32i
50-
%5 = cir.const(#cir.int<1> : !u32i) : !u32i
51-
%6 = cir.binop(add, %4, %5) : !u32i
52-
cir.store %6, %0 : !u32i, cir.ptr <!u32i>
53-
%7 = cir.const(#true) : !cir.bool
54-
cir.if %7 {
55-
cir.continue
56-
}
57-
cir.yield
58-
}
59-
}
6037

6138
cir.return
6239
}
@@ -84,74 +61,3 @@ cir.func @l0() {
8461
// CHECK-NEXT: }
8562
// CHECK-NEXT: cir.yield
8663
// CHECK-NEXT: }
87-
88-
// CHECK: cir.loop while(cond : {
89-
// CHECK-NEXT: %4 = cir.load %2 : cir.ptr <!u32i>, !u32i
90-
// CHECK-NEXT: %5 = cir.const(#cir.int<10> : !u32i) : !u32i
91-
// CHECK-NEXT: %6 = cir.cmp(lt, %4, %5) : !u32i, !cir.bool
92-
// CHECK-NEXT: cir.condition(%6)
93-
// CHECK-NEXT: }, step : {
94-
// CHECK-NEXT: cir.yield
95-
// CHECK-NEXT: }) {
96-
// CHECK-NEXT: %4 = cir.load %0 : cir.ptr <!u32i>, !u32i
97-
// CHECK-NEXT: %5 = cir.const(#cir.int<1> : !u32i) : !u32i
98-
// CHECK-NEXT: %6 = cir.binop(add, %4, %5) : !u32i
99-
// CHECK-NEXT: cir.store %6, %0 : !u32i, cir.ptr <!u32i>
100-
// CHECK-NEXT: %7 = cir.const(#true) : !cir.bool
101-
// CHECK-NEXT: cir.if %7 {
102-
// CHECK-NEXT: cir.continue
103-
// CHECK-NEXT: }
104-
// CHECK-NEXT: cir.yield
105-
// CHECK-NEXT: }
106-
107-
cir.func @l1(%arg0 : !cir.bool) {
108-
cir.scope {
109-
cir.loop while(cond : {
110-
cir.condition(%arg0)
111-
}, step : {
112-
cir.yield
113-
}) {
114-
cir.yield
115-
}
116-
}
117-
cir.return
118-
}
119-
120-
// CHECK: cir.func @l1
121-
// CHECK-NEXT: cir.scope {
122-
// CHECK-NEXT: cir.loop while(cond : {
123-
// CHECK-NEXT: cir.condition(%arg0)
124-
// CHECK-NEXT: }, step : {
125-
// CHECK-NEXT: cir.yield
126-
// CHECK-NEXT: }) {
127-
// CHECK-NEXT: cir.yield
128-
// CHECK-NEXT: }
129-
// CHECK-NEXT: }
130-
// CHECK-NEXT: cir.return
131-
// CHECK-NEXT: }
132-
133-
cir.func @l2(%arg0 : !cir.bool) {
134-
cir.scope {
135-
cir.loop while(cond : {
136-
cir.condition(%arg0)
137-
}, step : {
138-
cir.yield
139-
}) {
140-
cir.yield
141-
}
142-
}
143-
cir.return
144-
}
145-
146-
// CHECK: cir.func @l2
147-
// CHECK-NEXT: cir.scope {
148-
// CHECK-NEXT: cir.loop while(cond : {
149-
// CHECK-NEXT: cir.condition(%arg0)
150-
// CHECK-NEXT: }, step : {
151-
// CHECK-NEXT: cir.yield
152-
// CHECK-NEXT: }) {
153-
// CHECK-NEXT: cir.yield
154-
// CHECK-NEXT: }
155-
// CHECK-NEXT: }
156-
// CHECK-NEXT: cir.return
157-
// CHECK-NEXT: }

clang/test/CIR/IR/while.cir

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// RUN: cir-opt %s -o %t.cir
2+
// RUN: FileCheck --input-file=%t.cir %s
3+
4+
cir.func @testPrintingParsing(%arg0 : !cir.bool) {
5+
cir.while {
6+
cir.condition(%arg0)
7+
} do {
8+
cir.yield
9+
}
10+
cir.return
11+
}
12+
13+
// CHECK: @testPrintingParsing
14+
// CHECK: cir.while {
15+
// CHECK: cir.condition(%arg0)
16+
// CHECK: } do {
17+
// CHECK: cir.yield
18+
// CHECK: }

0 commit comments

Comments
 (0)