[Mlir-commits] [mlir] [mlir][arith] Fix overflow flags when folding nested truncations (PR #233167)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Sat Oct 17 20:13:16 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-mlir
Author: Matthias Springer (matthias-springer)
<details>
<summary>Changes</summary>
Assisted-by: Codex
---
Full diff: https://github.com/llvm/llvm-project/pull/233167.diff
2 Files Affected:
- (modified) mlir/lib/Dialect/Arith/IR/ArithOps.cpp (+5-3)
- (modified) mlir/test/Dialect/Arith/canonicalize.mlir (+52)
``````````diff
diff --git a/mlir/lib/Dialect/Arith/IR/ArithOps.cpp b/mlir/lib/Dialect/Arith/IR/ArithOps.cpp
index 40fcfa5c458819..b2a69cfa0877f8 100644
--- a/mlir/lib/Dialect/Arith/IR/ArithOps.cpp
+++ b/mlir/lib/Dialect/Arith/IR/ArithOps.cpp
@@ -2041,9 +2041,11 @@ OpFoldResult arith::TruncIOp::fold(FoldAdaptor adaptor) {
return src;
}
- // trunci(trunci(a)) -> trunci(a))
- if (matchPattern(getOperand(), m_Op<arith::TruncIOp>())) {
- setOperand(getOperand().getDefiningOp()->getOperand(0));
+ // trunci(trunci(a)) -> trunci(a)
+ if (auto truncOp = getOperand().getDefiningOp<arith::TruncIOp>()) {
+ // Preserve a flag only if both truncations are lossless in that signedness.
+ setOverflowFlags(getOverflowFlags() & truncOp.getOverflowFlags());
+ setOperand(truncOp.getIn());
return getResult();
}
diff --git a/mlir/test/Dialect/Arith/canonicalize.mlir b/mlir/test/Dialect/Arith/canonicalize.mlir
index 0da65a4a0f4028..797cf996b773dd 100644
--- a/mlir/test/Dialect/Arith/canonicalize.mlir
+++ b/mlir/test/Dialect/Arith/canonicalize.mlir
@@ -1668,6 +1668,58 @@ func.func @truncTrunc(%arg0: i64) -> i8 {
return %tr2 : i8
}
+// The first truncation may discard nonzero bits. For example, 65537 truncates
+// to 1 without poison, but a direct flagged truncation would produce poison.
+// CHECK-LABEL: @truncTruncDropFlags(
+// CHECK-SAME: %[[ARG:.*]]: i32
+// CHECK-NEXT: %[[RES:.*]] = arith.trunci %[[ARG]] : i32 to i8
+// CHECK-NEXT: return %[[RES]] : i8
+func.func @truncTruncDropFlags(%arg0: i32) -> i8 {
+ %tr1 = arith.trunci %arg0 : i32 to i16
+ %tr2 = arith.trunci %tr1 overflow<nsw, nuw> : i16 to i8
+ return %tr2 : i8
+}
+
+// CHECK-LABEL: @truncTruncNsw(
+// CHECK-SAME: %[[ARG:.*]]: i32
+// CHECK-NEXT: %[[RES:.*]] = arith.trunci %[[ARG]] overflow<nsw> : i32 to i8
+// CHECK-NEXT: return %[[RES]] : i8
+func.func @truncTruncNsw(%arg0: i32) -> i8 {
+ %tr1 = arith.trunci %arg0 overflow<nsw> : i32 to i16
+ %tr2 = arith.trunci %tr1 overflow<nsw, nuw> : i16 to i8
+ return %tr2 : i8
+}
+
+// CHECK-LABEL: @truncTruncNuw(
+// CHECK-SAME: %[[ARG:.*]]: i32
+// CHECK-NEXT: %[[RES:.*]] = arith.trunci %[[ARG]] overflow<nuw> : i32 to i8
+// CHECK-NEXT: return %[[RES]] : i8
+func.func @truncTruncNuw(%arg0: i32) -> i8 {
+ %tr1 = arith.trunci %arg0 overflow<nuw> : i32 to i16
+ %tr2 = arith.trunci %tr1 overflow<nsw, nuw> : i16 to i8
+ return %tr2 : i8
+}
+
+// CHECK-LABEL: @truncTruncBothFlags(
+// CHECK-SAME: %[[ARG:.*]]: i32
+// CHECK-NEXT: %[[RES:.*]] = arith.trunci %[[ARG]] overflow<nsw, nuw> : i32 to i8
+// CHECK-NEXT: return %[[RES]] : i8
+func.func @truncTruncBothFlags(%arg0: i32) -> i8 {
+ %tr1 = arith.trunci %arg0 overflow<nsw, nuw> : i32 to i16
+ %tr2 = arith.trunci %tr1 overflow<nsw, nuw> : i16 to i8
+ return %tr2 : i8
+}
+
+// CHECK-LABEL: @truncTruncDisjointFlags(
+// CHECK-SAME: %[[ARG:.*]]: i32
+// CHECK-NEXT: %[[RES:.*]] = arith.trunci %[[ARG]] : i32 to i8
+// CHECK-NEXT: return %[[RES]] : i8
+func.func @truncTruncDisjointFlags(%arg0: i32) -> i8 {
+ %tr1 = arith.trunci %arg0 overflow<nsw> : i32 to i16
+ %tr2 = arith.trunci %tr1 overflow<nuw> : i16 to i8
+ return %tr2 : i8
+}
+
// CHECK-LABEL: @truncFPConstant
// CHECK: %[[cres:.+]] = arith.constant 1.000000e+00 : bf16
// CHECK: return %[[cres]]
``````````
</details>
https://github.com/llvm/llvm-project/pull/233167
More information about the Mlir-commits
mailing list