Skip to content

Commit 3ed899c

Browse files
committed
[flang] handle allocatable components when creating array temps
When creating an array temporary in the array copy pass, care must be taken with allocatable components. The element components needs to be given a clean unallocated status before being used in the assignments. This is because assignment of allocatable components makes deep copy, and may cause deallocation of the previous value if it was allocated. Hence the previous allocation status cannot be let undefined. On top of that, when cleaning-up the temp, all allocatable components that may have been allocated must be deallocated. This patch implements this by centralizing the code making and cleaning array temps in ArrayValueCopy.cpp, and by calling Initialize and Destroy runtime entry points when they are allocatable components. Differential Revision: https://reviews.llvm.org/D121892
1 parent 0e694e1 commit 3ed899c

File tree

2 files changed

+107
-12
lines changed

2 files changed

+107
-12
lines changed

flang/lib/Optimizer/Transforms/ArrayValueCopy.cpp

Lines changed: 52 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "flang/Optimizer/Builder/BoxValue.h"
1313
#include "flang/Optimizer/Builder/FIRBuilder.h"
1414
#include "flang/Optimizer/Builder/Factory.h"
15+
#include "flang/Optimizer/Builder/Runtime/Derived.h"
1516
#include "flang/Optimizer/Dialect/FIRDialect.h"
1617
#include "flang/Optimizer/Dialect/FIROpsSupport.h"
1718
#include "flang/Optimizer/Support/FIRContext.h"
@@ -1008,6 +1009,50 @@ findNonconstantExtents(mlir::Type memrefTy,
10081009
return nce;
10091010
}
10101011

