[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