From af5e83f569819bab68a070ca59128651feefb7ef Mon Sep 17 00:00:00 2001 From: Uday Bondhugula Date: Fri, 10 Apr 2020 17:12:49 +0530 Subject: [PATCH] [MLIR] Introduce utility to hoist affine if/else conditions This revision introduces a utility to unswitch affine.for/parallel loops by hoisting affine.if operations past surrounding affine.for/parallel. The hoisting works for both perfect/imperfect nests and in the presence of else blocks. The hoisting is currently to as outermost a level as possible. Uses a test pass to test the utility. Add convenience method Operation::getParentWithTrait. Depends on D77487. Differential Revision: https://reviews.llvm.org/D77870 --- mlir/include/mlir/Dialect/Affine/IR/AffineOps.td | 10 +- mlir/include/mlir/Dialect/Affine/Utils.h | 29 +++ mlir/include/mlir/IR/OpDefinition.h | 6 + mlir/include/mlir/IR/Operation.h | 10 + mlir/lib/Dialect/Affine/CMakeLists.txt | 1 + mlir/lib/Dialect/Affine/Utils/CMakeLists.txt | 11 + mlir/lib/Dialect/Affine/Utils/Utils.cpp | 175 ++++++++++++++ mlir/test/Dialect/Affine/loop-unswitch.mlir | 258 +++++++++++++++++++++ mlir/test/lib/Dialect/Affine/CMakeLists.txt | 1 + .../Dialect/Affine/TestAffineLoopUnswitching.cpp | 60 +++++ mlir/tools/mlir-opt/mlir-opt.cpp | 2 + 11 files changed, 561 insertions(+), 2 deletions(-) create mode 100644 mlir/include/mlir/Dialect/Affine/Utils.h create mode 100644 mlir/lib/Dialect/Affine/Utils/CMakeLists.txt create mode 100644 mlir/lib/Dialect/Affine/Utils/Utils.cpp create mode 100644 mlir/test/Dialect/Affine/loop-unswitch.mlir create mode 100644 mlir/test/lib/Dialect/Affine/TestAffineLoopUnswitching.cpp diff --git a/mlir/include/mlir/Dialect/Affine/IR/AffineOps.td b/mlir/include/mlir/Dialect/Affine/IR/AffineOps.td index d30e6b2..cb82739 100644 --- a/mlir/include/mlir/Dialect/Affine/IR/AffineOps.td +++ b/mlir/include/mlir/Dialect/Affine/IR/AffineOps.td @@ -337,13 +337,16 @@ def AffineIfOp : Affine_Op<"if", /// list of AffineIf is not resizable. void setConditional(IntegerSet set, ValueRange operands); + /// Returns true if an else block exists. + bool hasElse() { return !elseRegion().empty(); } + Block *getThenBlock() { assert(!thenRegion().empty() && "Unexpected empty 'then' region."); return &thenRegion().front(); } Block *getElseBlock() { - assert(!elseRegion().empty() && "Empty 'else' region."); + assert(hasElse() && "Empty 'else' region."); return &elseRegion().front(); } @@ -353,7 +356,7 @@ def AffineIfOp : Affine_Op<"if", return OpBuilder(&body, std::prev(body.end())); } OpBuilder getElseBodyBuilder() { - assert(!elseRegion().empty() && "Unexpected empty 'else' region."); + assert(hasElse() && "No 'else' block"); Block &body = elseRegion().front(); return OpBuilder(&body, std::prev(body.end())); } @@ -491,6 +494,9 @@ def AffineParallelOp : Affine_Op<"parallel", [ImplicitAffineTerminator]> { Block *getBody(); OpBuilder getBodyBuilder(); + MutableArrayRef getIVs() { + return getBody()->getArguments(); + } void setSteps(ArrayRef newSteps); static StringRef getLowerBoundsMapAttrName() { return "lowerBoundsMap"; } diff --git a/mlir/include/mlir/Dialect/Affine/Utils.h b/mlir/include/mlir/Dialect/Affine/Utils.h new file mode 100644 index 0000000..a2c0211 --- /dev/null +++ b/mlir/include/mlir/Dialect/Affine/Utils.h @@ -0,0 +1,29 @@ +//===- Utils.h - Affine dialect utilities -----------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This header file declares a set of utilities for the affine dialect ops. +// +//===----------------------------------------------------------------------===// + +#ifndef MLIR_DIALECT_AFFINE_UTILS_H +#define MLIR_DIALECT_AFFINE_UTILS_H + +namespace mlir { + +class AffineIfOp; +struct LogicalResult; + +/// Hoists out affine.if/else to as high as possible, i.e., past all invariant +/// affine.fors/parallel's. Returns success if any hoisting happened; folded` is +/// set to true if the op was folded or erased. This hoisting could lead to +/// significant code expansion in some cases. +LogicalResult hoistAffineIfOp(AffineIfOp ifOp, bool *folded = nullptr); + +} // namespace mlir + +#endif // MLIR_DIALECT_AFFINE_UTILS_H diff --git a/mlir/include/mlir/IR/OpDefinition.h b/mlir/include/mlir/IR/OpDefinition.h index a503c1e..f2b174c 100644 --- a/mlir/include/mlir/IR/OpDefinition.h +++ b/mlir/include/mlir/IR/OpDefinition.h @@ -116,6 +116,12 @@ public: return getOperation()->getParentOfType(); } + /// Returns the closest surrounding parent operation with trait `Trait`. + template