diff --git a/mlir/include/mlir/Dialect/Affine/EDSC/Builders.h b/mlir/include/mlir/Dialect/Affine/EDSC/Builders.h --- a/mlir/include/mlir/Dialect/Affine/EDSC/Builders.h +++ b/mlir/include/mlir/Dialect/Affine/EDSC/Builders.h @@ -22,53 +22,6 @@ namespace mlir { namespace edsc { -/// Constructs a new AffineForOp and captures the associated induction -/// variable. A Value pointer is passed as the first argument and is the -/// *only* way to capture the loop induction variable. -LoopBuilder makeAffineLoopBuilder(Value *iv, ArrayRef lbs, - ArrayRef ubs, int64_t step); - -/// Deprecated. Use affineLoopNestBuilder instead. -/// -/// Explicit nested LoopBuilder. Offers a compressed multi-loop builder to avoid -/// explicitly writing all the loops in a nest. This simple functionality is -/// also useful to write rank-agnostic custom ops. -/// -/// Usage: -/// -/// ```c++ -/// AffineLoopNestBuilder({&i, &j, &k}, {lb, lb, lb}, {ub, ub, ub}, {1, 1, -/// 1})( -/// [&](){ -/// ... -/// }); -/// ``` -/// -/// ```c++ -/// AffineLoopNestBuilder({&i}, {lb}, {ub}, {1})([&](){ -/// AffineLoopNestBuilder({&j}, {lb}, {ub}, {1})([&](){ -/// AffineLoopNestBuilder({&k}, {lb}, {ub}, {1})([&](){ -/// ... -/// }), -/// }), -/// }); -/// ``` -class AffineLoopNestBuilder { -public: - /// This entry point accommodates the fact that AffineForOp implicitly uses - /// multiple `lbs` and `ubs` with one single `iv` and `step` to encode `max` - /// and and `min` constraints respectively. - AffineLoopNestBuilder(Value *iv, ArrayRef lbs, ArrayRef ubs, - int64_t step); - AffineLoopNestBuilder(MutableArrayRef ivs, ArrayRef lbs, - ArrayRef ubs, ArrayRef steps); - - void operator()(function_ref fun = nullptr); - -private: - SmallVector loops; -}; - /// Creates a perfect nest of affine "for" loops, given the list of lower /// bounds, upper bounds and steps. The three lists are expected to contain the /// same number of elements. Uses the OpBuilder and Location stored in diff --git a/mlir/include/mlir/Dialect/Linalg/EDSC/Builders.h b/mlir/include/mlir/Dialect/Linalg/EDSC/Builders.h --- a/mlir/include/mlir/Dialect/Linalg/EDSC/Builders.h +++ b/mlir/include/mlir/Dialect/Linalg/EDSC/Builders.h @@ -14,8 +14,6 @@ #define MLIR_DIALECT_LINALG_EDSC_BUILDERS_H_ #include "mlir/Dialect/Linalg/IR/LinalgOps.h" -// TODO(ntv): Needed for SubViewOp::Range, clean this up. -#include "mlir/Dialect/StandardOps/IR/Ops.h" #include "mlir/Dialect/Utils/StructuredOpsUtils.h" #include "mlir/EDSC/Builders.h" #include "mlir/IR/AffineExpr.h" @@ -24,37 +22,12 @@ namespace mlir { class AffineForOp; class BlockArgument; -class SubViewOp; namespace scf { class ParallelOp; } // namespace scf namespace edsc { -class AffineLoopNestBuilder; -class LoopNestBuilder; -class ParallelLoopNestBuilder; - -/// Helper template class for building scf.for and affine.loop nests from -/// ranges. -template class GenericLoopNestRangeBuilder { -public: - GenericLoopNestRangeBuilder(MutableArrayRef ivs, - ArrayRef ranges); - void operator()(std::function fun = nullptr) { (*builder)(fun); } - -private: - using LoopOrAffineLoopBuilder = - typename std::conditional_t::value, - AffineLoopNestBuilder, LoopNestBuilder>; - using BuilderType = - typename std::conditional_t::value, - ParallelLoopNestBuilder, - LoopOrAffineLoopBuilder>; - - std::unique_ptr builder; -}; - inline void defaultRegionBuilder(ValueRange args) {} /// Build a `linalg.generic` op with the specified `inputs`, `outputs` and diff --git a/mlir/include/mlir/Dialect/SCF/EDSC/Builders.h b/mlir/include/mlir/Dialect/SCF/EDSC/Builders.h --- a/mlir/include/mlir/Dialect/SCF/EDSC/Builders.h +++ b/mlir/include/mlir/Dialect/SCF/EDSC/Builders.h @@ -22,55 +22,6 @@ namespace mlir { namespace edsc { -/// Constructs a new scf::ParallelOp and captures the associated induction -/// variables. An array of Value pointers is passed as the first -/// argument and is the *only* way to capture loop induction variables. -LoopBuilder makeParallelLoopBuilder(MutableArrayRef ivs, - ArrayRef lbs, ArrayRef ubs, - ArrayRef steps); -/// Constructs a new scf::ForOp and captures the associated induction -/// variable. A Value pointer is passed as the first argument and is the -/// *only* way to capture the loop induction variable. -LoopBuilder makeLoopBuilder(Value *iv, Value lb, Value ub, Value step, - MutableArrayRef iterArgsHandles, - ValueRange iterArgsInitValues); -LoopBuilder makeLoopBuilder(Value *iv, Value lb, Value ub, Value step, - MutableArrayRef iterArgsHandles, - ValueRange iterArgsInitValues); -inline LoopBuilder makeLoopBuilder(Value *iv, Value lb, Value ub, Value step) { - return makeLoopBuilder(iv, lb, ub, step, MutableArrayRef{}, {}); -} - -/// Helper class to sugar building scf.parallel loop nests from lower/upper -/// bounds and step sizes. -class ParallelLoopNestBuilder { -public: - ParallelLoopNestBuilder(MutableArrayRef ivs, ArrayRef lbs, - ArrayRef ubs, ArrayRef steps); - - void operator()(function_ref fun = nullptr); - -private: - SmallVector loops; -}; - -/// Helper class to sugar building scf.for loop nests from ranges. -/// This is similar to edsc::AffineLoopNestBuilder except it operates on -/// scf.for. -class LoopNestBuilder { -public: - LoopNestBuilder(Value *iv, Value lb, Value ub, Value step); - LoopNestBuilder(Value *iv, Value lb, Value ub, Value step, - MutableArrayRef iterArgsHandles, - ValueRange iterArgsInitValues); - LoopNestBuilder(MutableArrayRef ivs, ArrayRef lbs, - ArrayRef ubs, ArrayRef steps); - ValueRange operator()(std::function fun = nullptr); - -private: - SmallVector loops; -}; - /// Adapters for building loop nests using the builder and the location stored /// in ScopedContext. Actual builders are in scf::buildLoopNest. scf::ValueVector loopNestBuilder(ValueRange lbs, ValueRange ubs, diff --git a/mlir/include/mlir/EDSC/Builders.h b/mlir/include/mlir/EDSC/Builders.h --- a/mlir/include/mlir/EDSC/Builders.h +++ b/mlir/include/mlir/EDSC/Builders.h @@ -147,42 +147,6 @@ ScopedContext *bodyScope = nullptr; }; -/// A LoopBuilder is a generic NestedBuilder for loop-like MLIR operations. -/// More specifically it is meant to be used as a temporary object for -/// representing any nested MLIR construct that is "related to" an mlir::Value -/// (for now an induction variable). -/// This is extensible and will evolve in the future as MLIR evolves, hence -/// the name LoopBuilder (as opposed to say ForBuilder or AffineForBuilder). -class LoopBuilder : public NestedBuilder { -public: - LoopBuilder(const LoopBuilder &) = delete; - LoopBuilder(LoopBuilder &&) = default; - - LoopBuilder &operator=(const LoopBuilder &) = delete; - LoopBuilder &operator=(LoopBuilder &&) = default; - - /// The only purpose of this operator is to serve as a sequence point so that - /// the evaluation of `fun` (which build IR snippets in a scoped fashion) is - /// scoped within a LoopBuilder. - void operator()(function_ref fun = nullptr); - void setOp(Operation *op) { this->op = op; } - Operation *getOp() { return op; } - -private: - LoopBuilder() = default; - - friend LoopBuilder makeAffineLoopBuilder(Value *iv, ArrayRef lbs, - ArrayRef ubs, int64_t step); - friend LoopBuilder makeParallelLoopBuilder(MutableArrayRef ivs, - ArrayRef lbs, - ArrayRef ubs, - ArrayRef steps); - friend LoopBuilder makeLoopBuilder(Value *iv, Value lb, Value ub, Value step, - MutableArrayRef iterArgsHandles, - ValueRange iterArgsInitValues); - Operation *op; -}; - // This class exists solely to handle the C++ vexing parse case when // trying to enter a Block that has already been constructed. class Append {}; diff --git a/mlir/lib/Dialect/Affine/EDSC/Builders.cpp b/mlir/lib/Dialect/Affine/EDSC/Builders.cpp --- a/mlir/lib/Dialect/Affine/EDSC/Builders.cpp +++ b/mlir/lib/Dialect/Affine/EDSC/Builders.cpp @@ -14,56 +14,6 @@ using namespace mlir; using namespace mlir::edsc; -static Optional emitStaticFor(ArrayRef lbs, ArrayRef ubs, - int64_t step) { - if (lbs.size() != 1 || ubs.size() != 1) - return Optional(); - - auto *lbDef = lbs.front().getDefiningOp(); - auto *ubDef = ubs.front().getDefiningOp(); - if (!lbDef || !ubDef) - return Optional(); - - auto lbConst = dyn_cast(lbDef); - auto ubConst = dyn_cast(ubDef); - if (!lbConst || !ubConst) - return Optional(); - return ScopedContext::getBuilderRef() - .create(ScopedContext::getLocation(), lbConst.getValue(), - ubConst.getValue(), step) - .getInductionVar(); -} - -LoopBuilder mlir::edsc::makeAffineLoopBuilder(Value *iv, ArrayRef lbs, - ArrayRef ubs, - int64_t step) { - mlir::edsc::LoopBuilder result; - if (auto staticForIv = emitStaticFor(lbs, ubs, step)) - *iv = staticForIv.getValue(); - else - *iv = ScopedContext::getBuilderRef() - .create( - ScopedContext::getLocation(), lbs, - ScopedContext::getBuilderRef().getMultiDimIdentityMap( - lbs.size()), - ubs, - ScopedContext::getBuilderRef().getMultiDimIdentityMap( - ubs.size()), - step) - .getInductionVar(); - - auto *body = getForInductionVarOwner(*iv).getBody(); - result.enter(body); - return result; -} - -mlir::edsc::AffineLoopNestBuilder::AffineLoopNestBuilder(Value *iv, - ArrayRef lbs, - ArrayRef ubs, - int64_t step) { - loops.emplace_back(makeAffineLoopBuilder(iv, lbs, ubs, step)); -} - void mlir::edsc::affineLoopNestBuilder( ValueRange lbs, ValueRange ubs, ArrayRef steps, function_ref bodyBuilderFn) { @@ -137,30 +87,6 @@ }); } -mlir::edsc::AffineLoopNestBuilder::AffineLoopNestBuilder( - MutableArrayRef ivs, ArrayRef lbs, ArrayRef ubs, - ArrayRef steps) { - assert(ivs.size() == lbs.size() && "Mismatch in number of arguments"); - assert(ivs.size() == ubs.size() && "Mismatch in number of arguments"); - assert(ivs.size() == steps.size() && "Mismatch in number of arguments"); - for (auto it : llvm::zip(ivs, lbs, ubs, steps)) - loops.emplace_back(makeAffineLoopBuilder(&std::get<0>(it), std::get<1>(it), - std::get<2>(it), std::get<3>(it))); -} - -void mlir::edsc::AffineLoopNestBuilder::operator()( - function_ref fun) { - if (fun) - fun(); - // Iterate on the calling operator() on all the loops in the nest. - // The iteration order is from innermost to outermost because enter/exit needs - // to be asymmetric (i.e. enter() occurs on LoopBuilder construction, exit() - // occurs on calling operator()). The asymmetry is required for properly - // nesting imperfectly nested regions (see LoopBuilder::operator()). - for (auto lit = loops.rbegin(), eit = loops.rend(); lit != eit; ++lit) - (*lit)(); -} - static std::pair categorizeValueByAffineType(MLIRContext *context, Value val, unsigned &numDims, unsigned &numSymbols) { diff --git a/mlir/lib/Dialect/Linalg/EDSC/Builders.cpp b/mlir/lib/Dialect/Linalg/EDSC/Builders.cpp --- a/mlir/lib/Dialect/Linalg/EDSC/Builders.cpp +++ b/mlir/lib/Dialect/Linalg/EDSC/Builders.cpp @@ -21,55 +21,6 @@ using namespace mlir::linalg; using namespace mlir::scf; -static void unpackRanges(ArrayRef ranges, - SmallVectorImpl &lbs, - SmallVectorImpl &ubs, - SmallVectorImpl &steps) { - for (SubViewOp::Range range : ranges) { - lbs.emplace_back(range.offset); - ubs.emplace_back(range.size); - steps.emplace_back(range.stride); - } -} - -namespace mlir { -namespace edsc { - -template <> -GenericLoopNestRangeBuilder::GenericLoopNestRangeBuilder( - MutableArrayRef ivs, ArrayRef ranges) { - SmallVector lbs, ubs, steps; - unpackRanges(ranges, lbs, ubs, steps); - builder = std::make_unique(ivs, lbs, ubs, steps); -} - -template <> -GenericLoopNestRangeBuilder::GenericLoopNestRangeBuilder( - MutableArrayRef ivs, ArrayRef ranges) { - SmallVector lbs, ubs, steps; - unpackRanges(ranges, lbs, ubs, steps); - SmallVector constantSteps; - constantSteps.reserve(steps.size()); - for (Value v : steps) { - auto op = v.getDefiningOp(); - assert(op && "Affine loops require constant steps"); - constantSteps.push_back(op.getValue()); - } - builder = - std::make_unique(ivs, lbs, ubs, constantSteps); -} - -template <> -GenericLoopNestRangeBuilder::GenericLoopNestRangeBuilder( - MutableArrayRef ivs, ArrayRef ranges) { - SmallVector lbs, ubs, steps; - unpackRanges(ranges, lbs, ubs, steps); - builder = std::make_unique(ivs, lbs, ubs, steps); -} - -} // namespace edsc -} // namespace mlir - Operation *mlir::edsc::makeGenericLinalgOp( ArrayRef iteratorTypes, ArrayRef inputs, ArrayRef outputs, diff --git a/mlir/lib/Dialect/SCF/EDSC/Builders.cpp b/mlir/lib/Dialect/SCF/EDSC/Builders.cpp --- a/mlir/lib/Dialect/SCF/EDSC/Builders.cpp +++ b/mlir/lib/Dialect/SCF/EDSC/Builders.cpp @@ -14,105 +14,6 @@ using namespace mlir; using namespace mlir::edsc; -mlir::edsc::ParallelLoopNestBuilder::ParallelLoopNestBuilder( - MutableArrayRef ivs, ArrayRef lbs, ArrayRef ubs, - ArrayRef steps) { - assert(ivs.size() == lbs.size() && "Mismatch in number of arguments"); - assert(ivs.size() == ubs.size() && "Mismatch in number of arguments"); - assert(ivs.size() == steps.size() && "Mismatch in number of arguments"); - - loops.emplace_back(makeParallelLoopBuilder(ivs, lbs, ubs, steps)); -} - -void mlir::edsc::ParallelLoopNestBuilder::operator()( - function_ref fun) { - if (fun) - fun(); - // Iterate on the calling operator() on all the loops in the nest. - // The iteration order is from innermost to outermost because enter/exit needs - // to be asymmetric (i.e. enter() occurs on LoopBuilder construction, exit() - // occurs on calling operator()). The asymmetry is required for properly - // nesting imperfectly nested regions (see LoopBuilder::operator()). - for (auto lit = loops.rbegin(), eit = loops.rend(); lit != eit; ++lit) - (*lit)(); -} - -mlir::edsc::LoopNestBuilder::LoopNestBuilder(MutableArrayRef ivs, - ArrayRef lbs, - ArrayRef ubs, - ArrayRef steps) { - assert(ivs.size() == lbs.size() && "expected size of ivs and lbs to match"); - assert(ivs.size() == ubs.size() && "expected size of ivs and ubs to match"); - assert(ivs.size() == steps.size() && - "expected size of ivs and steps to match"); - loops.reserve(ivs.size()); - for (auto it : llvm::zip(ivs, lbs, ubs, steps)) - loops.emplace_back(makeLoopBuilder(&std::get<0>(it), std::get<1>(it), - std::get<2>(it), std::get<3>(it))); - assert(loops.size() == ivs.size() && "Mismatch loops vs ivs size"); -} - -mlir::edsc::LoopNestBuilder::LoopNestBuilder( - Value *iv, Value lb, Value ub, Value step, - MutableArrayRef iterArgsHandles, ValueRange iterArgsInitValues) { - assert(iterArgsInitValues.size() == iterArgsHandles.size() && - "expected size of arguments and argument_handles to match"); - loops.emplace_back( - makeLoopBuilder(iv, lb, ub, step, iterArgsHandles, iterArgsInitValues)); -} - -mlir::edsc::LoopNestBuilder::LoopNestBuilder(Value *iv, Value lb, Value ub, - Value step) { - SmallVector noArgs; - loops.emplace_back(makeLoopBuilder(iv, lb, ub, step, noArgs, {})); -} - -ValueRange mlir::edsc::LoopNestBuilder::LoopNestBuilder::operator()( - std::function fun) { - if (fun) - fun(); - - for (auto &lit : reverse(loops)) - lit({}); - - if (!loops.empty()) - return loops[0].getOp()->getResults(); - return {}; -} - -LoopBuilder mlir::edsc::makeParallelLoopBuilder(MutableArrayRef ivs, - ArrayRef lbs, - ArrayRef ubs, - ArrayRef steps) { - scf::ParallelOp parallelOp = OperationBuilder( - SmallVector(lbs.begin(), lbs.end()), - SmallVector(ubs.begin(), ubs.end()), - SmallVector(steps.begin(), steps.end())); - for (size_t i = 0, e = ivs.size(); i < e; ++i) - ivs[i] = parallelOp.getBody()->getArgument(i); - LoopBuilder result; - result.enter(parallelOp.getBody()); - return result; -} - -mlir::edsc::LoopBuilder -mlir::edsc::makeLoopBuilder(Value *iv, Value lb, Value ub, Value step, - MutableArrayRef iterArgsHandles, - ValueRange iterArgsInitValues) { - mlir::edsc::LoopBuilder result; - scf::ForOp forOp = - OperationBuilder(lb, ub, step, iterArgsInitValues); - *iv = Value(forOp.getInductionVar()); - auto *body = scf::getForInductionVarOwner(*iv).getBody(); - for (size_t i = 0, e = iterArgsHandles.size(); i < e; ++i) { - // Skipping the induction variable. - iterArgsHandles[i] = body->getArgument(i + 1); - } - result.setOp(forOp); - result.enter(body); - return result; -} - mlir::scf::ValueVector mlir::edsc::loopNestBuilder(ValueRange lbs, ValueRange ubs, ValueRange steps, function_ref fun) { diff --git a/mlir/lib/EDSC/Builders.cpp b/mlir/lib/EDSC/Builders.cpp --- a/mlir/lib/EDSC/Builders.cpp +++ b/mlir/lib/EDSC/Builders.cpp @@ -140,30 +140,6 @@ return block; } -void mlir::edsc::LoopBuilder::operator()(function_ref fun) { - // Call to `exit` must be explicit and asymmetric (cannot happen in the - // destructor) because of ordering wrt comma operator. - /// The particular use case concerns nested blocks: - /// - /// ```c++ - /// For (&i, lb, ub, 1)({ - /// /--- destructor for this `For` is not always called before ... - /// V - /// For (&j1, lb, ub, 1)({ - /// some_op_1, - /// }), - /// /--- ... this scope is entered, resulting in improperly nested IR. - /// V - /// For (&j2, lb, ub, 1)({ - /// some_op_2, - /// }), - /// }); - /// ``` - if (fun) - fun(); - exit(); -} - mlir::edsc::BlockBuilder::BlockBuilder(BlockHandle bh, Append) { assert(bh && "Expected already captured BlockHandle"); enter(bh.getBlock());