1012+
/// Allocate temporary storage for an ArrayLoadOp \load and initialize any
1013+
/// allocatable direct components of the array elements with an unallocated
1014+
/// status. Returns the temporary address as well as a callback to generate the
1015+
/// temporary clean-up once it has been used. The clean-up will take care of
1016+
/// deallocating all the element allocatable components that may have been
1017+
/// allocated while using the temporary.
1018+
static std::pair<mlir::Value,
1019+
std::function<void(mlir::PatternRewriter &rewriter)>>
1020+
allocateArrayTemp(mlir::Location loc, mlir::PatternRewriter &rewriter,
1021+
ArrayLoadOp load, llvm::ArrayRef<mlir::Value> extents,
1022+
mlir::Value shape) {
1023+
mlir::Type baseType = load.getMemref().getType();
1024+
llvm::SmallVector<mlir::Value> nonconstantExtents =
1025+
findNonconstantExtents(baseType, extents);
1026+
llvm::SmallVector<mlir::Value> typeParams =
1027+
genArrayLoadTypeParameters(loc, rewriter, load);
1028+
mlir::Value allocmem = rewriter.create<AllocMemOp>(
1029+
loc, dyn_cast_ptrOrBoxEleTy(baseType), typeParams, nonconstantExtents);
1030+
mlir::Type eleType =
1031+
fir::unwrapSequenceType(fir::unwrapPassByRefType(baseType));
1032+
if (fir::isRecordWithAllocatableMember(eleType)) {
1033+
// The allocatable component descriptors need to be set to a clean
1034+
// deallocated status before anything is done with them.
1035+
mlir::Value box = rewriter.create<fir::EmboxOp>(
1036+
loc, fir::BoxType::get(baseType), allocmem, shape,
1037+
/*slice=*/mlir::Value{}, typeParams);
1038+
auto module = load->getParentOfType<mlir::ModuleOp>();
1039+
FirOpBuilder builder(rewriter, getKindMapping(module));
1040+
runtime::genDerivedTypeInitialize(builder, loc, box);
1041+
// Any allocatable component that may have been allocated must be
1042+
// deallocated during the clean-up.
1043+
auto cleanup = [=](mlir::PatternRewriter &r) {
1044+
FirOpBuilder builder(r, getKindMapping(module));
1045+
runtime::genDerivedTypeDestroy(builder, loc, box);
1046+
r.create<FreeMemOp>(loc, allocmem);
1047+
};
1048+
return {allocmem, cleanup};
1049+
}
1050+
auto cleanup = [=](mlir::PatternRewriter &r) {
1051+
r.create<FreeMemOp>(loc, allocmem);
1052+
};
1053+
return {allocmem, cleanup};
1054+
}
1055+
10111056
namespace {
10121057
/// Conversion of fir.array_update and fir.array_modify Ops.
10131058
/// If there is a conflict for the update, then we need to perform a
@@ -1039,11 +1084,8 @@ class ArrayUpdateConversionBase : public mlir::OpRewritePattern<ArrayOp> {
10391084
bool copyUsingSlice = false;
10401085
auto shapeOp = getOrReadExtentsAndShapeOp(loc, rewriter, load, extents,
10411086
copyUsingSlice);
1042-
llvm::SmallVector<mlir::Value> nonconstantExtents =
1043-
findNonconstantExtents(load.getMemref().getType(), extents);
1044-
auto allocmem = rewriter.create<AllocMemOp>(
1045-
loc, dyn_cast_ptrOrBoxEleTy(load.getMemref().getType()),
1046-
genArrayLoadTypeParameters(loc, rewriter, load), nonconstantExtents);
1087+
auto [allocmem, genTempCleanUp] =
1088+
allocateArrayTemp(loc, rewriter, load, extents, shapeOp);
10471089
genArrayCopy</*copyIn=*/true>(load.getLoc(), rewriter, allocmem,
10481090
load.getMemref(), shapeOp, load.getSlice(),
10491091
load);
@@ -1061,7 +1103,7 @@ class ArrayUpdateConversionBase : public mlir::OpRewritePattern<ArrayOp> {
10611103
// Copy out.
10621104
genArrayCopy</*copyIn=*/false>(store.getLoc(), rewriter, store.getMemref(),
10631105
allocmem, shapeOp, store.getSlice(), load);
1064-
rewriter.create<FreeMemOp>(loc, allocmem);
1106+
genTempCleanUp(rewriter);
10651107
return coor;
10661108
}
10671109

@@ -1091,11 +1133,9 @@ class ArrayUpdateConversionBase : public mlir::OpRewritePattern<ArrayOp> {
10911133
bool copyUsingSlice = false;
10921134
auto shapeOp = getOrReadExtentsAndShapeOp(loc, rewriter, load, extents,
10931135
copyUsingSlice);
1094-
llvm::SmallVector<mlir::Value> nonconstantExtents =
1095-
findNonconstantExtents(load.getMemref().getType(), extents);
1096-
auto allocmem = rewriter.create<AllocMemOp>(
1097-
loc, dyn_cast_ptrOrBoxEleTy(load.getMemref().getType()),
1098-
genArrayLoadTypeParameters(loc, rewriter, load), nonconstantExtents);
1136+
auto [allocmem, genTempCleanUp] =
1137+
allocateArrayTemp(loc, rewriter, load, extents, shapeOp);
1138+
10991139
genArrayCopy</*copyIn=*/true>(load.getLoc(), rewriter, allocmem,
11001140
load.getMemref(), shapeOp, load.getSlice(),
11011141
load);
@@ -1113,7 +1153,7 @@ class ArrayUpdateConversionBase : public mlir::OpRewritePattern<ArrayOp> {
11131153
genArrayCopy</*copyIn=*/false>(store.getLoc(), rewriter,
11141154
store.getMemref(), allocmem, shapeOp,
11151155
store.getSlice(), load);
1116-
rewriter.create<FreeMemOp>(loc, allocmem);
1156+
genTempCleanUp(rewriter);
11171157
return {coor, load.getResult()};
11181158
}
11191159
// Otherwise, when there is no conflict (a possible loop-carried

flang/test/Fir/array-value-copy-3.fir

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// Test overlapping assignment of derived type arrays with allocatable components.
2+
// This requires initializing the allocatable components to an unallocated status
3+
// before they can be used in component assignments, and to deallocate the components
4+
// that may have been allocated in the end.
5+
6+
// RUN: fir-opt --array-value-copy %s | FileCheck %s
7+
8+
9+
!t_with_alloc_comp = type !fir.type<t{i:!fir.box<!fir.heap<!fir.array<?xi32>>>}>
10+
func private @custom_assign(!fir.ref<!t_with_alloc_comp>, !fir.ref<!t_with_alloc_comp>)
11+
func @test_overlap_with_alloc_components(%arg0: !fir.ref<!fir.array<10x!t_with_alloc_comp>>) {
12+
%0 = fir.alloca !fir.box<!t_with_alloc_comp>
13+
%c10 = arith.constant 10 : index
14+
%c9 = arith.constant 9 : index
15+
%c1 = arith.constant 1 : index
16+
%c-1 = arith.constant -1 : index
17+
%c0 = arith.constant 0 : index
18+
%1 = fir.shape %c10 : (index) -> !fir.shape<1>
19+
%6 = fir.slice %c10, %c1, %c-1 : (index, index, index) -> !fir.slice<1>
20+
%2 = fir.array_load %arg0(%1) : (!fir.ref<!fir.array<10x!t_with_alloc_comp>>, !fir.shape<1>) -> !fir.array<10x!t_with_alloc_comp>
21+
%7 = fir.array_load %arg0(%1) [%6] : (!fir.ref<!fir.array<10x!t_with_alloc_comp>>, !fir.shape<1>, !fir.slice<1>) -> !fir.array<10x!t_with_alloc_comp>
22+
%9 = fir.do_loop %arg1 = %c0 to %c9 step %c1 unordered iter_args(%arg2 = %2) -> (!fir.array<10x!t_with_alloc_comp>) {
23+
%10 = fir.array_access %7, %arg1 : (!fir.array<10x!t_with_alloc_comp>, index) -> !fir.ref<!t_with_alloc_comp>
24+
%11 = fir.array_access %arg2, %arg1 : (!fir.array<10x!t_with_alloc_comp>, index) -> !fir.ref<!t_with_alloc_comp>
25+
fir.call @custom_assign(%11, %10) : (!fir.ref<!t_with_alloc_comp>, !fir.ref<!t_with_alloc_comp>) -> none
26+
%19 = fir.array_amend %arg2, %11 : (!fir.array<10x!t_with_alloc_comp>, !fir.ref<!t_with_alloc_comp>) -> !fir.array<10x!t_with_alloc_comp>
27+
fir.result %19 : !fir.array<10x!t_with_alloc_comp>
28+
}
29+
fir.array_merge_store %2, %9 to %arg0 : !fir.array<10x!t_with_alloc_comp>, !fir.array<10x!t_with_alloc_comp>, !fir.ref<!fir.array<10x!t_with_alloc_comp>>
30+
return
31+
}
32+
33+
// CHECK-LABEL: func @test_overlap_with_alloc_components(
34+
// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<!fir.array<10x!fir.type<t{i:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>>) {
35+
// CHECK: %[[VAL_4:.*]] = arith.constant 10 : index
36+
// CHECK: %[[VAL_6:.*]] = arith.constant 1 : index
37+
// CHECK: %[[VAL_7:.*]] = arith.constant -1 : index
38+
// CHECK: %[[VAL_9:.*]] = fir.shape %[[VAL_4]] : (index) -> !fir.shape<1>
39+
// CHECK: %[[VAL_10:.*]] = fir.slice %[[VAL_4]], %[[VAL_6]], %[[VAL_7]] : (index, index, index) -> !fir.slice<1>
40+
// CHECK: %[[VAL_11:.*]] = fir.allocmem !fir.array<10x!fir.type<t{i:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>
41+
// CHECK: %[[VAL_12:.*]] = fir.embox %[[VAL_11]](%[[VAL_9]]) : (!fir.heap<!fir.array<10x!fir.type<t{i:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>>, !fir.shape<1>) -> !fir.box<!fir.ref<!fir.array<10x!fir.type<t{i:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>>>
42+
// CHECK: %[[VAL_16:.*]] = fir.convert %[[VAL_12]] : (!fir.box<!fir.ref<!fir.array<10x!fir.type<t{i:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>>>) -> !fir.box<none>
43+
// CHECK: fir.call @_FortranAInitialize(%[[VAL_16]], %{{.*}}, %{{.*}}) : (!fir.box<none>, !fir.ref<i8>, i32) -> none
44+
// CHECK: fir.do_loop {{.*}} {
45+
// CHECK: fir.call @_FortranAAssign
46+
// CHECK: }
47+
// CHECK: fir.do_loop {{.*}} {
48+
// CHECK: fir.call @custom_assign
49+
// CHECK: }
50+
// CHECK: fir.do_loop %{{.*}} {
51+
// CHECK: fir.call @_FortranAAssign
52+
// CHECK: }
53+
// CHECK: %[[VAL_72:.*]] = fir.convert %[[VAL_12]] : (!fir.box<!fir.ref<!fir.array<10x!fir.type<t{i:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>>>) -> !fir.box<none>
54+
// CHECK: %[[VAL_73:.*]] = fir.call @_FortranADestroy(%[[VAL_72]]) : (!fir.box<none>) -> none
55+
// CHECK: fir.freemem %[[VAL_11]]

0 commit comments

Comments
 (0)