This Flang feature was discussed and documented in 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 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, 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:
- 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_11inlining report:
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
- 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_11inlining report:
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 (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