@@ -56,117 +56,67 @@ static bool canBeHoisted(Operation *op,
5656 op, [&](OpOperand &operand) { return definedOutside (operand.get ()); });
5757}
5858
59- static bool dependsOnGuarded (Operation *op,
60- function_ref<bool (OpOperand &)> condition) {
61- auto walkFn = [&](Operation *child) {
62- for (OpOperand &operand : child->getOpOperands ()) {
63- if (!condition (operand))
64- return WalkResult::interrupt ();
65- }
66- return WalkResult::advance ();
67- };
68- return op->walk (walkFn).wasInterrupted ();
69- }
70-
71- static bool dependsOnGuarded (Operation *op,
72- function_ref<bool (Value)> definedOutsideGuard) {
73- return dependsOnGuarded (op, [&](OpOperand &operand) {
74- return definedOutsideGuard (operand.get ());
75- });
76- }
77-
78- static bool loopSideEffectFreeOrHasOnlyReadEffect (Operation *loop) {
79- for (Region ®ion : loop->getRegions ()) {
80- for (Block &block : region.getBlocks ()) {
81- for (Operation &op : block.getOperations ()) {
82- if (!isMemoryEffectFree (&op) && !hasOnlyReadEffect (&op))
83- return false ;
84- }
85- }
86- }
87- return true ;
88- }
89-
9059size_t mlir::moveLoopInvariantCode (
9160 ArrayRef<Region *> regions,
9261 function_ref<bool (Value, Region *)> isDefinedOutsideRegion,
9362 function_ref<bool(Operation *, Region *)> shouldMoveOutOfRegion,
94- function_ref<FailureOr<std::pair<Operation *, Region *>>()> wrapInGuard,
95- function_ref<void(Operation *, Region *)> moveOutOfRegion,
96- function_ref<LogicalResult()> unwrapGuard) {
63+ function_ref<void(Operation *)> moveOutOfRegionWithoutGuard,
64+ function_ref<void(Operation *)> moveOutOfRegionWithGuard) {
9765 size_t numMoved = 0 ;
9866
9967 for (Region *region : regions) {
10068 LLVM_DEBUG (llvm::dbgs () << " Original loop:\n "
10169 << *region->getParentOp () << " \n " );
10270
103- auto loopSideEffectFreeOrHasOnlyReadSideEffect =
104- loopSideEffectFreeOrHasOnlyReadEffect (region->getParentOp ());
105-
106- size_t numMovedWithoutGuard = 0 ;
107-
108- FailureOr<std::pair<Operation *, Region *>> ifOpAndRegion = wrapInGuard ();
109- Region *loopRegion = region;
110- auto isLoopWrapped = false ;
111- if (succeeded (ifOpAndRegion)) {
112- loopRegion = ifOpAndRegion->second ;
113- isLoopWrapped = true ;
114- }
71+ bool anyOpHoistedWithGuard = false ;
72+ bool loopSideEffectFreeOrHasOnlyReadSideEffect =
73+ isMemoryEffectFreeOrOnlyRead (region->getParentOp ());
11574
11675 std::queue<Operation *> worklist;
11776 // Add top-level operations in the loop body to the worklist.
118- for (Operation &op : loopRegion ->getOps ())
77+ for (Operation &op : region ->getOps ())
11978 worklist.push (&op);
12079
12180 auto definedOutside = [&](Value value) {
122- return isDefinedOutsideRegion (value, loopRegion);
123- };
124-
125- auto definedOutsideGuard = [&](Value value) {
126- return isDefinedOutsideRegion (value, loopRegion->getParentRegion ());
81+ return isDefinedOutsideRegion (value, region);
12782 };
12883
12984 while (!worklist.empty ()) {
13085 Operation *op = worklist.front ();
13186 worklist.pop ();
13287 // Skip ops that have already been moved. Check if the op can be hoisted.
133- if (op->getParentRegion () != loopRegion )
88+ if (op->getParentRegion () != region )
13489 continue ;
13590
13691 LLVM_DEBUG (llvm::dbgs () << " Checking op: " << *op << " \n " );
13792
138- if (!shouldMoveOutOfRegion (op, loopRegion ) ||
93+ if (!shouldMoveOutOfRegion (op, region ) ||
13994 !canBeHoisted (op, definedOutside))
14095 continue ;
14196 // Can only hoist pure ops (side-effect free) when there is an op with
14297 // write and/or unknown side effects in the loop.
14398 if (!loopSideEffectFreeOrHasOnlyReadSideEffect && !isMemoryEffectFree (op))
14499 continue ;
145100
146- LLVM_DEBUG (llvm::dbgs () << " Moving loop-invariant op: " << *op << " \n " );
147-
148- auto moveWithoutGuard = isMemoryEffectFree (op) &&
149- !dependsOnGuarded (op, definedOutsideGuard) &&
150- isLoopWrapped;
151- numMovedWithoutGuard += moveWithoutGuard;
152-
153- moveOutOfRegion (op, moveWithoutGuard ? loopRegion->getParentRegion ()
154- : loopRegion);
101+ bool moveWithoutGuard = !anyOpHoistedWithGuard && isMemoryEffectFree (op);
102+ if (moveWithoutGuard) {
103+ LLVM_DEBUG (llvm::dbgs () << " Moving loop-invariant op: " << *op
104+ << " without guard\n " );
105+ moveOutOfRegionWithoutGuard (op);
106+ } else {
107+ LLVM_DEBUG (llvm::dbgs ()
108+ << " Moving loop-invariant op: " << *op << " with guard\n " );
109+ moveOutOfRegionWithGuard (op);
110+ anyOpHoistedWithGuard = true ;
111+ }
155112 ++numMoved;
156113
157114 // Since the op has been moved, we need to check its users within the
158115 // top-level of the loop body.
159116 for (Operation *user : op->getUsers ())
160- if (user->getParentRegion () == loopRegion )
117+ if (user->getParentRegion () == region )
161118 worklist.push (user);
162119 }
163-
164- // Unwrap the loop if it was wrapped but no ops were moved in the guard.
165- if (isLoopWrapped && numMovedWithoutGuard == numMoved) {
166- auto tripCountCheckUnwrapped = unwrapGuard ();
167- if (failed (tripCountCheckUnwrapped))
168- llvm_unreachable (" Should not fail unwrapping trip-count check" );
169- }
170120 }
171121
172122 return numMoved;
@@ -179,14 +129,10 @@ size_t mlir::moveLoopInvariantCode(LoopLikeOpInterface loopLike) {
179129 return !region->isAncestor (value.getParentRegion ());
180130 },
181131 [&](Operation *op, Region *) {
182- return isSpeculatable (op) &&
183- (isMemoryEffectFree (op) || hasOnlyReadEffect (op));
184- },
185- [&]() { return loopLike.wrapInTripCountCheck (); },
186- [&](Operation *op, Region *region) {
187- op->moveBefore (region->getParentOp ());
132+ return isSpeculatable (op) && isMemoryEffectFreeOrOnlyRead (op);
188133 },
189- [&]() { return loopLike.unwrapTripCountCheck (); });
134+ [&](Operation *op) { loopLike.moveOutOfLoop (op); },
135+ [&](Operation *op) { loopLike.moveOutOfLoopWithGuard (op); });
190136}
191137
192138namespace {
0 commit comments