Skip to content

Commit 0f604c7

Browse files
committed
[mlir][OpenACC] add genPrivateDestroy to MappableTypeInterface
1 parent f299e79 commit 0f604c7

File tree

5 files changed

+151
-3
lines changed

5 files changed

+151
-3
lines changed

flang/include/flang/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ struct OpenACCMappableModel
5353
mlir::acc::VariableTypeCategory getTypeCategory(mlir::Type type,
5454
mlir::Value var) const;
5555

56+
bool generatePrivateDestroy(mlir::Type type, mlir::OpBuilder &builder,
57+
mlir::Location loc, mlir::Value privatized) const;
58+
5659
mlir::Value generatePrivateInit(mlir::Type type, mlir::OpBuilder &builder,
5760
mlir::Location loc,
5861
mlir::TypedValue<mlir::acc::MappableType> var,

flang/lib/Lower/OpenACC.cpp

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -988,8 +988,30 @@ static RecipeOp genRecipeOp(
988988
initValue, needsDestroy);
989989
mlir::acc::YieldOp::create(builder, loc,
990990
retVal ? retVal : initBlock->getArgument(0));
991-
// TODO: insert destruction when needed.
992-
(void)needsDestroy;
991+
// Create destroy region and generate destruction if requested.
992+
if (needsDestroy) {
993+
llvm::SmallVector<mlir::Type> destroyArgsTy;
994+
llvm::SmallVector<mlir::Location> destroyArgsLoc;
995+
// original and privatized/reduction value
996+
destroyArgsTy.push_back(ty);
997+
destroyArgsTy.push_back(ty);
998+
destroyArgsLoc.push_back(loc);
999+
destroyArgsLoc.push_back(loc);
1000+
// Append bounds arguments (if any) in the same order as init region
1001+
if (argsTy.size() > 1) {
1002+
destroyArgsTy.append(argsTy.begin() + 1, argsTy.end());
1003+
destroyArgsLoc.insert(destroyArgsLoc.end(), argsTy.size() - 1, loc);
1004+
}
1005+
1006+
builder.createBlock(&recipe.getDestroyRegion(),
1007+
recipe.getDestroyRegion().end(), destroyArgsTy,
1008+
destroyArgsLoc);
1009+
builder.setInsertionPointToEnd(&recipe.getDestroyRegion().back());
1010+
// Call interface on the privatized/reduction value (2nd argument).
1011+
(void)mappableTy.generatePrivateDestroy(
1012+
builder, loc, recipe.getDestroyRegion().front().getArgument(1));
1013+
mlir::acc::TerminatorOp::create(builder, loc);
1014+
}
9931015
return recipe;
9941016
}
9951017

flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,4 +692,50 @@ OpenACCMappableModel<fir::PointerType>::generatePrivateInit(
692692
mlir::TypedValue<mlir::acc::MappableType> var, llvm::StringRef varName,
693693
mlir::ValueRange extents, mlir::Value initVal, bool &needsDestroy) const;
694694

