-
Notifications
You must be signed in to change notification settings - Fork 171
[CIR][ThroughMLIR] Lower WhileOp with break #1735
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
base: main
Are you sure you want to change the base?
Changes from all commits
6c4ad61
6e5d5af
05b092c
0aceb4a
0aa4f77
1093db8
da94019
887c6d1
d9f3e99
74b72f2
da01f09
7e7a821
01c27e9
01a1748
f26fff3
a00b403
5f03b07
cadb738
4318044
37abce3
49383ee
f556661
52cf5c0
fe2206a
bf52b48
9b0b837
f896192
6e31c6e
0aef9ed
867d736
4f8c2a8
9e8806a
17935d6
bce7507
6369507
e74e226
dd37e38
d73d4cb
e810ed3
6a3e881
8f04109
28b0986
aefb5e7
126956d
778bedb
86a85ef
c66f98b
0004b81
59f739d
571e56f
6b19f09
a442924
2a6a8d8
49be891
beccc39
f60e828
a61a0d8
ec817c5
06cee96
3af8b3f
a468e26
de866fa
45e6aa1
54bc877
86d6c7b
4a39d45
2089f53
ea4458a
c861519
dfef455
7ec6a86
cf67fcf
657db03
29fae5c
40cce88
2b63b2c
a2cbfbf
c9b58ef
91a32b0
ee4805a
a2fe8b8
ea5bfe3
64f01d1
0a624db
a8c9ca9
b8299a5
c653658
13a5e65
5987318
98e8811
24ab10f
e5c6935
61259b3
84b4603
6502f55
4e7a223
cdef49c
204c03e
90833a4
4c4a762
9f6742f
4991421
0bae1fd
390cf25
6c34681
5933d4b
3b2053c
099c13c
2d5a287
efc735d
8c264de
c7b27ec
395999a
92927ee
9c7f38a
d071f2f
c5f0f97
756da17
d2645a7
62a7cbd
a9eac21
dec120e
f22115a
1982513
e552f87
2788db7
c154087
a922f1a
54e3648
d32bb94
86d0efd
1e8297f
d64637c
ce06512
0678431
301077a
2a034be
b6db825
d5527cc
4c77420
7fa1da4
74e4b40
91c21c4
70813ef
5df5009
3166478
1fb346d
594543f
092c0df
57a49fd
8b050d4
b7bc94c
a99c839
88d7931
bc95e0b
583e6b6
be501d5
0c944f9
3793010
b28b6e1
9e0d9b7
466e3b2
311a5aa
9707b1d
ac73827
99c6b4b
bcc30f4
791c327
25dda94
6f9d25c
f04dd8d
576d2ff
16718e6
105d898
868a945
04c46ba
6e116b5
6e5fa09
94402e2
4c5a4d9
ca092dd
7b8a99b
47fa3eb
f077eec
209df5a
fb381bb
2afbab5
481118d
960c0b0
bc6df70
51e17c0
26b1332
25a9b13
74f16f7
e90e366
849edca
3401122
1ca3376
6ddc48e
bd610ad
dd5986c
c21ed7f
734afe6
daaf817
32e3971
076219a
31c0728
24e9e75
f74a380
4ddd7e2
bcb595a
19c36a6
3adac49
96a37b4
ceb178c
2070fcf
7bef37f
ffa62b5
4820d60
6ef0921
ad9389c
f87bee5
b22961d
30718ac
48c2115
9642d52
3235864
5da800f
8bb46a9
7b07102
4b45e3b
56b5111
7527508
e52d295
289f05f
fa2193e
e60a7d2
da1e2cd
1bbf343
60da1a4
0f6459e
f17639c
165bb53
d039db9
c0fb3b0
33c739f
f9d47e9
b7dffc3
41fb026
bfadbaa
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,6 +24,7 @@ | |
#include "clang/CIR/Dialect/IR/CIRTypes.h" | ||
#include "clang/CIR/LowerToMLIR.h" | ||
#include "llvm/ADT/TypeSwitch.h" | ||
#include "llvm/Support/raw_ostream.h" | ||
|
||
using namespace cir; | ||
using namespace llvm; | ||
|
@@ -570,6 +571,70 @@ class CIRWhileOpLowering : public mlir::OpConversionPattern<cir::WhileOp> { | |
} | ||
} | ||
|
||
void rewriteBreak(mlir::scf::WhileOp whileOp, | ||
mlir::ConversionPatternRewriter &rewriter) const { | ||
// Collect all BreakOp inside this while. | ||
llvm::SmallVector<cir::BreakOp> breaks; | ||
whileOp->walk([&](mlir::Operation *op) { | ||
if (auto breakOp = dyn_cast<BreakOp>(op)) | ||
breaks.push_back(breakOp); | ||
}); | ||
if (breaks.empty()) | ||
return; | ||
auto *pp = whileOp->getParentOp(); | ||
pp->dump(); | ||
for (auto breakOp : breaks) { | ||
// When there is another loop between this WhileOp and the BreakOp, | ||
// we should change that loop instead. | ||
if (breakOp->getParentOfType<mlir::scf::WhileOp>() != whileOp) | ||
continue; | ||
// Similar to the case of ContinueOp, when there is an `IfOp`, | ||
// we need to take special care. | ||
for (mlir::Operation *parent = breakOp->getParentOp(); parent != whileOp; | ||
parent = parent->getParentOp()) { | ||
if (auto ifOp = dyn_cast<cir::IfOp>(parent)) | ||
llvm_unreachable("NYI"); | ||
} | ||
// Operations after this BreakOp has to be removed. | ||
for (mlir::Operation *runner = breakOp->getNextNode(); runner;) { | ||
mlir::Operation *next = runner->getNextNode(); | ||
runner->erase(); | ||
runner = next; | ||
} | ||
|
||
// Blocks after this BreakOp also has to be removed. | ||
for (mlir::Block *block = breakOp->getBlock()->getNextNode(); block;) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This ties back to the other comment |
||
mlir::Block *next = block->getNextNode(); | ||
block->erase(); | ||
block = next; | ||
} | ||
|
||
// We know this BreakOp isn't nested in any IfOp. | ||
// Therefore, the loop is executed only once. | ||
// We pull everything out of the loop. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Seems like your are optimizing while you are lowering, why isn't this a separate pass? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we need to erase the BreakOp because scf doesn't support it, so we have to rewrite the loop in some way to preserve semantics. Deleting the loop is the most straightforward way I can think of. Could you suggest better ways of rewriting? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see your point! This is good for now. Thinking more about this it seems like these things should actually be handled in a pass before the actual SCF lowering (something like a CoreDialectPrepare kinda thing) - just like we have a CFGFlatten pre LLVM we could have something that massage CIR loops into CIR loops suitable for more direct SCF translation. This is more food for thought for the future, where you will probably have gathered more examples ( There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's a good idea. I think I'll do the |
||
auto &beforeOps = whileOp.getBeforeBody()->getOperations(); | ||
for (mlir::Operation *op = &*beforeOps.begin(); op;) { | ||
if (isa<ConditionOp>(op)) | ||
break; | ||
auto *next = op->getNextNode(); | ||
op->moveBefore(whileOp); | ||
op = next; | ||
} | ||
|
||
auto &afterOps = whileOp.getAfterBody()->getOperations(); | ||
for (mlir::Operation *op = &*afterOps.begin(); op;) { | ||
if (isa<YieldOp>(op)) | ||
break; | ||
auto *next = op->getNextNode(); | ||
op->moveBefore(whileOp); | ||
op = next; | ||
} | ||
} | ||
|
||
rewriter.eraseOp(whileOp); | ||
pp->dump(); | ||
} | ||
|
||
public: | ||
using OpConversionPattern<cir::WhileOp>::OpConversionPattern; | ||
|
||
|
@@ -579,6 +644,7 @@ class CIRWhileOpLowering : public mlir::OpConversionPattern<cir::WhileOp> { | |
SCFWhileLoop loop(op, adaptor, &rewriter); | ||
auto whileOp = loop.transferToSCFWhileOp(); | ||
rewriteContinue(whileOp, rewriter); | ||
rewriteBreak(whileOp, rewriter); | ||
rewriter.eraseOp(op); | ||
return mlir::success(); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -fno-clangir-direct-lowering -emit-mlir=core %s -o %t.mlir | ||
// RUN: FileCheck --input-file=%t.mlir %s | ||
|
||
void for_continue() { | ||
for (int i = 0; i < 100; i++) | ||
continue; | ||
|
||
// CHECK: scf.while : () -> () { | ||
// CHECK: %[[IV:.+]] = memref.load %alloca[] | ||
// CHECK: %[[CMP:.+]] = arith.cmpi slt, %[[IV]], %c100_i32 | ||
// CHECK: scf.condition(%[[CMP]]) | ||
// CHECK: } do { | ||
// CHECK: %[[IV2:.+]] = memref.load %alloca[] | ||
// CHECK: %[[ONE:.+]] = arith.constant 1 | ||
// CHECK: %[[CMP2:.+]] = arith.addi %[[IV2]], %[[ONE]] | ||
// CHECK: memref.store %[[CMP2]], %alloca[] | ||
// CHECK: scf.yield | ||
// 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.
Why you need to remove this? Looks like we should just split the block at this point and create an unrecheable block (which should get later DCE'd by canonicalizer)?
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 don't know whether it's allowed to delete a non-empty loop (as I'm deleting the loop below). I'll change it to splitting the block if it doesn't matter or we can find a better way below.