[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