1111#include " mlir/Dialect/MemRef/IR/MemRef.h"
1212#include " mlir/Dialect/UB/IR/UBOps.h"
1313#include " mlir/Dialect/Utils/StaticValueUtils.h"
14+ #include " mlir/IR/AffineExpr.h"
1415#include " mlir/IR/AffineExprVisitor.h"
1516#include " mlir/IR/IRMapping.h"
1617#include " mlir/IR/IntegerSet.h"
1718#include " mlir/IR/Matchers.h"
1819#include " mlir/IR/OpDefinition.h"
1920#include " mlir/IR/PatternMatch.h"
21+ #include " mlir/IR/Value.h"
2022#include " mlir/Interfaces/ShapedOpInterfaces.h"
2123#include " mlir/Interfaces/ValueBoundsOpInterface.h"
2224#include " mlir/Transforms/InliningUtils.h"
2628#include " llvm/ADT/SmallVectorExtras.h"
2729#include " llvm/ADT/TypeSwitch.h"
2830#include " llvm/Support/Debug.h"
31+ #include " llvm/Support/LogicalResult.h"
2932#include " llvm/Support/MathExtras.h"
33+ #include < limits>
3034#include < numeric>
3135#include < optional>
3236
@@ -1042,6 +1046,62 @@ simplifyMapWithOperands(AffineMap &map, ArrayRef<Value> operands) {
10421046 map.getContext ());
10431047}
10441048
1049+ // / Assuming `dimOrSym` is a quantity in `map` that is defined by `minOp`.
1050+ // / Assuming that the quantity is of the form:
1051+ // / `affine_min(f(x, y), symbolic_cst)`.
1052+ // / This function checks that `0 < affine_min(f(x, y), symbolic_cst)` and
1053+ // / proceeds with replacing the patterns:
1054+ // / ```
1055+ // / dimOrSym.ceildiv(symbolic_cst)
1056+ // / (dimOrSym + symbolic_cst - 1).floordiv(symbolic_cst)
1057+ // / ```
1058+ // / by `1`.
1059+ // /
1060+ // / Additionally, allows the caller to pass `affineMinKnownToBeNonNegative` to
1061+ // / inject static information that may not be statically discoverable.
1062+ // /
1063+ // / Warning: ValueBoundsConstraintSet::computeConstantBound is needed to check
1064+ // / for the nonnegative case, if `affineMinKnownToBeNonNegative` is false.
1065+ static LogicalResult replaceAffineMinBoundingBoxExpression (
1066+ AffineMinOp minOp, AffineExpr dimOrSym, AffineMap *map,
1067+ bool affineMinKnownToBeNonNegative = false ) {
1068+ auto affineMinMap = minOp.getAffineMap ();
1069+ if (!affineMinKnownToBeNonNegative) {
1070+ ValueRange values = minOp->getOperands ();
1071+ for (unsigned i = 0 , e = affineMinMap.getNumResults (); i < e; ++i) {
1072+ AffineMap row = affineMinMap.getSubMap (ArrayRef<unsigned >{i});
1073+ FailureOr<int64_t > lowerBound =
1074+ ValueBoundsConstraintSet::computeConstantBound (
1075+ presburger::BoundType::LB, {row, values},
1076+ /* stopCondition=*/ nullptr ,
1077+ /* closedUB=*/ true );
1078+ if (failed (lowerBound) || lowerBound.value () <= 0 )
1079+ return failure ();
1080+ }
1081+ }
1082+
1083+ AffineMap initialMap = *map;
1084+ for (unsigned i = 0 , e = affineMinMap.getNumResults (); i != e; ++i) {
1085+ auto m = affineMinMap.getSubMap (ArrayRef<unsigned >{i});
1086+ AffineExpr expr = m.getResult (0 );
1087+ if (!expr.isSymbolicOrConstant ())
1088+ continue ;
1089+
1090+ DenseMap<AffineExpr, AffineExpr> repl;
1091+ // dimOrSym.ceilDiv(expr) -> 1
1092+ repl[dimOrSym.ceilDiv (expr)] = getAffineConstantExpr (1 , minOp.getContext ());
1093+ // (dimOrSym + expr - 1).floorDiv(expr) -> 1
1094+ repl[(dimOrSym + expr - 1 ).floorDiv (expr)] =
1095+ getAffineConstantExpr (1 , minOp.getContext ());
1096+ auto newMap = map->replace (repl);
1097+ if (newMap == *map)
1098+ continue ;
1099+ *map = newMap;
1100+ }
1101+
1102+ return success (*map != initialMap);
1103+ }
1104+
10451105// / Replace all occurrences of AffineExpr at position `pos` in `map` by the
10461106// / defining AffineApplyOp expression and operands.
10471107// / When `dimOrSymbolPosition < dims.size()`, AffineDimExpr@[pos] is replaced.
@@ -1052,10 +1112,13 @@ simplifyMapWithOperands(AffineMap &map, ArrayRef<Value> operands) {
10521112// / 2. `map` dim and symbols are gradually shifted to higher positions.
10531113// / 3. Old `dim` and `sym` entries are replaced by nullptr
10541114// / This avoids the need for any bookkeeping.
1115+ // / If `replaceAffineMin` is set to true, additionally triggers more expensive
1116+ // / replacements involving affine_min operations.
10551117static LogicalResult replaceDimOrSym (AffineMap *map,
10561118 unsigned dimOrSymbolPosition,
10571119 SmallVectorImpl<Value> &dims,
1058- SmallVectorImpl<Value> &syms) {
1120+ SmallVectorImpl<Value> &syms,
1121+ bool replaceAffineMin) {
10591122 MLIRContext *ctx = map->getContext ();
10601123 bool isDimReplacement = (dimOrSymbolPosition < dims.size ());
10611124 unsigned pos = isDimReplacement ? dimOrSymbolPosition
@@ -1064,6 +1127,13 @@ static LogicalResult replaceDimOrSym(AffineMap *map,
10641127 if (!v)
10651128 return failure ();
10661129
1130+ auto minOp = v.getDefiningOp <AffineMinOp>();
1131+ if (minOp && replaceAffineMin) {
1132+ AffineExpr dimOrSym = isDimReplacement ? getAffineDimExpr (pos, ctx)
1133+ : getAffineSymbolExpr (pos, ctx);
1134+ return replaceAffineMinBoundingBoxExpression (minOp, dimOrSym, map);
1135+ }
1136+
10671137 auto affineApply = v.getDefiningOp <AffineApplyOp>();
10681138 if (!affineApply)
10691139 return failure ();
@@ -1101,7 +1171,8 @@ static LogicalResult replaceDimOrSym(AffineMap *map,
11011171// / iteratively. Perform canonicalization of map and operands as well as
11021172// / AffineMap simplification. `map` and `operands` are mutated in place.
11031173static void composeAffineMapAndOperands (AffineMap *map,
1104- SmallVectorImpl<Value> *operands) {
1174+ SmallVectorImpl<Value> *operands,
1175+ bool composeAffineMin = false ) {
11051176 if (map->getNumResults () == 0 ) {
11061177 canonicalizeMapAndOperands (map, operands);
11071178 *map = simplifyAffineMap (*map);
@@ -1122,7 +1193,8 @@ static void composeAffineMapAndOperands(AffineMap *map,
11221193 while (true ) {
11231194 bool changed = false ;
11241195 for (unsigned pos = 0 ; pos != dims.size () + syms.size (); ++pos)
1125- if ((changed |= succeeded (replaceDimOrSym (map, pos, dims, syms))))
1196+ if ((changed |=
1197+ succeeded (replaceDimOrSym (map, pos, dims, syms, composeAffineMin))))
11261198 break ;
11271199 if (!changed)
11281200 break ;
@@ -1163,38 +1235,41 @@ static void composeAffineMapAndOperands(AffineMap *map,
11631235}
11641236
11651237void mlir::affine::fullyComposeAffineMapAndOperands (
1166- AffineMap *map, SmallVectorImpl<Value> *operands) {
1238+ AffineMap *map, SmallVectorImpl<Value> *operands, bool composeAffineMin ) {
11671239 while (llvm::any_of (*operands, [](Value v) {
11681240 return isa_and_nonnull<AffineApplyOp>(v.getDefiningOp ());
11691241 })) {
1170- composeAffineMapAndOperands (map, operands);
1242+ composeAffineMapAndOperands (map, operands, composeAffineMin );
11711243 }
11721244}
11731245
11741246AffineApplyOp
11751247mlir::affine::makeComposedAffineApply (OpBuilder &b, Location loc, AffineMap map,
1176- ArrayRef<OpFoldResult> operands) {
1248+ ArrayRef<OpFoldResult> operands,
1249+ bool composeAffineMin) {
11771250 SmallVector<Value> valueOperands;
11781251 map = foldAttributesIntoMap (b, map, operands, valueOperands);
1179- composeAffineMapAndOperands (&map, &valueOperands);
1252+ composeAffineMapAndOperands (&map, &valueOperands, composeAffineMin );
11801253 assert (map);
11811254 return b.create <AffineApplyOp>(loc, map, valueOperands);
11821255}
11831256
11841257AffineApplyOp
11851258mlir::affine::makeComposedAffineApply (OpBuilder &b, Location loc, AffineExpr e,
1186- ArrayRef<OpFoldResult> operands) {
1259+ ArrayRef<OpFoldResult> operands,
1260+ bool composeAffineMin) {
11871261 return makeComposedAffineApply (
11881262 b, loc,
11891263 AffineMap::inferFromExprList (ArrayRef<AffineExpr>{e}, b.getContext ())
11901264 .front (),
1191- operands);
1265+ operands, composeAffineMin );
11921266}
11931267
11941268// / Composes the given affine map with the given list of operands, pulling in
11951269// / the maps from any affine.apply operations that supply the operands.
11961270static void composeMultiResultAffineMap (AffineMap &map,
1197- SmallVectorImpl<Value> &operands) {
1271+ SmallVectorImpl<Value> &operands,
1272+ bool composeAffineMin = false ) {
11981273 // Compose and canonicalize each expression in the map individually because
11991274 // composition only applies to single-result maps, collecting potentially
12001275 // duplicate operands in a single list with shifted dimensions and symbols.
@@ -1203,7 +1278,8 @@ static void composeMultiResultAffineMap(AffineMap &map,
12031278 for (unsigned i : llvm::seq<unsigned >(0 , map.getNumResults ())) {
12041279 SmallVector<Value> submapOperands (operands.begin (), operands.end ());
12051280 AffineMap submap = map.getSubMap ({i});
1206- fullyComposeAffineMapAndOperands (&submap, &submapOperands);
1281+ fullyComposeAffineMapAndOperands (&submap, &submapOperands,
1282+ composeAffineMin);
12071283 canonicalizeMapAndOperands (&submap, &submapOperands);
12081284 unsigned numNewDims = submap.getNumDims ();
12091285 submap = submap.shiftDims (dims.size ()).shiftSymbols (symbols.size ());
@@ -1221,10 +1297,9 @@ static void composeMultiResultAffineMap(AffineMap &map,
12211297 canonicalizeMapAndOperands (&map, &operands);
12221298}
12231299
1224- OpFoldResult
1225- mlir::affine::makeComposedFoldedAffineApply (OpBuilder &b, Location loc,
1226- AffineMap map,
1227- ArrayRef<OpFoldResult> operands) {
1300+ OpFoldResult mlir::affine::makeComposedFoldedAffineApply (
1301+ OpBuilder &b, Location loc, AffineMap map, ArrayRef<OpFoldResult> operands,
1302+ bool composeAffineMin) {
12281303 assert (map.getNumResults () == 1 && " building affine.apply with !=1 result" );
12291304
12301305 // Create new builder without a listener, so that no notification is
@@ -1236,7 +1311,7 @@ mlir::affine::makeComposedFoldedAffineApply(OpBuilder &b, Location loc,
12361311
12371312 // Create op.
12381313 AffineApplyOp applyOp =
1239- makeComposedAffineApply (newBuilder, loc, map, operands);
1314+ makeComposedAffineApply (newBuilder, loc, map, operands, composeAffineMin );
12401315
12411316 // Get constant operands.
12421317 SmallVector<Attribute> constOperands (applyOp->getNumOperands ());
@@ -1256,26 +1331,25 @@ mlir::affine::makeComposedFoldedAffineApply(OpBuilder &b, Location loc,
12561331 return llvm::getSingleElement (foldResults);
12571332}
12581333
1259- OpFoldResult
1260- mlir::affine::makeComposedFoldedAffineApply (OpBuilder &b, Location loc,
1261- AffineExpr expr,
1262- ArrayRef<OpFoldResult> operands) {
1334+ OpFoldResult mlir::affine::makeComposedFoldedAffineApply (
1335+ OpBuilder &b, Location loc, AffineExpr expr,
1336+ ArrayRef<OpFoldResult> operands, bool composeAffineMin) {
12631337 return makeComposedFoldedAffineApply (
12641338 b, loc,
12651339 AffineMap::inferFromExprList (ArrayRef<AffineExpr>{expr}, b.getContext ())
12661340 .front (),
1267- operands);
1341+ operands, composeAffineMin );
12681342}
12691343
12701344SmallVector<OpFoldResult>
12711345mlir::affine::makeComposedFoldedMultiResultAffineApply (
1272- OpBuilder &b, Location loc, AffineMap map,
1273- ArrayRef<OpFoldResult> operands ) {
1274- return llvm::map_to_vector (llvm::seq< unsigned >( 0 , map. getNumResults ()),
1275- [&](unsigned i) {
1276- return makeComposedFoldedAffineApply (
1277- b, loc, map. getSubMap ({i}), operands);
1278- });
1346+ OpBuilder &b, Location loc, AffineMap map, ArrayRef<OpFoldResult> operands,
1347+ bool composeAffineMin ) {
1348+ return llvm::map_to_vector (
1349+ llvm::seq< unsigned >( 0 , map. getNumResults ()), [&](unsigned i) {
1350+ return makeComposedFoldedAffineApply (b, loc, map. getSubMap ({i}),
1351+ operands, composeAffineMin );
1352+ });
12791353}
12801354
12811355template <typename OpTy>
@@ -3024,7 +3098,8 @@ void AffineIfOp::build(OpBuilder &builder, OperationState &result,
30243098// / `set` by composing the maps of such affine.apply ops with the integer
30253099// / set constraints.
30263100static void composeSetAndOperands (IntegerSet &set,
3027- SmallVectorImpl<Value> &operands) {
3101+ SmallVectorImpl<Value> &operands,
3102+ bool composeAffineMin = false ) {
30283103 // We will simply reuse the API of the map composition by viewing the LHSs of
30293104 // the equalities and inequalities of `set` as the affine exprs of an affine
30303105 // map. Convert to equivalent map, compose, and convert back to set.
@@ -3035,7 +3110,7 @@ static void composeSetAndOperands(IntegerSet &set,
30353110 [](Value v) { return v.getDefiningOp <AffineApplyOp>(); }))
30363111 return ;
30373112
3038- composeAffineMapAndOperands (&map, &operands);
3113+ composeAffineMapAndOperands (&map, &operands, composeAffineMin );
30393114 set = IntegerSet::get (map.getNumDims (), map.getNumSymbols (), map.getResults (),
30403115 set.getEqFlags ());
30413116}
0 commit comments