695+
template <typename Ty>
696+
bool OpenACCMappableModel<Ty>::generatePrivateDestroy(
697+
mlir::Type type, mlir::OpBuilder &builder, mlir::Location loc,
698+
mlir::Value privatized) const {
699+
// TODO: This is only dealing with cleaning-up heap allocation of the
700+
// variable when any was made. Some Fortran types may have allocatable
701+
// components. Currently the init is not doing deep copies of such components,
702+
// so they are not freed here either. Likewise, the copies, when any, are not
703+
// made using Fortran user defined assignments, so the destructors are not
704+
// called either. This deserve a standard clarification, and in the meantime,
705+
// it would likely be better to reject the privatization of such types.
706+
mlir::Type unwrappedTy = fir::unwrapRefType(type);
707+
// For boxed scalars allocated with AllocMem during init, free the heap.
708+
if (auto boxTy = mlir::dyn_cast_or_null<fir::BaseBoxType>(unwrappedTy)) {
709+
// Load the box, take the address and free target if it was heap allocated.
710+
mlir::Value boxVal = privatized;
711+
if (fir::isa_ref_type(boxVal.getType()))
712+
boxVal = fir::LoadOp::create(builder, loc, boxVal);
713+
mlir::Value addr = fir::BoxAddrOp::create(builder, loc, boxVal);
714+
// FreeMem only accepts fir.heap and this may not be represented in the box
715+
// type if the privatized entity is not an allocatable.
716+
mlir::Type heapType =
717+
fir::HeapType::get(fir::unwrapRefType(addr.getType()));
718+
if (heapType != addr.getType())
719+
addr = fir::ConvertOp::create(builder, loc, heapType, addr);
720+
fir::FreeMemOp::create(builder, loc, addr);
721+
return true;
722+
}
723+
724+
// Nothing to do for other categories by default, they are stack allocated.
725+
return true;
726+
}
727+
728+
template bool OpenACCMappableModel<fir::BaseBoxType>::generatePrivateDestroy(
729+
mlir::Type type, mlir::OpBuilder &builder, mlir::Location loc,
730+
mlir::Value privatized) const;
731+
template bool OpenACCMappableModel<fir::ReferenceType>::generatePrivateDestroy(
732+
mlir::Type type, mlir::OpBuilder &builder, mlir::Location loc,
733+
mlir::Value privatized) const;
734+
template bool OpenACCMappableModel<fir::HeapType>::generatePrivateDestroy(
735+
mlir::Type type, mlir::OpBuilder &builder, mlir::Location loc,
736+
mlir::Value privatized) const;
737+
template bool OpenACCMappableModel<fir::PointerType>::generatePrivateDestroy(
738+
mlir::Type type, mlir::OpBuilder &builder, mlir::Location loc,
739+
mlir::Value privatized) const;
740+
695741
} // namespace fir::acc

flang/test/Lower/OpenACC/acc-private.f90

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@
2626
! CHECK: %[[DES_DST:.*]] = hlfir.designate %[[ARG1]] shape %[[SHAPE]] : (!fir.box<!fir.array<?x?x2xi32>>, !fir.shape<3>) -> !fir.box<!fir.array<?x?x2xi32>>
2727
! CHECK: hlfir.assign %[[DES_SRC]] to %[[DES_DST]] : !fir.box<!fir.array<?x?x2xi32>>, !fir.box<!fir.array<?x?x2xi32>>
2828
! CHECK: acc.terminator
29+
! CHECK: } destroy {
30+
! CHECK: ^bb0(%[[ARG0:.*]]: !fir.box<!fir.array<?x?x2xi32>>, %[[ARG1:.*]]: !fir.box<!fir.array<?x?x2xi32>>):
31+
! CHECK: %[[ADDR:.*]] = fir.box_addr %[[ARG1]] : (!fir.box<!fir.array<?x?x2xi32>>) -> !fir.ref<!fir.array<?x?x2xi32>>
32+
! CHECK: %[[CAST:.*]] = fir.convert %[[ADDR]] : (!fir.ref<!fir.array<?x?x2xi32>>) -> !fir.heap<!fir.array<?x?x2xi32>>
33+
! CHECK: fir.freemem %[[CAST]] : !fir.heap<!fir.array<?x?x2xi32>>
34+
! CHECK: acc.terminator
2935
! CHECK: }
3036

3137
! CHECK-LABEL: acc.firstprivate.recipe @firstprivatization_section_lb4.ub9_box_Uxi32 : !fir.box<!fir.array<?xi32>> init {
@@ -47,6 +53,12 @@
4753
! CHECK: %[[RIGHT:.*]] = hlfir.designate %[[ARG1]] shape %[[SHAPE]] : (!fir.box<!fir.array<?xi32>>, !fir.shape<1>) -> !fir.box<!fir.array<?xi32>>
4854
! CHECK: hlfir.assign %[[LEFT]] to %[[RIGHT]] : !fir.box<!fir.array<?xi32>>, !fir.box<!fir.array<?xi32>>
4955
! CHECK: acc.terminator
56+
! CHECK: } destroy {
57+
! CHECK: ^bb0(%[[ARG0:.*]]: !fir.box<!fir.array<?xi32>>, %[[ARG1:.*]]: !fir.box<!fir.array<?xi32>>):
58+
! CHECK: %[[ADDR:.*]] = fir.box_addr %[[ARG1]] : (!fir.box<!fir.array<?xi32>>) -> !fir.ref<!fir.array<?xi32>>
59+
! CHECK: %[[CAST:.*]] = fir.convert %[[ADDR]] : (!fir.ref<!fir.array<?xi32>>) -> !fir.heap<!fir.array<?xi32>>
60+
! CHECK: fir.freemem %[[CAST]] : !fir.heap<!fir.array<?xi32>>
61+
! CHECK: acc.terminator
5062
! CHECK: }
5163

