1ee6f84aeSAlex Zinenko //===- RegionUtils.cpp - Region-related transformation utilities ----------===//
2ee6f84aeSAlex Zinenko //
330857107SMehdi Amini // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
456222a06SMehdi Amini // See https://llvm.org/LICENSE.txt for license information.
556222a06SMehdi Amini // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6ee6f84aeSAlex Zinenko //
756222a06SMehdi Amini //===----------------------------------------------------------------------===//
8ee6f84aeSAlex Zinenko 
9ee6f84aeSAlex Zinenko #include "mlir/Transforms/RegionUtils.h"
10ee6f84aeSAlex Zinenko #include "mlir/IR/Block.h"
11ee6f84aeSAlex Zinenko #include "mlir/IR/Operation.h"
12d75a611aSRiver Riddle #include "mlir/IR/PatternMatch.h"
13fafb708bSRiver Riddle #include "mlir/IR/RegionGraphTraits.h"
14ee6f84aeSAlex Zinenko #include "mlir/IR/Value.h"
157ce1e7abSRiver Riddle #include "mlir/Interfaces/ControlFlowInterfaces.h"
16eb623ae8SStephen Neuendorffer #include "mlir/Interfaces/SideEffectInterfaces.h"
17ee6f84aeSAlex Zinenko 
18fafb708bSRiver Riddle #include "llvm/ADT/DepthFirstIterator.h"
19fafb708bSRiver Riddle #include "llvm/ADT/PostOrderIterator.h"
204291ae74SAlex Zinenko #include "llvm/ADT/SmallSet.h"
214291ae74SAlex Zinenko 
22ee6f84aeSAlex Zinenko using namespace mlir;
23ee6f84aeSAlex Zinenko 
replaceAllUsesInRegionWith(Value orig,Value replacement,Region & region)24e62a6956SRiver Riddle void mlir::replaceAllUsesInRegionWith(Value orig, Value replacement,
25ee6f84aeSAlex Zinenko                                       Region &region) {
262bdf33ccSRiver Riddle   for (auto &use : llvm::make_early_inc_range(orig.getUses())) {
271e429540SRiver Riddle     if (region.isAncestor(use.getOwner()->getParentRegion()))
28ee6f84aeSAlex Zinenko       use.set(replacement);
29ee6f84aeSAlex Zinenko   }
30ee6f84aeSAlex Zinenko }
314291ae74SAlex Zinenko 
visitUsedValuesDefinedAbove(Region & region,Region & limit,function_ref<void (OpOperand *)> callback)326443583bSMehdi Amini void mlir::visitUsedValuesDefinedAbove(
334562e389SRiver Riddle     Region &region, Region &limit, function_ref<void(OpOperand *)> callback) {
344291ae74SAlex Zinenko   assert(limit.isAncestor(&region) &&
354291ae74SAlex Zinenko          "expected isolation limit to be an ancestor of the given region");
364291ae74SAlex Zinenko 
374291ae74SAlex Zinenko   // Collect proper ancestors of `limit` upfront to avoid traversing the region
384291ae74SAlex Zinenko   // tree for every value.
394562e389SRiver Riddle   SmallPtrSet<Region *, 4> properAncestors;
401e429540SRiver Riddle   for (auto *reg = limit.getParentRegion(); reg != nullptr;
411e429540SRiver Riddle        reg = reg->getParentRegion()) {
424291ae74SAlex Zinenko     properAncestors.insert(reg);
434291ae74SAlex Zinenko   }
444291ae74SAlex Zinenko 
456443583bSMehdi Amini   region.walk([callback, &properAncestors](Operation *op) {
466443583bSMehdi Amini     for (OpOperand &operand : op->getOpOperands())
476443583bSMehdi Amini       // Callback on values defined in a proper ancestor of region.
482bdf33ccSRiver Riddle       if (properAncestors.count(operand.get().getParentRegion()))
496443583bSMehdi Amini         callback(&operand);
506443583bSMehdi Amini   });
516443583bSMehdi Amini }
526443583bSMehdi Amini 
visitUsedValuesDefinedAbove(MutableArrayRef<Region> regions,function_ref<void (OpOperand *)> callback)536443583bSMehdi Amini void mlir::visitUsedValuesDefinedAbove(
544562e389SRiver Riddle     MutableArrayRef<Region> regions, function_ref<void(OpOperand *)> callback) {
556443583bSMehdi Amini   for (Region &region : regions)
566443583bSMehdi Amini     visitUsedValuesDefinedAbove(region, region, callback);
576443583bSMehdi Amini }
586443583bSMehdi Amini 
getUsedValuesDefinedAbove(Region & region,Region & limit,SetVector<Value> & values)596443583bSMehdi Amini void mlir::getUsedValuesDefinedAbove(Region &region, Region &limit,
604efb7754SRiver Riddle                                      SetVector<Value> &values) {
616443583bSMehdi Amini   visitUsedValuesDefinedAbove(region, limit, [&](OpOperand *operand) {
626443583bSMehdi Amini     values.insert(operand->get());
634291ae74SAlex Zinenko   });
644291ae74SAlex Zinenko }
65ce702fc8SMehdi Amini 
getUsedValuesDefinedAbove(MutableArrayRef<Region> regions,SetVector<Value> & values)664562e389SRiver Riddle void mlir::getUsedValuesDefinedAbove(MutableArrayRef<Region> regions,
674efb7754SRiver Riddle                                      SetVector<Value> &values) {
68ce702fc8SMehdi Amini   for (Region &region : regions)
69ce702fc8SMehdi Amini     getUsedValuesDefinedAbove(region, region, values);
70ce702fc8SMehdi Amini }
71fafb708bSRiver Riddle 
72fafb708bSRiver Riddle //===----------------------------------------------------------------------===//
73fafb708bSRiver Riddle // Unreachable Block Elimination
74fafb708bSRiver Riddle //===----------------------------------------------------------------------===//
75fafb708bSRiver Riddle 
76fafb708bSRiver Riddle /// Erase the unreachable blocks within the provided regions. Returns success
77fafb708bSRiver Riddle /// if any blocks were erased, failure otherwise.
78fafb708bSRiver Riddle // TODO: We could likely merge this with the DCE algorithm below.
eraseUnreachableBlocks(RewriterBase & rewriter,MutableArrayRef<Region> regions)7978d69182SValentin Clement LogicalResult mlir::eraseUnreachableBlocks(RewriterBase &rewriter,
80d75a611aSRiver Riddle                                            MutableArrayRef<Region> regions) {
81fafb708bSRiver Riddle   // Set of blocks found to be reachable within a given region.
82fafb708bSRiver Riddle   llvm::df_iterator_default_set<Block *, 16> reachable;
83fafb708bSRiver Riddle   // If any blocks were found to be dead.
84fafb708bSRiver Riddle   bool erasedDeadBlocks = false;
85fafb708bSRiver Riddle 
86fafb708bSRiver Riddle   SmallVector<Region *, 1> worklist;
87fafb708bSRiver Riddle   worklist.reserve(regions.size());
88fafb708bSRiver Riddle   for (Region &region : regions)
89fafb708bSRiver Riddle     worklist.push_back(&region);
90fafb708bSRiver Riddle   while (!worklist.empty()) {
91fafb708bSRiver Riddle     Region *region = worklist.pop_back_val();
92fafb708bSRiver Riddle     if (region->empty())
93fafb708bSRiver Riddle       continue;
94fafb708bSRiver Riddle 
95fafb708bSRiver Riddle     // If this is a single block region, just collect the nested regions.
96fafb708bSRiver Riddle     if (std::next(region->begin()) == region->end()) {
97fafb708bSRiver Riddle       for (Operation &op : region->front())
98fafb708bSRiver Riddle         for (Region &region : op.getRegions())
99fafb708bSRiver Riddle           worklist.push_back(&region);
100fafb708bSRiver Riddle       continue;
101fafb708bSRiver Riddle     }
102fafb708bSRiver Riddle 
103fafb708bSRiver Riddle     // Mark all reachable blocks.
104fafb708bSRiver Riddle     reachable.clear();
105fafb708bSRiver Riddle     for (Block *block : depth_first_ext(&region->front(), reachable))
106fafb708bSRiver Riddle       (void)block /* Mark all reachable blocks */;
107fafb708bSRiver Riddle 
108fafb708bSRiver Riddle     // Collect all of the dead blocks and push the live regions onto the
109fafb708bSRiver Riddle     // worklist.
110fafb708bSRiver Riddle     for (Block &block : llvm::make_early_inc_range(*region)) {
111fafb708bSRiver Riddle       if (!reachable.count(&block)) {
112fafb708bSRiver Riddle         block.dropAllDefinedValueUses();
113d75a611aSRiver Riddle         rewriter.eraseBlock(&block);
114fafb708bSRiver Riddle         erasedDeadBlocks = true;
115fafb708bSRiver Riddle         continue;
116fafb708bSRiver Riddle       }
117fafb708bSRiver Riddle 
118fafb708bSRiver Riddle       // Walk any regions within this block.
119fafb708bSRiver Riddle       for (Operation &op : block)
120fafb708bSRiver Riddle         for (Region &region : op.getRegions())
121fafb708bSRiver Riddle           worklist.push_back(&region);
122fafb708bSRiver Riddle     }
123fafb708bSRiver Riddle   }
124fafb708bSRiver Riddle 
125fafb708bSRiver Riddle   return success(erasedDeadBlocks);
126fafb708bSRiver Riddle }
127fafb708bSRiver Riddle 
128fafb708bSRiver Riddle //===----------------------------------------------------------------------===//
129fafb708bSRiver Riddle // Dead Code Elimination
130fafb708bSRiver Riddle //===----------------------------------------------------------------------===//
131fafb708bSRiver Riddle 
132fafb708bSRiver Riddle namespace {
133fafb708bSRiver Riddle /// Data structure used to track which values have already been proved live.
134fafb708bSRiver Riddle ///
135fafb708bSRiver Riddle /// Because Operation's can have multiple results, this data structure tracks
136fafb708bSRiver Riddle /// liveness for both Value's and Operation's to avoid having to look through
137fafb708bSRiver Riddle /// all Operation results when analyzing a use.
138fafb708bSRiver Riddle ///
139fafb708bSRiver Riddle /// This data structure essentially tracks the dataflow lattice.
140fafb708bSRiver Riddle /// The set of values/ops proved live increases monotonically to a fixed-point.
141fafb708bSRiver Riddle class LiveMap {
142fafb708bSRiver Riddle public:
143fafb708bSRiver Riddle   /// Value methods.
wasProvenLive(Value value)1444e02eb80SRiver Riddle   bool wasProvenLive(Value value) {
1454e02eb80SRiver Riddle     // TODO: For results that are removable, e.g. for region based control flow,
1464e02eb80SRiver Riddle     // we could allow for these values to be tracked independently.
1474e02eb80SRiver Riddle     if (OpResult result = value.dyn_cast<OpResult>())
1484e02eb80SRiver Riddle       return wasProvenLive(result.getOwner());
1494e02eb80SRiver Riddle     return wasProvenLive(value.cast<BlockArgument>());
1504e02eb80SRiver Riddle   }
wasProvenLive(BlockArgument arg)1514e02eb80SRiver Riddle   bool wasProvenLive(BlockArgument arg) { return liveValues.count(arg); }
setProvedLive(Value value)152e62a6956SRiver Riddle   void setProvedLive(Value value) {
1534e02eb80SRiver Riddle     // TODO: For results that are removable, e.g. for region based control flow,
1544e02eb80SRiver Riddle     // we could allow for these values to be tracked independently.
1554e02eb80SRiver Riddle     if (OpResult result = value.dyn_cast<OpResult>())
1564e02eb80SRiver Riddle       return setProvedLive(result.getOwner());
1574e02eb80SRiver Riddle     setProvedLive(value.cast<BlockArgument>());
1584e02eb80SRiver Riddle   }
setProvedLive(BlockArgument arg)1594e02eb80SRiver Riddle   void setProvedLive(BlockArgument arg) {
1604e02eb80SRiver Riddle     changed |= liveValues.insert(arg).second;
161fafb708bSRiver Riddle   }
162fafb708bSRiver Riddle 
163fafb708bSRiver Riddle   /// Operation methods.
wasProvenLive(Operation * op)164fafb708bSRiver Riddle   bool wasProvenLive(Operation *op) { return liveOps.count(op); }
setProvedLive(Operation * op)165fafb708bSRiver Riddle   void setProvedLive(Operation *op) { changed |= liveOps.insert(op).second; }
166fafb708bSRiver Riddle 
167fafb708bSRiver Riddle   /// Methods for tracking if we have reached a fixed-point.
resetChanged()168fafb708bSRiver Riddle   void resetChanged() { changed = false; }
hasChanged()169fafb708bSRiver Riddle   bool hasChanged() { return changed; }
170fafb708bSRiver Riddle 
171fafb708bSRiver Riddle private:
172fafb708bSRiver Riddle   bool changed = false;
173e62a6956SRiver Riddle   DenseSet<Value> liveValues;
174fafb708bSRiver Riddle   DenseSet<Operation *> liveOps;
175fafb708bSRiver Riddle };
176fafb708bSRiver Riddle } // namespace
177fafb708bSRiver Riddle 
isUseSpeciallyKnownDead(OpOperand & use,LiveMap & liveMap)178fafb708bSRiver Riddle static bool isUseSpeciallyKnownDead(OpOperand &use, LiveMap &liveMap) {
179fafb708bSRiver Riddle   Operation *owner = use.getOwner();
180fafb708bSRiver Riddle   unsigned operandIndex = use.getOperandNumber();
181fafb708bSRiver Riddle   // This pass generally treats all uses of an op as live if the op itself is
182fafb708bSRiver Riddle   // considered live. However, for successor operands to terminators we need a
183fafb708bSRiver Riddle   // finer-grained notion where we deduce liveness for operands individually.
184fafb708bSRiver Riddle   // The reason for this is easiest to think about in terms of a classical phi
185fafb708bSRiver Riddle   // node based SSA IR, where each successor operand is really an operand to a
186fafb708bSRiver Riddle   // *separate* phi node, rather than all operands to the branch itself as with
187fafb708bSRiver Riddle   // the block argument representation that MLIR uses.
188fafb708bSRiver Riddle   //
189fafb708bSRiver Riddle   // And similarly, because each successor operand is really an operand to a phi
190fafb708bSRiver Riddle   // node, rather than to the terminator op itself, a terminator op can't e.g.
191fafb708bSRiver Riddle   // "print" the value of a successor operand.
192fe7c0d90SRiver Riddle   if (owner->hasTrait<OpTrait::IsTerminator>()) {
193cb177712SRiver Riddle     if (BranchOpInterface branchInterface = dyn_cast<BranchOpInterface>(owner))
194cb177712SRiver Riddle       if (auto arg = branchInterface.getSuccessorBlockArgument(operandIndex))
195fafb708bSRiver Riddle         return !liveMap.wasProvenLive(*arg);
196fafb708bSRiver Riddle     return false;
197fafb708bSRiver Riddle   }
198fafb708bSRiver Riddle   return false;
199fafb708bSRiver Riddle }
200fafb708bSRiver Riddle 
processValue(Value value,LiveMap & liveMap)201e62a6956SRiver Riddle static void processValue(Value value, LiveMap &liveMap) {
2022bdf33ccSRiver Riddle   bool provedLive = llvm::any_of(value.getUses(), [&](OpOperand &use) {
203fafb708bSRiver Riddle     if (isUseSpeciallyKnownDead(use, liveMap))
204fafb708bSRiver Riddle       return false;
205fafb708bSRiver Riddle     return liveMap.wasProvenLive(use.getOwner());
206fafb708bSRiver Riddle   });
207fafb708bSRiver Riddle   if (provedLive)
208fafb708bSRiver Riddle     liveMap.setProvedLive(value);
209fafb708bSRiver Riddle }
210fafb708bSRiver Riddle 
211fafb708bSRiver Riddle static void propagateLiveness(Region &region, LiveMap &liveMap);
212cb177712SRiver Riddle 
propagateTerminatorLiveness(Operation * op,LiveMap & liveMap)213cb177712SRiver Riddle static void propagateTerminatorLiveness(Operation *op, LiveMap &liveMap) {
214cb177712SRiver Riddle   // Terminators are always live.
215cb177712SRiver Riddle   liveMap.setProvedLive(op);
216cb177712SRiver Riddle 
217cb177712SRiver Riddle   // Check to see if we can reason about the successor operands and mutate them.
218cb177712SRiver Riddle   BranchOpInterface branchInterface = dyn_cast<BranchOpInterface>(op);
2190752d98cSRiver Riddle   if (!branchInterface) {
220cb177712SRiver Riddle     for (Block *successor : op->getSuccessors())
221cb177712SRiver Riddle       for (BlockArgument arg : successor->getArguments())
222cb177712SRiver Riddle         liveMap.setProvedLive(arg);
223cb177712SRiver Riddle     return;
224cb177712SRiver Riddle   }
225cb177712SRiver Riddle 
226*0c789db5SMarkus Böck   // If we can't reason about the operand to a successor, conservatively mark
227*0c789db5SMarkus Böck   // it as live.
228cb177712SRiver Riddle   for (unsigned i = 0, e = op->getNumSuccessors(); i != e; ++i) {
229*0c789db5SMarkus Böck     SuccessorOperands successorOperands =
230*0c789db5SMarkus Böck         branchInterface.getSuccessorOperands(i);
231*0c789db5SMarkus Böck     for (unsigned opI = 0, opE = successorOperands.getProducedOperandCount();
232*0c789db5SMarkus Böck          opI != opE; ++opI)
233*0c789db5SMarkus Böck       liveMap.setProvedLive(op->getSuccessor(i)->getArgument(opI));
234cb177712SRiver Riddle   }
235cb177712SRiver Riddle }
236cb177712SRiver Riddle 
propagateLiveness(Operation * op,LiveMap & liveMap)237fafb708bSRiver Riddle static void propagateLiveness(Operation *op, LiveMap &liveMap) {
238fafb708bSRiver Riddle   // Recurse on any regions the op has.
239fafb708bSRiver Riddle   for (Region &region : op->getRegions())
240fafb708bSRiver Riddle     propagateLiveness(region, liveMap);
241fafb708bSRiver Riddle 
242cb177712SRiver Riddle   // Process terminator operations.
243fe7c0d90SRiver Riddle   if (op->hasTrait<OpTrait::IsTerminator>())
244cb177712SRiver Riddle     return propagateTerminatorLiveness(op, liveMap);
245cb177712SRiver Riddle 
2464e02eb80SRiver Riddle   // Don't reprocess live operations.
2474e02eb80SRiver Riddle   if (liveMap.wasProvenLive(op))
248fafb708bSRiver Riddle     return;
2494e02eb80SRiver Riddle 
2504e02eb80SRiver Riddle   // Process the op itself.
2514e02eb80SRiver Riddle   if (!wouldOpBeTriviallyDead(op))
2524e02eb80SRiver Riddle     return liveMap.setProvedLive(op);
2534e02eb80SRiver Riddle 
2544e02eb80SRiver Riddle   // If the op isn't intrinsically alive, check it's results.
255e62a6956SRiver Riddle   for (Value value : op->getResults())
256fafb708bSRiver Riddle     processValue(value, liveMap);
257fafb708bSRiver Riddle }
258fafb708bSRiver Riddle 
propagateLiveness(Region & region,LiveMap & liveMap)259fafb708bSRiver Riddle static void propagateLiveness(Region &region, LiveMap &liveMap) {
260fafb708bSRiver Riddle   if (region.empty())
261fafb708bSRiver Riddle     return;
262fafb708bSRiver Riddle 
263fafb708bSRiver Riddle   for (Block *block : llvm::post_order(&region.front())) {
264fafb708bSRiver Riddle     // We process block arguments after the ops in the block, to promote
265fafb708bSRiver Riddle     // faster convergence to a fixed point (we try to visit uses before defs).
266fafb708bSRiver Riddle     for (Operation &op : llvm::reverse(block->getOperations()))
267fafb708bSRiver Riddle       propagateLiveness(&op, liveMap);
2684e02eb80SRiver Riddle 
2694e02eb80SRiver Riddle     // We currently do not remove entry block arguments, so there is no need to
2704e02eb80SRiver Riddle     // track their liveness.
2714e02eb80SRiver Riddle     // TODO: We could track these and enable removing dead operands/arguments
2724e02eb80SRiver Riddle     // from region control flow operations.
2734e02eb80SRiver Riddle     if (block->isEntryBlock())
2744e02eb80SRiver Riddle       continue;
2754e02eb80SRiver Riddle 
2764e02eb80SRiver Riddle     for (Value value : block->getArguments()) {
2774e02eb80SRiver Riddle       if (!liveMap.wasProvenLive(value))
278fafb708bSRiver Riddle         processValue(value, liveMap);
279fafb708bSRiver Riddle     }
280fafb708bSRiver Riddle   }
2814e02eb80SRiver Riddle }
282fafb708bSRiver Riddle 
eraseTerminatorSuccessorOperands(Operation * terminator,LiveMap & liveMap)283fafb708bSRiver Riddle static void eraseTerminatorSuccessorOperands(Operation *terminator,
284fafb708bSRiver Riddle                                              LiveMap &liveMap) {
285cb177712SRiver Riddle   BranchOpInterface branchOp = dyn_cast<BranchOpInterface>(terminator);
286cb177712SRiver Riddle   if (!branchOp)
287cb177712SRiver Riddle     return;
288cb177712SRiver Riddle 
289fafb708bSRiver Riddle   for (unsigned succI = 0, succE = terminator->getNumSuccessors();
290fafb708bSRiver Riddle        succI < succE; succI++) {
291fafb708bSRiver Riddle     // Iterating successors in reverse is not strictly needed, since we
292fafb708bSRiver Riddle     // aren't erasing any successors. But it is slightly more efficient
293fafb708bSRiver Riddle     // since it will promote later operands of the terminator being erased
294fafb708bSRiver Riddle     // first, reducing the quadratic-ness.
295fafb708bSRiver Riddle     unsigned succ = succE - succI - 1;
296*0c789db5SMarkus Böck     SuccessorOperands succOperands = branchOp.getSuccessorOperands(succ);
297cb177712SRiver Riddle     Block *successor = terminator->getSuccessor(succ);
298cb177712SRiver Riddle 
299*0c789db5SMarkus Böck     for (unsigned argI = 0, argE = succOperands.size(); argI < argE; ++argI) {
300fafb708bSRiver Riddle       // Iterating args in reverse is needed for correctness, to avoid
301fafb708bSRiver Riddle       // shifting later args when earlier args are erased.
302fafb708bSRiver Riddle       unsigned arg = argE - argI - 1;
303cb177712SRiver Riddle       if (!liveMap.wasProvenLive(successor->getArgument(arg)))
304*0c789db5SMarkus Böck         succOperands.erase(arg);
305fafb708bSRiver Riddle     }
306fafb708bSRiver Riddle   }
307fafb708bSRiver Riddle }
308fafb708bSRiver Riddle 
deleteDeadness(RewriterBase & rewriter,MutableArrayRef<Region> regions,LiveMap & liveMap)309d75a611aSRiver Riddle static LogicalResult deleteDeadness(RewriterBase &rewriter,
310d75a611aSRiver Riddle                                     MutableArrayRef<Region> regions,
311fafb708bSRiver Riddle                                     LiveMap &liveMap) {
312fafb708bSRiver Riddle   bool erasedAnything = false;
313fafb708bSRiver Riddle   for (Region &region : regions) {
314fafb708bSRiver Riddle     if (region.empty())
315fafb708bSRiver Riddle       continue;
316973ddb7dSMehdi Amini     bool hasSingleBlock = llvm::hasSingleElement(region);
317fafb708bSRiver Riddle 
318f178c13fSAndrew Young     // Delete every operation that is not live. Graph regions may have cycles
319f178c13fSAndrew Young     // in the use-def graph, so we must explicitly dropAllUses() from each
320f178c13fSAndrew Young     // operation as we erase it. Visiting the operations in post-order
321f178c13fSAndrew Young     // guarantees that in SSA CFG regions value uses are removed before defs,
322f178c13fSAndrew Young     // which makes dropAllUses() a no-op.
323fafb708bSRiver Riddle     for (Block *block : llvm::post_order(&region.front())) {
324973ddb7dSMehdi Amini       if (!hasSingleBlock)
325fafb708bSRiver Riddle         eraseTerminatorSuccessorOperands(block->getTerminator(), liveMap);
326fafb708bSRiver Riddle       for (Operation &childOp :
327fafb708bSRiver Riddle            llvm::make_early_inc_range(llvm::reverse(block->getOperations()))) {
328fafb708bSRiver Riddle         if (!liveMap.wasProvenLive(&childOp)) {
329fafb708bSRiver Riddle           erasedAnything = true;
330f178c13fSAndrew Young           childOp.dropAllUses();
331d75a611aSRiver Riddle           rewriter.eraseOp(&childOp);
3324e02eb80SRiver Riddle         } else {
333d75a611aSRiver Riddle           erasedAnything |= succeeded(
334d75a611aSRiver Riddle               deleteDeadness(rewriter, childOp.getRegions(), liveMap));
335fafb708bSRiver Riddle         }
336fafb708bSRiver Riddle       }
337fafb708bSRiver Riddle     }
338fafb708bSRiver Riddle     // Delete block arguments.
339fafb708bSRiver Riddle     // The entry block has an unknown contract with their enclosing block, so
340fafb708bSRiver Riddle     // skip it.
3414ea92a05SRiver Riddle     for (Block &block : llvm::drop_begin(region.getBlocks(), 1)) {
3424e02eb80SRiver Riddle       block.eraseArguments(
3434e02eb80SRiver Riddle           [&](BlockArgument arg) { return !liveMap.wasProvenLive(arg); });
344fafb708bSRiver Riddle     }
345fafb708bSRiver Riddle   }
346fafb708bSRiver Riddle   return success(erasedAnything);
347fafb708bSRiver Riddle }
348fafb708bSRiver Riddle 
349fafb708bSRiver Riddle // This function performs a simple dead code elimination algorithm over the
350fafb708bSRiver Riddle // given regions.
351fafb708bSRiver Riddle //
352fafb708bSRiver Riddle // The overall goal is to prove that Values are dead, which allows deleting ops
353fafb708bSRiver Riddle // and block arguments.
354fafb708bSRiver Riddle //
355fafb708bSRiver Riddle // This uses an optimistic algorithm that assumes everything is dead until
356fafb708bSRiver Riddle // proved otherwise, allowing it to delete recursively dead cycles.
357fafb708bSRiver Riddle //
358fafb708bSRiver Riddle // This is a simple fixed-point dataflow analysis algorithm on a lattice
359fafb708bSRiver Riddle // {Dead,Alive}. Because liveness flows backward, we generally try to
360fafb708bSRiver Riddle // iterate everything backward to speed up convergence to the fixed-point. This
361fafb708bSRiver Riddle // allows for being able to delete recursively dead cycles of the use-def graph,
362fafb708bSRiver Riddle // including block arguments.
363fafb708bSRiver Riddle //
364fafb708bSRiver Riddle // This function returns success if any operations or arguments were deleted,
365fafb708bSRiver Riddle // failure otherwise.
runRegionDCE(RewriterBase & rewriter,MutableArrayRef<Region> regions)36678d69182SValentin Clement LogicalResult mlir::runRegionDCE(RewriterBase &rewriter,
367d75a611aSRiver Riddle                                  MutableArrayRef<Region> regions) {
368fafb708bSRiver Riddle   LiveMap liveMap;
369fafb708bSRiver Riddle   do {
370fafb708bSRiver Riddle     liveMap.resetChanged();
371fafb708bSRiver Riddle 
372fafb708bSRiver Riddle     for (Region &region : regions)
373fafb708bSRiver Riddle       propagateLiveness(region, liveMap);
374fafb708bSRiver Riddle   } while (liveMap.hasChanged());
375fafb708bSRiver Riddle 
376d75a611aSRiver Riddle   return deleteDeadness(rewriter, regions, liveMap);
377fafb708bSRiver Riddle }
378fafb708bSRiver Riddle 
379fafb708bSRiver Riddle //===----------------------------------------------------------------------===//
380469c02d0SRiver Riddle // Block Merging
381469c02d0SRiver Riddle //===----------------------------------------------------------------------===//
382469c02d0SRiver Riddle 
383469c02d0SRiver Riddle //===----------------------------------------------------------------------===//
384469c02d0SRiver Riddle // BlockEquivalenceData
385469c02d0SRiver Riddle 
386469c02d0SRiver Riddle namespace {
387469c02d0SRiver Riddle /// This class contains the information for comparing the equivalencies of two
388469c02d0SRiver Riddle /// blocks. Blocks are considered equivalent if they contain the same operations
389469c02d0SRiver Riddle /// in the same order. The only allowed divergence is for operands that come
390469c02d0SRiver Riddle /// from sources outside of the parent block, i.e. the uses of values produced
391469c02d0SRiver Riddle /// within the block must be equivalent.
392469c02d0SRiver Riddle ///   e.g.,
393469c02d0SRiver Riddle /// Equivalent:
394469c02d0SRiver Riddle ///  ^bb1(%arg0: i32)
395469c02d0SRiver Riddle ///    return %arg0, %foo : i32, i32
396469c02d0SRiver Riddle ///  ^bb2(%arg1: i32)
397469c02d0SRiver Riddle ///    return %arg1, %bar : i32, i32
398469c02d0SRiver Riddle /// Not Equivalent:
399469c02d0SRiver Riddle ///  ^bb1(%arg0: i32)
400469c02d0SRiver Riddle ///    return %foo, %arg0 : i32, i32
401469c02d0SRiver Riddle ///  ^bb2(%arg1: i32)
402469c02d0SRiver Riddle ///    return %arg1, %bar : i32, i32
403469c02d0SRiver Riddle struct BlockEquivalenceData {
404469c02d0SRiver Riddle   BlockEquivalenceData(Block *block);
405469c02d0SRiver Riddle 
406469c02d0SRiver Riddle   /// Return the order index for the given value that is within the block of
407469c02d0SRiver Riddle   /// this data.
408469c02d0SRiver Riddle   unsigned getOrderOf(Value value) const;
409469c02d0SRiver Riddle 
410469c02d0SRiver Riddle   /// The block this data refers to.
411469c02d0SRiver Riddle   Block *block;
412469c02d0SRiver Riddle   /// A hash value for this block.
413469c02d0SRiver Riddle   llvm::hash_code hash;
414469c02d0SRiver Riddle   /// A map of result producing operations to their relative orders within this
415469c02d0SRiver Riddle   /// block. The order of an operation is the number of defined values that are
416469c02d0SRiver Riddle   /// produced within the block before this operation.
417469c02d0SRiver Riddle   DenseMap<Operation *, unsigned> opOrderIndex;
418469c02d0SRiver Riddle };
419be0a7e9fSMehdi Amini } // namespace
420469c02d0SRiver Riddle 
BlockEquivalenceData(Block * block)421469c02d0SRiver Riddle BlockEquivalenceData::BlockEquivalenceData(Block *block)
422469c02d0SRiver Riddle     : block(block), hash(0) {
423469c02d0SRiver Riddle   unsigned orderIt = block->getNumArguments();
424469c02d0SRiver Riddle   for (Operation &op : *block) {
425469c02d0SRiver Riddle     if (unsigned numResults = op.getNumResults()) {
426469c02d0SRiver Riddle       opOrderIndex.try_emplace(&op, orderIt);
427469c02d0SRiver Riddle       orderIt += numResults;
428469c02d0SRiver Riddle     }
429469c02d0SRiver Riddle     auto opHash = OperationEquivalence::computeHash(
4300be5d1a9SMehdi Amini         &op, OperationEquivalence::ignoreHashValue,
4310be5d1a9SMehdi Amini         OperationEquivalence::ignoreHashValue,
4320be5d1a9SMehdi Amini         OperationEquivalence::IgnoreLocations);
433469c02d0SRiver Riddle     hash = llvm::hash_combine(hash, opHash);
434469c02d0SRiver Riddle   }
435469c02d0SRiver Riddle }
436469c02d0SRiver Riddle 
getOrderOf(Value value) const437469c02d0SRiver Riddle unsigned BlockEquivalenceData::getOrderOf(Value value) const {
438469c02d0SRiver Riddle   assert(value.getParentBlock() == block && "expected value of this block");
439469c02d0SRiver Riddle 
440469c02d0SRiver Riddle   // Arguments use the argument number as the order index.
441469c02d0SRiver Riddle   if (BlockArgument arg = value.dyn_cast<BlockArgument>())
442469c02d0SRiver Riddle     return arg.getArgNumber();
443469c02d0SRiver Riddle 
444469c02d0SRiver Riddle   // Otherwise, the result order is offset from the parent op's order.
445469c02d0SRiver Riddle   OpResult result = value.cast<OpResult>();
446469c02d0SRiver Riddle   auto opOrderIt = opOrderIndex.find(result.getDefiningOp());
447469c02d0SRiver Riddle   assert(opOrderIt != opOrderIndex.end() && "expected op to have an order");
448469c02d0SRiver Riddle   return opOrderIt->second + result.getResultNumber();
449469c02d0SRiver Riddle }
450469c02d0SRiver Riddle 
451469c02d0SRiver Riddle //===----------------------------------------------------------------------===//
452469c02d0SRiver Riddle // BlockMergeCluster
453469c02d0SRiver Riddle 
454469c02d0SRiver Riddle namespace {
455469c02d0SRiver Riddle /// This class represents a cluster of blocks to be merged together.
456469c02d0SRiver Riddle class BlockMergeCluster {
457469c02d0SRiver Riddle public:
BlockMergeCluster(BlockEquivalenceData && leaderData)458469c02d0SRiver Riddle   BlockMergeCluster(BlockEquivalenceData &&leaderData)
459469c02d0SRiver Riddle       : leaderData(std::move(leaderData)) {}
460469c02d0SRiver Riddle 
461469c02d0SRiver Riddle   /// Attempt to add the given block to this cluster. Returns success if the
462469c02d0SRiver Riddle   /// block was merged, failure otherwise.
463469c02d0SRiver Riddle   LogicalResult addToCluster(BlockEquivalenceData &blockData);
464469c02d0SRiver Riddle 
465469c02d0SRiver Riddle   /// Try to merge all of the blocks within this cluster into the leader block.
466d75a611aSRiver Riddle   LogicalResult merge(RewriterBase &rewriter);
467469c02d0SRiver Riddle 
468469c02d0SRiver Riddle private:
469469c02d0SRiver Riddle   /// The equivalence data for the leader of the cluster.
470469c02d0SRiver Riddle   BlockEquivalenceData leaderData;
471469c02d0SRiver Riddle 
472469c02d0SRiver Riddle   /// The set of blocks that can be merged into the leader.
473469c02d0SRiver Riddle   llvm::SmallSetVector<Block *, 1> blocksToMerge;
474469c02d0SRiver Riddle 
475469c02d0SRiver Riddle   /// A set of operand+index pairs that correspond to operands that need to be
476469c02d0SRiver Riddle   /// replaced by arguments when the cluster gets merged.
477469c02d0SRiver Riddle   std::set<std::pair<int, int>> operandsToMerge;
478469c02d0SRiver Riddle };
479be0a7e9fSMehdi Amini } // namespace
480469c02d0SRiver Riddle 
addToCluster(BlockEquivalenceData & blockData)481469c02d0SRiver Riddle LogicalResult BlockMergeCluster::addToCluster(BlockEquivalenceData &blockData) {
482469c02d0SRiver Riddle   if (leaderData.hash != blockData.hash)
483469c02d0SRiver Riddle     return failure();
484469c02d0SRiver Riddle   Block *leaderBlock = leaderData.block, *mergeBlock = blockData.block;
485469c02d0SRiver Riddle   if (leaderBlock->getArgumentTypes() != mergeBlock->getArgumentTypes())
486469c02d0SRiver Riddle     return failure();
487469c02d0SRiver Riddle 
488469c02d0SRiver Riddle   // A set of operands that mismatch between the leader and the new block.
489469c02d0SRiver Riddle   SmallVector<std::pair<int, int>, 8> mismatchedOperands;
490469c02d0SRiver Riddle   auto lhsIt = leaderBlock->begin(), lhsE = leaderBlock->end();
491469c02d0SRiver Riddle   auto rhsIt = blockData.block->begin(), rhsE = blockData.block->end();
492469c02d0SRiver Riddle   for (int opI = 0; lhsIt != lhsE && rhsIt != rhsE; ++lhsIt, ++rhsIt, ++opI) {
493469c02d0SRiver Riddle     // Check that the operations are equivalent.
494469c02d0SRiver Riddle     if (!OperationEquivalence::isEquivalentTo(
4950be5d1a9SMehdi Amini             &*lhsIt, &*rhsIt, OperationEquivalence::ignoreValueEquivalence,
4960be5d1a9SMehdi Amini             OperationEquivalence::ignoreValueEquivalence,
4970be5d1a9SMehdi Amini             OperationEquivalence::Flags::IgnoreLocations))
498469c02d0SRiver Riddle       return failure();
499469c02d0SRiver Riddle 
500469c02d0SRiver Riddle     // Compare the operands of the two operations. If the operand is within
501469c02d0SRiver Riddle     // the block, it must refer to the same operation.
502469c02d0SRiver Riddle     auto lhsOperands = lhsIt->getOperands(), rhsOperands = rhsIt->getOperands();
503469c02d0SRiver Riddle     for (int operand : llvm::seq<int>(0, lhsIt->getNumOperands())) {
504469c02d0SRiver Riddle       Value lhsOperand = lhsOperands[operand];
505469c02d0SRiver Riddle       Value rhsOperand = rhsOperands[operand];
506469c02d0SRiver Riddle       if (lhsOperand == rhsOperand)
507469c02d0SRiver Riddle         continue;
508474f7639SRiver Riddle       // Check that the types of the operands match.
509474f7639SRiver Riddle       if (lhsOperand.getType() != rhsOperand.getType())
510474f7639SRiver Riddle         return failure();
511469c02d0SRiver Riddle 
512469c02d0SRiver Riddle       // Check that these uses are both external, or both internal.
513469c02d0SRiver Riddle       bool lhsIsInBlock = lhsOperand.getParentBlock() == leaderBlock;
514469c02d0SRiver Riddle       bool rhsIsInBlock = rhsOperand.getParentBlock() == mergeBlock;
515469c02d0SRiver Riddle       if (lhsIsInBlock != rhsIsInBlock)
516469c02d0SRiver Riddle         return failure();
517469c02d0SRiver Riddle       // Let the operands differ if they are defined in a different block. These
518469c02d0SRiver Riddle       // will become new arguments if the blocks get merged.
519469c02d0SRiver Riddle       if (!lhsIsInBlock) {
520c14ba3c4SMarkus Böck 
521c14ba3c4SMarkus Böck         // Check whether the operands aren't the result of an immediate
522c14ba3c4SMarkus Böck         // predecessors terminator. In that case we are not able to use it as a
523c14ba3c4SMarkus Böck         // successor operand when branching to the merged block as it does not
524c14ba3c4SMarkus Böck         // dominate its producing operation.
525c14ba3c4SMarkus Böck         auto isValidSuccessorArg = [](Block *block, Value operand) {
526c14ba3c4SMarkus Böck           if (operand.getDefiningOp() !=
527c14ba3c4SMarkus Böck               operand.getParentBlock()->getTerminator())
528c14ba3c4SMarkus Böck             return true;
529c14ba3c4SMarkus Böck           return !llvm::is_contained(block->getPredecessors(),
530c14ba3c4SMarkus Böck                                      operand.getParentBlock());
531c14ba3c4SMarkus Böck         };
532c14ba3c4SMarkus Böck 
533c14ba3c4SMarkus Böck         if (!isValidSuccessorArg(leaderBlock, lhsOperand) ||
534c14ba3c4SMarkus Böck             !isValidSuccessorArg(mergeBlock, rhsOperand))
535a7865228SMarkus Böck           return failure();
536c14ba3c4SMarkus Böck 
537469c02d0SRiver Riddle         mismatchedOperands.emplace_back(opI, operand);
538469c02d0SRiver Riddle         continue;
539469c02d0SRiver Riddle       }
540469c02d0SRiver Riddle 
541469c02d0SRiver Riddle       // Otherwise, these operands must have the same logical order within the
542469c02d0SRiver Riddle       // parent block.
543469c02d0SRiver Riddle       if (leaderData.getOrderOf(lhsOperand) != blockData.getOrderOf(rhsOperand))
544469c02d0SRiver Riddle         return failure();
545469c02d0SRiver Riddle     }
546469c02d0SRiver Riddle 
547f5c5fd1cSWilliam S. Moses     // If the lhs or rhs has external uses, the blocks cannot be merged as the
548f5c5fd1cSWilliam S. Moses     // merged version of this operation will not be either the lhs or rhs
549f88fab50SKazuaki Ishizaki     // alone (thus semantically incorrect), but some mix dependending on which
550f5c5fd1cSWilliam S. Moses     // block preceeded this.
551f5c5fd1cSWilliam S. Moses     // TODO allow merging of operations when one block does not dominate the
552f5c5fd1cSWilliam S. Moses     // other
553f5c5fd1cSWilliam S. Moses     if (rhsIt->isUsedOutsideOfBlock(mergeBlock) ||
554f5c5fd1cSWilliam S. Moses         lhsIt->isUsedOutsideOfBlock(leaderBlock)) {
555f5c5fd1cSWilliam S. Moses       return failure();
556f5c5fd1cSWilliam S. Moses     }
557469c02d0SRiver Riddle   }
558469c02d0SRiver Riddle   // Make sure that the block sizes are equivalent.
559469c02d0SRiver Riddle   if (lhsIt != lhsE || rhsIt != rhsE)
560469c02d0SRiver Riddle     return failure();
561469c02d0SRiver Riddle 
562469c02d0SRiver Riddle   // If we get here, the blocks are equivalent and can be merged.
563469c02d0SRiver Riddle   operandsToMerge.insert(mismatchedOperands.begin(), mismatchedOperands.end());
564469c02d0SRiver Riddle   blocksToMerge.insert(blockData.block);
565469c02d0SRiver Riddle   return success();
566469c02d0SRiver Riddle }
567469c02d0SRiver Riddle 
568469c02d0SRiver Riddle /// Returns true if the predecessor terminators of the given block can not have
569469c02d0SRiver Riddle /// their operands updated.
ableToUpdatePredOperands(Block * block)570469c02d0SRiver Riddle static bool ableToUpdatePredOperands(Block *block) {
571469c02d0SRiver Riddle   for (auto it = block->pred_begin(), e = block->pred_end(); it != e; ++it) {
572*0c789db5SMarkus Böck     if (!isa<BranchOpInterface>((*it)->getTerminator()))
573469c02d0SRiver Riddle       return false;
574469c02d0SRiver Riddle   }
575469c02d0SRiver Riddle   return true;
576469c02d0SRiver Riddle }
577469c02d0SRiver Riddle 
merge(RewriterBase & rewriter)578d75a611aSRiver Riddle LogicalResult BlockMergeCluster::merge(RewriterBase &rewriter) {
579469c02d0SRiver Riddle   // Don't consider clusters that don't have blocks to merge.
580469c02d0SRiver Riddle   if (blocksToMerge.empty())
581469c02d0SRiver Riddle     return failure();
582469c02d0SRiver Riddle 
583469c02d0SRiver Riddle   Block *leaderBlock = leaderData.block;
584469c02d0SRiver Riddle   if (!operandsToMerge.empty()) {
585469c02d0SRiver Riddle     // If the cluster has operands to merge, verify that the predecessor
586469c02d0SRiver Riddle     // terminators of each of the blocks can have their successor operands
587469c02d0SRiver Riddle     // updated.
588469c02d0SRiver Riddle     // TODO: We could try and sub-partition this cluster if only some blocks
589469c02d0SRiver Riddle     // cause the mismatch.
590469c02d0SRiver Riddle     if (!ableToUpdatePredOperands(leaderBlock) ||
591469c02d0SRiver Riddle         !llvm::all_of(blocksToMerge, ableToUpdatePredOperands))
592469c02d0SRiver Riddle       return failure();
593469c02d0SRiver Riddle 
594469c02d0SRiver Riddle     // Collect the iterators for each of the blocks to merge. We will walk all
595469c02d0SRiver Riddle     // of the iterators at once to avoid operand index invalidation.
596469c02d0SRiver Riddle     SmallVector<Block::iterator, 2> blockIterators;
597469c02d0SRiver Riddle     blockIterators.reserve(blocksToMerge.size() + 1);
598469c02d0SRiver Riddle     blockIterators.push_back(leaderBlock->begin());
599469c02d0SRiver Riddle     for (Block *mergeBlock : blocksToMerge)
600469c02d0SRiver Riddle       blockIterators.push_back(mergeBlock->begin());
601469c02d0SRiver Riddle 
602469c02d0SRiver Riddle     // Update each of the predecessor terminators with the new arguments.
603469c02d0SRiver Riddle     SmallVector<SmallVector<Value, 8>, 2> newArguments(
604469c02d0SRiver Riddle         1 + blocksToMerge.size(),
605469c02d0SRiver Riddle         SmallVector<Value, 8>(operandsToMerge.size()));
606469c02d0SRiver Riddle     unsigned curOpIndex = 0;
607e4853be2SMehdi Amini     for (const auto &it : llvm::enumerate(operandsToMerge)) {
608469c02d0SRiver Riddle       unsigned nextOpOffset = it.value().first - curOpIndex;
609469c02d0SRiver Riddle       curOpIndex = it.value().first;
610469c02d0SRiver Riddle 
611469c02d0SRiver Riddle       // Process the operand for each of the block iterators.
612469c02d0SRiver Riddle       for (unsigned i = 0, e = blockIterators.size(); i != e; ++i) {
613469c02d0SRiver Riddle         Block::iterator &blockIter = blockIterators[i];
614469c02d0SRiver Riddle         std::advance(blockIter, nextOpOffset);
615469c02d0SRiver Riddle         auto &operand = blockIter->getOpOperand(it.value().second);
616469c02d0SRiver Riddle         newArguments[i][it.index()] = operand.get();
617469c02d0SRiver Riddle 
618469c02d0SRiver Riddle         // Update the operand and insert an argument if this is the leader.
619e084679fSRiver Riddle         if (i == 0) {
620e084679fSRiver Riddle           Value operandVal = operand.get();
621e084679fSRiver Riddle           operand.set(leaderBlock->addArgument(operandVal.getType(),
622e084679fSRiver Riddle                                                operandVal.getLoc()));
623e084679fSRiver Riddle         }
624469c02d0SRiver Riddle       }
625469c02d0SRiver Riddle     }
626469c02d0SRiver Riddle     // Update the predecessors for each of the blocks.
627469c02d0SRiver Riddle     auto updatePredecessors = [&](Block *block, unsigned clusterIndex) {
628469c02d0SRiver Riddle       for (auto predIt = block->pred_begin(), predE = block->pred_end();
629469c02d0SRiver Riddle            predIt != predE; ++predIt) {
630469c02d0SRiver Riddle         auto branch = cast<BranchOpInterface>((*predIt)->getTerminator());
631469c02d0SRiver Riddle         unsigned succIndex = predIt.getSuccessorIndex();
632*0c789db5SMarkus Böck         branch.getSuccessorOperands(succIndex).append(
633469c02d0SRiver Riddle             newArguments[clusterIndex]);
634469c02d0SRiver Riddle       }
635469c02d0SRiver Riddle     };
636469c02d0SRiver Riddle     updatePredecessors(leaderBlock, /*clusterIndex=*/0);
637469c02d0SRiver Riddle     for (unsigned i = 0, e = blocksToMerge.size(); i != e; ++i)
638469c02d0SRiver Riddle       updatePredecessors(blocksToMerge[i], /*clusterIndex=*/i + 1);
639469c02d0SRiver Riddle   }
640469c02d0SRiver Riddle 
641469c02d0SRiver Riddle   // Replace all uses of the merged blocks with the leader and erase them.
642469c02d0SRiver Riddle   for (Block *block : blocksToMerge) {
643469c02d0SRiver Riddle     block->replaceAllUsesWith(leaderBlock);
644d75a611aSRiver Riddle     rewriter.eraseBlock(block);
645469c02d0SRiver Riddle   }
646469c02d0SRiver Riddle   return success();
647469c02d0SRiver Riddle }
648469c02d0SRiver Riddle 
649469c02d0SRiver Riddle /// Identify identical blocks within the given region and merge them, inserting
650469c02d0SRiver Riddle /// new block arguments as necessary. Returns success if any blocks were merged,
651469c02d0SRiver Riddle /// failure otherwise.
mergeIdenticalBlocks(RewriterBase & rewriter,Region & region)652d75a611aSRiver Riddle static LogicalResult mergeIdenticalBlocks(RewriterBase &rewriter,
653d75a611aSRiver Riddle                                           Region &region) {
654469c02d0SRiver Riddle   if (region.empty() || llvm::hasSingleElement(region))
655469c02d0SRiver Riddle     return failure();
656469c02d0SRiver Riddle 
657469c02d0SRiver Riddle   // Identify sets of blocks, other than the entry block, that branch to the
658469c02d0SRiver Riddle   // same successors. We will use these groups to create clusters of equivalent
659469c02d0SRiver Riddle   // blocks.
660469c02d0SRiver Riddle   DenseMap<SuccessorRange, SmallVector<Block *, 1>> matchingSuccessors;
661469c02d0SRiver Riddle   for (Block &block : llvm::drop_begin(region, 1))
662469c02d0SRiver Riddle     matchingSuccessors[block.getSuccessors()].push_back(&block);
663469c02d0SRiver Riddle 
664469c02d0SRiver Riddle   bool mergedAnyBlocks = false;
665469c02d0SRiver Riddle   for (ArrayRef<Block *> blocks : llvm::make_second_range(matchingSuccessors)) {
666469c02d0SRiver Riddle     if (blocks.size() == 1)
667469c02d0SRiver Riddle       continue;
668469c02d0SRiver Riddle 
669469c02d0SRiver Riddle     SmallVector<BlockMergeCluster, 1> clusters;
670469c02d0SRiver Riddle     for (Block *block : blocks) {
671469c02d0SRiver Riddle       BlockEquivalenceData data(block);
672469c02d0SRiver Riddle 
673469c02d0SRiver Riddle       // Don't allow merging if this block has any regions.
674469c02d0SRiver Riddle       // TODO: Add support for regions if necessary.
675469c02d0SRiver Riddle       bool hasNonEmptyRegion = llvm::any_of(*block, [](Operation &op) {
676469c02d0SRiver Riddle         return llvm::any_of(op.getRegions(),
677469c02d0SRiver Riddle                             [](Region &region) { return !region.empty(); });
678469c02d0SRiver Riddle       });
679469c02d0SRiver Riddle       if (hasNonEmptyRegion)
680469c02d0SRiver Riddle         continue;
681469c02d0SRiver Riddle 
682469c02d0SRiver Riddle       // Try to add this block to an existing cluster.
683469c02d0SRiver Riddle       bool addedToCluster = false;
684469c02d0SRiver Riddle       for (auto &cluster : clusters)
685469c02d0SRiver Riddle         if ((addedToCluster = succeeded(cluster.addToCluster(data))))
686469c02d0SRiver Riddle           break;
687469c02d0SRiver Riddle       if (!addedToCluster)
688469c02d0SRiver Riddle         clusters.emplace_back(std::move(data));
689469c02d0SRiver Riddle     }
690469c02d0SRiver Riddle     for (auto &cluster : clusters)
691d75a611aSRiver Riddle       mergedAnyBlocks |= succeeded(cluster.merge(rewriter));
692469c02d0SRiver Riddle   }
693469c02d0SRiver Riddle 
694469c02d0SRiver Riddle   return success(mergedAnyBlocks);
695469c02d0SRiver Riddle }
696469c02d0SRiver Riddle 
697469c02d0SRiver Riddle /// Identify identical blocks within the given regions and merge them, inserting
698469c02d0SRiver Riddle /// new block arguments as necessary.
mergeIdenticalBlocks(RewriterBase & rewriter,MutableArrayRef<Region> regions)699d75a611aSRiver Riddle static LogicalResult mergeIdenticalBlocks(RewriterBase &rewriter,
700d75a611aSRiver Riddle                                           MutableArrayRef<Region> regions) {
701469c02d0SRiver Riddle   llvm::SmallSetVector<Region *, 1> worklist;
702469c02d0SRiver Riddle   for (auto &region : regions)
703469c02d0SRiver Riddle     worklist.insert(&region);
704469c02d0SRiver Riddle   bool anyChanged = false;
705469c02d0SRiver Riddle   while (!worklist.empty()) {
706469c02d0SRiver Riddle     Region *region = worklist.pop_back_val();
707d75a611aSRiver Riddle     if (succeeded(mergeIdenticalBlocks(rewriter, *region))) {
708469c02d0SRiver Riddle       worklist.insert(region);
709469c02d0SRiver Riddle       anyChanged = true;
710469c02d0SRiver Riddle     }
711469c02d0SRiver Riddle 
712469c02d0SRiver Riddle     // Add any nested regions to the worklist.
713469c02d0SRiver Riddle     for (Block &block : *region)
714469c02d0SRiver Riddle       for (auto &op : block)
715469c02d0SRiver Riddle         for (auto &nestedRegion : op.getRegions())
716469c02d0SRiver Riddle           worklist.insert(&nestedRegion);
717469c02d0SRiver Riddle   }
718469c02d0SRiver Riddle 
719469c02d0SRiver Riddle   return success(anyChanged);
720469c02d0SRiver Riddle }
721469c02d0SRiver Riddle 
722469c02d0SRiver Riddle //===----------------------------------------------------------------------===//
723fafb708bSRiver Riddle // Region Simplification
724fafb708bSRiver Riddle //===----------------------------------------------------------------------===//
725fafb708bSRiver Riddle 
726fafb708bSRiver Riddle /// Run a set of structural simplifications over the given regions. This
727fafb708bSRiver Riddle /// includes transformations like unreachable block elimination, dead argument
728fafb708bSRiver Riddle /// elimination, as well as some other DCE. This function returns success if any
729fafb708bSRiver Riddle /// of the regions were simplified, failure otherwise.
simplifyRegions(RewriterBase & rewriter,MutableArrayRef<Region> regions)730d75a611aSRiver Riddle LogicalResult mlir::simplifyRegions(RewriterBase &rewriter,
731d75a611aSRiver Riddle                                     MutableArrayRef<Region> regions) {
732d75a611aSRiver Riddle   bool eliminatedBlocks = succeeded(eraseUnreachableBlocks(rewriter, regions));
733d75a611aSRiver Riddle   bool eliminatedOpsOrArgs = succeeded(runRegionDCE(rewriter, regions));
734d75a611aSRiver Riddle   bool mergedIdenticalBlocks =
735d75a611aSRiver Riddle       succeeded(mergeIdenticalBlocks(rewriter, regions));
736469c02d0SRiver Riddle   return success(eliminatedBlocks || eliminatedOpsOrArgs ||
737469c02d0SRiver Riddle                  mergedIdenticalBlocks);
738fafb708bSRiver Riddle }
739