1 //===- Transforms.h - Transforms Entrypoints --------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This header file defines a set of transforms specific for the AffineOps 10 // dialect. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #ifndef MLIR_DIALECT_AFFINE_TRANSFORMS_TRANSFORMS_H 15 #define MLIR_DIALECT_AFFINE_TRANSFORMS_TRANSFORMS_H 16 17 #include "mlir/Interfaces/ValueBoundsOpInterface.h" 18 #include "mlir/Support/LLVM.h" 19 20 namespace mlir { 21 class AffineMap; 22 class Location; 23 class OpBuilder; 24 class OpFoldResult; 25 class RewritePatternSet; 26 class RewriterBase; 27 class Value; 28 29 namespace presburger { 30 enum class BoundType; 31 } // namespace presburger 32 33 namespace affine { 34 class AffineApplyOp; 35 36 /// Populate patterns that expand affine index operations into more fundamental 37 /// operations (not necessarily restricted to Affine dialect). 38 void populateAffineExpandIndexOpsPatterns(RewritePatternSet &patterns); 39 40 /// Populate patterns that expand affine index operations into their equivalent 41 /// `affine.apply` representations. 42 void populateAffineExpandIndexOpsAsAffinePatterns(RewritePatternSet &patterns); 43 44 /// Helper function to rewrite `op`'s affine map and reorder its operands such 45 /// that they are in increasing order of hoistability (i.e. the least hoistable) 46 /// operands come first in the operand list. 47 void reorderOperandsByHoistability(RewriterBase &rewriter, AffineApplyOp op); 48 49 /// Split an "affine.apply" operation into smaller ops. 50 /// This reassociates a large AffineApplyOp into an ordered list of smaller 51 /// AffineApplyOps. This can be used right before lowering affine ops to arith 52 /// to exhibit more opportunities for CSE and LICM. 53 /// Return the sink AffineApplyOp on success or failure if `op` does not 54 /// decompose into smaller AffineApplyOps. 55 /// Note that this can be undone by canonicalization which tries to 56 /// maximally compose chains of AffineApplyOps. 57 FailureOr<AffineApplyOp> decompose(RewriterBase &rewriter, AffineApplyOp op); 58 59 /// Reify a bound for the given variable in terms of SSA values for which 60 /// `stopCondition` is met. 61 /// 62 /// By default, lower/equal bounds are closed and upper bounds are open. If 63 /// `closedUB` is set to "true", upper bounds are also closed. 64 FailureOr<OpFoldResult> 65 reifyValueBound(OpBuilder &b, Location loc, presburger::BoundType type, 66 const ValueBoundsConstraintSet::Variable &var, 67 ValueBoundsConstraintSet::StopConditionFn stopCondition, 68 bool closedUB = false); 69 70 /// Reify a bound for the given index-typed value in terms of SSA values for 71 /// which `stopCondition` is met. If no stop condition is specified, reify in 72 /// terms of the operands of the owner op. 73 /// 74 /// By default, lower/equal bounds are closed and upper bounds are open. If 75 /// `closedUB` is set to "true", upper bounds are also closed. 76 /// 77 /// Example: 78 /// %0 = arith.addi %a, %b : index 79 /// %1 = arith.addi %0, %c : index 80 /// 81 /// * If `stopCondition` evaluates to "true" for %0 and %c, "%0 + %c" is an EQ 82 /// bound for %1. 83 /// * If `stopCondition` evaluates to "true" for %a, %b and %c, "%a + %b + %c" 84 /// is an EQ bound for %1. 85 /// * Otherwise, if the owners of %a, %b or %c do not implement the 86 /// ValueBoundsOpInterface, no bound can be computed. 87 FailureOr<OpFoldResult> reifyIndexValueBound( 88 OpBuilder &b, Location loc, presburger::BoundType type, Value value, 89 ValueBoundsConstraintSet::StopConditionFn stopCondition = nullptr, 90 bool closedUB = false); 91 92 /// Reify a bound for the specified dimension of the given shaped value in terms 93 /// of SSA values for which `stopCondition` is met. If no stop condition is 94 /// specified, reify in terms of the operands of the owner op. 95 /// 96 /// By default, lower/equal bounds are closed and upper bounds are open. If 97 /// `closedUB` is set to "true", upper bounds are also closed. 98 FailureOr<OpFoldResult> reifyShapedValueDimBound( 99 OpBuilder &b, Location loc, presburger::BoundType type, Value value, 100 int64_t dim, 101 ValueBoundsConstraintSet::StopConditionFn stopCondition = nullptr, 102 bool closedUB = false); 103 104 /// Materialize an already computed bound with Affine dialect ops. 105 /// 106 /// * `ValueBoundsOpInterface::computeBound` computes bounds but does not 107 /// create IR. It is dialect independent. 108 /// * `materializeComputedBound` materializes computed bounds with Affine 109 /// dialect ops. 110 /// * `reifyIndexValueBound`/`reifyShapedValueDimBound` are a combination of 111 /// the two functions mentioned above. 112 OpFoldResult materializeComputedBound( 113 OpBuilder &b, Location loc, AffineMap boundMap, 114 ArrayRef<std::pair<Value, std::optional<int64_t>>> mapOperands); 115 116 } // namespace affine 117 } // namespace mlir 118 119 #endif // MLIR_DIALECT_AFFINE_TRANSFORMS_TRANSFORMS_H 120