# \[RFC\] Assumed-shape dummy arrays repacking

**URL:** <https://discourse.llvm.org/t/rfc-assumed-shape-dummy-arrays-repacking/85589>\
**Category:** Flang\
**Created:** [March 31, 2025, 8:14pm UTC](https://discourse.llvm.org/t/rfc-assumed-shape-dummy-arrays-repacking/85589 "2025-03-31T20:14:49Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![szakharin](https://sea1.discourse-cdn.com/flex021/user_avatar/discourse.llvm.org/szakharin/32/14675_2.png) [@szakharin](https://discourse.llvm.org/u/szakharin)\
**Post date:** [March 31, 2025, 8:14pm UTC](https://discourse.llvm.org/t/rfc-assumed-shape-dummy-arrays-repacking/85589/1 "2025-03-31T20:14:49Z")

</div>

This Flang feature was discussed and documented in [https://github.com/llvm/llvm-project/pull/127147](https://github.com/llvm/llvm-project/pull/127147)

I would like to share the status, and look for an agreement to proceed with exposing the user options for this feature.

# Status

## Pending patches

[[flang] Support fir.pack\_array in FIR alias analysis. by vzakhari · Pull Request #131946 · llvm/llvm-project · GitHub](https://github.com/llvm/llvm-project/pull/131946) is pending approval. This patch is required for avoiding performance regressions caused by the generation of extra FIR operations that make FIR alias analysis suboptimal.

## Correctness

As described in [llvm-project/flang/docs/ArrayRepacking.md at main · llvm/llvm-project · GitHub](https://github.com/llvm/llvm-project/blob/main/flang/docs/ArrayRepacking.md#usability), enabling array repacking changes behavior of Fortran programs that use `LOC` and `IS_CONTIGUOUS` intrinsics. It may also miscompile OpenACC/OpenMP programs.

## Performance

I measured performance using the `innermost` contiguity mode.

`Polyhderon/capacita_11` speeds up by 2x on x86 with the array repacking enabled.

`channel2_11` and `fatigue2_11` slow down by about 20% on x86. There are two issues:

1. When Flang allocates the temporary array on the stack, a dynamic alloca appears in MLIR/LLVM-IR. LLVM function inline analysis prevents inlining of any routine with dynamic allocas. Thus, even though the actual repacking does not happen in this benchmarks (because the dummy arrays are contiguous), the dynamically dead code with the dynamic alloca changes the LLVM inliner behavior and affects performance. Here is `channel2_11` inlining report:

```auto
Inlining calls in: _QQmain
    Function size: 892
    NOT Inlining (cost=never): dynamic alloca, Call: call fastcc void @_QFPddx(ptr nonnull @_QFEdudx, ptr %4, ptr %.val, ptr %.val709), !dbg !10
    NOT Inlining (cost=never): dynamic alloca, Call: call fastcc void @_QFPddy(ptr nonnull @_QFEdvdy, ptr %3, ptr %.val712, ptr %.val713), !dbg !9
    NOT Inlining (cost=never): dynamic alloca, Call: call fastcc void @_QFPddx(ptr nonnull @_QFEdhdx, ptr %2, ptr %.val710, ptr %.val711), !dbg !8
    NOT Inlining (cost=never): dynamic alloca, Call: call fastcc void @_QFPddy(ptr nonnull @_QFEdhdy, ptr %1, ptr %.val714, ptr %.val715), !dbg !7

```

1. When Flang allocates the temporary array on the heap, LLVM inliner is also affected by the extra code generated for the repacking. Here is `channel2_11` inlining report:

```auto
Inlining calls in: _QQmain
    Function size: 892
    NOT Inlining (cost=735, threshold=525), Call: call fastcc void @_QFPddx(ptr nonnull @_QFEdudx, ptr %4, ptr %.val, ptr %.val709), !dbg !10
    NOT Inlining (cost=895, threshold=525), Call: call fastcc void @_QFPddy(ptr nonnull @_QFEdvdy, ptr %3, ptr %.val712, ptr %.val713), !dbg !9
    NOT Inlining (cost=735, threshold=525), Call: call fastcc void @_QFPddx(ptr nonnull @_QFEdhdx, ptr %2, ptr %.val710, ptr %.val711), !dbg !8
    NOT Inlining (cost=895, threshold=525), Call: call fastcc void @_QFPddy(ptr nonnull @_QFEdhdy, ptr %1, ptr %.val714, ptr %.val715), !dbg !7

```

Overriding the threshold with `-mllvm -locally-hot-callsite-threshold=896` does bring `channel2_11` performance back. I did not experiment with overriding the threshold for `fatigue2_11`, but I expect performance will come back with proper function inlining.

## Is it good enough to expose the user option?

I have a patch that wires `-frepack-arrays` option through Flang driver. The patch also allows `-fstack-arrays` option to control whether the temporary arrays are stack/heap allocated.

Q1. Would that be acceptable to document the current “side effects” of `-frepack-arrays` and proceed with the driver change?

Q2. If yes to Q1, is [https://flang.llvm.org/docs/FlangCommandLineReference.html](https://flang.llvm.org/docs/FlangCommandLineReference.html) (i.e. `clang/include/clang/Driver/Options.td`) the right place to document the limitations or should it be done in a separate document with a link in `Options.td`?

Q3. Given the current limitations of LLVM function inliner (see dynamic alloca case above), and the absence of working FIR inliner, does it make sence to add a user control to pick the stack/heap allocation just for `-frepack-arrays`, which would be orthogonal to `-fstack-arrays`? For example, a program may be compiled with `-fstack-arrays -frepack-arrays=heap` to minimize the effect of the dynamic alloca on LLVM function inliner (there would still be the threshold side effect, though).

Q4. In general, I think the inlining performance issues may only be solved by FIR inliner that would account for `fir.pack_array`/`fir.unpack_array` code size overhead, but will also enable optimization of redundant `fir.pack_array` operations (e.g. if the contiguity of the actual argument becomes apparent after FIR inlining). Please let me know if you can think of other solutions?

Thank you,  
Slava

---

<div class="post-metadata">

**Author:** ![szakharin](https://sea1.discourse-cdn.com/flex021/user_avatar/discourse.llvm.org/szakharin/32/14675_2.png) [@szakharin](https://discourse.llvm.org/u/szakharin)\
**Post date:** [March 31, 2025, 8:15pm UTC](https://discourse.llvm.org/t/rfc-assumed-shape-dummy-arrays-repacking/85589/2 "2025-03-31T20:15:17Z")

</div>

@sscalpone, @kiranchandramohan FYI

---

<div class="post-metadata">

**Author:** ![kiranchandramohan](https://sea1.discourse-cdn.com/flex021/user_avatar/discourse.llvm.org/kiranchandramohan/32/729_2.png) [@kiranchandramohan](https://discourse.llvm.org/u/kiranchandramohan)\
**Post date:** [April 1, 2025, 2:28pm UTC](https://discourse.llvm.org/t/rfc-assumed-shape-dummy-arrays-repacking/85589/3 "2025-04-01T14:28:43Z")

</div>

Thanks Slava for posting this RFC. I think this feature has progressed well to a point where it can be made user visible. Since the feature is not default-enabled in the optimization passes, it is up to the user to enable it as per their judgement based on the feature’s pros and cons.

Just sharing my replies to the questions below. You might want to wait from experts.

> [@szakharin](#):
>
> Q1. Would that be acceptable to document the current “side effects” of `-frepack-arrays` and proceed with the driver change?

Yes

> [@szakharin](#):
>
> Q2. If yes to Q1, is [Flang command line argument reference — The Flang Compiler](https://flang.llvm.org/docs/FlangCommandLineReference.html) (i.e. `clang/include/clang/Driver/Options.td`) the right place to document the limitations or should it be done in a separate document with a link in `Options.td`?

Yes, I think populating a short message in HelpText and detailed info in DocBrief might be a good way to do this.

> [@szakharin](#):
>
> Q3. Given the current limitations of LLVM function inliner (see dynamic alloca case above), and the absence of working FIR inliner, does it make sence to add a user control to pick the stack/heap allocation just for `-frepack-arrays`, which would be orthogonal to `-fstack-arrays`? For example, a program may be compiled with `-fstack-arrays -frepack-arrays=heap` to minimize the effect of the dynamic alloca on LLVM function inliner (there would still be the threshold side effect, though).

Sounds OK to me.

> [@szakharin](#):
>
> Q4. In general, I think the inlining performance issues may only be solved by FIR inliner that would account for `fir.pack_array`/`fir.unpack_array` code size overhead, but will also enable optimization of redundant `fir.pack_array` operations (e.g. if the contiguity of the actual argument becomes apparent after FIR inlining). Please let me know if you can think of other solutions?

FIR Inliner could be limited because it does not operate at the LTO stage. Can we pass hints to the LLVM inliner to always inline code with repacking? Would adding inlining attributes to the function where there is array packing help?

---

<div class="post-metadata">

**Author:** ![szakharin](https://sea1.discourse-cdn.com/flex021/user_avatar/discourse.llvm.org/szakharin/32/14675_2.png) [@szakharin](https://discourse.llvm.org/u/szakharin)\
**Post date:** [April 1, 2025, 11:18pm UTC](https://discourse.llvm.org/t/rfc-assumed-shape-dummy-arrays-repacking/85589/4 "2025-04-01T23:18:57Z")

</div>

Thank you for the feedback, Kiran!

I uploaded [[flang] Added driver options for arrays repacking. by vzakhari · Pull Request #134002 · llvm/llvm-project · GitHub](https://github.com/llvm/llvm-project/pull/134002) for review.

> FIR Inliner could be limited because it does not operate at the LTO stage. Can we pass hints to the LLVM inliner to always inline code with repacking? Would adding inlining attributes to the function where there is array packing help?

I agree that the lack of LTO at MLIR level will be a problem, but I think it is a must-have, if we want to produce highly optimized code for Fortran using Fortran-specific optimizations like temporary arrays elision (here, I imply that cross-module function inlining may happen at HLFIR level).

I looked for any related LLVM metadata/attributes that can affect the inlining cost of a particular piece of LLVM IR in a function, but I did not find any existing one. I was thinking that I could artificially lower the cost of the repacking code somehow.

Forcing the inlining for functions that contain repacking code is not an option, I think. The repacking is generated for any assumed-shape dummy, and forcing the inlining based on this fact does not seem reasonable. I think a more appropriate way might be to set a new function metadata/attribute that will tell LLVM inliner to ignore certain amount of cost introduced by the compiler-generated code. I am not sure though, whether it violates the whole idea of cost-based inlining.