5264
! CHECK-LABEL: acc.firstprivate.recipe @firstprivatization_box_Uxi32 : !fir.box<!fir.array<?xi32>> init {
@@ -64,6 +76,12 @@
6476
! CHECK: %[[DES_V2:.*]] = hlfir.designate %[[ARG1]] shape %[[SHAPE]] : (!fir.box<!fir.array<?xi32>>, !fir.shape<1>) -> !fir.box<!fir.array<?xi32>>
6577
! CHECK: hlfir.assign %[[DES_V1]] to %[[DES_V2]] : !fir.box<!fir.array<?xi32>>, !fir.box<!fir.array<?xi32>>
6678
! CHECK: acc.terminator
79+
! CHECK: } destroy {
80+
! CHECK: ^bb0(%[[ARG0:.*]]: !fir.box<!fir.array<?xi32>>, %[[ARG1:.*]]: !fir.box<!fir.array<?xi32>>):
81+
! CHECK: %[[ADDR:.*]] = fir.box_addr %[[ARG1]] : (!fir.box<!fir.array<?xi32>>) -> !fir.ref<!fir.array<?xi32>>
82+
! CHECK: %[[CAST:.*]] = fir.convert %[[ADDR]] : (!fir.ref<!fir.array<?xi32>>) -> !fir.heap<!fir.array<?xi32>>
83+
! CHECK: fir.freemem %[[CAST]] : !fir.heap<!fir.array<?xi32>>
84+
! CHECK: acc.terminator
6785
! CHECK: }
6886

6987
! CHECK-LABEL: acc.private.recipe @privatization_box_UxUx2xi32 : !fir.box<!fir.array<?x?x2xi32>> init {
@@ -74,6 +92,12 @@
7492
! CHECK: %[[TEMP:.*]] = fir.allocmem !fir.array<?x?x2xi32>, %[[DIM0]]#1, %[[DIM1]]#1 {bindc_name = ".tmp", uniq_name = ""}
7593
! CHECK: %[[DECL:.*]]:2 = hlfir.declare %[[TEMP]](%[[SHAPE]]) {uniq_name = ".tmp"} : (!fir.heap<!fir.array<?x?x2xi32>>, !fir.shape<3>) -> (!fir.box<!fir.array<?x?x2xi32>>, !fir.heap<!fir.array<?x?x2xi32>>)
7694
! CHECK: acc.yield %[[DECL]]#0 : !fir.box<!fir.array<?x?x2xi32>>
95+
! CHECK: } destroy {
96+
! CHECK: ^bb0(%[[ARG0:.*]]: !fir.box<!fir.array<?x?x2xi32>>, %[[ARG1:.*]]: !fir.box<!fir.array<?x?x2xi32>>):
97+
! CHECK: %[[ADDR:.*]] = fir.box_addr %[[ARG1]] : (!fir.box<!fir.array<?x?x2xi32>>) -> !fir.ref<!fir.array<?x?x2xi32>>
98+
! CHECK: %[[CAST:.*]] = fir.convert %[[ADDR]] : (!fir.ref<!fir.array<?x?x2xi32>>) -> !fir.heap<!fir.array<?x?x2xi32>>
99+
! CHECK: fir.freemem %[[CAST]] : !fir.heap<!fir.array<?x?x2xi32>>
100+
! CHECK: acc.terminator
77101
! CHECK: }
78102

