[flang-commits] [flang] [FIRToMemRef] Fix wrong indexing for converted array_coor over sliced fir.embox (PR #207749)
Kareem Ergawy via flang-commits
flang-commits at lists.llvm.org
Tue Jul 7 03:55:20 PDT 2026
================
@@ -456,6 +460,100 @@ static Value castTypeToIndexType(Value originalValue,
originalValue);
}
+/// Fold the embox's slice per-dim (lb - 1) shift into `indices` after
+/// `getMemrefIndices` has produced them. Handles both range and rank-reducing
+/// (scalar-subscript) slice triples uniformly.
+///
+/// Necessary because `getMemrefIndices` only consumes the first `rank*3`
+/// entries of `sliceInfo.sliceVec` (the array_coor's own slice); the embox's
+/// triples sit at `sliceVec[rank*3 .. 2*rank*3-1]` and are otherwise dropped,
+/// leaving the memref access short by `(lb - 1)` per dim -- and, for
+/// collapsed dims, additionally polluted with the array_coor's own scalar
+/// subscript (typically a loop variable) that would drag the load off the
+/// target dim across iterations.
+///
+/// Behaviour, per Fortran dim `d` of the embox slice (memref position
+/// `m = parentRank - 1 - d`):
+/// - Range triple `(lb, ub, step)`:
+/// indices[m] += (lb - 1)
+/// Adds the (lb - 1) shift on top of whatever `getMemrefIndices` produced
+/// for that dim.
+/// - Scalar-subscript triple `(lb, undef, undef)`:
+/// indices[m] = (lb - 1)
+/// Overwrites the memref position outright. The dim is collapsed in the
+/// box's rank, but the reinterpret_cast still keeps a memref index slot
+/// for it (with the correct parent stride). Placing `(lb - 1)` there is
+/// mathematically equivalent to shifting the flat offset by
+/// `(lb - 1) * parentStride[d]`, without needing any parent-shape
+/// lookups from the caller.
+///
+/// Example A -- non-rank-reducing (2-D):
+///
+/// `fir.array_coor %box(...)[%innerSlice] %i, %j` with
+/// - array_coor slice: identity in both dims
+/// - embox slice : `fir.slice %c2,%c2,%c1, %c1,%c1,%c1`
+/// (Fortran dim 0 lb = 2, dim 1 lb = 1)
+///
+/// Incoming `indices` (memref order): [ %j', %i' ]
+/// Fold:
+/// - dim 0 (range): delta = 1 -> indices[1] += 1
+/// - dim 1 (range): delta = 0 -> indices[0] += 0
+/// Result: [ %j', %i' + 1 ]
+///
+/// Example B -- rank-reducing (3-D parent, dim 1 collapsed):
+///
+/// %parent : !fir.ref<!fir.array<3x2x2xi32>>
+/// %shape = fir.shape %c3, %c2, %c2
+/// %eslc = fir.slice %c1, %c3, %c1, %c2, %undef, %undef, %c1, %c2, %c1
+/// %box = fir.embox %parent(%shape) [%eslc]
+/// : !fir.box<!fir.array<3x2xi32>>
+/// %bshape = fir.shape %c3, %c2 ; box's rank-2 shape
+/// %addr = fir.array_coor %box(%bshape) %ii, %jj
+/// : (!fir.box<!fir.array<3x2xi32>>, !fir.shape<2>, index, index)
+/// -> !fir.ref<i32>
+///
+/// parentRank = 3. `getRankFromEmbox` returns the parent's rank, so
+/// `getMemrefIndices` builds a rank-3 index vector (memref order):
+/// indices = [ %jj', <ac scalar sub for collapsed dim>, %ii' ]
+/// ^ dim 2 ^ dim 1 (collapsed) ^ dim 0
+///
+/// Fold:
+/// - dim 0 (range, lb=1): indices[2] += 0
+/// - dim 1 (scalar, lb=2): indices[1] = 1 (overwrite)
+/// - dim 2 (range, lb=1): indices[0] += 0
+///
+/// Final: `memref.load %reinterpret_cast[%jj', 1, %ii'] : memref<?x?x?xi32,
+/// strided<[?, ?, ?], offset: ?>>` -- stride 3 on the middle position
+/// lands on the correct plane, `offset` stays at 0.
+void FIRToMemRef::foldSliceLbIntoIndices(SmallVectorImpl<Value> &indices,
+ fir::EmboxOp embox,
+ PatternRewriter &rewriter,
+ Location loc) const {
+ auto sliceOp = getSliceOp(embox.getSlice());
+ if (!sliceOp)
+ return;
+ auto triples = sliceOp.getTriples();
+ unsigned parentRank = triples.size() / 3;
+ if (parentRank == 0)
+ return;
+
+ auto isUndef = [](Value v) {
+ return v && v.getDefiningOp<fir::UndefOp>() != nullptr;
+ };
+ Value cOne = arith::ConstantIndexOp::create(rewriter, loc, 1);
+ for (unsigned d = 0; d < parentRank; ++d) {
+ unsigned m = parentRank - 1 - d;
+ if (m >= indices.size())
+ continue;
+ Value lb = castTypeToIndexType(triples[d * 3], rewriter);
+ Value delta = arith::SubIOp::create(rewriter, loc, lb, cOne);
+ bool isScalar = isUndef(triples[d * 3 + 1]) || isUndef(triples[d * 3 + 2]);
+ indices[m] = isScalar
+ ? delta
+ : arith::AddIOp::create(rewriter, loc, indices[m], delta);
----------------
ergawy wrote:
Done. You uncovered a bug. The formula should be:
* 1-based indexing: `lb + (idx - 1) * stride`
* 0-based indexing: `(lb - 1) + idx * stride`.
Thanks a lot.
https://github.com/llvm/llvm-project/pull/207749
More information about the flang-commits
mailing list