[flang-commits] [flang] [flang][FIRToMemRef] Fix lowering of complex array component slices (z%re, z%im) (PR #191846)
Slava Zakharin via flang-commits
flang-commits at lists.llvm.org
Mon Apr 13 19:57:36 PDT 2026
================
@@ -0,0 +1,142 @@
+// RUN: fir-opt %s --fir-to-memref --allow-unregistered-dialect | FileCheck %s
+
+// Tests for fir.slice with a path component (projected component slice).
+// A projected slice changes the element type of the boxed view, e.g.
+// z%re projects complex<f32> -> f32. The layout (strides / base address)
+// must come from the projected box descriptor, NOT from reconstructing the
+// triplets, because memref.reinterpret_cast requires the same element type
+// on both sides and the triplet strides are in storage-element units
+// (complex<f32>) while the MemRef strides must be in projected-element units
+// (f32).
+//
+// Derived from:
+// complex, target :: z(4) = 0.
+// real, pointer :: r(:)
+// r => z%re
+// r = r + z(4:1:-1)%re
+
+// ----------------------------------------------------------------------------
+// Forward projected slice: z(1:4:1)%re
+// The slice path %c0 projects complex<f32> -> f32 (real part).
+// Expected lowering:
+// - fir.box_addr on the projected box (!fir.box<!fir.array<4xf32>>)
+// - fir.convert to memref<4xf32> (NOT to memref<4xcomplex<f32>>)
+// - index = i - 1 (1-based, no triplet arithmetic)
+// - strides from fir.box_dims / fir.box_elesize on the projected box
+// ----------------------------------------------------------------------------
+// CHECK-LABEL: func.func @projected_slice_fwd
+// CHECK: [[C1:%.*]] = arith.constant 1 : index
+// CHECK: [[C4:%.*]] = arith.constant 4 : index
+// CHECK: [[C0:%.*]] = arith.constant 0 : index
+// CHECK: [[SHAPE:%.*]] = fir.shape [[C4]] : (index) -> !fir.shape<1>
+// CHECK: [[SLICE:%.*]] = fir.slice [[C1]], [[C4]], [[C1]] path [[C0]] : (index, index, index, index) -> !fir.slice<1>
+// CHECK: [[EMBOX:%.*]] = fir.embox %arg0([[SHAPE]]) {{\[}}[[SLICE]]{{\]}} : (!fir.ref<!fir.array<4xcomplex<f32>>>, !fir.shape<1>, !fir.slice<1>) -> !fir.box<!fir.array<4xf32>>
+// CHECK: fir.do_loop [[I:%.*]] = [[C1]] to [[C4]] step [[C1]] unordered {
+// Projected box_addr gives f32 pointer, not complex<f32>.
+// CHECK: [[BOXADDR:%.*]] = fir.box_addr [[EMBOX]] : (!fir.box<!fir.array<4xf32>>) -> !fir.ref<!fir.array<4xf32>>
+// CHECK: [[CONVERT:%.*]] = fir.convert [[BOXADDR]] : (!fir.ref<!fir.array<4xf32>>) -> memref<4xf32>
+// Index: i-1 (1-based). The lowering emits: delta=i-1, scaled=delta*1,
+// offset=1-1=0, finalIdx=scaled+offset. The addi result is what feeds the load.
+// CHECK: [[C1_0:%.*]] = arith.constant 1 : index
+// CHECK: [[DELTA:%.*]] = arith.subi [[I]], [[C1_0]] : index
+// CHECK: [[SCALED:%.*]] = arith.muli [[DELTA]], [[C1_0]] : index
+// CHECK: [[OFFSET:%.*]] = arith.subi [[C1_0]], [[C1_0]] : index
+// CHECK: [[IDX:%.*]] = arith.addi [[SCALED]], [[OFFSET]] : index
+// Layout: extent and stride come from the projected box descriptor.
+// CHECK: [[ELE:%.*]] = fir.box_elesize [[EMBOX]] : (!fir.box<!fir.array<4xf32>>) -> index
+// CHECK: [[C0_0:%.*]] = arith.constant 0 : index
+// CHECK: [[DIMS:%.*]]:3 = fir.box_dims [[EMBOX]], [[C0_0]] : (!fir.box<!fir.array<4xf32>>, index) -> (index, index, index)
+// CHECK: [[STRIDE:%.*]] = arith.divsi [[DIMS]]#2, [[ELE]] : index
+// CHECK: [[C0_1:%.*]] = arith.constant 0 : index
+// CHECK: [[VIEW:%.*]] = memref.reinterpret_cast [[CONVERT]] to offset: {{\[}}[[C0_1]]{{\]}}, sizes: {{\[}}[[DIMS]]#1{{\]}}, strides: {{\[}}[[STRIDE]]{{\]}} : memref<4xf32> to memref<?xf32, strided<[?], offset: ?>>
+// CHECK: memref.load [[VIEW]]{{\[}}[[IDX]]{{\]}} : memref<?xf32, strided<[?], offset: ?>>
+func.func @projected_slice_fwd(%arg0: !fir.ref<!fir.array<4xcomplex<f32>>>) {
+ %c1 = arith.constant 1 : index
+ %c4 = arith.constant 4 : index
+ %c0 = arith.constant 0 : index
+ %shape = fir.shape %c4 : (index) -> !fir.shape<1>
+ %slice = fir.slice %c1, %c4, %c1 path %c0 : (index, index, index, index) -> !fir.slice<1>
+ %embox = fir.embox %arg0(%shape) [%slice] : (!fir.ref<!fir.array<4xcomplex<f32>>>, !fir.shape<1>, !fir.slice<1>) -> !fir.box<!fir.array<4xf32>>
+ fir.do_loop %i = %c1 to %c4 step %c1 unordered {
+ %coor = fir.array_coor %embox %i : (!fir.box<!fir.array<4xf32>>, index) -> !fir.ref<f32>
+ %val = fir.load %coor : !fir.ref<f32>
+ }
+ return
+}
+
+// ----------------------------------------------------------------------------
+// Reverse projected slice: z(4:1:-1)%re (the original bug reproducer)
----------------
vzakhari wrote:
I do not see how this test is different from the above one. I mean, I understand that the slice is different, but both cases pass the same paths in the new code. So it looks like this test is redundant.
https://github.com/llvm/llvm-project/pull/191846
More information about the flang-commits
mailing list