79103
! CHECK-LABEL: acc.private.recipe @privatization_ref_box_ptr_Uxi32 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>> init {
@@ -89,6 +113,13 @@
89113
! CHECK: %[[CONV:.*]] = fir.convert %[[DECLAREBOX]]#0 : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>) -> !fir.ref<!fir.box<!fir.array<?xi32>>>
90114
! CHECK: fir.store %[[DECLARE]]#0 to %[[CONV]] : !fir.ref<!fir.box<!fir.array<?xi32>>>
91115
! CHECK: acc.yield %[[DECLAREBOX]]#0 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
116+
! CHECK: } destroy {
117+
! CHECK: ^bb0(%arg0: !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>, %arg1: !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>):
118+
! CHECK: %[[LOAD:.*]] = fir.load %arg1 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
119+
! CHECK: %[[ADDR:.*]] = fir.box_addr %[[LOAD]] : (!fir.box<!fir.ptr<!fir.array<?xi32>>>) -> !fir.ptr<!fir.array<?xi32>>
120+
! CHECK: %[[CAST:.*]] = fir.convert %[[ADDR]] : (!fir.ptr<!fir.array<?xi32>>) -> !fir.heap<!fir.array<?xi32>>
121+
! CHECK: fir.freemem %[[CAST]] : !fir.heap<!fir.array<?xi32>>
122+
! CHECK: acc.terminator
92123
! CHECK: }
93124

94125
! CHECK-LABEL: @privatization_ref_box_heap_i32 : !fir.ref<!fir.box<!fir.heap<i32>>> init {
@@ -99,6 +130,12 @@
99130
! CHECK: %[[BOX:.*]] = fir.embox %[[ALLOCMEM]] : (!fir.heap<i32>) -> !fir.box<!fir.heap<i32>>
100131
! CHECK: fir.store %[[BOX]] to %[[DECLARE]]#0 : !fir.ref<!fir.box<!fir.heap<i32>>>
101132
! CHECK: acc.yield %[[DECLARE]]#0 : !fir.ref<!fir.box<!fir.heap<i32>>>
133+
! CHECK: } destroy {
134+
! CHECK: ^bb0(%arg0: !fir.ref<!fir.box<!fir.heap<i32>>>, %arg1: !fir.ref<!fir.box<!fir.heap<i32>>>):
135+
! CHECK: %[[LOAD:.*]] = fir.load %arg1 : !fir.ref<!fir.box<!fir.heap<i32>>>
136+
! CHECK: %[[ADDR:.*]] = fir.box_addr %[[LOAD]] : (!fir.box<!fir.heap<i32>>) -> !fir.heap<i32>
137+
! CHECK: fir.freemem %[[ADDR]] : !fir.heap<i32>
138+
! CHECK: acc.terminator
102139
! CHECK: }
103140

104141
! CHECK-LABEL: acc.private.recipe @privatization_ref_box_heap_Uxi32 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>> init {
@@ -114,6 +151,12 @@
114151
! CHECK: %[[CONV:.*]] = fir.convert %[[DECLAREBOX]]#0 : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> !fir.ref<!fir.box<!fir.array<?xi32>>>
115152
! CHECK: fir.store %[[DECLARE]]#0 to %[[CONV]] : !fir.ref<!fir.box<!fir.array<?xi32>>>
116153
! CHECK: acc.yield %[[DECLAREBOX]]#0 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
154+
! CHECK: } destroy {
155+
! CHECK: ^bb0(%arg0: !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, %arg1: !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>):
156+
! CHECK: %[[LOAD:.*]] = fir.load %arg1 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
157+
! CHECK: %[[ADDR:.*]] = fir.box_addr %[[LOAD]] : (!fir.box<!fir.heap<!fir.array<?xi32>>>) -> !fir.heap<!fir.array<?xi32>>
158+
! CHECK: fir.freemem %[[ADDR]] : !fir.heap<!fir.array<?xi32>>
159+
! CHECK: acc.terminator
117160
! CHECK: }
118161

