[flang-commits] [flang] 3791c8b - [flang][FIRToMemRef] Non-box complex slices use shapeVec strides, not `fir.box_dims` (#200285)

via flang-commits flang-commits at lists.llvm.org
Fri May 29 07:02:32 PDT 2026


Author: Susan Tan (ス-ザン タン)
Date: 2026-05-29T10:02:25-04:00
New Revision: 3791c8b8773735a20fcb07f7f8d87fb2222b795c

URL: https://github.com/llvm/llvm-project/commit/3791c8b8773735a20fcb07f7f8d87fb2222b795c
DIFF: https://github.com/llvm/llvm-project/commit/3791c8b8773735a20fcb07f7f8d87fb2222b795c.diff

LOG: [flang][FIRToMemRef] Non-box complex slices use shapeVec strides, not `fir.box_dims` (#200285)

FIRToMemRef now lowers `fir.array_coor` on projected complex %re / %im
when the base is a contiguous `!fir.ref` with `fir.shape` (e.g. a static
component array in a derived type), without calling `fir.box_dims` on
the ref and with strides that match the memref<…×2×T> view.

Previously, any projected slice is lowered through the descriptor path
and produced invalid `fir.box_dims` on a ref. Fixed to take descriptor
strides only when the coor base is actually a box. For ref + shape, it
keeps the synthesized row-major layout and scales array strides by two
scalar slots per complex, with a re/im dimension (extent 2, stride 1).

Added: 
    

Modified: 
    flang/lib/Optimizer/Transforms/FIRToMemRef.cpp
    flang/test/Transforms/FIRToMemRef/slice-projected.mlir

Removed: 
    


################################################################################
diff  --git a/flang/lib/Optimizer/Transforms/FIRToMemRef.cpp b/flang/lib/Optimizer/Transforms/FIRToMemRef.cpp
index 26289c388fd3e..7186debace74e 100644
--- a/flang/lib/Optimizer/Transforms/FIRToMemRef.cpp
+++ b/flang/lib/Optimizer/Transforms/FIRToMemRef.cpp
@@ -725,17 +725,21 @@ FIRToMemRef::convertArrayCoorOp(Operation *memOp, fir::ArrayCoorOp arrayCoorOp,
   //     matches CodeGen XArrayCoorOp's non-boxed branch.
   //
   //   box_dims path: query the descriptor at runtime. Required when:
-  //     (a) the slice is projected (physical layout is owned by the box);
-  //     (b) we have no shape information at all; or
-  //     (c) the array_coor base is a fir.box that is NOT a fir.embox result.
+  //     (a) we have no shape information at all; or
+  //     (b) the array_coor base is a fir.box that is NOT a fir.embox result;
+  //         or a fir.box with a projected slice (layout in the descriptor); or
+  //     (c) embox cannot supply layout for this coor (non-embox box above).
   //         getFIRConvert materializes fir.box_addr(box) -- an opaque pointer
   //         with no layout in its type -- so strides must come from the
   //         descriptor. This matches CodeGen XArrayCoorOp's boxed branch
   //         (getStrideFromBox); shape/shape_shift on array_coor is
   //         informational only (lower bounds for index translation).
-  const bool descriptorOwnsLayout = sliceInfo.hasProjectedSlice ||
-                                    shapeVec.empty() ||
-                                    (firMemrefIsBox && !firMemrefIsEmbox);
+  //     Projected complex %re/%im on a bare ref uses the shapeVec path with
+  //     strides scaled by two scalar slots per complex.
+  const bool boxNeedsDescriptorStrides =
+      firMemrefIsBox && (!firMemrefIsEmbox || sliceInfo.hasProjectedSlice);
+  const bool descriptorOwnsLayout =
+      shapeVec.empty() || boxNeedsDescriptorStrides;
   if (descriptorOwnsLayout) {
     // Complex %re/%im: memref_stride = box_dims_byte_stride / sizeof(T),
     Value boxElementSize =
@@ -776,13 +780,28 @@ FIRToMemRef::convertArrayCoorOp(Operation *memOp, fir::ArrayCoorOp arrayCoorOp,
       Value stride = shapeVec[0];
       for (unsigned j = 1; j <= i - 1; ++j)
         stride = arith::MulIOp::create(rewriter, loc, shapeVec[j], stride);
+      if (complexPartIdx)
+        stride = arith::MulIOp::create(
+            rewriter, loc, stride,
+            arith::ConstantIndexOp::create(rewriter, loc, 2));
       strides.push_back(castTypeToIndexType(stride, rewriter));
     }
 
     sizes.push_back(castTypeToIndexType(shapeVec[0], rewriter));
-    strides.push_back(oneIdx);
+    // shapeVec strides count array elements (complexes).  After fir.convert to
+    // memref<...x2xT>, each step along an array dim must skip two scalars (re
+    // then im), so multiply by 2.  (Box path uses byte_stride / sizeof(T) for
+    // the same spacing; no /8 here because extents are already index units.)
+    if (complexPartIdx)
+      strides.push_back(arith::ConstantIndexOp::create(rewriter, loc, 2));
+    else
+      strides.push_back(oneIdx);
   }
 
+  // fir.convert above already made memref<...x2xT>; sizes/strides built so far
+  // cover only the array section (rank from array_coor).  Finish the
+  // reinterpret_cast layout with the pair dim that view already has: extent 2
+  // (re and im), stride 1 (contiguous scalars — index 0/1 from array_coor).
   if (complexPartIdx) {
     sizes.push_back(arith::ConstantIndexOp::create(rewriter, loc, 2));
     strides.push_back(arith::ConstantIndexOp::create(rewriter, loc, 1));

diff  --git a/flang/test/Transforms/FIRToMemRef/slice-projected.mlir b/flang/test/Transforms/FIRToMemRef/slice-projected.mlir
index 920b0b2185d45..7d29fca000fad 100644
--- a/flang/test/Transforms/FIRToMemRef/slice-projected.mlir
+++ b/flang/test/Transforms/FIRToMemRef/slice-projected.mlir
@@ -258,3 +258,49 @@ func.func @derived_component_not_projected(
   }
   return
 }
+
+// ----------------------------------------------------------------------------
+// ref + fir.shape + projected %re/%im (0093_0105): shapeVec path, no box_dims.
+// ----------------------------------------------------------------------------
+
+// CHECK-LABEL: func.func @projected_slice_ref_shapevec_stride_store
+// CHECK:       fir.do_loop
+// CHECK:         [[COMP:%[0-9]+]] = fir.convert %{{.*}} : (memref<5xcomplex<f32>>) -> memref<5x2xf32>
+// CHECK-NOT:     fir.box_dims %arg0
+// CHECK:         memref.reinterpret_cast [[COMP]]{{.*}}strides: [%c2{{.*}}, %c1{{.*}}] : memref<5x2xf32> to memref<?x?xf32, strided<
+// CHECK-NEXT:    memref.store
+func.func @projected_slice_ref_shapevec_stride_store(
+    %arg0: !fir.ref<!fir.array<5xcomplex<f32>>>, %arg1: f32) {
+  %c1 = arith.constant 1 : index
+  %c5 = arith.constant 5 : index
+  %c0 = arith.constant 0 : index
+  %shape = fir.shape %c5 : (index) -> !fir.shape<1>
+  %slice = fir.slice %c1, %c5, %c1 path %c0 : (index, index, index, index) -> !fir.slice<1>
+  fir.do_loop %i = %c1 to %c5 step %c1 unordered {
+    %coor = fir.array_coor %arg0 (%shape) [%slice] %i
+        : (!fir.ref<!fir.array<5xcomplex<f32>>>, !fir.shape<1>, !fir.slice<1>, index) -> !fir.ref<f32>
+    fir.store %arg1 to %coor : !fir.ref<f32>
+  }
+  return
+}
+
+// CHECK-LABEL: func.func @projected_slice_ref_shapevec_stride_load_im
+// CHECK:       fir.do_loop
+// CHECK:         [[COMP:%[0-9]+]] = fir.convert %{{.*}} : (memref<4xcomplex<f64>>) -> memref<4x2xf64>
+// CHECK-NOT:     fir.box_dims
+// CHECK:         memref.reinterpret_cast [[COMP]]{{.*}}strides: [%c2{{.*}}, %c1{{.*}}] : memref<4x2xf64> to memref<?x?xf64, strided<
+// CHECK-NEXT:    memref.load
+func.func @projected_slice_ref_shapevec_stride_load_im(
+    %arg0: !fir.ref<!fir.array<4xcomplex<f64>>>) {
+  %c1 = arith.constant 1 : index
+  %c4 = arith.constant 4 : index
+  %c1_im = arith.constant 1 : index
+  %shape = fir.shape %c4 : (index) -> !fir.shape<1>
+  %slice = fir.slice %c1, %c4, %c1 path %c1_im : (index, index, index, index) -> !fir.slice<1>
+  fir.do_loop %i = %c1 to %c4 step %c1 unordered {
+    %coor = fir.array_coor %arg0 (%shape) [%slice] %i
+        : (!fir.ref<!fir.array<4xcomplex<f64>>>, !fir.shape<1>, !fir.slice<1>, index) -> !fir.ref<f64>
+    %val = fir.load %coor : !fir.ref<f64>
+  }
+  return
+}


        


More information about the flang-commits mailing list