Skip to content

Commit 2c91f10

Browse files
authored
[flang] Fixed repacking for TARGET and INTENT(OUT) (#131972)
TARGET dummy arrays can be accessed indirectly, so it is unsafe to repack them. INTENT(OUT) dummy arrays that require finalization on entry to their subroutine must be copied-in by `fir.pack_arrays`. In addition, based on my testing results, I think it will be useful to document that `LOC` and `IS_CONTIGUOUS` will have different values for the repacked arrays. I still need to decide where to document this, so just added a note in the design doc for the time being.
1 parent c50d39f commit 2c91f10

File tree

5 files changed

+85
-7
lines changed

5 files changed

+85
-7
lines changed

flang/docs/ArrayRepacking.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ So it does not seem practical/reasonable to enable the array repacking by defaul
145145
3. Provide consistent behavior of the temporary arrays with relation to `-fstack-arrays` (that forces all temporary arrays to be allocated on the stack).
146146
4. Produce correct debug information to substitute the original array with the copy array when accessing values in the debugger.
147147
5. Document potential correctness issues that array repacking may cause in multithreaded/offload execution.
148+
6. Document the expected changes of the programs behavior, such as applying `LOC` and `IS_CONTIGUOUS` intrinsic functions to the repacked arrays (one cannot expect the same results as if these intrinsics were applied to the original arrays).
148149

149150
## Proposed design
150151

@@ -346,6 +347,8 @@ The copy creation is also restricted for `ASYNCHRONOUS` and `VOLATILE` arguments
346347

347348
It does not make sense to generate the new operations for `CONTIGUOUS` arguments and for arguments with statically known element size that exceeds the `max-element-size` threshold.
348349

350+
The `fir.pack_array`'s copy-in action cannot be skipped for `INTENT(OUT)` dummy argument of a derived type that requires finalization on entry to the subprogram, as long as the finalization subroutines may access the value of the dummy argument. In this case `fir.pack_array` operation cannot have `no_copy` attribute, so that it creates a contiguous temporary matching the value of the original array, and then the temporary is finalized before execution of the subprogram's body begins.
351+
349352
#### Optional behavior
350353

351354
In case of the `whole` continuity mode or with 1-D array, Flang can propagate this information to `hlfir.declare` - this may improve optimizations down the road. This can be done iff the repacking has no dynamic constraints and/or heuristics. For example:

flang/lib/Lower/ConvertVariable.cpp

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -916,10 +916,7 @@ needDeallocationOrFinalization(const Fortran::lower::pft::Variable &var) {
916916
/// point 7.
917917
/// Must be nonpointer, nonallocatable, INTENT (OUT) dummy argument.
918918
static bool
919-
needDummyIntentoutFinalization(const Fortran::lower::pft::Variable &var) {
920-
if (!var.hasSymbol())
921-
return false;
922-
const Fortran::semantics::Symbol &sym = var.getSymbol();
919+
needDummyIntentoutFinalization(const Fortran::semantics::Symbol &sym) {
923920
if (!Fortran::semantics::IsDummy(sym) ||
924921
!Fortran::semantics::IsIntentOut(sym) ||
925922
Fortran::semantics::IsAllocatable(sym) ||
@@ -938,6 +935,16 @@ needDummyIntentoutFinalization(const Fortran::lower::pft::Variable &var) {
938935
return hasFinalization(sym) || hasAllocatableDirectComponent(sym);
939936
}
940937

938+
/// Check whether a variable needs the be finalized according to clause 7.5.6.3
939+
/// point 7.
940+
/// Must be nonpointer, nonallocatable, INTENT (OUT) dummy argument.
941+
static bool
942+
needDummyIntentoutFinalization(const Fortran::lower::pft::Variable &var) {
943+
if (!var.hasSymbol())
944+
return false;
945+
return needDummyIntentoutFinalization(var.getSymbol());
946+
}
947+
941948
/// Call default initialization runtime routine to initialize \p var.
942949
static void finalizeAtRuntime(Fortran::lower::AbstractConverter &converter,
943950
const Fortran::lower::pft::Variable &var,
@@ -1009,12 +1016,25 @@ static void deallocateIntentOut(Fortran::lower::AbstractConverter &converter,
10091016
}
10101017
}
10111018

1019+
/// Return true iff the given symbol represents a dummy array
1020+
/// that needs to be repacked when -frepack-arrays is set.
1021+
/// In general, the repacking is done for assumed-shape
1022+
/// dummy arguments, but there are limitations.
10121023
static bool needsRepack(Fortran::lower::AbstractConverter &converter,
10131024
const Fortran::semantics::Symbol &sym) {
1025+
const auto &attrs = sym.attrs();
10141026
if (!converter.getLoweringOptions().getRepackArrays() ||
10151027
!converter.isRegisteredDummySymbol(sym) ||
10161028
!Fortran::semantics::IsAssumedShape(sym) ||
1017-
Fortran::evaluate::IsSimplyContiguous(sym, converter.getFoldingContext()))
1029+
Fortran::evaluate::IsSimplyContiguous(sym,
1030+
converter.getFoldingContext()) ||
1031+
// TARGET dummy may be accessed indirectly, so it is unsafe
1032+
// to repack it. Some compilers provide options to override
1033+
// this.
1034+
// Repacking of VOLATILE and ASYNCHRONOUS is also unsafe.
1035+
attrs.HasAny({Fortran::semantics::Attr::ASYNCHRONOUS,
1036+
Fortran::semantics::Attr::TARGET,
1037+
Fortran::semantics::Attr::VOLATILE}))
10181038
return false;
10191039

10201040
return true;
@@ -2613,8 +2633,12 @@ Fortran::lower::genPackArray(Fortran::lower::AbstractConverter &converter,
26132633
bool stackAlloc = opts.getStackArrays();
26142634
// 1D arrays must always use 'whole' mode.
26152635
bool isInnermostMode = !opts.getRepackArraysWhole() && sym.Rank() > 1;
2616-
// Avoid copy-in for 'intent(out)' variables.
2617-
bool noCopy = Fortran::semantics::IsIntentOut(sym);
2636+
// Avoid copy-in for 'intent(out)' variable, unless this is a dummy
2637+
// argument with INTENT(OUT) that needs finalization on entry
2638+
// to the subprogram. The finalization routine may read the initial
2639+
// value of the array.
2640+
bool noCopy = Fortran::semantics::IsIntentOut(sym) &&
2641+
!needDummyIntentoutFinalization(sym);
26182642
auto boxType = mlir::cast<fir::BaseBoxType>(fir::getBase(exv).getType());
26192643
mlir::Type elementType = boxType.unwrapInnerType();
26202644
llvm::SmallVector<mlir::Value> elidedLenParams =
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
! RUN: bbc -emit-hlfir -frepack-arrays %s -o - | FileCheck --check-prefixes=CHECK %s
2+
3+
! Check that there is no repacking for ASYNCHRONOUS dummy argument.
4+
5+
! CHECK-LABEL: func.func @_QPtest(
6+
! CHECK-NOT: fir.pack_array
7+
! CHECK-NOT: fir.unpack_array
8+
subroutine test(x)
9+
integer, asynchronous :: x(:)
10+
end subroutine test
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
! RUN: bbc -emit-hlfir -frepack-arrays %s -o - -I nowhere | FileCheck --check-prefixes=CHECK %s
2+
3+
! Check that the original array is copied on entry to the subroutine
4+
! before it is being finalized, otherwise the finalization routine
5+
! may read the uninitialized temporary.
6+
! Verify that fir.pack_array does not have no_copy attribute.
7+
8+
module m
9+
type t
10+
contains
11+
final :: my_final
12+
end type t
13+
interface
14+
subroutine my_final(x)
15+
type(t) :: x(:)
16+
end subroutine my_final
17+
end interface
18+
contains
19+
! CHECK-LABEL: func.func @_QMmPtest(
20+
! CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.class<!fir.array<?x!fir.type<_QMmTt>>> {fir.bindc_name = "x"}) {
21+
subroutine test(x)
22+
class(t), intent(out) :: x(:)
23+
! CHECK: %[[VAL_2:.*]] = fir.pack_array %[[VAL_0]] heap whole : (!fir.class<!fir.array<?x!fir.type<_QMmTt>>>) -> !fir.class<!fir.array<?x!fir.type<_QMmTt>>>
24+
! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_2]]
25+
! CHECK: %[[VAL_4:.*]] = fir.convert %[[VAL_3]]#1
26+
! CHECK: fir.call @_FortranADestroy(%[[VAL_4]]) fastmath<contract> : (!fir.box<none>) -> ()
27+
! CHECK: %[[VAL_7:.*]] = fir.convert %[[VAL_3]]#1
28+
! CHECK: fir.call @_FortranAInitialize(%[[VAL_7]]
29+
! CHECK: fir.unpack_array %[[VAL_2]] to %[[VAL_0]] heap : !fir.class<!fir.array<?x!fir.type<_QMmTt>>>
30+
end subroutine test
31+
end module m
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
! RUN: bbc -emit-hlfir -frepack-arrays %s -o - | FileCheck --check-prefixes=CHECK %s
2+
3+
! Check that there is no repacking for TARGET dummy argument.
4+
5+
! CHECK-LABEL: func.func @_QPtest(
6+
! CHECK-NOT: fir.pack_array
7+
! CHECK-NOT: fir.unpack_array
8+
subroutine test(x)
9+
integer, target :: x(:)
10+
end subroutine test

0 commit comments

Comments
 (0)