@@ -56,54 +56,39 @@ namespace py {
5656 return mlir::isa<TryOp, ForLoopOp, WithOp, WhileOp, TryHandlerOp>(op);
5757 }
5858
59- // True when `yield_op`, a loop-control (break/continue) yield, binds to the
60- // loop whose body region is `body`.
61- //
62- // Python binds break/continue to the innermost loop whose *body* lexically
63- // contains it. An else clause is not part of its own loop's body, so a yield
64- // sitting there keeps searching outwards — and transitively so: an else nested
65- // inside another else is still lexically part of whatever body encloses the
66- // pair. Regions that are neither body nor orelse (a try body, a with body) are
67- // likewise transparent, which is what makes `break` inside a `try` bind to the
68- // loop around it.
69- bool binds_to_loop (mlir::Region &body, mlir::py::BranchYieldOp yield_op)
59+ // True when `yield_op` is a loop-control (break/continue) yield that binds to
60+ // the loop *enclosing* `loop` rather than to `loop` itself — i.e. it sits in
61+ // `loop`'s orelse, which is not part of the loop body.
62+ bool binds_to_enclosing_loop (mlir::py::PyLoopOpInterface loop,
63+ mlir::py::BranchYieldOp yield_op)
7064 {
71- for (mlir::Region *region = yield_op->getParentRegion (); region != nullptr ;
72- region = region->getParentRegion ()) {
73- if (region == &body) { return true ; }
74- auto loop =
75- mlir::dyn_cast_if_present<mlir::py::PyLoopOpInterface>(region->getParentOp ());
76- // A loop body (or a for's step) stops the search: the yield is that
77- // loop's, and its own pattern claims it.
78- if (loop && !loop.isLoopOrelse (region)) { return false ; }
79- }
80- return false ;
65+ return yield_op.getKind ().has_value () && loop.isLoopOrelse (yield_op->getParentRegion ());
8166 }
8267
83- // True when a break/continue that binds to the loop whose body is `body` is
84- // somewhere replace_loop_branch_yields cannot reach yet — inside a nested
85- // region that has not been flattened into ours. Branching it to our target
86- // block now would be a cross-region block reference, which is invalid IR.
68+ // True when some loop nested in `region` still holds a break/continue that
69+ // binds to the loop being lowered — i.e. one sitting in that nested loop's
70+ // orelse. Such a yield cannot be rewritten yet: it lives in a region that has
71+ // not been flattened, so branching it to our target block would be a
72+ // cross-region block reference, which is invalid IR.
8773 //
88- // The caller defers (fails the match) until the nested op lowers and inlines
74+ // The caller defers (fails the match) until the nested loop lowers and inlines
8975 // the yield into our region, the same innermost-first trick TryOpLowering uses
90- // for nested trys. Terminates because the innermost such op has nothing nested
91- // to wait on.
92- bool has_pending_nested_orelse_control (mlir::Region &body )
76+ // for nested trys. Terminates because the innermost such loop has nothing
77+ // nested to wait on.
78+ bool has_pending_nested_orelse_control (mlir::Region ®ion )
9379 {
94- if (body .empty ()) { return false ; }
80+ if (region .empty ()) { return false ; }
9581 bool pending = false ;
96- body.walk <WalkOrder::PreOrder>([&pending, &body](mlir::Operation *op) {
97- // Mirror replace_loop_branch_yields: what it walks through it rewrites
98- // in place, so only what it skips over can be pending.
99- if (!is_flattened_region_op (op)) { return WalkResult::advance (); }
100- op->walk ([&pending, &body](mlir::py::BranchYieldOp yield_op) {
101- if (!yield_op.getKind ().has_value ()) { return WalkResult::advance (); }
102- if (!binds_to_loop (body, yield_op)) { return WalkResult::advance (); }
103- pending = true ;
104- return WalkResult::interrupt ();
105- });
106- return pending ? WalkResult::interrupt () : WalkResult::skip ();
82+ region.walk <WalkOrder::PreOrder>([&pending](mlir::Operation *op) {
83+ auto loop = mlir::dyn_cast<mlir::py::PyLoopOpInterface>(op);
84+ if (!loop) { return WalkResult::advance (); }
85+ loop.getLoopOrelseRegion ().walk <WalkOrder::PreOrder>(
86+ [&pending, loop](mlir::py::BranchYieldOp yield_op) {
87+ if (binds_to_enclosing_loop (loop, yield_op)) { pending = true ; }
88+ });
89+ // Only this loop's own orelse matters here; anything deeper is the
90+ // nested loop's problem and it defers on it in turn.
91+ return WalkResult::skip ();
10792 });
10893 return pending;
10994 }
@@ -348,8 +333,8 @@ namespace py {
348333 mlir::cf::BranchOp::create (rewriter, condition_op.getLoc (), &condition_start);
349334
350335 rewriter.setInsertionPoint (condition_op);
351- auto should_jump = rewriter. create < mlir::py::CastToBoolOp> (
352- condition_op.getLoc (), rewriter.getI1Type (), condition_op.getCond ());
336+ auto should_jump = mlir::py::CastToBoolOp::create (
337+ rewriter, condition_op.getLoc (), rewriter.getI1Type (), condition_op.getCond ());
353338 ASSERT (!op.getBody ().empty ());
354339 mlir::cf::CondBranchOp::create (rewriter,
355340 condition_op.getLoc (),
@@ -759,9 +744,9 @@ namespace py {
759744 auto *current = y->getBlock ();
760745 auto *next = rewriter.splitBlock (current, y->getIterator ());
761746 rewriter.setInsertionPointToEnd (current);
762- rewriter. create < mlir::emitpybytecode::LeaveExceptionHandle> (
763- y->getLoc ());
764- rewriter. create < mlir::cf::BranchOp>( y->getLoc (), exit_block);
747+ mlir::emitpybytecode::LeaveExceptionHandle::create (
748+ rewriter, y->getLoc ());
749+ mlir::cf::BranchOp::create (rewriter, y->getLoc (), exit_block);
765750 rewriter.eraseBlock (next);
766751 } else if (auto y = mlir::dyn_cast<mlir::py::BranchYieldOp>(childOp);
767752 y && y.getKind ().has_value ()) {
@@ -772,12 +757,12 @@ namespace py {
772757 auto *next = rewriter.splitBlock (current, y->getIterator ());
773758 auto *lc_block = rewriter.createBlock (endBlock);
774759 rewriter.setInsertionPointToEnd (current);
775- rewriter. create < mlir::emitpybytecode::LeaveExceptionHandle> (
776- y->getLoc ());
777- rewriter. create < mlir::cf::BranchOp>( y->getLoc (), lc_block);
760+ mlir::emitpybytecode::LeaveExceptionHandle::create (
761+ rewriter, y->getLoc ());
762+ mlir::cf::BranchOp::create (rewriter, y->getLoc (), lc_block);
778763 rewriter.setInsertionPointToStart (lc_block);
779764 emit_normal_exit ();
780- rewriter. create < mlir::py::BranchYieldOp>( y->getLoc (), y.getKindAttr ());
765+ mlir::py::BranchYieldOp::create (rewriter, y->getLoc (), y.getKindAttr ());
781766 rewriter.eraseBlock (next);
782767 }
783768 return WalkResult::advance ();
0 commit comments