[Mlir-commits] [mlir] f2e42d9 - [mlir][IntRangeInference] Handle ceildivsi(INT_MIN, x > 1) as expected (#116284)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Fri Nov 15 09:43:08 PST 2024
Author: Krzysztof Drewniak
Date: 2024-11-15T11:43:05-06:00
New Revision: f2e42d9324f488ef113b8d2157f52ef1699b95f9
URL: https://github.com/llvm/llvm-project/commit/f2e42d9324f488ef113b8d2157f52ef1699b95f9
DIFF: https://github.com/llvm/llvm-project/commit/f2e42d9324f488ef113b8d2157f52ef1699b95f9.diff
LOG: [mlir][IntRangeInference] Handle ceildivsi(INT_MIN, x > 1) as expected (#116284)
Fixes #115293
While the definition of ceildivsi is integer division, rounding up, most
implementations will use `-(-a / b)` for dividing `a ceildiv b` with `a`
negative and `b` positive.
Mathematically, and for most integers, these two definitions are
equivalent. However, with `a == INT_MIN`, the initial negation is a
noop, which means that, while divinding and rounding up would give a
negative result, `-((- INT_MIN) / b)` is `-(INT_MIN / b)`, which is
positive.
This commit adds a special case to ceilDivSI inference to handle this
case and bring it in line with the operational instead of the
mathematical semantics of ceiling division.
Added:
Modified:
mlir/lib/Interfaces/Utils/InferIntRangeCommon.cpp
mlir/test/Dialect/Arith/int-range-interface.mlir
Removed:
################################################################################
diff --git a/mlir/lib/Interfaces/Utils/InferIntRangeCommon.cpp b/mlir/lib/Interfaces/Utils/InferIntRangeCommon.cpp
index c5610ba5d3c0bc..0b085b10b2b337 100644
--- a/mlir/lib/Interfaces/Utils/InferIntRangeCommon.cpp
+++ b/mlir/lib/Interfaces/Utils/InferIntRangeCommon.cpp
@@ -375,6 +375,15 @@ mlir::intrange::inferCeilDivS(ArrayRef<ConstantIntRanges> argRanges) {
result.sadd_ov(APInt(result.getBitWidth(), 1), overflowed);
return overflowed ? std::optional<APInt>() : corrected;
}
+ // Special case where the usual implementation of ceilDiv causes
+ // INT_MIN / [positive number] to be positive. This doesn't match the
+ // definition of signed ceiling division mathematically, but it prevents
+ // inconsistent constant-folding results. This arises because (-int_min) is
+ // still negative, so -(-int_min / b) is -(int_min / b), which is
+ // positive See #115293.
+ if (lhs.isMinSignedValue() && rhs.sgt(1)) {
+ return -result;
+ }
return result;
};
return inferDivSRange(lhs, rhs, ceilDivSIFix);
diff --git a/mlir/test/Dialect/Arith/int-range-interface.mlir b/mlir/test/Dialect/Arith/int-range-interface.mlir
index 6d66da2fc1eb35..afb0b4929bce70 100644
--- a/mlir/test/Dialect/Arith/int-range-interface.mlir
+++ b/mlir/test/Dialect/Arith/int-range-interface.mlir
@@ -249,6 +249,19 @@ func.func @ceil_divsi(%arg0 : index) -> i1 {
func.return %10 : i1
}
+// CHECK-LABEL: func @ceil_divsi_intmin_bug_115293
+// CHECK: %[[ret:.*]] = arith.constant true
+// CHECK: return %[[ret]]
+func.func @ceil_divsi_intmin_bug_115293() -> i1 {
+ %intMin_i64 = test.with_bounds { smin = -9223372036854775808 : si64, smax = -9223372036854775808 : si64, umin = 9223372036854775808 : ui64, umax = 9223372036854775808 : ui64 } : i64
+ %denom_i64 = test.with_bounds { smin = 1189465982 : si64, smax = 1189465982 : si64, umin = 1189465982 : ui64, umax = 1189465982 : ui64 } : i64
+ %res_i64 = test.with_bounds { smin = 7754212542 : si64, smax = 7754212542 : si64, umin = 7754212542 : ui64, umax = 7754212542 : ui64 } : i64
+
+ %0 = arith.ceildivsi %intMin_i64, %denom_i64 : i64
+ %1 = arith.cmpi eq, %0, %res_i64 : i64
+ func.return %1 : i1
+}
+
// CHECK-LABEL: func @floor_divsi
// CHECK: %[[true:.*]] = arith.constant true
// CHECK: return %[[true]]
More information about the Mlir-commits
mailing list