11
11
#include " mlir/Dialect/MemRef/IR/MemRef.h"
12
12
#include " mlir/Dialect/UB/IR/UBOps.h"
13
13
#include " mlir/Dialect/Utils/StaticValueUtils.h"
14
+ #include " mlir/IR/AffineExpr.h"
14
15
#include " mlir/IR/AffineExprVisitor.h"
15
16
#include " mlir/IR/IRMapping.h"
16
17
#include " mlir/IR/IntegerSet.h"
17
18
#include " mlir/IR/Matchers.h"
18
19
#include " mlir/IR/OpDefinition.h"
19
20
#include " mlir/IR/PatternMatch.h"
21
+ #include " mlir/IR/Value.h"
20
22
#include " mlir/Interfaces/ShapedOpInterfaces.h"
21
23
#include " mlir/Interfaces/ValueBoundsOpInterface.h"
22
24
#include " mlir/Transforms/InliningUtils.h"
26
28
#include " llvm/ADT/SmallVectorExtras.h"
27
29
#include " llvm/ADT/TypeSwitch.h"
28
30
#include " llvm/Support/Debug.h"
31
+ #include " llvm/Support/LogicalResult.h"
29
32
#include " llvm/Support/MathExtras.h"
33
+ #include < limits>
30
34
#include < numeric>
31
35
#include < optional>
32
36
@@ -1042,6 +1046,62 @@ simplifyMapWithOperands(AffineMap &map, ArrayRef<Value> operands) {
1042
1046
map.getContext ());
1043
1047
}
1044
1048
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
+
1045
1105
// / Replace all occurrences of AffineExpr at position `pos` in `map` by the
1046
1106
// / defining AffineApplyOp expression and operands.
1047
1107
// / When `dimOrSymbolPosition < dims.size()`, AffineDimExpr@[pos] is replaced.
@@ -1052,10 +1112,13 @@ simplifyMapWithOperands(AffineMap &map, ArrayRef<Value> operands) {
1052
1112
// / 2. `map` dim and symbols are gradually shifted to higher positions.
1053
1113
// / 3. Old `dim` and `sym` entries are replaced by nullptr
1054
1114
// / This avoids the need for any bookkeeping.
1115
+ // / If `replaceAffineMin` is set to true, additionally triggers more expensive
1116
+ // / replacements involving affine_min operations.
1055
1117
static LogicalResult replaceDimOrSym (AffineMap *map,
1056
1118
unsigned dimOrSymbolPosition,
1057
1119
SmallVectorImpl<Value> &dims,
1058
- SmallVectorImpl<Value> &syms) {
1120
+ SmallVectorImpl<Value> &syms,
1121
+ bool replaceAffineMin) {
1059
1122
MLIRContext *ctx = map->getContext ();
1060
1123
bool isDimReplacement = (dimOrSymbolPosition < dims.size ());
1061
1124
unsigned pos = isDimReplacement ? dimOrSymbolPosition
@@ -1064,6 +1127,13 @@ static LogicalResult replaceDimOrSym(AffineMap *map,
1064
1127
if (!v)
1065
1128
return failure ();
1066
1129
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
+
1067
1137
auto affineApply = v.getDefiningOp <AffineApplyOp>();
1068
1138
if (!affineApply)
1069
1139
return failure ();
@@ -1101,7 +1171,8 @@ static LogicalResult replaceDimOrSym(AffineMap *map,
1101
1171
// / iteratively. Perform canonicalization of map and operands as well as
1102
1172
// / AffineMap simplification. `map` and `operands` are mutated in place.
1103
1173
static void composeAffineMapAndOperands (AffineMap *map,
1104
- SmallVectorImpl<Value> *operands) {
1174
+ SmallVectorImpl<Value> *operands,
1175
+ bool composeAffineMin = false ) {
1105
1176
if (map->getNumResults () == 0 ) {
1106
1177
canonicalizeMapAndOperands (map, operands);
1107
1178
*map = simplifyAffineMap (*map);
@@ -1122,7 +1193,8 @@ static void composeAffineMapAndOperands(AffineMap *map,
1122
1193
while (true ) {
1123
1194
bool changed = false ;
1124
1195
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))))
1126
1198
break ;
1127
1199
if (!changed)
1128
1200
break ;
@@ -1163,38 +1235,41 @@ static void composeAffineMapAndOperands(AffineMap *map,
1163
1235
}
1164
1236
1165
1237
void mlir::affine::fullyComposeAffineMapAndOperands (
1166
- AffineMap *map, SmallVectorImpl<Value> *operands) {
1238
+ AffineMap *map, SmallVectorImpl<Value> *operands, bool composeAffineMin ) {
1167
1239
while (llvm::any_of (*operands, [](Value v) {
1168
1240
return isa_and_nonnull<AffineApplyOp>(v.getDefiningOp ());
1169
1241
})) {
1170
- composeAffineMapAndOperands (map, operands);
1242
+ composeAffineMapAndOperands (map, operands, composeAffineMin );
1171
1243
}
1172
1244
}
1173
1245
1174
1246
AffineApplyOp
1175
1247
mlir::affine::makeComposedAffineApply (OpBuilder &b, Location loc, AffineMap map,
1176
- ArrayRef<OpFoldResult> operands) {
1248
+ ArrayRef<OpFoldResult> operands,
1249
+ bool composeAffineMin) {
1177
1250
SmallVector<Value> valueOperands;
1178
1251
map = foldAttributesIntoMap (b, map, operands, valueOperands);
1179
- composeAffineMapAndOperands (&map, &valueOperands);
1252
+ composeAffineMapAndOperands (&map, &valueOperands, composeAffineMin );
1180
1253
assert (map);
1181
1254
return b.create <AffineApplyOp>(loc, map, valueOperands);
1182
1255
}
1183
1256
1184
1257
AffineApplyOp
1185
1258
mlir::affine::makeComposedAffineApply (OpBuilder &b, Location loc, AffineExpr e,
1186
- ArrayRef<OpFoldResult> operands) {
1259
+ ArrayRef<OpFoldResult> operands,
1260
+ bool composeAffineMin) {
1187
1261
return makeComposedAffineApply (
1188
1262
b, loc,
1189
1263
AffineMap::inferFromExprList (ArrayRef<AffineExpr>{e}, b.getContext ())
1190
1264
.front (),
1191
- operands);
1265
+ operands, composeAffineMin );
1192
1266
}
1193
1267
1194
1268
// / Composes the given affine map with the given list of operands, pulling in
1195
1269
// / the maps from any affine.apply operations that supply the operands.
1196
1270
static void composeMultiResultAffineMap (AffineMap &map,
1197
- SmallVectorImpl<Value> &operands) {
1271
+ SmallVectorImpl<Value> &operands,
1272
+ bool composeAffineMin = false ) {
1198
1273
// Compose and canonicalize each expression in the map individually because
1199
1274
// composition only applies to single-result maps, collecting potentially
1200
1275
// duplicate operands in a single list with shifted dimensions and symbols.
@@ -1203,7 +1278,8 @@ static void composeMultiResultAffineMap(AffineMap &map,
1203
1278
for (unsigned i : llvm::seq<unsigned >(0 , map.getNumResults ())) {
1204
1279
SmallVector<Value> submapOperands (operands.begin (), operands.end ());
1205
1280
AffineMap submap = map.getSubMap ({i});
1206
- fullyComposeAffineMapAndOperands (&submap, &submapOperands);
1281
+ fullyComposeAffineMapAndOperands (&submap, &submapOperands,
1282
+ composeAffineMin);
1207
1283
canonicalizeMapAndOperands (&submap, &submapOperands);
1208
1284
unsigned numNewDims = submap.getNumDims ();
1209
1285
submap = submap.shiftDims (dims.size ()).shiftSymbols (symbols.size ());
@@ -1221,10 +1297,9 @@ static void composeMultiResultAffineMap(AffineMap &map,
1221
1297
canonicalizeMapAndOperands (&map, &operands);
1222
1298
}
1223
1299
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) {
1228
1303
assert (map.getNumResults () == 1 && " building affine.apply with !=1 result" );
1229
1304
1230
1305
// Create new builder without a listener, so that no notification is
@@ -1236,7 +1311,7 @@ mlir::affine::makeComposedFoldedAffineApply(OpBuilder &b, Location loc,
1236
1311
1237
1312
// Create op.
1238
1313
AffineApplyOp applyOp =
1239
- makeComposedAffineApply (newBuilder, loc, map, operands);
1314
+ makeComposedAffineApply (newBuilder, loc, map, operands, composeAffineMin );
1240
1315
1241
1316
// Get constant operands.
1242
1317
SmallVector<Attribute> constOperands (applyOp->getNumOperands ());
@@ -1256,26 +1331,25 @@ mlir::affine::makeComposedFoldedAffineApply(OpBuilder &b, Location loc,
1256
1331
return llvm::getSingleElement (foldResults);
1257
1332
}
1258
1333
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) {
1263
1337
return makeComposedFoldedAffineApply (
1264
1338
b, loc,
1265
1339
AffineMap::inferFromExprList (ArrayRef<AffineExpr>{expr}, b.getContext ())
1266
1340
.front (),
1267
- operands);
1341
+ operands, composeAffineMin );
1268
1342
}
1269
1343
1270
1344
SmallVector<OpFoldResult>
1271
1345
mlir::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
+ });
1279
1353
}
1280
1354
1281
1355
template <typename OpTy>
@@ -3024,7 +3098,8 @@ void AffineIfOp::build(OpBuilder &builder, OperationState &result,
3024
3098
// / `set` by composing the maps of such affine.apply ops with the integer
3025
3099
// / set constraints.
3026
3100
static void composeSetAndOperands (IntegerSet &set,
3027
- SmallVectorImpl<Value> &operands) {
3101
+ SmallVectorImpl<Value> &operands,
3102
+ bool composeAffineMin = false ) {
3028
3103
// We will simply reuse the API of the map composition by viewing the LHSs of
3029
3104
// the equalities and inequalities of `set` as the affine exprs of an affine
3030
3105
// map. Convert to equivalent map, compose, and convert back to set.
@@ -3035,7 +3110,7 @@ static void composeSetAndOperands(IntegerSet &set,
3035
3110
[](Value v) { return v.getDefiningOp <AffineApplyOp>(); }))
3036
3111
return ;
3037
3112
3038
- composeAffineMapAndOperands (&map, &operands);
3113
+ composeAffineMapAndOperands (&map, &operands, composeAffineMin );
3039
3114
set = IntegerSet::get (map.getNumDims (), map.getNumSymbols (), map.getResults (),
3040
3115
set.getEqFlags ());
3041
3116
}
0 commit comments