summaryrefslogtreecommitdiffstats
path: root/mlir/lib/Transforms
diff options
context:
space:
mode:
Diffstat (limited to 'mlir/lib/Transforms')
-rw-r--r--mlir/lib/Transforms/CSE.cpp1
-rw-r--r--mlir/lib/Transforms/ComposeAffineMaps.cpp15
-rw-r--r--mlir/lib/Transforms/ConstantFold.cpp11
-rw-r--r--mlir/lib/Transforms/LoopFusion.cpp90
-rw-r--r--mlir/lib/Transforms/LoopUnroll.cpp49
-rw-r--r--mlir/lib/Transforms/LoopUnrollAndJam.cpp20
-rw-r--r--mlir/lib/Transforms/MemRefDataFlowOpt.cpp17
-rw-r--r--mlir/lib/Transforms/PipelineDataTransfer.cpp6
-rw-r--r--mlir/lib/Transforms/Utils/LoopUtils.cpp7
9 files changed, 88 insertions, 128 deletions
diff --git a/mlir/lib/Transforms/CSE.cpp b/mlir/lib/Transforms/CSE.cpp
index 63a676d7b52..de10fe8a461 100644
--- a/mlir/lib/Transforms/CSE.cpp
+++ b/mlir/lib/Transforms/CSE.cpp
@@ -24,7 +24,6 @@
#include "mlir/IR/Attributes.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/Function.h"
-#include "mlir/IR/InstVisitor.h"
#include "mlir/Pass.h"
#include "mlir/Support/Functional.h"
#include "mlir/Transforms/Passes.h"
diff --git a/mlir/lib/Transforms/ComposeAffineMaps.cpp b/mlir/lib/Transforms/ComposeAffineMaps.cpp
index 289b00d3b51..796477c64f2 100644
--- a/mlir/lib/Transforms/ComposeAffineMaps.cpp
+++ b/mlir/lib/Transforms/ComposeAffineMaps.cpp
@@ -27,7 +27,6 @@
#include "mlir/IR/Attributes.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinOps.h"
-#include "mlir/IR/InstVisitor.h"
#include "mlir/Pass.h"
#include "mlir/StandardOps/StandardOps.h"
#include "mlir/Transforms/Passes.h"
@@ -46,10 +45,9 @@ namespace {
// result of any AffineApplyOp). After this composition, AffineApplyOps with no
// remaining uses are erased.
// TODO(andydavis) Remove this when Chris adds instruction combiner pass.
-struct ComposeAffineMaps : public FunctionPass, InstWalker<ComposeAffineMaps> {
+struct ComposeAffineMaps : public FunctionPass {
explicit ComposeAffineMaps() : FunctionPass(&ComposeAffineMaps::passID) {}
PassResult runOnFunction(Function *f) override;
- void visitInstruction(Instruction *opInst);
SmallVector<OpPointer<AffineApplyOp>, 8> affineApplyOps;
@@ -68,15 +66,11 @@ static bool affineApplyOp(const Instruction &inst) {
return inst.isa<AffineApplyOp>();
}
-void ComposeAffineMaps::visitInstruction(Instruction *opInst) {
- if (auto afOp = opInst->dyn_cast<AffineApplyOp>())
- affineApplyOps.push_back(afOp);
-}
-
PassResult ComposeAffineMaps::runOnFunction(Function *f) {
// If needed for future efficiency, reserve space based on a pre-walk.
affineApplyOps.clear();
- walk(f);
+ f->walk<AffineApplyOp>(
+ [&](OpPointer<AffineApplyOp> afOp) { affineApplyOps.push_back(afOp); });
for (auto afOp : affineApplyOps) {
SmallVector<Value *, 8> operands(afOp->getOperands());
FuncBuilder b(afOp->getInstruction());
@@ -87,7 +81,8 @@ PassResult ComposeAffineMaps::runOnFunction(Function *f) {
// Erase dead affine apply ops.
affineApplyOps.clear();
- walk(f);
+ f->walk<AffineApplyOp>(
+ [&](OpPointer<AffineApplyOp> afOp) { affineApplyOps.push_back(afOp); });
for (auto it = affineApplyOps.rbegin(); it != affineApplyOps.rend(); ++it) {
if ((*it)->use_empty()) {
(*it)->erase();
diff --git a/mlir/lib/Transforms/ConstantFold.cpp b/mlir/lib/Transforms/ConstantFold.cpp
index 54486cdb293..e41ac0ad329 100644
--- a/mlir/lib/Transforms/ConstantFold.cpp
+++ b/mlir/lib/Transforms/ConstantFold.cpp
@@ -18,7 +18,6 @@
#include "mlir/AffineOps/AffineOps.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/Function.h"
-#include "mlir/IR/InstVisitor.h"
#include "mlir/Pass.h"
#include "mlir/Transforms/Passes.h"
#include "mlir/Transforms/Utils.h"
@@ -27,7 +26,7 @@ using namespace mlir;
namespace {
/// Simple constant folding pass.
-struct ConstantFold : public FunctionPass, InstWalker<ConstantFold> {
+struct ConstantFold : public FunctionPass {
ConstantFold() : FunctionPass(&ConstantFold::passID) {}
// All constants in the function post folding.
@@ -35,9 +34,7 @@ struct ConstantFold : public FunctionPass, InstWalker<ConstantFold> {
// Operations that were folded and that need to be erased.
std::vector<Instruction *> opInstsToErase;
- bool foldOperation(Instruction *op,
- SmallVectorImpl<Value *> &existingConstants);
- void visitInstruction(Instruction *op);
+ void foldInstruction(Instruction *op);
PassResult runOnFunction(Function *f) override;
static char passID;
@@ -49,7 +46,7 @@ char ConstantFold::passID = 0;
/// Attempt to fold the specified operation, updating the IR to match. If
/// constants are found, we keep track of them in the existingConstants list.
///
-void ConstantFold::visitInstruction(Instruction *op) {
+void ConstantFold::foldInstruction(Instruction *op) {
// If this operation is an AffineForOp, then fold the bounds.
if (auto forOp = op->dyn_cast<AffineForOp>()) {
constantFoldBounds(forOp);
@@ -111,7 +108,7 @@ PassResult ConstantFold::runOnFunction(Function *f) {
existingConstants.clear();
opInstsToErase.clear();
- walk(f);
+ f->walk([&](Instruction *inst) { foldInstruction(inst); });
// At this point, these operations are dead, remove them.
// TODO: This is assuming that all constant foldable operations have no
diff --git a/mlir/lib/Transforms/LoopFusion.cpp b/mlir/lib/Transforms/LoopFusion.cpp
index 7a002168528..77e5a6aa04f 100644
--- a/mlir/lib/Transforms/LoopFusion.cpp
+++ b/mlir/lib/Transforms/LoopFusion.cpp
@@ -28,7 +28,6 @@
#include "mlir/IR/AffineMap.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinOps.h"
-#include "mlir/IR/InstVisitor.h"
#include "mlir/Pass.h"
#include "mlir/StandardOps/StandardOps.h"
#include "mlir/Transforms/LoopUtils.h"
@@ -111,22 +110,23 @@ namespace {
// LoopNestStateCollector walks loop nests and collects load and store
// operations, and whether or not an IfInst was encountered in the loop nest.
-class LoopNestStateCollector : public InstWalker<LoopNestStateCollector> {
-public:
+struct LoopNestStateCollector {
SmallVector<OpPointer<AffineForOp>, 4> forOps;
SmallVector<Instruction *, 4> loadOpInsts;
SmallVector<Instruction *, 4> storeOpInsts;
bool hasNonForRegion = false;
- void visitInstruction(Instruction *opInst) {
- if (opInst->isa<AffineForOp>())
- forOps.push_back(opInst->cast<AffineForOp>());
- else if (opInst->getNumBlockLists() != 0)
- hasNonForRegion = true;
- else if (opInst->isa<LoadOp>())
- loadOpInsts.push_back(opInst);
- else if (opInst->isa<StoreOp>())
- storeOpInsts.push_back(opInst);
+ void collect(Instruction *instToWalk) {
+ instToWalk->walk([&](Instruction *opInst) {
+ if (opInst->isa<AffineForOp>())
+ forOps.push_back(opInst->cast<AffineForOp>());
+ else if (opInst->getNumBlockLists() != 0)
+ hasNonForRegion = true;
+ else if (opInst->isa<LoadOp>())
+ loadOpInsts.push_back(opInst);
+ else if (opInst->isa<StoreOp>())
+ storeOpInsts.push_back(opInst);
+ });
}
};
@@ -510,7 +510,7 @@ bool MemRefDependenceGraph::init(Function *f) {
// Create graph node 'id' to represent top-level 'forOp' and record
// all loads and store accesses it contains.
LoopNestStateCollector collector;
- collector.walk(&inst);
+ collector.collect(&inst);
// Return false if a non 'for' region was found (not currently supported).
if (collector.hasNonForRegion)
return false;
@@ -606,41 +606,39 @@ struct LoopNestStats {
// LoopNestStatsCollector walks a single loop nest and gathers per-loop
// trip count and operation count statistics and records them in 'stats'.
-class LoopNestStatsCollector : public InstWalker<LoopNestStatsCollector> {
-public:
+struct LoopNestStatsCollector {
LoopNestStats *stats;
bool hasLoopWithNonConstTripCount = false;
LoopNestStatsCollector(LoopNestStats *stats) : stats(stats) {}
- void visitInstruction(Instruction *opInst) {
- auto forOp = opInst->dyn_cast<AffineForOp>();
- if (!forOp)
- return;
-
- auto *forInst = forOp->getInstruction();
- auto *parentInst = forOp->getInstruction()->getParentInst();
- if (parentInst != nullptr) {
- assert(parentInst->isa<AffineForOp>() && "Expected parent AffineForOp");
- // Add mapping to 'forOp' from its parent AffineForOp.
- stats->loopMap[parentInst].push_back(forOp);
- }
+ void collect(Instruction *inst) {
+ inst->walk<AffineForOp>([&](OpPointer<AffineForOp> forOp) {
+ auto *forInst = forOp->getInstruction();
+ auto *parentInst = forOp->getInstruction()->getParentInst();
+ if (parentInst != nullptr) {
+ assert(parentInst->isa<AffineForOp>() && "Expected parent AffineForOp");
+ // Add mapping to 'forOp' from its parent AffineForOp.
+ stats->loopMap[parentInst].push_back(forOp);
+ }
- // Record the number of op instructions in the body of 'forOp'.
- unsigned count = 0;
- stats->opCountMap[forInst] = 0;
- for (auto &inst : *forOp->getBody()) {
- if (!(inst.isa<AffineForOp>() || inst.isa<AffineIfOp>()))
- ++count;
- }
- stats->opCountMap[forInst] = count;
- // Record trip count for 'forOp'. Set flag if trip count is not constant.
- Optional<uint64_t> maybeConstTripCount = getConstantTripCount(forOp);
- if (!maybeConstTripCount.hasValue()) {
- hasLoopWithNonConstTripCount = true;
- return;
- }
- stats->tripCountMap[forInst] = maybeConstTripCount.getValue();
+ // Record the number of op instructions in the body of 'forOp'.
+ unsigned count = 0;
+ stats->opCountMap[forInst] = 0;
+ for (auto &inst : *forOp->getBody()) {
+ if (!(inst.isa<AffineForOp>() || inst.isa<AffineIfOp>()))
+ ++count;
+ }
+ stats->opCountMap[forInst] = count;
+ // Record trip count for 'forOp'. Set flag if trip count is not
+ // constant.
+ Optional<uint64_t> maybeConstTripCount = getConstantTripCount(forOp);
+ if (!maybeConstTripCount.hasValue()) {
+ hasLoopWithNonConstTripCount = true;
+ return;
+ }
+ stats->tripCountMap[forInst] = maybeConstTripCount.getValue();
+ });
}
};
@@ -1078,7 +1076,7 @@ static bool isFusionProfitable(Instruction *srcOpInst,
// Walk src loop nest and collect stats.
LoopNestStats srcLoopNestStats;
LoopNestStatsCollector srcStatsCollector(&srcLoopNestStats);
- srcStatsCollector.walk(srcLoopIVs[0]->getInstruction());
+ srcStatsCollector.collect(srcLoopIVs[0]->getInstruction());
// Currently only constant trip count loop nests are supported.
if (srcStatsCollector.hasLoopWithNonConstTripCount)
return false;
@@ -1089,7 +1087,7 @@ static bool isFusionProfitable(Instruction *srcOpInst,
LoopNestStats dstLoopNestStats;
LoopNestStatsCollector dstStatsCollector(&dstLoopNestStats);
- dstStatsCollector.walk(dstLoopIVs[0]->getInstruction());
+ dstStatsCollector.collect(dstLoopIVs[0]->getInstruction());
// Currently only constant trip count loop nests are supported.
if (dstStatsCollector.hasLoopWithNonConstTripCount)
return false;
@@ -1474,7 +1472,7 @@ public:
// Collect slice loop stats.
LoopNestStateCollector sliceCollector;
- sliceCollector.walk(sliceLoopNest->getInstruction());
+ sliceCollector.collect(sliceLoopNest->getInstruction());
// Promote single iteration slice loops to single IV value.
for (auto forOp : sliceCollector.forOps) {
promoteIfSingleIteration(forOp);
@@ -1498,7 +1496,7 @@ public:
// Collect dst loop stats after memref privatizaton transformation.
LoopNestStateCollector dstLoopCollector;
- dstLoopCollector.walk(dstAffineForOp->getInstruction());
+ dstLoopCollector.collect(dstAffineForOp->getInstruction());
// Add new load ops to current Node load op list 'loads' to
// continue fusing based on new operands.
diff --git a/mlir/lib/Transforms/LoopUnroll.cpp b/mlir/lib/Transforms/LoopUnroll.cpp
index b1e15ccb07b..3a7cfb85e08 100644
--- a/mlir/lib/Transforms/LoopUnroll.cpp
+++ b/mlir/lib/Transforms/LoopUnroll.cpp
@@ -27,7 +27,6 @@
#include "mlir/IR/AffineMap.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinOps.h"
-#include "mlir/IR/InstVisitor.h"
#include "mlir/Pass.h"
#include "mlir/Transforms/LoopUtils.h"
#include "llvm/ADT/DenseMap.h"
@@ -95,15 +94,16 @@ char LoopUnroll::passID = 0;
PassResult LoopUnroll::runOnFunction(Function *f) {
// Gathers all innermost loops through a post order pruned walk.
- class InnermostLoopGatherer : public InstWalker<InnermostLoopGatherer, bool> {
- public:
+ struct InnermostLoopGatherer {
// Store innermost loops as we walk.
std::vector<OpPointer<AffineForOp>> loops;
- // This method specialized to encode custom return logic.
- using InstListType = llvm::iplist<Instruction>;
- bool walkPostOrder(InstListType::iterator Start,
- InstListType::iterator End) {
+ void walkPostOrder(Function *f) {
+ for (auto &b : *f)
+ walkPostOrder(b.begin(), b.end());
+ }
+
+ bool walkPostOrder(Block::iterator Start, Block::iterator End) {
bool hasInnerLoops = false;
// We need to walk all elements since all innermost loops need to be
// gathered as opposed to determining whether this list has any inner
@@ -112,7 +112,6 @@ PassResult LoopUnroll::runOnFunction(Function *f) {
hasInnerLoops |= walkPostOrder(&(*Start++));
return hasInnerLoops;
}
-
bool walkPostOrder(Instruction *opInst) {
bool hasInnerLoops = false;
for (auto &blockList : opInst->getBlockLists())
@@ -125,39 +124,21 @@ PassResult LoopUnroll::runOnFunction(Function *f) {
}
return hasInnerLoops;
}
-
- // FIXME: can't use base class method for this because that in turn would
- // need to use the derived class method above. CRTP doesn't allow it, and
- // the compiler error resulting from it is also misleading.
- using InstWalker<InnermostLoopGatherer, bool>::walkPostOrder;
};
- // Gathers all loops with trip count <= minTripCount.
- class ShortLoopGatherer : public InstWalker<ShortLoopGatherer> {
- public:
+ if (clUnrollFull.getNumOccurrences() > 0 &&
+ clUnrollFullThreshold.getNumOccurrences() > 0) {
// Store short loops as we walk.
std::vector<OpPointer<AffineForOp>> loops;
- const unsigned minTripCount;
- ShortLoopGatherer(unsigned minTripCount) : minTripCount(minTripCount) {}
- void visitInstruction(Instruction *opInst) {
- auto forOp = opInst->dyn_cast<AffineForOp>();
- if (!forOp)
- return;
+ // Gathers all loops with trip count <= minTripCount. Do a post order walk
+ // so that loops are gathered from innermost to outermost (or else unrolling
+ // an outer one may delete gathered inner ones).
+ f->walkPostOrder<AffineForOp>([&](OpPointer<AffineForOp> forOp) {
Optional<uint64_t> tripCount = getConstantTripCount(forOp);
- if (tripCount.hasValue() && tripCount.getValue() <= minTripCount)
+ if (tripCount.hasValue() && tripCount.getValue() <= clUnrollFullThreshold)
loops.push_back(forOp);
- }
- };
-
- if (clUnrollFull.getNumOccurrences() > 0 &&
- clUnrollFullThreshold.getNumOccurrences() > 0) {
- ShortLoopGatherer slg(clUnrollFullThreshold);
- // Do a post order walk so that loops are gathered from innermost to
- // outermost (or else unrolling an outer one may delete gathered inner
- // ones).
- slg.walkPostOrder(f);
- auto &loops = slg.loops;
+ });
for (auto forOp : loops)
loopUnrollFull(forOp);
return success();
diff --git a/mlir/lib/Transforms/LoopUnrollAndJam.cpp b/mlir/lib/Transforms/LoopUnrollAndJam.cpp
index 74c54fde047..b2aed7d9d7f 100644
--- a/mlir/lib/Transforms/LoopUnrollAndJam.cpp
+++ b/mlir/lib/Transforms/LoopUnrollAndJam.cpp
@@ -50,7 +50,6 @@
#include "mlir/IR/BlockAndValueMapping.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinOps.h"
-#include "mlir/IR/InstVisitor.h"
#include "mlir/Pass.h"
#include "mlir/Transforms/LoopUtils.h"
#include "llvm/ADT/DenseMap.h"
@@ -136,24 +135,25 @@ bool mlir::loopUnrollJamByFactor(OpPointer<AffineForOp> forOp,
// Gathers all maximal sub-blocks of instructions that do not themselves
// include a for inst (a instruction could have a descendant for inst though
// in its tree).
- class JamBlockGatherer : public InstWalker<JamBlockGatherer> {
- public:
- using InstListType = llvm::iplist<Instruction>;
- using InstWalker<JamBlockGatherer>::walk;
-
+ struct JamBlockGatherer {
// Store iterators to the first and last inst of each sub-block found.
std::vector<std::pair<Block::iterator, Block::iterator>> subBlocks;
// This is a linear time walk.
- void walk(InstListType::iterator Start, InstListType::iterator End) {
- for (auto it = Start; it != End;) {
+ void walk(Instruction *inst) {
+ for (auto &blockList : inst->getBlockLists())
+ for (auto &block : blockList)
+ walk(block);
+ }
+ void walk(Block &block) {
+ for (auto it = block.begin(), e = block.end(); it != e;) {
auto subBlockStart = it;
- while (it != End && !it->isa<AffineForOp>())
+ while (it != e && !it->isa<AffineForOp>())
++it;
if (it != subBlockStart)
subBlocks.push_back({subBlockStart, std::prev(it)});
// Process all for insts that appear next.
- while (it != End && it->isa<AffineForOp>())
+ while (it != e && it->isa<AffineForOp>())
walk(&*it++);
}
}
diff --git a/mlir/lib/Transforms/MemRefDataFlowOpt.cpp b/mlir/lib/Transforms/MemRefDataFlowOpt.cpp
index 2d06a327315..9c9db30d163 100644
--- a/mlir/lib/Transforms/MemRefDataFlowOpt.cpp
+++ b/mlir/lib/Transforms/MemRefDataFlowOpt.cpp
@@ -25,7 +25,6 @@
#include "mlir/Analysis/AffineAnalysis.h"
#include "mlir/Analysis/Dominance.h"
#include "mlir/Analysis/Utils.h"
-#include "mlir/IR/InstVisitor.h"
#include "mlir/Pass.h"
#include "mlir/StandardOps/StandardOps.h"
#include "mlir/Transforms/Passes.h"
@@ -70,12 +69,12 @@ namespace {
// currently only eliminates the stores only if no other loads/uses (other
// than dealloc) remain.
//
-struct MemRefDataFlowOpt : public FunctionPass, InstWalker<MemRefDataFlowOpt> {
+struct MemRefDataFlowOpt : public FunctionPass {
explicit MemRefDataFlowOpt() : FunctionPass(&MemRefDataFlowOpt::passID) {}
PassResult runOnFunction(Function *f) override;
- void visitInstruction(Instruction *opInst);
+ void forwardStoreToLoad(OpPointer<LoadOp> loadOp);
// A list of memref's that are potentially dead / could be eliminated.
SmallPtrSet<Value *, 4> memrefsToErase;
@@ -100,14 +99,9 @@ FunctionPass *mlir::createMemRefDataFlowOptPass() {
// This is a straightforward implementation not optimized for speed. Optimize
// this in the future if needed.
-void MemRefDataFlowOpt::visitInstruction(Instruction *opInst) {
+void MemRefDataFlowOpt::forwardStoreToLoad(OpPointer<LoadOp> loadOp) {
Instruction *lastWriteStoreOp = nullptr;
-
- auto loadOp = opInst->dyn_cast<LoadOp>();
- if (!loadOp)
- return;
-
- Instruction *loadOpInst = opInst;
+ Instruction *loadOpInst = loadOp->getInstruction();
// First pass over the use list to get minimum number of surrounding
// loops common between the load op and the store op, with min taken across
@@ -235,7 +229,8 @@ PassResult MemRefDataFlowOpt::runOnFunction(Function *f) {
memrefsToErase.clear();
// Walk all load's and perform load/store forwarding.
- walk(f);
+ f->walk<LoadOp>(
+ [&](OpPointer<LoadOp> loadOp) { forwardStoreToLoad(loadOp); });
// Erase all load op's whose results were replaced with store fwd'ed ones.
for (auto *loadOp : loadOpsToErase) {
diff --git a/mlir/lib/Transforms/PipelineDataTransfer.cpp b/mlir/lib/Transforms/PipelineDataTransfer.cpp
index ba3be5e95f4..4ca48a53485 100644
--- a/mlir/lib/Transforms/PipelineDataTransfer.cpp
+++ b/mlir/lib/Transforms/PipelineDataTransfer.cpp
@@ -142,10 +142,8 @@ PassResult PipelineDataTransfer::runOnFunction(Function *f) {
// deleted and replaced by a prologue, a new steady-state loop and an
// epilogue).
forOps.clear();
- f->walkPostOrder([&](Instruction *opInst) {
- if (auto forOp = opInst->dyn_cast<AffineForOp>())
- forOps.push_back(forOp);
- });
+ f->walkPostOrder<AffineForOp>(
+ [&](OpPointer<AffineForOp> forOp) { forOps.push_back(forOp); });
bool ret = false;
for (auto forOp : forOps) {
ret = ret | runOnAffineForOp(forOp);
diff --git a/mlir/lib/Transforms/Utils/LoopUtils.cpp b/mlir/lib/Transforms/Utils/LoopUtils.cpp
index 5bf17989bef..95875adca6e 100644
--- a/mlir/lib/Transforms/Utils/LoopUtils.cpp
+++ b/mlir/lib/Transforms/Utils/LoopUtils.cpp
@@ -28,7 +28,6 @@
#include "mlir/IR/BlockAndValueMapping.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinOps.h"
-#include "mlir/IR/InstVisitor.h"
#include "mlir/IR/Instruction.h"
#include "mlir/StandardOps/StandardOps.h"
#include "llvm/ADT/DenseMap.h"
@@ -135,10 +134,8 @@ bool mlir::promoteIfSingleIteration(OpPointer<AffineForOp> forOp) {
/// their body into the containing Block.
void mlir::promoteSingleIterationLoops(Function *f) {
// Gathers all innermost loops through a post order pruned walk.
- f->walkPostOrder([](Instruction *inst) {
- if (auto forOp = inst->dyn_cast<AffineForOp>())
- promoteIfSingleIteration(forOp);
- });
+ f->walkPostOrder<AffineForOp>(
+ [](OpPointer<AffineForOp> forOp) { promoteIfSingleIteration(forOp); });
}
/// Generates a 'for' inst with the specified lower and upper bounds while
OpenPOWER on IntegriCloud