-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[CIR] Upstream support for while and do..while loops #133157
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
This adds basic support for while and do..while loops. Support for break and continue are left for a subsequent patch.
@llvm/pr-subscribers-clang @llvm/pr-subscribers-clangir Author: Andy Kaylor (andykaylor) ChangesThis adds basic support for while and do..while loops. Support for break and continue are left for a subsequent patch. Full diff: https://github.com/llvm/llvm-project/pull/133157.diff 7 Files Affected:
diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
index ac7658276ec37..36ad22046deb5 100644
--- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
+++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
@@ -87,6 +87,22 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
return cir::BoolAttr::get(getContext(), getBoolTy(), state);
}
+ /// Create a do-while operation.
+ cir::DoWhileOp createDoWhile(
+ mlir::Location loc,
+ llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> condBuilder,
+ llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> bodyBuilder) {
+ return create<cir::DoWhileOp>(loc, condBuilder, bodyBuilder);
+ }
+
+ /// Create a while operation.
+ cir::WhileOp createWhile(
+ mlir::Location loc,
+ llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> condBuilder,
+ llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> bodyBuilder) {
+ return create<cir::WhileOp>(loc, condBuilder, bodyBuilder);
+ }
+
/// Create a for operation.
cir::ForOp createFor(
mlir::Location loc,
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 455cc2b8b0277..7a604421212d9 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -424,7 +424,8 @@ def StoreOp : CIR_Op<"store", [
// ReturnOp
//===----------------------------------------------------------------------===//
-def ReturnOp : CIR_Op<"return", [ParentOneOf<["FuncOp", "ScopeOp", "ForOp"]>,
+def ReturnOp : CIR_Op<"return", [ParentOneOf<["FuncOp", "ScopeOp", "DoWhileOp",
+ "WhileOp", "ForOp"]>,
Terminator]> {
let summary = "Return from function";
let description = [{
@@ -511,7 +512,8 @@ def ConditionOp : CIR_Op<"condition", [
//===----------------------------------------------------------------------===//
def YieldOp : CIR_Op<"yield", [ReturnLike, Terminator,
- ParentOneOf<["ScopeOp", "ForOp"]>]> {
+ ParentOneOf<["ScopeOp", "WhileOp", "ForOp",
+ "DoWhileOp"]>]> {
let summary = "Represents the default branching behaviour of a region";
let description = [{
The `cir.yield` operation terminates regions on different CIR operations,
@@ -759,6 +761,84 @@ def BrCondOp : CIR_Op<"brcond",
}];
}
+//===----------------------------------------------------------------------===//
+// While & DoWhileOp
+//===----------------------------------------------------------------------===//
+
+class WhileOpBase<string mnemonic> : CIR_Op<mnemonic, [
+ LoopOpInterface,
+ NoRegionArguments,
+]> {
+ defvar isWhile = !eq(mnemonic, "while");
+ let summary = "C/C++ " # !if(isWhile, "while", "do-while") # " loop";
+ let builders = [
+ OpBuilder<(ins "llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)>":$condBuilder,
+ "llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)>":$bodyBuilder), [{
+ mlir::OpBuilder::InsertionGuard guard($_builder);
+ $_builder.createBlock($_state.addRegion());
+ }] # !if(isWhile, [{
+ condBuilder($_builder, $_state.location);
+ $_builder.createBlock($_state.addRegion());
+ bodyBuilder($_builder, $_state.location);
+ }], [{
+ bodyBuilder($_builder, $_state.location);
+ $_builder.createBlock($_state.addRegion());
+ condBuilder($_builder, $_state.location);
+ }])>
+ ];
+}
+
+def WhileOp : WhileOpBase<"while"> {
+ let regions = (region SizedRegion<1>:$cond, MinSizedRegion<1>:$body);
+ let assemblyFormat = "$cond `do` $body attr-dict";
+
+ let description = [{
+ Represents a C/C++ while loop. It consists of two regions:
+
+ - `cond`: single block region with the loop's condition. Should be
+ terminated with a `cir.condition` operation.
+ - `body`: contains the loop body and an arbitrary number of blocks.
+
+ Example:
+
+ ```mlir
+ cir.while {
+ cir.break
+ ^bb2:
+ cir.yield
+ } do {
+ cir.condition %cond : cir.bool
+ }
+ ```
+ }];
+}
+
+def DoWhileOp : WhileOpBase<"do"> {
+ let regions = (region MinSizedRegion<1>:$body, SizedRegion<1>:$cond);
+ let assemblyFormat = " $body `while` $cond attr-dict";
+
+ let extraClassDeclaration = [{
+ mlir::Region &getEntry() { return getBody(); }
+ }];
+
+ let description = [{
+ Represents a C/C++ do-while loop. Identical to `cir.while` but the
+ condition is evaluated after the body.
+
+ Example:
+
+ ```mlir
+ cir.do {
+ cir.break
+ ^bb2:
+ cir.yield
+ } while {
+ cir.condition %cond : cir.bool
+ }
+ ```
+ }];
+}
+
//===----------------------------------------------------------------------===//
// ForOp
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 87d10ff4cd954..7d11ea71e7637 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -399,6 +399,8 @@ class CIRGenFunction : public CIRGenTypeCache {
LValue emitBinaryOperatorLValue(const BinaryOperator *e);
+ mlir::LogicalResult emitDoStmt(const clang::DoStmt &s);
+
/// Emit an expression as an initializer for an object (variable, field, etc.)
/// at the given location. The expression is not necessarily the normal
/// initializer for the object, and the address is not necessarily
@@ -497,6 +499,8 @@ class CIRGenFunction : public CIRGenTypeCache {
/// inside a function, including static vars etc.
void emitVarDecl(const clang::VarDecl &d);
+ mlir::LogicalResult emitWhileStmt(const clang::WhileStmt &s);
+
/// ----------------------
/// CIR build helpers
/// -----------------
diff --git a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
index aa04ff6345fc6..b5c1f0ae2a7ef 100644
--- a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
@@ -75,6 +75,10 @@ mlir::LogicalResult CIRGenFunction::emitStmt(const Stmt *s,
case Stmt::ForStmtClass:
return emitForStmt(cast<ForStmt>(*s));
+ case Stmt::WhileStmtClass:
+ return emitWhileStmt(cast<WhileStmt>(*s));
+ case Stmt::DoStmtClass:
+ return emitDoStmt(cast<DoStmt>(*s));
case Stmt::OMPScopeDirectiveClass:
case Stmt::OMPErrorDirectiveClass:
@@ -97,8 +101,6 @@ mlir::LogicalResult CIRGenFunction::emitStmt(const Stmt *s,
case Stmt::SYCLKernelCallStmtClass:
case Stmt::IfStmtClass:
case Stmt::SwitchStmtClass:
- case Stmt::WhileStmtClass:
- case Stmt::DoStmtClass:
case Stmt::CoroutineBodyStmtClass:
case Stmt::CoreturnStmtClass:
case Stmt::CXXTryStmtClass:
@@ -387,3 +389,110 @@ mlir::LogicalResult CIRGenFunction::emitForStmt(const ForStmt &s) {
terminateBody(builder, forOp.getBody(), getLoc(s.getEndLoc()));
return mlir::success();
}
+
+mlir::LogicalResult CIRGenFunction::emitDoStmt(const DoStmt &s) {
+ cir::DoWhileOp doWhileOp;
+
+ // TODO: pass in array of attributes.
+ auto doStmtBuilder = [&]() -> mlir::LogicalResult {
+ mlir::LogicalResult loopRes = mlir::success();
+ assert(!cir::MissingFeatures::loopInfoStack());
+ // From LLVM: if there are any cleanups between here and the loop-exit
+ // scope, create a block to stage a loop exit along.
+ // We probably already do the right thing because of ScopeOp, but make
+ // sure we handle all cases.
+ assert(!cir::MissingFeatures::requiresCleanups());
+
+ doWhileOp = builder.createDoWhile(
+ getLoc(s.getSourceRange()),
+ /*condBuilder=*/
+ [&](mlir::OpBuilder &b, mlir::Location loc) {
+ assert(!cir::MissingFeatures::createProfileWeightsForLoop());
+ assert(!cir::MissingFeatures::emitCondLikelihoodViaExpectIntrinsic());
+ // C99 6.8.5p2/p4: The first substatement is executed if the
+ // expression compares unequal to 0. The condition must be a
+ // scalar type.
+ mlir::Value condVal = evaluateExprAsBool(s.getCond());
+ builder.createCondition(condVal);
+ },
+ /*bodyBuilder=*/
+ [&](mlir::OpBuilder &b, mlir::Location loc) {
+ // The scope of the do-while loop body is a nested scope.
+ if (emitStmt(s.getBody(), /*useCurrentScope=*/false).failed())
+ loopRes = mlir::failure();
+ emitStopPoint(&s);
+ });
+ return loopRes;
+ };
+
+ mlir::LogicalResult res = mlir::success();
+ mlir::Location scopeLoc = getLoc(s.getSourceRange());
+ builder.create<cir::ScopeOp>(scopeLoc, /*scopeBuilder=*/
+ [&](mlir::OpBuilder &b, mlir::Location loc) {
+ LexicalScope lexScope{
+ *this, loc, builder.getInsertionBlock()};
+ res = doStmtBuilder();
+ });
+
+ if (res.failed())
+ return res;
+
+ terminateBody(builder, doWhileOp.getBody(), getLoc(s.getEndLoc()));
+ return mlir::success();
+}
+
+mlir::LogicalResult CIRGenFunction::emitWhileStmt(const WhileStmt &s) {
+ cir::WhileOp whileOp;
+
+ // TODO: pass in array of attributes.
+ auto whileStmtBuilder = [&]() -> mlir::LogicalResult {
+ mlir::LogicalResult loopRes = mlir::success();
+ assert(!cir::MissingFeatures::loopInfoStack());
+ // From LLVM: if there are any cleanups between here and the loop-exit
+ // scope, create a block to stage a loop exit along.
+ // We probably already do the right thing because of ScopeOp, but make
+ // sure we handle all cases.
+ assert(!cir::MissingFeatures::requiresCleanups());
+
+ whileOp = builder.createWhile(
+ getLoc(s.getSourceRange()),
+ /*condBuilder=*/
+ [&](mlir::OpBuilder &b, mlir::Location loc) {
+ assert(!cir::MissingFeatures::createProfileWeightsForLoop());
+ assert(!cir::MissingFeatures::emitCondLikelihoodViaExpectIntrinsic());
+ mlir::Value condVal;
+ // If the for statement has a condition scope,
+ // emit the local variable declaration.
+ if (s.getConditionVariable())
+ emitDecl(*s.getConditionVariable());
+ // C99 6.8.5p2/p4: The first substatement is executed if the
+ // expression compares unequal to 0. The condition must be a
+ // scalar type.
+ condVal = evaluateExprAsBool(s.getCond());
+ builder.createCondition(condVal);
+ },
+ /*bodyBuilder=*/
+ [&](mlir::OpBuilder &b, mlir::Location loc) {
+ // The scope of the while loop body is a nested scope.
+ if (emitStmt(s.getBody(), /*useCurrentScope=*/false).failed())
+ loopRes = mlir::failure();
+ emitStopPoint(&s);
+ });
+ return loopRes;
+ };
+
+ mlir::LogicalResult res = mlir::success();
+ mlir::Location scopeLoc = getLoc(s.getSourceRange());
+ builder.create<cir::ScopeOp>(scopeLoc, /*scopeBuilder=*/
+ [&](mlir::OpBuilder &b, mlir::Location loc) {
+ LexicalScope lexScope{
+ *this, loc, builder.getInsertionBlock()};
+ res = whileStmtBuilder();
+ });
+
+ if (res.failed())
+ return res;
+
+ terminateBody(builder, whileOp.getBody(), getLoc(s.getEndLoc()));
+ return mlir::success();
+}
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index cdcfa77b66379..94d52521e38d5 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -539,9 +539,29 @@ Block *cir::BrCondOp::getSuccessorForOperands(ArrayRef<Attribute> operands) {
}
//===----------------------------------------------------------------------===//
-// ForOp
+// LoopOpInterface Methods
//===----------------------------------------------------------------------===//
+void cir::DoWhileOp::getSuccessorRegions(
+ mlir::RegionBranchPoint point,
+ llvm::SmallVectorImpl<mlir::RegionSuccessor> ®ions) {
+ LoopOpInterface::getLoopOpSuccessorRegions(*this, point, regions);
+}
+
+llvm::SmallVector<Region *> cir::DoWhileOp::getLoopRegions() {
+ return {&getBody()};
+}
+
+void cir::WhileOp::getSuccessorRegions(
+ mlir::RegionBranchPoint point,
+ llvm::SmallVectorImpl<mlir::RegionSuccessor> ®ions) {
+ LoopOpInterface::getLoopOpSuccessorRegions(*this, point, regions);
+}
+
+llvm::SmallVector<Region *> cir::WhileOp::getLoopRegions() {
+ return {&getBody()};
+}
+
void cir::ForOp::getSuccessorRegions(
mlir::RegionBranchPoint point,
llvm::SmallVectorImpl<mlir::RegionSuccessor> ®ions) {
diff --git a/clang/test/CIR/CodeGen/loop.cpp b/clang/test/CIR/CodeGen/loop.cpp
index f0b570a92964d..a950460e8838d 100644
--- a/clang/test/CIR/CodeGen/loop.cpp
+++ b/clang/test/CIR/CodeGen/loop.cpp
@@ -189,3 +189,79 @@ void l3() {
// OGCG: [[FOR_COND]]:
// OGCG: store i32 0, ptr %[[I]], align 4
// OGCG: br label %[[FOR_COND]]
+
+void test_do_while_false() {
+ do {
+ } while (0);
+}
+
+// CIR: cir.func @test_do_while_false()
+// CIR-NEXT: cir.scope {
+// CIR-NEXT: cir.do {
+// CIR-NEXT: cir.yield
+// CIR-NEXT: } while {
+// CIR-NEXT: %[[ZERO:.*]] = cir.const #cir.int<0> : !s32i
+// CIR-NEXT: %[[FALSE:.*]] = cir.cast(int_to_bool, %[[ZERO]] : !s32i), !cir.bool
+// CIR-NEXT: cir.condition(%[[FALSE]])
+
+// LLVM: define void @test_do_while_false()
+// LLVM: br label %[[LABEL1:.*]]
+// LLVM: [[LABEL1]]:
+// LLVM: br label %[[LABEL3:.*]]
+// LLVM: [[LABEL2:.*]]:
+// LLVM: br i1 false, label %[[LABEL3]], label %[[LABEL4:.*]]
+// LLVM: [[LABEL3]]:
+// LLVM: br label %[[LABEL2]]
+// LLVM: [[LABEL4]]:
+// LLVM: br label %[[LABEL5:.*]]
+// LLVM: [[LABEL5]]:
+// LLVM: ret void
+
+// OGCG: define{{.*}} void @_Z19test_do_while_falsev()
+// OGCG: entry:
+// OGCG: br label %[[DO_BODY:.*]]
+// OGCG: [[DO_BODY]]:
+// OGCG: br label %[[DO_END:.*]]
+// OGCG: [[DO_END]]:
+// OGCG: ret void
+
+void test_empty_while_true() {
+ while (true) {
+ return;
+ }
+}
+
+// CIR: cir.func @test_empty_while_true()
+// CIR-NEXT: cir.scope {
+// CIR-NEXT: cir.while {
+// CIR-NEXT: %[[TRUE:.*]] = cir.const #true
+// CIR-NEXT: cir.condition(%[[TRUE]])
+// CIR-NEXT: } do {
+// CIR-NEXT: cir.scope {
+// CIR-NEXT: cir.return
+// CIR-NEXT: }
+// CIR-NEXT: cir.yield
+
+// LLVM: define void @test_empty_while_true()
+// LLVM: br label %[[LABEL1:.*]]
+// LLVM: [[LABEL1]]:
+// LLVM: br label %[[LABEL2:.*]]
+// LLVM: [[LABEL2]]:
+// LLVM: br i1 true, label %[[LABEL3:.*]], label %[[LABEL6:.*]]
+// LLVM: [[LABEL3]]:
+// LLVM: br label %[[LABEL4]]
+// LLVM: [[LABEL4]]:
+// LLVM: ret void
+// LLVM: [[LABEL5:.*]]:
+// LLVM-SAME: ; No predecessors!
+// LLVM: br label %[[LABEL2:.*]]
+// LLVM: [[LABEL6]]:
+// LLVM: br label %[[LABEL7:.*]]
+// LLVM: [[LABEL7]]:
+// LLVM: ret void
+
+// OGCG: define{{.*}} void @_Z21test_empty_while_truev()
+// OGCG: entry:
+// OGCG: br label %[[WHILE_BODY:.*]]
+// OGCG: [[WHILE_BODY]]:
+// OGCG: ret void
diff --git a/clang/test/CIR/Transforms/loop.cir b/clang/test/CIR/Transforms/loop.cir
index 4fde3a7bb43f1..d02412d049158 100644
--- a/clang/test/CIR/Transforms/loop.cir
+++ b/clang/test/CIR/Transforms/loop.cir
@@ -26,4 +26,45 @@ module {
// CHECK: cir.br ^bb[[#COND:]]
// CHECK: ^bb[[#EXIT]]:
// CHECK: cir.return
+// CHECK: }
+
+ // Test while cir.loop operation lowering.
+ cir.func @testWhile(%arg0 : !cir.bool) {
+ cir.while {
+ cir.condition(%arg0)
+ } do {
+ cir.yield
+ }
+ cir.return
+ }
+
+// CHECK: cir.func @testWhile(%arg0: !cir.bool) {
+// CHECK: cir.br ^bb[[#COND:]]
+// CHECK: ^bb[[#COND]]:
+// CHECK: cir.brcond %arg0 ^bb[[#BODY:]], ^bb[[#EXIT:]]
+// CHECK: ^bb[[#BODY]]:
+// CHECK: cir.br ^bb[[#COND:]]
+// CHECK: ^bb[[#EXIT]]:
+// CHECK: cir.return
+// CHECK: }
+
+
+ // Test do-while cir.loop operation lowering.
+ cir.func @testDoWhile(%arg0 : !cir.bool) {
+ cir.do {
+ cir.yield
+ } while {
+ cir.condition(%arg0)
+ }
+ cir.return
+ }
+
+// CHECK: cir.func @testDoWhile(%arg0: !cir.bool) {
+// CHECK: cir.br ^bb[[#BODY:]]
+// CHECK: ^bb[[#COND]]:
+// CHECK: cir.brcond %arg0 ^bb[[#BODY:]], ^bb[[#EXIT:]]
+// CHECK: ^bb[[#BODY]]:
+// CHECK: cir.br ^bb[[#COND:]]
+// CHECK: ^bb[[#EXIT]]:
+// CHECK: cir.return
// CHECK: }
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks straight-forward to me, one minor nit!
defvar isWhile = !eq(mnemonic, "while"); | ||
let summary = "C/C++ " # !if(isWhile, "while", "do-while") # " loop"; | ||
let builders = [ | ||
OpBuilder<(ins "llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)>":$condBuilder, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be worth trying to fit 80-col here, tho it looks hard to get something
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, we haven't been fitting the .td files in 80 columns, though I have also thought we probably should do so.
It looks like tablegen will accept it like this:
let builders = [
OpBuilder<(ins "llvm::function_ref<void(mlir::OpBuilder &, "
"mlir::Location)>":$condBuilder,
"llvm::function_ref<void(mlir::OpBuilder &, "
"mlir::Location)>":$bodyBuilder), [{
mlir::OpBuilder::InsertionGuard guard($_builder);
$_builder.createBlock($_state.addRegion());
}] # !if(isWhile, [{
condBuilder($_builder, $_state.location);
$_builder.createBlock($_state.addRegion());
bodyBuilder($_builder, $_state.location);
}], [{
bodyBuilder($_builder, $_state.location);
$_builder.createBlock($_state.addRegion());
condBuilder($_builder, $_state.location);
}])>
];
What do you think? Is that readable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Other option is to add type alias. Something like BuilderCallbackRef
.
Then you need to define it before CIROps.h.inc
is included in CIRDialect.h
:
using BuilderCallbackRef = llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)>;
This turned out to be useful in vast on multiple places to make builders more readable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think? Is that readable?
Works for me!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm also fine if Henrich suggestion comes as a follow up PR!
defvar isWhile = !eq(mnemonic, "while"); | ||
let summary = "C/C++ " # !if(isWhile, "while", "do-while") # " loop"; | ||
let builders = [ | ||
OpBuilder<(ins "llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)>":$condBuilder, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Other option is to add type alias. Something like BuilderCallbackRef
.
Then you need to define it before CIROps.h.inc
is included in CIRDialect.h
:
using BuilderCallbackRef = llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)>;
This turned out to be useful in vast on multiple places to make builders more readable.
void cir::DoWhileOp::getSuccessorRegions( | ||
mlir::RegionBranchPoint point, | ||
llvm::SmallVectorImpl<mlir::RegionSuccessor> ®ions) { | ||
LoopOpInterface::getLoopOpSuccessorRegions(*this, point, regions); | ||
} | ||
|
||
llvm::SmallVector<Region *> cir::DoWhileOp::getLoopRegions() { | ||
return {&getBody()}; | ||
} | ||
|
||
void cir::WhileOp::getSuccessorRegions( | ||
mlir::RegionBranchPoint point, | ||
llvm::SmallVectorImpl<mlir::RegionSuccessor> ®ions) { | ||
LoopOpInterface::getLoopOpSuccessorRegions(*this, point, regions); | ||
} | ||
|
||
llvm::SmallVector<Region *> cir::WhileOp::getLoopRegions() { | ||
return {&getBody()}; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can be deduplicated as extraClassDefinition in WhileOpBase
as:
let extraClassDefinition = [{
void $cppClass::getSuccessorRegions(
mlir::RegionBranchPoint point,
llvm::SmallVectorImpl<mlir::RegionSuccessor> ®ions) {
LoopOpInterface::getLoopOpSuccessorRegions(*this, point, regions);
}
llvm::SmallVector<Region *> $cppClass::getLoopRegions() {
return {&getBody()};
}
}];
@bcardosolopes @xlauko Are you happy with this after my latest refactoring? |
Yep! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No real concerns here, happy when others are.
LGTM! |
This adds basic support for while and do..while loops. Support for break and continue are left for a subsequent patch.
This adds basic support for while and do..while loops. Support for break and continue are left for a subsequent patch.