[Mlir-commits] [flang] [mlir] [flang][OpenACC] Changed memory management for private POINTERs. (PR #219052)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Wed Aug 26 14:46:45 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-mlir-openacc
Author: Slava Zakharin (vzakhari)
<details>
<summary>Changes</summary>
The motivating example:
```
!$acc parallel loop private(ptr) present(target_data)
do i = 1, 128
ptr => target_data(i)%array
ptr(...) = ...
```
The OpenACC privatization recipe was allocating private data
for `ptr`, storing it in `ptr` private descriptor and then
trying to deallocate `ptr->base_addr` at the end of the region.
`ptr->base_addr` is pointing to `target_data(i)%array` that is allocated
in device global memory and it is illegal to `free()` it in the device code.
The `destroy` part of the recipe can only `free()` the private data
that was originally allocated in the `init` part.
This approach works well for the two most common case.
Case 1: `ptr` is originally unassociated and it is used to point
to some target data (the example above).
Case 2: `ptr` is originally associated and it is used as a normal
private variable for storing something into it without reassociating
`ptr` to some other data.
This change, on the other hand, breaks the following case:
```
allocate(ptr(10))
!$acc parallel private(ptr)...
deallocate(ptr)
ptr => ...
```
The private memory for `ptr` data may be allocated from the host
using CUDA runtime or driver API, and it is illegal to deallocate
it via `free()` which flang-rt's implementation is using.
Moreover, flang-rt's implementation of `DEALLOCATE` assumes
there is an 8-byte footer after the data payload that it uses
to verify whether a `POINTER` deallocation is valid. OpenACC
privatization recipe uses `fir.allocmem` that does not create
the footer, so flang-rt may read past the allocated data
and crash the kernel.
The reference compiler implements `DEALLOCATE` as `free()`, so
the compute-sanitizer reports invalid `free()` errors, though,
w/o the sanitizer the kernel silently passes.
Flang's implementation either fails in `DEALLOCATE` runtime with
`DEALLOCATE of a pointer that is not the whole content of a pointer ALLOCATE`
error or crashes the kernel due to accessing past the allocated memory.
OpenACC spec does not explicitly specify what should happen in this case,
so I suggest that Flang's implementation always reports a runtime error
when program tries to deallocate the private data. This is left for
future improvement.
Assisted-by: Cursor
---
Patch is 56.18 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/219052.diff
15 Files Affected:
- (modified) flang/include/flang/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.h (+7-7)
- (modified) flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp (+83-21)
- (modified) flang/lib/Optimizer/OpenACC/Support/FIROpenACCUtils.cpp (+16-6)
- (modified) flang/test/Fir/OpenACC/recipe-populate-private.mlir (+35-8)
- (modified) flang/test/Lower/OpenACC/acc-private.f90 (+14-8)
- (modified) flang/test/Lower/OpenACC/acc-reduction.f90 (+44-18)
- (modified) flang/test/Transforms/OpenACC/acc-recipe-materialization-firstprivate.fir (+43)
- (modified) flang/test/Transforms/OpenACC/acc-recipe-materialization-private.fir (+35)
- (modified) mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td (+9-5)
- (modified) mlir/include/mlir/Dialect/OpenACC/OpenACCTypeInterfaces.td (+11-6)
- (modified) mlir/include/mlir/Dialect/OpenACC/OpenACCUtilsLoop.h (+4-3)
- (modified) mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp (+33-15)
- (modified) mlir/lib/Dialect/OpenACC/Transforms/ACCRecipeMaterialization.cpp (+20-15)
- (modified) mlir/lib/Dialect/OpenACC/Utils/OpenACCUtilsLoop.cpp (+2-1)
- (modified) mlir/unittests/Dialect/OpenACC/OpenACCUtilsLoopTest.cpp (+6-2)
``````````diff
diff --git a/flang/include/flang/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.h b/flang/include/flang/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.h
index ae47805a1af42..4e4e0d5f2c6f2 100644
--- a/flang/include/flang/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.h
+++ b/flang/include/flang/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.h
@@ -91,16 +91,16 @@ struct OpenACCMappableModel
genPrivateVariableInfo(mlir::Type type,
mlir::TypedValue<mlir::acc::MappableType> var) const;
- mlir::Value generatePrivateInit(mlir::Type type, mlir::OpBuilder &builder,
- mlir::Location loc,
- mlir::TypedValue<mlir::acc::MappableType> var,
- llvm::StringRef varName,
- mlir::ValueRange extents, mlir::Value initVal,
- mlir::acc::VariableInfoAttr varInfo,
- bool &needsDestroy) const;
+ mlir::Value generatePrivateInit(
+ mlir::Type type, mlir::OpBuilder &builder, mlir::Location loc,
+ mlir::TypedValue<mlir::acc::MappableType> var, llvm::StringRef varName,
+ mlir::ValueRange extents, mlir::Value initVal,
+ mlir::acc::VariableInfoAttr varInfo, bool &needsDestroy,
+ llvm::SmallVectorImpl<mlir::Value> &destroyValues) const;
bool generatePrivateDestroy(mlir::Type type, mlir::OpBuilder &builder,
mlir::Location loc, mlir::Value privatized,
+ mlir::ValueRange destroyValues,
mlir::ValueRange bounds,
mlir::acc::VariableInfoAttr varInfo) const;
diff --git a/flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp b/flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp
index e7e522e8e1570..0580eedcac51d 100644
--- a/flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp
+++ b/flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp
@@ -741,13 +741,22 @@ mlir::Value OpenACCMappableModel<Ty>::generatePrivateInit(
mlir::Type type, mlir::OpBuilder &mlirBuilder, mlir::Location loc,
mlir::TypedValue<mlir::acc::MappableType> var, llvm::StringRef varName,
mlir::ValueRange bounds, mlir::Value initVal,
- mlir::acc::VariableInfoAttr varInfo, bool &needsDestroy) const {
+ mlir::acc::VariableInfoAttr varInfo, bool &needsDestroy,
+ llvm::SmallVectorImpl<mlir::Value> &destroyValues) const {
mlir::ModuleOp mod = mlirBuilder.getInsertionBlock()
->getParent()
->getParentOfType<mlir::ModuleOp>();
assert(mod && "failed to retrieve ModuleOp");
fir::FirOpBuilder builder(mlirBuilder, mod);
+ hlfir::Entity inputVar = hlfir::Entity{var};
+ bool preservePointerAllocation =
+ fir::isPointerType(inputVar.getType()) && bounds.empty();
+ mlir::Type pointerAllocationType;
+ if (preservePointerAllocation)
+ pointerAllocationType =
+ fir::HeapType::get(inputVar.getElementOrSequenceType());
+
// When variable is optional: use fir.is_present to check. When non-optional,
// skip the conditional to avoid unnecessary branches.
std::optional<fir::IfOp> optIfOp;
@@ -759,13 +768,15 @@ mlir::Value OpenACCMappableModel<Ty>::generatePrivateInit(
if (mayBeOptional) {
mlir::Value cond =
fir::IsPresentOp::create(builder, loc, builder.getI1Type(), var);
- optIfOp = fir::IfOp::create(builder, loc, mlir::TypeRange{type}, cond,
+ llvm::SmallVector<mlir::Type> resultTypes{type};
+ if (preservePointerAllocation)
+ resultTypes.push_back(pointerAllocationType);
+ optIfOp = fir::IfOp::create(builder, loc, resultTypes, cond,
/*withElseRegion=*/true);
builder.setInsertionPointToStart(&optIfOp->getThenRegion().front());
}
}
- hlfir::Entity inputVar = hlfir::Entity{var};
if (inputVar.isPolymorphic())
TODO(loc, "OpenACC: polymorphic variable privatization");
if (auto recType =
@@ -833,6 +844,7 @@ mlir::Value OpenACCMappableModel<Ty>::generatePrivateInit(
mlir::acc::VarNameAttr::get(builder.getContext(),
mlir::acc::getVarNamePlaceholder()));
mlir::Value alloc;
+ mlir::Value pointerAllocation;
if (fir::hasDynamicSize(baseType) ||
(isPointerOrAllocatable && bounds.empty())) {
// Note: heap allocation is forced for whole pointers/allocatable so that
@@ -842,9 +854,32 @@ mlir::Value OpenACCMappableModel<Ty>::generatePrivateInit(
// array POINTER and ALLOCATABLE always have dynamic size. Constant sections
// of POINTER/ALLOCATABLE can use alloca since only part of the data is
// privatized (it makes no sense to deallocate them).
- alloc = builder.createHeapTemporary(loc, baseType, varName, tempExtents,
- typeParams, {placeholderAttr});
+ if (preservePointerAllocation) {
+ mlir::Value originalAddr =
+ hlfir::genVariableRawAddress(loc, builder, inputVar);
+ mlir::Value isAssociated = builder.genIsNotNullAddr(loc, originalAddr);
+ auto ifOp = fir::IfOp::create(
+ builder, loc, mlir::TypeRange{pointerAllocationType}, isAssociated,
+ /*withElseRegion=*/true);
+ builder.setInsertionPointToStart(&ifOp.getThenRegion().front());
+ mlir::Value privateAllocation = builder.createHeapTemporary(
+ loc, baseType, varName, tempExtents, typeParams, {placeholderAttr});
+ fir::ResultOp::create(builder, loc, privateAllocation);
+ builder.setInsertionPointToStart(&ifOp.getElseRegion().front());
+ fir::ResultOp::create(
+ builder, loc, builder.createNullConstant(loc, pointerAllocationType));
+ builder.setInsertionPointAfter(ifOp);
+ alloc = ifOp.getResult(0);
+ } else {
+ alloc = builder.createHeapTemporary(loc, baseType, varName, tempExtents,
+ typeParams, {placeholderAttr});
+ }
needsDestroy = true;
+ if (preservePointerAllocation) {
+ assert(alloc.getType() == pointerAllocationType &&
+ "unexpected private pointer allocation type");
+ pointerAllocation = alloc;
+ }
} else {
alloc = builder.createTemporary(loc, baseType, varName, tempExtents,
typeParams, {placeholderAttr});
@@ -946,11 +981,22 @@ mlir::Value OpenACCMappableModel<Ty>::generatePrivateInit(
}
if (mayBeOptional) {
- fir::ResultOp::create(builder, loc, retVal);
+ llvm::SmallVector<mlir::Value> thenResults{retVal};
+ if (preservePointerAllocation)
+ thenResults.push_back(pointerAllocation);
+ fir::ResultOp::create(builder, loc, thenResults);
builder.setInsertionPointToStart(&optIfOp->getElseRegion().front());
mlir::Value absent = fir::AbsentOp::create(builder, loc, type);
- fir::ResultOp::create(builder, loc, absent);
+ llvm::SmallVector<mlir::Value> elseResults{absent};
+ if (preservePointerAllocation)
+ elseResults.push_back(
+ builder.createNullConstant(loc, pointerAllocationType));
+ fir::ResultOp::create(builder, loc, elseResults);
retVal = optIfOp->getResult(0);
+ if (preservePointerAllocation)
+ destroyValues.push_back(optIfOp->getResult(1));
+ } else if (preservePointerAllocation) {
+ destroyValues.push_back(pointerAllocation);
}
return retVal;
@@ -961,27 +1007,31 @@ OpenACCMappableModel<fir::BaseBoxType>::generatePrivateInit(
mlir::Type type, mlir::OpBuilder &builder, mlir::Location loc,
mlir::TypedValue<mlir::acc::MappableType> var, llvm::StringRef varName,
mlir::ValueRange extents, mlir::Value initVal,
- mlir::acc::VariableInfoAttr varInfo, bool &needsDestroy) const;
+ mlir::acc::VariableInfoAttr varInfo, bool &needsDestroy,
+ llvm::SmallVectorImpl<mlir::Value> &destroyValues) const;
template mlir::Value
OpenACCMappableModel<fir::ReferenceType>::generatePrivateInit(
mlir::Type type, mlir::OpBuilder &builder, mlir::Location loc,
mlir::TypedValue<mlir::acc::MappableType> var, llvm::StringRef varName,
mlir::ValueRange extents, mlir::Value initVal,
- mlir::acc::VariableInfoAttr varInfo, bool &needsDestroy) const;
+ mlir::acc::VariableInfoAttr varInfo, bool &needsDestroy,
+ llvm::SmallVectorImpl<mlir::Value> &destroyValues) const;
template mlir::Value OpenACCMappableModel<fir::HeapType>::generatePrivateInit(
mlir::Type type, mlir::OpBuilder &builder, mlir::Location loc,
mlir::TypedValue<mlir::acc::MappableType> var, llvm::StringRef varName,
mlir::ValueRange extents, mlir::Value initVal,
- mlir::acc::VariableInfoAttr varInfo, bool &needsDestroy) const;
+ mlir::acc::VariableInfoAttr varInfo, bool &needsDestroy,
+ llvm::SmallVectorImpl<mlir::Value> &destroyValues) const;
template mlir::Value
OpenACCMappableModel<fir::PointerType>::generatePrivateInit(
mlir::Type type, mlir::OpBuilder &builder, mlir::Location loc,
mlir::TypedValue<mlir::acc::MappableType> var, llvm::StringRef varName,
mlir::ValueRange extents, mlir::Value initVal,
- mlir::acc::VariableInfoAttr varInfo, bool &needsDestroy) const;
+ mlir::acc::VariableInfoAttr varInfo, bool &needsDestroy,
+ llvm::SmallVectorImpl<mlir::Value> &destroyValues) const;
template <typename Ty>
bool OpenACCMappableModel<Ty>::generateCopy(
@@ -1242,13 +1292,25 @@ template bool OpenACCMappableModel<fir::HeapType>::generateCombiner(
template <typename Ty>
bool OpenACCMappableModel<Ty>::generatePrivateDestroy(
mlir::Type type, mlir::OpBuilder &mlirBuilder, mlir::Location loc,
- mlir::Value privatized, mlir::ValueRange bounds,
- mlir::acc::VariableInfoAttr varInfo) const {
+ mlir::Value privatized, mlir::ValueRange destroyValues,
+ mlir::ValueRange bounds, mlir::acc::VariableInfoAttr varInfo) const {
hlfir::Entity inputVar = hlfir::Entity{privatized};
mlir::ModuleOp mod =
mlirBuilder.getBlock()->getParent()->getParentOfType<mlir::ModuleOp>();
assert(mod && "failed to retrieve parent module");
fir::FirOpBuilder builder(mlirBuilder, mod);
+ if (!destroyValues.empty()) {
+ assert(destroyValues.size() == 1 &&
+ "expected one private pointer allocation to destroy");
+ mlir::Value privateAllocation = destroyValues.front();
+ mlir::Value isAllocated = builder.genIsNotNullAddr(loc, privateAllocation);
+ auto ifOp =
+ fir::IfOp::create(builder, loc, isAllocated, /*withElseRegion=*/false);
+ builder.setInsertionPointToStart(&ifOp.getThenRegion().front());
+ fir::FreeMemOp::create(builder, loc, privateAllocation);
+ builder.setInsertionPointAfter(ifOp);
+ return true;
+ }
auto genFreeRawAddress = [&](hlfir::Entity entity) {
mlir::Value addr = hlfir::genVariableRawAddress(loc, builder, entity);
mlir::Type heapType =
@@ -1278,20 +1340,20 @@ bool OpenACCMappableModel<Ty>::generatePrivateDestroy(
template bool OpenACCMappableModel<fir::BaseBoxType>::generatePrivateDestroy(
mlir::Type type, mlir::OpBuilder &builder, mlir::Location loc,
- mlir::Value privatized, mlir::ValueRange bounds,
- mlir::acc::VariableInfoAttr varInfo) const;
+ mlir::Value privatized, mlir::ValueRange destroyValues,
+ mlir::ValueRange bounds, mlir::acc::VariableInfoAttr varInfo) const;
template bool OpenACCMappableModel<fir::ReferenceType>::generatePrivateDestroy(
mlir::Type type, mlir::OpBuilder &builder, mlir::Location loc,
- mlir::Value privatized, mlir::ValueRange bounds,
- mlir::acc::VariableInfoAttr varInfo) const;
+ mlir::Value privatized, mlir::ValueRange destroyValues,
+ mlir::ValueRange bounds, mlir::acc::VariableInfoAttr varInfo) const;
template bool OpenACCMappableModel<fir::HeapType>::generatePrivateDestroy(
mlir::Type type, mlir::OpBuilder &builder, mlir::Location loc,
- mlir::Value privatized, mlir::ValueRange bounds,
- mlir::acc::VariableInfoAttr varInfo) const;
+ mlir::Value privatized, mlir::ValueRange destroyValues,
+ mlir::ValueRange bounds, mlir::acc::VariableInfoAttr varInfo) const;
template bool OpenACCMappableModel<fir::PointerType>::generatePrivateDestroy(
mlir::Type type, mlir::OpBuilder &builder, mlir::Location loc,
- mlir::Value privatized, mlir::ValueRange bounds,
- mlir::acc::VariableInfoAttr varInfo) const;
+ mlir::Value privatized, mlir::ValueRange destroyValues,
+ mlir::ValueRange bounds, mlir::acc::VariableInfoAttr varInfo) const;
template <typename Ty>
mlir::Value OpenACCPointerLikeModel<Ty>::genAllocate(
diff --git a/flang/lib/Optimizer/OpenACC/Support/FIROpenACCUtils.cpp b/flang/lib/Optimizer/OpenACC/Support/FIROpenACCUtils.cpp
index 4417b769fa314..77c9f2b2b9700 100644
--- a/flang/lib/Optimizer/OpenACC/Support/FIROpenACCUtils.cpp
+++ b/flang/lib/Optimizer/OpenACC/Support/FIROpenACCUtils.cpp
@@ -475,13 +475,16 @@ static RecipeOp genRecipeOp(
"Expected that all variable types are considered mappable");
auto initArg = mlir::cast<MappableValue>(initBlock->getArgument(0));
bool needsDestroy = false;
+ llvm::SmallVector<mlir::Value> destroyValues;
llvm::SmallVector<mlir::Value> initBounds =
getRecipeBounds(builder, loc, dataOperationBounds,
initBlock->getArguments().drop_front(1));
mlir::Value retVal = mappableTy.generatePrivateInit(
builder, loc, initArg, initName, initBounds, initValue, varInfo,
- needsDestroy);
- mlir::acc::YieldOp::create(builder, loc, retVal);
+ needsDestroy, destroyValues);
+ llvm::SmallVector<mlir::Value> initResults{retVal};
+ initResults.append(destroyValues);
+ mlir::acc::YieldOp::create(builder, loc, initResults);
// Create destroy region and generate destruction if requested.
if (needsDestroy) {
llvm::SmallVector<mlir::Type> destroyArgsTy;
@@ -491,6 +494,10 @@ static RecipeOp genRecipeOp(
destroyArgsTy.push_back(ty);
destroyArgsLoc.push_back(loc);
destroyArgsLoc.push_back(loc);
+ for (mlir::Value destroyValue : destroyValues) {
+ destroyArgsTy.push_back(destroyValue.getType());
+ destroyArgsLoc.push_back(loc);
+ }
// Append bounds arguments (if any) in the same order as init region
if (argsTy.size() > 1) {
destroyArgsTy.append(argsTy.begin() + 1, argsTy.end());
@@ -502,11 +509,14 @@ static RecipeOp genRecipeOp(
destroyArgsTy, destroyArgsLoc);
builder.setInsertionPointToEnd(destroyBlock);
- llvm::SmallVector<mlir::Value> destroyBounds =
- getRecipeBounds(builder, loc, dataOperationBounds,
- destroyBlock->getArguments().drop_front(2));
+ llvm::SmallVector<mlir::Value> destroyBounds = getRecipeBounds(
+ builder, loc, dataOperationBounds,
+ destroyBlock->getArguments().drop_front(2 + destroyValues.size()));
+ mlir::ValueRange destroyArgs =
+ destroyBlock->getArguments().slice(2, destroyValues.size());
[[maybe_unused]] bool success = mappableTy.generatePrivateDestroy(
- builder, loc, destroyBlock->getArgument(1), destroyBounds, varInfo);
+ builder, loc, destroyBlock->getArgument(1), destroyArgs, destroyBounds,
+ varInfo);
assert(success && "failed to generate destroy region");
mlir::acc::TerminatorOp::create(builder, loc);
}
diff --git a/flang/test/Fir/OpenACC/recipe-populate-private.mlir b/flang/test/Fir/OpenACC/recipe-populate-private.mlir
index f5200f70a3ba8..c5e37db7d450b 100644
--- a/flang/test/Fir/OpenACC/recipe-populate-private.mlir
+++ b/flang/test/Fir/OpenACC/recipe-populate-private.mlir
@@ -115,7 +115,10 @@ func.func @test_derived() {
// CHECK: fir.store %[[EMBOX]] to %[[BOXALLOC]] : !fir.ref<!fir.box<!fir.heap<f64>>>
// CHECK: acc.yield %[[BOXALLOC]] : !fir.ref<!fir.box<!fir.heap<f64>>>
// CHECK: } destroy {
-// CHECK: ^bb0(%{{.*}}: !fir.ref<!fir.box<!fir.heap<f64>>>, %{{.*}}: !fir.ref<!fir.box<!fir.heap<f64>>>):
+// CHECK: ^bb0(%{{.*}}: !fir.ref<!fir.box<!fir.heap<f64>>>, %[[PRIVATE:.*]]: !fir.ref<!fir.box<!fir.heap<f64>>>):
+// CHECK: %[[BOX:.*]] = fir.load %[[PRIVATE]] : !fir.ref<!fir.box<!fir.heap<f64>>>
+// CHECK: %[[ADDR:.*]] = fir.box_addr %[[BOX]] : (!fir.box<!fir.heap<f64>>) -> !fir.heap<f64>
+// CHECK: fir.freemem %[[ADDR]] : !fir.heap<f64>
// CHECK: acc.terminator
// CHECK: }
@@ -131,13 +134,23 @@ func.func @test_box_heap_scalar() {
// Test box type with pointer scalar (needs destroy)
// CHECK: acc.private.recipe @private_box_ptr_scalar : !fir.ref<!fir.box<!fir.ptr<i32>>> init {
// CHECK: ^bb0(%{{.*}}: !fir.ref<!fir.box<!fir.ptr<i32>>>):
-// CHECK: %[[SCALAR:.*]] = fir.allocmem i32
-// CHECK: %[[EMBOX:.*]] = fir.embox %[[SCALAR]] : (!fir.heap<i32>) -> !fir.box<!fir.ptr<i32>>
+// CHECK: %[[PRIVATE_ALLOC:.*]] = fir.if {{.*}} -> (!fir.heap<i32>) {
+// CHECK: %[[SCALAR:.*]] = fir.allocmem i32
+// CHECK: fir.result %[[SCALAR]] : !fir.heap<i32>
+// CHECK: } else {
+// CHECK: %[[NULL_ALLOC:.*]] = fir.zero_bits !fir.heap<i32>
+// CHECK: fir.result %[[NULL_ALLOC]] : !fir.heap<i32>
+// CHECK: }
+// CHECK: %[[EMBOX:.*]] = fir.embox %[[PRIVATE_ALLOC]] : (!fir.heap<i32>) -> !fir.box<!fir.ptr<i32>>
// CHECK: %[[BOXALLOC:.*]] = fir.alloca !fir.box<!fir.ptr<i32>>
// CHECK: fir.store %[[EMBOX]] to %[[BOXALLOC]] : !fir.ref<!fir.box<!fir.ptr<i32>>>
-// CHECK: acc.yield %[[BOXALLOC]] : !fir.ref<!fir.box<!fir.ptr<i32>>>
+// CHECK: acc.yield %[[BOXALLOC]], %[[PRIVATE_ALLOC]] : !fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.heap<i32>
// CHECK: } destroy {
-// CHECK: ^bb0(%{{.*}}: !fir.ref<!fir.box<!fir.ptr<i32>>>, %{{.*}}: !fir.ref<!fir.box<!fir.ptr<i32>>>):
+// CHECK: ^bb0(%{{.*}}: !fir.ref<!fir.box<!fir.ptr<i32>>>, %{{.*}}: !fir.ref<!fir.box<!fir.ptr<i32>>>, %[[PRIVATE_ALLOC:.*]]: !fir.heap<i32>):
+// CHECK-NOT: fir.box_addr
+// CHECK: fir.if {{.*}} {
+// CHECK: fir.freemem %[[PRIVATE_ALLOC]] : !fir.heap<i32>
+// CHECK: }
// CHECK: acc.terminator
// CHECK: }
@@ -156,7 +169,10 @@ func.func @test_box_ptr_scalar() {
// CHECK: %[[BOXALLOC:.*]] = fir.alloca !fir.box<!fir.heap<!fir.array<?xf32>>>
// CHECK: acc.yield %[[BOXALLOC]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>
// CHECK: } destroy {
-// CHECK: ^bb0(%{{.*}}: !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>, %{{.*}}: !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>):
+// CHECK: ^bb0(%{{.*}}: !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>, %[[PRIVATE:.*]]: !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>):
+// CHECK: %[[BOX:.*]] = fir.load %[[PRIVATE]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>
+// CHECK: %[[ADDR:.*]] = fir.box_addr %[[BOX]] : (!fir.box<!fir.heap<!fir.array<?xf32>>>) -> !fir.heap<!fir.array<?xf32>>
+// CHECK: fir.freemem %[[ADDR]] : !fir.heap<!fir.array<?xf32>>
// CHECK: acc.terminator
// CHECK: }
@@ -191,10 +207,21 @@ func.func @test_box_heap_array_2d() {
// Test box type with pointer array (needs destroy)
// CHECK: acc.private.recipe @private_box_ptr_array : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>> init {
// CHECK: ^bb0(%{{.*}}: !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>):
+// CHECK: %[[PRIVATE_ALLOC:.*]] = fir.if {{.*}} -> (!fir.heap<!fir.array<?xf32>>) {
+// CHECK: %[[ARRAY:.*]] = fir.allocmem !fir.array<?xf32>
+// CHECK: fir.result %[[ARRAY]] : !fir.heap<!fir.array<?xf32>>
+// CHECK: } else {
+// CHECK: %[[NULL_ALLOC:.*]] = fir.zero_bits !fir.heap<!fir.array<?xf32>>
+// CHECK: fir.result %[[NULL_ALLOC]] : !fir.heap<!fir.array<?xf32>>
+// CHECK: }
// CHECK: %[[BOXALLOC:.*]] = fir.alloca !fir.box<!fir.ptr<!fir.array<?xf32>>>
-// CHECK: acc.yield %[[BOXALLOC]] : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>
+// CHECK: acc.yield %[[BOXALLOC]], %[[PRIVATE_ALLOC]] : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>, !fir.heap<!fir.array<?xf32>>
// CHECK: } destroy {
-// CHECK: ^bb0(%{{.*}}: !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>, %{{.*}}: !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>):
+// CHECK: ^bb0(%{{.*}}: !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>, %{{.*}}: !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>, %[[PRIVATE_ALLOC:.*]]: !fir.heap<!fir.array<?xf32>>):
+// CHECK-NOT: fir.box_addr
+// CHECK: fir.if {{.*}} {
+// CHECK: fir.freemem %[[PRIVATE_ALLOC]] : !fir.heap<!fir.array<?xf32>>
+// CHECK: }
// CHECK: acc.terminator
// CHECK: }
diff ...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/219052
More information about the Mlir-commits
mailing list