[flang-commits] [flang] [flang] Choose nsw/nuw/none for XArrayCoor slice steps (PR #212639)
via flang-commits
flang-commits at lists.llvm.org
Tue Jul 28 15:47:13 PDT 2026
https://github.com/khaki3 updated https://github.com/llvm/llvm-project/pull/212639
>From e5c9ec999eb843e26e2f55c79b29da23f6ff5267 Mon Sep 17 00:00:00 2001
From: Kazuaki Matsumura <kmatsumura at nvidia.com>
Date: Tue, 28 Jul 2026 15:25:43 -0700
Subject: [PATCH 1/3] [flang] Choose nsw/nuw/none for XArrayCoor slice steps
Reverse sections make idx*step negative; add/mul nuw is then poison
and LLVM -O2 can drop stores. Choose overflow flags from the pre-cast
slice step: nsw|nuw if positive, nsw if negative, none if zero/unknown.
---
flang/lib/Optimizer/CodeGen/CodeGen.cpp | 24 +++-
flang/test/Fir/array_coor_nuw_nusw.fir | 153 ++++++++++++++++++++++++
flang/test/Fir/convert-to-llvm.fir | 48 ++++----
3 files changed, 197 insertions(+), 28 deletions(-)
diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
index 0e88524126f11..1ec0bbeadc369 100644
--- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp
+++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
@@ -3075,17 +3075,33 @@ struct XArrayCoorOpConversion
if (normalSlice)
step = integerCast(loc, rewriter, idxTy, operands[sliceOffset + 2]);
}
+ // Choose wrap flags from the pre-cast step so constants stay visible.
+ // Positive const: nsw|nuw. Negative const: nsw only (nuw is poison).
+ // Zero/unknown: none.
+ mlir::LLVM::IntegerOverflowFlags indexFlags = addMulFlags;
+ if (normalSlice) {
+ mlir::Value stepOperand = operands[sliceOffset + 2];
+ if (std::optional<llvm::APInt> stepCst =
+ fir::getIntIfConstant(stepOperand)) {
+ if (stepCst->isZero())
+ indexFlags = mlir::LLVM::IntegerOverflowFlags::none;
+ else if (stepCst->isNegative())
+ indexFlags = nsw;
+ } else {
+ indexFlags = mlir::LLVM::IntegerOverflowFlags::none;
+ }
+ }
auto idx =
mlir::LLVM::SubOp::create(rewriter, loc, idxTy, index, lb, subFlags);
mlir::Value diff = mlir::LLVM::MulOp::create(rewriter, loc, idxTy, idx,
- step, addMulFlags);
+ step, indexFlags);
if (normalSlice) {
mlir::Value sliceLb =
integerCast(loc, rewriter, idxTy, operands[sliceOffset]);
auto adj = mlir::LLVM::SubOp::create(rewriter, loc, idxTy, sliceLb, lb,
subFlags);
diff = mlir::LLVM::AddOp::create(rewriter, loc, idxTy, diff, adj,
- addMulFlags);
+ indexFlags);
}
// Update the offset given the stride and the zero based index `diff`
// that was just computed.
@@ -3100,9 +3116,9 @@ struct XArrayCoorOpConversion
} else {
// Use stride computed at last iteration.
auto sc = mlir::LLVM::MulOp::create(rewriter, loc, idxTy, diff, prevExt,
- addMulFlags);
+ indexFlags);
offset = mlir::LLVM::AddOp::create(rewriter, loc, idxTy, sc, offset,
- addMulFlags);
+ indexFlags);
// Compute next stride assuming contiguity of the base array
// (in element number).
auto nextExt = integerCast(loc, rewriter, idxTy, operands[shapeOffset]);
diff --git a/flang/test/Fir/array_coor_nuw_nusw.fir b/flang/test/Fir/array_coor_nuw_nusw.fir
index f30c42096b17e..96dbcd7bbc331 100644
--- a/flang/test/Fir/array_coor_nuw_nusw.fir
+++ b/flang/test/Fir/array_coor_nuw_nusw.fir
@@ -33,3 +33,156 @@ func.func @ext_array_coor_shifted_nuw_ineligble(%arg0: !fir.ref<!fir.array<?xi32
// CHECK: %[[VAL_3:.*]] = llvm.add %[[VAL_2]], %{{.*}} overflow<nsw, nuw> : i64
// CHECK: %{{.*}} = llvm.getelementptr nusw|nuw %{{.*}}[%[[VAL_3]]] : (!llvm.ptr, i64) -> !llvm.ptr, i32
+// -----
+
+// Reverse section: known negative step — nsw ok, nuw is poison.
+
+func.func @ext_array_coor_reverse_slice(%arg0: !fir.ref<!fir.array<10xi32>>) {
+ %extent = arith.constant 10 : i64
+ %lb = arith.constant 10 : i64
+ %ub = arith.constant 1 : i64
+ %step = arith.constant -1 : i64
+ %idx = arith.constant 1 : i64
+ %0 = fircg.ext_array_coor %arg0(%extent)[%lb, %ub, %step]<%idx>
+ : (!fir.ref<!fir.array<10xi32>>, i64, i64, i64, i64, i64) -> !fir.ref<i32>
+ return
+}
+
+// CHECK-LABEL: llvm.func @ext_array_coor_reverse_slice(
+// CHECK: %[[IDX:.*]] = llvm.sub %{{.*}}, %{{.*}} overflow<nsw, nuw> : i64
+// CHECK: %[[DIFF0:.*]] = llvm.mul %[[IDX]], %{{.*}} overflow<nsw> : i64
+// CHECK: %[[ADJ:.*]] = llvm.sub %{{.*}}, %{{.*}} overflow<nsw, nuw> : i64
+// CHECK: %[[DIFF1:.*]] = llvm.add %[[DIFF0]], %[[ADJ]] overflow<nsw> : i64
+// CHECK: %[[STRIDE:.*]] = llvm.mul %[[DIFF1]], %{{.*}} overflow<nsw> : i64
+// CHECK: %[[OFFSET:.*]] = llvm.add %[[STRIDE]], %{{.*}} overflow<nsw> : i64
+// CHECK: %{{.*}} = llvm.getelementptr nusw|nuw %{{.*}}[%[[OFFSET]]] : (!llvm.ptr, i64) -> !llvm.ptr, i32
+
+// -----
+
+// Unknown step: cannot prove nsw or nuw.
+
+func.func @ext_array_coor_unknown_step(%arg0: !fir.ref<!fir.array<?xi32>>, %step: i64, %idx: i64) {
+ %extent = arith.constant 10 : i64
+ %lb = arith.constant 1 : i64
+ %ub = arith.constant 10 : i64
+ %0 = fircg.ext_array_coor %arg0(%extent)[%lb, %ub, %step]<%idx>
+ : (!fir.ref<!fir.array<?xi32>>, i64, i64, i64, i64, i64) -> !fir.ref<i32>
+ return
+}
+
+// CHECK-LABEL: llvm.func @ext_array_coor_unknown_step(
+// CHECK: %[[IDX:.*]] = llvm.sub %{{.*}}, %{{.*}} overflow<nsw, nuw> : i64
+// CHECK: %[[DIFF0:.*]] = llvm.mul %[[IDX]], %{{.*}} : i64
+// CHECK: %[[ADJ:.*]] = llvm.sub %{{.*}}, %{{.*}} overflow<nsw, nuw> : i64
+// CHECK: %[[DIFF1:.*]] = llvm.add %[[DIFF0]], %[[ADJ]] : i64
+// CHECK: %[[STRIDE:.*]] = llvm.mul %[[DIFF1]], %{{.*}} : i64
+// CHECK: %[[OFFSET:.*]] = llvm.add %[[STRIDE]], %{{.*}} : i64
+
+// -----
+
+// Known positive step > 1: nsw|nuw.
+
+func.func @ext_array_coor_step_pos2(%arg0: !fir.ref<!fir.array<10xi32>>) {
+ %extent = arith.constant 10 : i64
+ %lb = arith.constant 1 : i64
+ %ub = arith.constant 9 : i64
+ %step = arith.constant 2 : i64
+ %idx = arith.constant 1 : i64
+ %0 = fircg.ext_array_coor %arg0(%extent)[%lb, %ub, %step]<%idx>
+ : (!fir.ref<!fir.array<10xi32>>, i64, i64, i64, i64, i64) -> !fir.ref<i32>
+ return
+}
+
+// CHECK-LABEL: llvm.func @ext_array_coor_step_pos2(
+// CHECK: %[[IDX:.*]] = llvm.sub %{{.*}}, %{{.*}} overflow<nsw, nuw> : i64
+// CHECK: %[[DIFF0:.*]] = llvm.mul %[[IDX]], %{{.*}} overflow<nsw, nuw> : i64
+// CHECK: %[[ADJ:.*]] = llvm.sub %{{.*}}, %{{.*}} overflow<nsw, nuw> : i64
+// CHECK: %[[DIFF1:.*]] = llvm.add %[[DIFF0]], %[[ADJ]] overflow<nsw, nuw> : i64
+// CHECK: %[[STRIDE:.*]] = llvm.mul %[[DIFF1]], %{{.*}} overflow<nsw, nuw> : i64
+// CHECK: %[[OFFSET:.*]] = llvm.add %[[STRIDE]], %{{.*}} overflow<nsw, nuw> : i64
+// CHECK: %{{.*}} = llvm.getelementptr nusw|nuw %{{.*}}[%[[OFFSET]]] : (!llvm.ptr, i64) -> !llvm.ptr, i32
+
+// -----
+
+// Known negative step < -1: nsw only.
+
+func.func @ext_array_coor_step_neg2(%arg0: !fir.ref<!fir.array<10xi32>>) {
+ %extent = arith.constant 10 : i64
+ %lb = arith.constant 9 : i64
+ %ub = arith.constant 1 : i64
+ %step = arith.constant -2 : i64
+ %idx = arith.constant 1 : i64
+ %0 = fircg.ext_array_coor %arg0(%extent)[%lb, %ub, %step]<%idx>
+ : (!fir.ref<!fir.array<10xi32>>, i64, i64, i64, i64, i64) -> !fir.ref<i32>
+ return
+}
+
+// CHECK-LABEL: llvm.func @ext_array_coor_step_neg2(
+// CHECK: %[[IDX:.*]] = llvm.sub %{{.*}}, %{{.*}} overflow<nsw, nuw> : i64
+// CHECK: %[[DIFF0:.*]] = llvm.mul %[[IDX]], %{{.*}} overflow<nsw> : i64
+// CHECK: %[[ADJ:.*]] = llvm.sub %{{.*}}, %{{.*}} overflow<nsw, nuw> : i64
+// CHECK: %[[DIFF1:.*]] = llvm.add %[[DIFF0]], %[[ADJ]] overflow<nsw> : i64
+// CHECK: %[[STRIDE:.*]] = llvm.mul %[[DIFF1]], %{{.*}} overflow<nsw> : i64
+// CHECK: %[[OFFSET:.*]] = llvm.add %[[STRIDE]], %{{.*}} overflow<nsw> : i64
+// CHECK: %{{.*}} = llvm.getelementptr nusw|nuw %{{.*}}[%[[OFFSET]]] : (!llvm.ptr, i64) -> !llvm.ptr, i32
+
+// -----
+
+// Per-dimension flags: dim0 step +2 → nsw|nuw, dim1 step -1 → nsw.
+
+func.func @ext_array_coor_mixed_steps(%arg0: !fir.ref<!fir.array<10x10xi32>>) {
+ %e = arith.constant 10 : i64
+ %lb0 = arith.constant 1 : i64
+ %ub0 = arith.constant 9 : i64
+ %s0 = arith.constant 2 : i64
+ %lb1 = arith.constant 10 : i64
+ %ub1 = arith.constant 1 : i64
+ %s1 = arith.constant -1 : i64
+ %i = arith.constant 1 : i64
+ %0 = fircg.ext_array_coor %arg0(%e, %e)[%lb0, %ub0, %s0, %lb1, %ub1, %s1]<%i, %i>
+ : (!fir.ref<!fir.array<10x10xi32>>, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64) -> !fir.ref<i32>
+ return
+}
+
+// CHECK-LABEL: llvm.func @ext_array_coor_mixed_steps(
+// CHECK: %[[IDX0:.*]] = llvm.sub %{{.*}}, %{{.*}} overflow<nsw, nuw> : i64
+// CHECK: %[[DIFF0:.*]] = llvm.mul %[[IDX0]], %{{.*}} overflow<nsw, nuw> : i64
+// CHECK: %[[ADJ0:.*]] = llvm.sub %{{.*}}, %{{.*}} overflow<nsw, nuw> : i64
+// CHECK: %[[DIFF1:.*]] = llvm.add %[[DIFF0]], %[[ADJ0]] overflow<nsw, nuw> : i64
+// CHECK: %[[STRIDE0:.*]] = llvm.mul %[[DIFF1]], %{{.*}} overflow<nsw, nuw> : i64
+// CHECK: %[[OFFSET0:.*]] = llvm.add %[[STRIDE0]], %{{.*}} overflow<nsw, nuw> : i64
+// CHECK: %[[EXT:.*]] = llvm.mul %{{.*}}, %{{.*}} overflow<nsw, nuw> : i64
+// CHECK: %[[IDX1:.*]] = llvm.sub %{{.*}}, %{{.*}} overflow<nsw, nuw> : i64
+// CHECK: %[[DIFF2:.*]] = llvm.mul %[[IDX1]], %{{.*}} overflow<nsw> : i64
+// CHECK: %[[ADJ1:.*]] = llvm.sub %{{.*}}, %{{.*}} overflow<nsw, nuw> : i64
+// CHECK: %[[DIFF3:.*]] = llvm.add %[[DIFF2]], %[[ADJ1]] overflow<nsw> : i64
+// CHECK: %[[STRIDE1:.*]] = llvm.mul %[[DIFF3]], %[[EXT]] overflow<nsw> : i64
+// CHECK: %[[OFFSET1:.*]] = llvm.add %[[STRIDE1]], %[[OFFSET0]] overflow<nsw> : i64
+// CHECK: %{{.*}} = llvm.getelementptr nusw|nuw %{{.*}}[%[[OFFSET1]]] : (!llvm.ptr, i64) -> !llvm.ptr, i32
+
+// -----
+
+// Boxed reverse slice: indexFlags nsw on idx*step/diff+adj; byte stride mul/add always nsw.
+
+func.func @ext_array_coor_boxed_reverse(%arg0: !fir.box<!fir.array<?xi32>>) {
+ %extent = arith.constant 10 : i64
+ %lb = arith.constant 10 : i64
+ %ub = arith.constant 1 : i64
+ %step = arith.constant -1 : i64
+ %idx = arith.constant 1 : i64
+ %0 = fircg.ext_array_coor %arg0(%extent)[%lb, %ub, %step]<%idx>
+ : (!fir.box<!fir.array<?xi32>>, i64, i64, i64, i64, i64) -> !fir.ref<i32>
+ return
+}
+
+// CHECK-LABEL: llvm.func @ext_array_coor_boxed_reverse(
+// CHECK: %[[IDX:.*]] = llvm.sub %{{.*}}, %{{.*}} overflow<nsw, nuw> : i64
+// CHECK: %[[DIFF0:.*]] = llvm.mul %[[IDX]], %{{.*}} overflow<nsw> : i64
+// CHECK: %[[ADJ:.*]] = llvm.sub %{{.*}}, %{{.*}} overflow<nsw, nuw> : i64
+// CHECK: %[[DIFF1:.*]] = llvm.add %[[DIFF0]], %[[ADJ]] overflow<nsw> : i64
+// CHECK: %[[STRIDE:.*]] = llvm.load %{{.*}} : !llvm.ptr -> i64
+// CHECK: %[[SC:.*]] = llvm.mul %[[DIFF1]], %[[STRIDE]] overflow<nsw> : i64
+// CHECK: %[[OFFSET:.*]] = llvm.add %[[SC]], %{{.*}} overflow<nsw> : i64
+// CHECK: %[[BASE:.*]] = llvm.load %{{.*}} : !llvm.ptr -> !llvm.ptr
+// CHECK: %{{.*}} = llvm.getelementptr nusw %[[BASE]][%[[OFFSET]]] : (!llvm.ptr, i64) -> !llvm.ptr, i8
+
diff --git a/flang/test/Fir/convert-to-llvm.fir b/flang/test/Fir/convert-to-llvm.fir
index 5209cb26d782c..d69156d5498c2 100644
--- a/flang/test/Fir/convert-to-llvm.fir
+++ b/flang/test/Fir/convert-to-llvm.fir
@@ -2260,11 +2260,11 @@ func.func @ext_array_coor1(%arg0: !fir.ref<!fir.array<?xi32>>) {
// CHECK: %[[C1:.*]] = llvm.mlir.constant(1 : i64) : i64
// CHECK: %[[C0_1:.*]] = llvm.mlir.constant(0 : i64) : i64
// CHECK: %[[IDX:.*]] = llvm.sub %[[C0]], %[[C0]] overflow<nsw> : i64
-// CHECK: %[[DIFF0:.*]] = llvm.mul %[[IDX]], %[[C0]] overflow<nsw, nuw> : i64
+// CHECK: %[[DIFF0:.*]] = llvm.mul %[[IDX]], %[[C0]] : i64
// CHECK: %[[ADJ:.*]] = llvm.sub %[[C0]], %[[C0]] overflow<nsw> : i64
-// CHECK: %[[DIFF1:.*]] = llvm.add %[[DIFF0]], %[[ADJ]] overflow<nsw, nuw> : i64
-// CHECK: %[[STRIDE:.*]] = llvm.mul %[[DIFF1]], %[[C1]] overflow<nsw, nuw> : i64
-// CHECK: %[[OFFSET:.*]] = llvm.add %[[STRIDE]], %[[C0_1]] overflow<nsw, nuw> : i64
+// CHECK: %[[DIFF1:.*]] = llvm.add %[[DIFF0]], %[[ADJ]] : i64
+// CHECK: %[[STRIDE:.*]] = llvm.mul %[[DIFF1]], %[[C1]] : i64
+// CHECK: %[[OFFSET:.*]] = llvm.add %[[STRIDE]], %[[C0_1]] : i64
// CHECK: %{{.*}} = llvm.getelementptr nusw|nuw %[[ARG0]][%[[OFFSET]]] : (!llvm.ptr, i64) -> !llvm.ptr, i32
// Conversion for a dynamic length char.
@@ -2348,11 +2348,11 @@ func.func @ext_array_coor5(%arg0: !fir.ref<!fir.array<?xi32>>, %idx1 : index, %i
// CHECK: %[[VAL_6:.*]] = llvm.mlir.constant(1 : i64) : i64
// CHECK: %[[VAL_7:.*]] = llvm.mlir.constant(0 : i64) : i64
// CHECK: %[[VAL_8:.*]] = llvm.sub %[[VAL_5]], %[[VAL_6]] overflow<nsw, nuw> : i64
-// CHECK: %[[VAL_9:.*]] = llvm.mul %[[VAL_8]], %[[VAL_4]] overflow<nsw, nuw> : i64
+// CHECK: %[[VAL_9:.*]] = llvm.mul %[[VAL_8]], %[[VAL_4]] : i64
// CHECK: %[[VAL_10:.*]] = llvm.sub %[[VAL_2]], %[[VAL_6]] overflow<nsw, nuw> : i64
-// CHECK: %[[VAL_11:.*]] = llvm.add %[[VAL_9]], %[[VAL_10]] overflow<nsw, nuw> : i64
-// CHECK: %[[VAL_12:.*]] = llvm.mul %[[VAL_11]], %[[VAL_6]] overflow<nsw, nuw> : i64
-// CHECK: %[[VAL_13:.*]] = llvm.add %[[VAL_12]], %[[VAL_7]] overflow<nsw, nuw> : i64
+// CHECK: %[[VAL_11:.*]] = llvm.add %[[VAL_9]], %[[VAL_10]] : i64
+// CHECK: %[[VAL_12:.*]] = llvm.mul %[[VAL_11]], %[[VAL_6]] : i64
+// CHECK: %[[VAL_13:.*]] = llvm.add %[[VAL_12]], %[[VAL_7]] : i64
// CHECK: %[[VAL_14:.*]] = llvm.mul %[[VAL_6]], %[[VAL_1]] overflow<nsw, nuw> : i64
// CHECK: %[[VAL_16:.*]] = llvm.getelementptr nusw|nuw %[[VAL_0]][%[[VAL_13]]] : (!llvm.ptr, i64) -> !llvm.ptr, i32
// CHECK: }
@@ -2369,25 +2369,25 @@ func.func @ext_array_coor6(%arg0: !fir.ref<!fir.array<?x?x?xi32>>, %idx1 : index
// CHECK: %[[VAL_6:.*]] = llvm.mlir.constant(1 : i64) : i64
// CHECK: %[[VAL_7:.*]] = llvm.mlir.constant(0 : i64) : i64
// CHECK: %[[VAL_8:.*]] = llvm.sub %[[VAL_5]], %[[VAL_6]] overflow<nsw, nuw> : i64
-// CHECK: %[[VAL_9:.*]] = llvm.mul %[[VAL_8]], %[[VAL_4]] overflow<nsw, nuw> : i64
+// CHECK: %[[VAL_9:.*]] = llvm.mul %[[VAL_8]], %[[VAL_4]] : i64
// CHECK: %[[VAL_10:.*]] = llvm.sub %[[VAL_2]], %[[VAL_6]] overflow<nsw, nuw> : i64
-// CHECK: %[[VAL_11:.*]] = llvm.add %[[VAL_9]], %[[VAL_10]] overflow<nsw, nuw> : i64
-// CHECK: %[[VAL_12:.*]] = llvm.mul %[[VAL_11]], %[[VAL_6]] overflow<nsw, nuw> : i64
-// CHECK: %[[VAL_13:.*]] = llvm.add %[[VAL_12]], %[[VAL_7]] overflow<nsw, nuw> : i64
+// CHECK: %[[VAL_11:.*]] = llvm.add %[[VAL_9]], %[[VAL_10]] : i64
+// CHECK: %[[VAL_12:.*]] = llvm.mul %[[VAL_11]], %[[VAL_6]] : i64
+// CHECK: %[[VAL_13:.*]] = llvm.add %[[VAL_12]], %[[VAL_7]] : i64
// CHECK: %[[VAL_14:.*]] = llvm.mul %[[VAL_6]], %[[VAL_1]] overflow<nsw, nuw> : i64
// CHECK: %[[VAL_15:.*]] = llvm.sub %[[VAL_5]], %[[VAL_6]] overflow<nsw, nuw> : i64
-// CHECK: %[[VAL_16:.*]] = llvm.mul %[[VAL_15]], %[[VAL_4]] overflow<nsw, nuw> : i64
+// CHECK: %[[VAL_16:.*]] = llvm.mul %[[VAL_15]], %[[VAL_4]] : i64
// CHECK: %[[VAL_17:.*]] = llvm.sub %[[VAL_2]], %[[VAL_6]] overflow<nsw, nuw> : i64
-// CHECK: %[[VAL_18:.*]] = llvm.add %[[VAL_16]], %[[VAL_17]] overflow<nsw, nuw> : i64
-// CHECK: %[[VAL_19:.*]] = llvm.mul %[[VAL_18]], %[[VAL_14]] overflow<nsw, nuw> : i64
-// CHECK: %[[VAL_20:.*]] = llvm.add %[[VAL_19]], %[[VAL_13]] overflow<nsw, nuw> : i64
+// CHECK: %[[VAL_18:.*]] = llvm.add %[[VAL_16]], %[[VAL_17]] : i64
+// CHECK: %[[VAL_19:.*]] = llvm.mul %[[VAL_18]], %[[VAL_14]] : i64
+// CHECK: %[[VAL_20:.*]] = llvm.add %[[VAL_19]], %[[VAL_13]] : i64
// CHECK: %[[VAL_21:.*]] = llvm.mul %[[VAL_14]], %[[VAL_1]] overflow<nsw, nuw> : i64
// CHECK: %[[VAL_22:.*]] = llvm.sub %[[VAL_5]], %[[VAL_6]] overflow<nsw, nuw> : i64
-// CHECK: %[[VAL_23:.*]] = llvm.mul %[[VAL_22]], %[[VAL_4]] overflow<nsw, nuw> : i64
+// CHECK: %[[VAL_23:.*]] = llvm.mul %[[VAL_22]], %[[VAL_4]] : i64
// CHECK: %[[VAL_24:.*]] = llvm.sub %[[VAL_2]], %[[VAL_6]] overflow<nsw, nuw> : i64
-// CHECK: %[[VAL_25:.*]] = llvm.add %[[VAL_23]], %[[VAL_24]] overflow<nsw, nuw> : i64
-// CHECK: %[[VAL_26:.*]] = llvm.mul %[[VAL_25]], %[[VAL_21]] overflow<nsw, nuw> : i64
-// CHECK: %[[VAL_27:.*]] = llvm.add %[[VAL_26]], %[[VAL_20]] overflow<nsw, nuw> : i64
+// CHECK: %[[VAL_25:.*]] = llvm.add %[[VAL_23]], %[[VAL_24]] : i64
+// CHECK: %[[VAL_26:.*]] = llvm.mul %[[VAL_25]], %[[VAL_21]] : i64
+// CHECK: %[[VAL_27:.*]] = llvm.add %[[VAL_26]], %[[VAL_20]] : i64
// CHECK: %[[VAL_28:.*]] = llvm.mul %[[VAL_21]], %[[VAL_1]] overflow<nsw, nuw> : i64
// CHECK: %[[VAL_30:.*]] = llvm.getelementptr nusw|nuw %[[VAL_0]][%[[VAL_27]]] : (!llvm.ptr, i64) -> !llvm.ptr, i32
// CHECK: llvm.return
@@ -2407,11 +2407,11 @@ func.func @ext_array_coor_dt_slice(%arg0: !fir.ref<!fir.array<20x!fir.type<_QFte
// CHECK: %[[VAL_7:.*]] = llvm.mlir.constant(1 : i64) : i64
// CHECK: %[[VAL_8:.*]] = llvm.mlir.constant(0 : i64) : i64
// CHECK: %[[VAL_9:.*]] = llvm.sub %[[VAL_5]], %[[VAL_7]] overflow<nsw, nuw> : i64
-// CHECK: %[[VAL_10:.*]] = llvm.mul %[[VAL_9]], %[[VAL_4]] overflow<nsw, nuw> : i64
+// CHECK: %[[VAL_10:.*]] = llvm.mul %[[VAL_9]], %[[VAL_4]] : i64
// CHECK: %[[VAL_11:.*]] = llvm.sub %[[VAL_2]], %[[VAL_7]] overflow<nsw, nuw> : i64
-// CHECK: %[[VAL_12:.*]] = llvm.add %[[VAL_10]], %[[VAL_11]] overflow<nsw, nuw> : i64
-// CHECK: %[[VAL_13:.*]] = llvm.mul %[[VAL_12]], %[[VAL_7]] overflow<nsw, nuw> : i64
-// CHECK: %[[VAL_14:.*]] = llvm.add %[[VAL_13]], %[[VAL_8]] overflow<nsw, nuw> : i64
+// CHECK: %[[VAL_12:.*]] = llvm.add %[[VAL_10]], %[[VAL_11]] : i64
+// CHECK: %[[VAL_13:.*]] = llvm.mul %[[VAL_12]], %[[VAL_7]] : i64
+// CHECK: %[[VAL_14:.*]] = llvm.add %[[VAL_13]], %[[VAL_8]] : i64
// CHECK: %[[VAL_15:.*]] = llvm.mul %[[VAL_7]], %[[VAL_1]] overflow<nsw, nuw> : i64
// CHECK: %[[VAL_17:.*]] = llvm.getelementptr nusw|nuw %[[VAL_0]][%[[VAL_14]], 0] : (!llvm.ptr, i64) -> !llvm.ptr, !llvm.struct<"_QFtest_dt_sliceTt", (i32, i32)>
// CHECK: llvm.return
>From 979cc4a2fd222094e8df814f44d90bb2dd5bb1f5 Mon Sep 17 00:00:00 2001
From: Kazuaki Matsumura <kmatsumura at nvidia.com>
Date: Tue, 28 Jul 2026 15:37:19 -0700
Subject: [PATCH 2/3] [flang] Clarify XArrayCoor slice wrap-flag comments
---
flang/lib/Optimizer/CodeGen/CodeGen.cpp | 5 ++---
flang/test/Fir/array_coor_nuw_nusw.fir | 2 +-
2 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
index 1ec0bbeadc369..5332be2b45858 100644
--- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp
+++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
@@ -3075,9 +3075,8 @@ struct XArrayCoorOpConversion
if (normalSlice)
step = integerCast(loc, rewriter, idxTy, operands[sliceOffset + 2]);
}
- // Choose wrap flags from the pre-cast step so constants stay visible.
- // Positive const: nsw|nuw. Negative const: nsw only (nuw is poison).
- // Zero/unknown: none.
+ // Wrap flags from the pre-cast step (keeps constants recognizable).
+ // Positive: nsw|nuw. Negative: nsw (result may be < 0). Zero/unknown: none.
mlir::LLVM::IntegerOverflowFlags indexFlags = addMulFlags;
if (normalSlice) {
mlir::Value stepOperand = operands[sliceOffset + 2];
diff --git a/flang/test/Fir/array_coor_nuw_nusw.fir b/flang/test/Fir/array_coor_nuw_nusw.fir
index 96dbcd7bbc331..fc6449fe7a0d6 100644
--- a/flang/test/Fir/array_coor_nuw_nusw.fir
+++ b/flang/test/Fir/array_coor_nuw_nusw.fir
@@ -35,7 +35,7 @@ func.func @ext_array_coor_shifted_nuw_ineligble(%arg0: !fir.ref<!fir.array<?xi32
// -----
-// Reverse section: known negative step — nsw ok, nuw is poison.
+// Reverse section: known negative step — nsw only (result may be < 0).
func.func @ext_array_coor_reverse_slice(%arg0: !fir.ref<!fir.array<10xi32>>) {
%extent = arith.constant 10 : i64
>From ef41aab6b9752bdd2a16092ae51c337a96e9867c Mon Sep 17 00:00:00 2001
From: Kazuaki Matsumura <kmatsumura at nvidia.com>
Date: Tue, 28 Jul 2026 15:46:46 -0700
Subject: [PATCH 3/3] [flang] clang-format XArrayCoor wrap-flag comment
---
flang/lib/Optimizer/CodeGen/CodeGen.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
index 5332be2b45858..2ef3dcb7b2c1b 100644
--- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp
+++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
@@ -3076,7 +3076,8 @@ struct XArrayCoorOpConversion
step = integerCast(loc, rewriter, idxTy, operands[sliceOffset + 2]);
}
// Wrap flags from the pre-cast step (keeps constants recognizable).
- // Positive: nsw|nuw. Negative: nsw (result may be < 0). Zero/unknown: none.
+ // Positive: nsw|nuw. Negative: nsw (result may be < 0). Zero/unknown:
+ // none.
mlir::LLVM::IntegerOverflowFlags indexFlags = addMulFlags;
if (normalSlice) {
mlir::Value stepOperand = operands[sliceOffset + 2];
More information about the flang-commits
mailing list