119162
! CHECK-LABEL: acc.private.recipe @privatization_box_Uxi32 : !fir.box<!fir.array<?xi32>> init {
@@ -124,6 +167,12 @@
124167
! CHECK: %[[TEMP:.*]] = fir.allocmem !fir.array<?xi32>, %0#1 {bindc_name = ".tmp", uniq_name = ""}
125168
! CHECK: %[[DECLARE:.*]]:2 = hlfir.declare %[[TEMP]](%[[SHAPE]]) {uniq_name = ".tmp"} : (!fir.heap<!fir.array<?xi32>>, !fir.shape<1>) -> (!fir.box<!fir.array<?xi32>>, !fir.heap<!fir.array<?xi32>>)
126169
! CHECK: acc.yield %[[DECLARE:.*]]#0 : !fir.box<!fir.array<?xi32>>
170+
! CHECK: } destroy {
171+
! CHECK: ^bb0(%[[ARG0:.*]]: !fir.box<!fir.array<?xi32>>, %[[ARG1:.*]]: !fir.box<!fir.array<?xi32>>):
172+
! CHECK: %[[ADDR:.*]] = fir.box_addr %[[ARG1]] : (!fir.box<!fir.array<?xi32>>) -> !fir.ref<!fir.array<?xi32>>
173+
! CHECK: %[[CAST:.*]] = fir.convert %[[ADDR]] : (!fir.ref<!fir.array<?xi32>>) -> !fir.heap<!fir.array<?xi32>>
174+
! CHECK: fir.freemem %[[CAST]] : !fir.heap<!fir.array<?xi32>>
175+
! CHECK: acc.terminator
127176
! CHECK: }
128177

129178
! CHECK-LABEL: acc.firstprivate.recipe @firstprivatization_section_lb50.ub99_ref_50xf32 : !fir.ref<!fir.array<50xf32>> init {
@@ -140,6 +189,7 @@
140189
! CHECK: %[[DES_SRC:.*]] = hlfir.designate %[[DECL_SRC]]#0 shape %[[SHAPE:.*]] : (!fir.ref<!fir.array<50xf32>>, !fir.shape<1>) -> !fir.ref<!fir.array<50xf32>>
141190
! CHECK: %[[DES_DST:.*]] = hlfir.designate %[[DECL_DST]]#0 shape %[[SHAPE:.*]] : (!fir.ref<!fir.array<50xf32>>, !fir.shape<1>) -> !fir.ref<!fir.array<50xf32>>
142191
! CHECK: hlfir.assign %[[DES_SRC]] to %[[DES_DST]] : !fir.ref<!fir.array<50xf32>>, !fir.ref<!fir.array<50xf32>>
192+
! CHECK: acc.terminator
143193
! CHECK: }
144194

145195
! CHECK-LABEL: acc.firstprivate.recipe @firstprivatization_ref_100xf32 : !fir.ref<!fir.array<100xf32>> init {

mlir/include/mlir/Dialect/OpenACC/OpenACCTypeInterfaces.td

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,9 @@ def OpenACC_MappableTypeInterface : TypeInterface<"MappableType"> {
278278
that destruction code must be generated after the returned private
279279
variable usages, typically in the destroy region of recipe operations
280280
(for example, when heap allocations or temporaries requiring cleanup
281-
are created during initialization).
281+
are created during initialization). When `needsDestroy` is set, callers
282+
should invoke `generatePrivateDestroy` in the recipe's destroy region
283+
with the privatized value returned by this method.
282284

283285
If the return value is empty, it means that recipe body was not
284286
successfully generated.
@@ -297,6 +299,31 @@ def OpenACC_MappableTypeInterface : TypeInterface<"MappableType"> {
297299
return {};
298300
}]
299301
>,
302+
InterfaceMethod<
303+
/*description=*/[{
304+
Generates destruction operations for a privatized value previously
305+
produced by `generatePrivateInit`. This is typically inserted in a
306+
recipe's destroy region, after all uses of the privatized value.
307+
308+
The `privatized` value is the SSA value yielded by the init region
309+
(and passed as the privatized argument to the destroy region).
310+
Implementations should free heap-allocated storage or perform any
311+
cleanup required for the given type. If no destruction is required,
312+
this function should be a no-op and return `true`.
313+
314+
Returns true if destruction was successfully generated or deemed not
315+
necessary, false otherwise.
316+
}],
317+
/*retTy=*/"bool",
318+
/*methodName=*/"generatePrivateDestroy",
319+
/*args=*/(ins "::mlir::OpBuilder &":$builder,
320+
"::mlir::Location":$loc,
321+
"::mlir::Value":$privatized),
322+
/*methodBody=*/"",
323+
/*defaultImplementation=*/[{
324+
return true;
325+
}]
326+
>,
300327
];
301328
}
302329

0 commit comments

Comments
 (0)