[flang-commits] [flang] d5d9d9d - [flang][acc] Preserve association status of privatized pointers (#228581)
via flang-commits
flang-commits at lists.llvm.org
Mon Oct 5 16:51:38 PDT 2026
Author: Razvan Lupusoru
Date: 2026-10-05T23:51:25Z
New Revision: d5d9d9da3c905b84aadca574ee46d80d2ff408e7
URL: https://github.com/llvm/llvm-project/commit/d5d9d9da3c905b84aadca574ee46d80d2ff408e7
DIFF: https://github.com/llvm/llvm-project/commit/d5d9d9da3c905b84aadca574ee46d80d2ff408e7.diff
LOG: [flang][acc] Preserve association status of privatized pointers (#228581)
Privatization allocated a target and copied it even when a Fortran
pointer or allocatable was unassociated or unallocated. That reads
through a null address. The private allocation now follows the original
association status. A reduction stores its initial value only when that
storage exists. The target is copied only when one exists.
Before:
```
%private = fir.allocmem f32
// Box %private into the private descriptor.
hlfir.assign %src to %private temporary_lhs : f32, !fir.heap<f32>
```
After:
```
%private = fir.if %is_associated -> !fir.heap<f32> {
%allocation = fir.allocmem f32
fir.result %allocation : !fir.heap<f32>
} else {
%null = fir.zero_bits !fir.heap<f32>
fir.result %null : !fir.heap<f32>
}
// Box %private into the private descriptor.
fir.if %is_associated {
hlfir.assign %src to %private temporary_lhs : f32, !fir.heap<f32>
}
```
Added:
Modified:
flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp
flang/test/Fir/OpenACC/recipe-populate-firstprivate.mlir
flang/test/Fir/OpenACC/recipe-populate-private.mlir
flang/test/Lower/OpenACC/acc-private.f90
flang/test/Lower/OpenACC/acc-reduction.f90
Removed:
################################################################################
diff --git a/flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp b/flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp
index 73be000f701b4..0adb4640e0bbf 100644
--- a/flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp
+++ b/flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp
@@ -769,10 +769,16 @@ mlir::Value OpenACCMappableModel<Ty>::generatePrivateInit(
fir::FirOpBuilder builder(mlirBuilder, mod);
hlfir::Entity inputVar = hlfir::Entity{var};
- bool preservePointerAllocation =
- fir::isPointerType(inputVar.getType()) && bounds.empty();
+ // Whole POINTER/ALLOCATABLE: allocate private storage only when the source
+ // is associated or allocated, so the private copy stays null otherwise.
+ // A reduction identity is stored only into that allocated storage.
+ // Reduction init yields only the private variable, so its destroy reloads
+ // that descriptor. Private and firstprivate also yield the allocation.
+ bool preserveNullAllocation =
+ bounds.empty() && (fir::isPointerType(inputVar.getType()) ||
+ fir::isAllocatableType(inputVar.getType()));
mlir::Type pointerAllocationType;
- if (preservePointerAllocation)
+ if (preserveNullAllocation)
pointerAllocationType =
fir::HeapType::get(inputVar.getElementOrSequenceType());
@@ -788,7 +794,8 @@ mlir::Value OpenACCMappableModel<Ty>::generatePrivateInit(
mlir::Value cond =
fir::IsPresentOp::create(builder, loc, builder.getI1Type(), var);
llvm::SmallVector<mlir::Type> resultTypes{type};
- if (preservePointerAllocation)
+ // Reduction init cannot yield the allocation alongside the variable.
+ if (preserveNullAllocation && !initVal)
resultTypes.push_back(pointerAllocationType);
optIfOp = fir::IfOp::create(builder, loc, resultTypes, cond,
/*withElseRegion=*/true);
@@ -873,16 +880,30 @@ 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).
- if (preservePointerAllocation) {
+ if (preserveNullAllocation) {
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);
+ ifOp.setUnlikelyIfWeights(/*unlikelyElse=*/true);
builder.setInsertionPointToStart(&ifOp.getThenRegion().front());
mlir::Value privateAllocation = builder.createHeapTemporary(
loc, baseType, varName, tempExtents, typeParams, {placeholderAttr});
+ // The identity is stored only when storage was allocated. Storing it
+ // after the branch would write through the null result.
+ if (initVal) {
+ mlir::Value tempEntity = privateAllocation;
+ if (fir::hasDynamicSize(baseType))
+ tempEntity = fir::EmboxOp::create(
+ builder, loc, fir::BoxType::get(baseType), privateAllocation,
+ tempShape, /*slice=*/mlir::Value{}, typeParams);
+ hlfir::genNoAliasAssignment(loc, builder, hlfir::Entity{initVal},
+ hlfir::Entity{tempEntity},
+ /*emitWorkshareLoop=*/false,
+ /*temporaryLHS=*/true);
+ }
fir::ResultOp::create(builder, loc, privateAllocation);
builder.setInsertionPointToStart(&ifOp.getElseRegion().front());
fir::ResultOp::create(
@@ -894,7 +915,7 @@ mlir::Value OpenACCMappableModel<Ty>::generatePrivateInit(
typeParams, {placeholderAttr});
}
needsDestroy = true;
- if (preservePointerAllocation) {
+ if (preserveNullAllocation && !initVal) {
assert(alloc.getType() == pointerAllocationType &&
"unexpected private pointer allocation type");
pointerAllocation = alloc;
@@ -904,7 +925,8 @@ mlir::Value OpenACCMappableModel<Ty>::generatePrivateInit(
typeParams, {placeholderAttr});
}
// Step3: Assign the initial value to the privatized part if any.
- if (initVal) {
+ // Pointer and allocatable reductions assign inside the allocated branch.
+ if (initVal && !preserveNullAllocation) {
mlir::Value tempEntity = alloc;
if (fir::hasDynamicSize(baseType))
tempEntity =
@@ -1004,22 +1026,25 @@ mlir::Value OpenACCMappableModel<Ty>::generatePrivateInit(
retVal = builder.createConvert(loc, type, retVal);
}
+ // Private and firstprivate destroy receives the allocation directly.
+ // A reduction yields only the private variable.
+ bool yieldAllocation = preserveNullAllocation && !initVal;
if (mayBeOptional) {
llvm::SmallVector<mlir::Value> thenResults{retVal};
- if (preservePointerAllocation)
+ if (yieldAllocation)
thenResults.push_back(pointerAllocation);
fir::ResultOp::create(builder, loc, thenResults);
builder.setInsertionPointToStart(&optIfOp->getElseRegion().front());
mlir::Value absent = fir::AbsentOp::create(builder, loc, type);
llvm::SmallVector<mlir::Value> elseResults{absent};
- if (preservePointerAllocation)
+ if (yieldAllocation)
elseResults.push_back(
builder.createNullConstant(loc, pointerAllocationType));
fir::ResultOp::create(builder, loc, elseResults);
retVal = optIfOp->getResult(0);
- if (preservePointerAllocation)
+ if (yieldAllocation)
destroyValues.push_back(optIfOp->getResult(1));
- } else if (preservePointerAllocation) {
+ } else if (yieldAllocation) {
destroyValues.push_back(pointerAllocation);
}
@@ -1070,27 +1095,41 @@ bool OpenACCMappableModel<Ty>::generateCopy(
hlfir::Entity source{src};
hlfir::Entity destination{dest};
- source = hlfir::derefPointersAndAllocatables(loc, builder, source);
- destination = hlfir::derefPointersAndAllocatables(loc, builder, destination);
-
// When optional: only copy when source is present (fir.is_present). When
// absent, destination is already null from init. When non-optional, copy
- // directly without the conditional.
+ // directly without the conditional. Presence is separate from association.
+ std::optional<fir::IfOp> presentIf;
if (auto fortranVarInfo =
mlir::dyn_cast_if_present<fir::OpenACCFortranVariableInfoAttr>(
varInfo)) {
if (fortranVarInfo.getMayBeOptional()) {
// 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;
mlir::Value cond =
fir::IsPresentOp::create(builder, loc, builder.getI1Type(), src);
- optIfOp = fir::IfOp::create(builder, loc, mlir::TypeRange{}, cond,
- /*withElseRegion=*/false);
- builder.setInsertionPointToStart(&optIfOp->getThenRegion().front());
+ presentIf = fir::IfOp::create(builder, loc, mlir::TypeRange{}, cond,
+ /*withElseRegion=*/false);
+ builder.setInsertionPointToStart(&presentIf->getThenRegion().front());
}
}
+ // A POINTER or ALLOCATABLE may have a null base address, including when
+ // the recipe covers only a section of it. Test the base address before
+ // dereferencing, and copy only when the variable is associated or allocated.
+ std::optional<fir::IfOp> allocatedIf;
+ if (fir::isPointerType(source.getType()) ||
+ fir::isAllocatableType(source.getType())) {
+ mlir::Value srcAddr = hlfir::genVariableRawAddress(loc, builder, source);
+ mlir::Value isAllocated = builder.genIsNotNullAddr(loc, srcAddr);
+ allocatedIf = fir::IfOp::create(builder, loc, mlir::TypeRange{},
+ isAllocated, /*withElseRegion=*/false);
+ allocatedIf->setUnlikelyIfWeights(/*unlikelyElse=*/true);
+ builder.setInsertionPointToStart(&allocatedIf->getThenRegion().front());
+ }
+
+ source = hlfir::derefPointersAndAllocatables(loc, builder, source);
+ destination = hlfir::derefPointersAndAllocatables(loc, builder, destination);
+
if (!bounds.empty())
std::tie(source, destination) =
genArraySectionsInRecipe(builder, loc, bounds, source, destination);
@@ -1111,6 +1150,12 @@ bool OpenACCMappableModel<Ty>::generateCopy(
hlfir::AssignOp::create(builder, loc, source, destination, /*realloc=*/false,
/*keep_lhs_length_if_realloc=*/false,
/*temporary_lhs=*/true);
+ // Callers that share this builder append the recipe terminator in the
+ // copy block, after these conditions.
+ if (allocatedIf)
+ builder.setInsertionPointAfter(*allocatedIf);
+ if (presentIf)
+ builder.setInsertionPointAfter(*presentIf);
return true;
}
@@ -1344,6 +1389,24 @@ bool OpenACCMappableModel<Ty>::generatePrivateDestroy(
fir::FreeMemOp::create(builder, loc, addr);
};
if (bounds.empty()) {
+ // Reduction init yields only the private descriptor. When that descriptor
+ // is a POINTER or ALLOCATABLE, its base address is null if the original
+ // was unassociated or unallocated, so free only in that case.
+ if (fir::isPointerType(inputVar.getType()) ||
+ fir::isAllocatableType(inputVar.getType())) {
+ mlir::Value addr = hlfir::genVariableRawAddress(loc, builder, inputVar);
+ mlir::Value isAllocated = builder.genIsNotNullAddr(loc, addr);
+ auto ifOp = fir::IfOp::create(builder, loc, isAllocated,
+ /*withElseRegion=*/false);
+ builder.setInsertionPointToStart(&ifOp.getThenRegion().front());
+ mlir::Type heapType =
+ fir::HeapType::get(fir::unwrapRefType(addr.getType()));
+ if (heapType != addr.getType())
+ addr = fir::ConvertOp::create(builder, loc, heapType, addr);
+ fir::FreeMemOp::create(builder, loc, addr);
+ builder.setInsertionPointAfter(ifOp);
+ return true;
+ }
genFreeRawAddress(inputVar);
return true;
}
diff --git a/flang/test/Fir/OpenACC/recipe-populate-firstprivate.mlir b/flang/test/Fir/OpenACC/recipe-populate-firstprivate.mlir
index ff582f93976f1..c3fd622409ea2 100644
--- a/flang/test/Fir/OpenACC/recipe-populate-firstprivate.mlir
+++ b/flang/test/Fir/OpenACC/recipe-populate-firstprivate.mlir
@@ -203,3 +203,101 @@ func.func @test_optional_ptr_f64() {
%1:2 = hlfir.declare %var uniq_name("load_hlfir") : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
return
}
+
+// -----
+
+// Whole scalar POINTER: copy the pointee only when base_addr is non-null.
+// CHECK: acc.firstprivate.recipe @firstprivate_box_ptr_scalar : !fir.ref<!fir.box<!fir.ptr<f64>>> init {
+// CHECK: } copy {
+// CHECK: ^bb0(%[[SRC:.*]]: !fir.ref<!fir.box<!fir.ptr<f64>>>, %[[DST:.*]]: !fir.ref<!fir.box<!fir.ptr<f64>>>):
+// CHECK: %[[BOX:.*]] = fir.load %[[SRC]] : !fir.ref<!fir.box<!fir.ptr<f64>>>
+// CHECK: %[[ADDR:.*]] = fir.box_addr %[[BOX]] : (!fir.box<!fir.ptr<f64>>) -> !fir.ptr<f64>
+// CHECK-NOT: fir.load %[[ADDR]]
+// CHECK: %[[COND:.*]] = arith.cmpi ne
+// CHECK: fir.if %[[COND]] weights([1, 0]) {
+// CHECK: hlfir.assign {{.*}} temporary_lhs
+// CHECK: }
+// CHECK-NOT: hlfir.assign
+// CHECK: acc.terminator
+// CHECK: }
+
+func.func @test_box_ptr_scalar() {
+ %0 = fir.alloca !fir.box<!fir.ptr<f64>> {test.var = "box_ptr_scalar"}
+ %var = fir.alloca f32
+ %1:2 = hlfir.declare %var uniq_name("load_hlfir") : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
+ return
+}
+
+// -----
+
+// Whole array POINTER: same association guard around the array assignment.
+// CHECK: acc.firstprivate.recipe @firstprivate_box_ptr_array : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>> init {
+// CHECK: } copy {
+// CHECK: ^bb0(%[[SRC:.*]]: !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>, %{{.*}}: !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>):
+// CHECK: %[[BOX:.*]] = fir.load %[[SRC]] : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>
+// CHECK: %[[ADDR:.*]] = fir.box_addr %[[BOX]] : (!fir.box<!fir.ptr<!fir.array<?xf32>>>) -> !fir.ptr<!fir.array<?xf32>>
+// CHECK-NOT: fir.load %[[ADDR]]
+// CHECK: %[[COND:.*]] = arith.cmpi ne
+// CHECK: fir.if %[[COND]] weights([1, 0]) {
+// CHECK: hlfir.assign {{.*}} temporary_lhs
+// CHECK: }
+// CHECK-NOT: hlfir.assign
+// CHECK: acc.terminator
+// CHECK: }
+
+func.func @test_box_ptr_array() {
+ %0 = fir.alloca !fir.box<!fir.ptr<!fir.array<?xf32>>> {test.var = "box_ptr_array"}
+ %var = fir.alloca f32
+ %1:2 = hlfir.declare %var uniq_name("load_hlfir") : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
+ return
+}
+
+// -----
+
+// Whole scalar ALLOCATABLE: copy only when allocated.
+// CHECK: acc.firstprivate.recipe @firstprivate_box_heap_scalar : !fir.ref<!fir.box<!fir.heap<f64>>> init {
+// CHECK: fir.if {{.*}} -> (!fir.heap<f64>) {
+// CHECK: } copy {
+// CHECK: ^bb0(%[[SRC:.*]]: !fir.ref<!fir.box<!fir.heap<f64>>>, %{{.*}}: !fir.ref<!fir.box<!fir.heap<f64>>>):
+// CHECK: %[[BOX:.*]] = fir.load %[[SRC]] : !fir.ref<!fir.box<!fir.heap<f64>>>
+// CHECK: %[[ADDR:.*]] = fir.box_addr %[[BOX]] : (!fir.box<!fir.heap<f64>>) -> !fir.heap<f64>
+// CHECK-NOT: fir.load %[[ADDR]]
+// CHECK: %[[COND:.*]] = arith.cmpi ne
+// CHECK: fir.if %[[COND]] weights([1, 0]) {
+// CHECK: hlfir.assign {{.*}} temporary_lhs
+// CHECK: }
+// CHECK-NOT: hlfir.assign
+// CHECK: acc.terminator
+// CHECK: }
+
+func.func @test_box_heap_scalar() {
+ %0 = fir.alloca !fir.box<!fir.heap<f64>> {test.var = "box_heap_scalar"}
+ %var = fir.alloca f32
+ %1:2 = hlfir.declare %var uniq_name("load_hlfir") : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
+ return
+}
+
+// -----
+
+// Whole array ALLOCATABLE: same allocation guard around the array assignment.
+// CHECK: acc.firstprivate.recipe @firstprivate_box_heap_array : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>> init {
+// CHECK: fir.if {{.*}} -> (!fir.heap<!fir.array<?xf32>>) {
+// CHECK: } copy {
+// CHECK: ^bb0(%[[SRC:.*]]: !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>, %{{.*}}: !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>):
+// CHECK: %[[BOX:.*]] = fir.load %[[SRC]] : !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-NOT: fir.load %[[ADDR]]
+// CHECK: %[[COND:.*]] = arith.cmpi ne
+// CHECK: fir.if %[[COND]] weights([1, 0]) {
+// CHECK: hlfir.assign {{.*}} temporary_lhs
+// CHECK: }
+// CHECK-NOT: hlfir.assign
+// CHECK: acc.terminator
+// CHECK: }
+
+func.func @test_box_heap_array() {
+ %0 = fir.alloca !fir.box<!fir.heap<!fir.array<?xf32>>> {test.var = "box_heap_array"}
+ %var = fir.alloca f32
+ %1:2 = hlfir.declare %var uniq_name("load_hlfir") : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
+ return
+}
diff --git a/flang/test/Fir/OpenACC/recipe-populate-private.mlir b/flang/test/Fir/OpenACC/recipe-populate-private.mlir
index abd01fe526ff1..bf67e34089ef6 100644
--- a/flang/test/Fir/OpenACC/recipe-populate-private.mlir
+++ b/flang/test/Fir/OpenACC/recipe-populate-private.mlir
@@ -106,19 +106,27 @@ func.func @test_derived() {
// -----
-// Test box type with heap scalar (needs destroy)
+// Test box type with heap scalar (needs destroy). Unallocated allocatables
+// keep a null private allocation.
// CHECK: acc.private.recipe @private_box_heap_scalar : !fir.ref<!fir.box<!fir.heap<f64>>> init {
// CHECK: ^bb0(%{{.*}}: !fir.ref<!fir.box<!fir.heap<f64>>>):
-// CHECK: %[[SCALAR:.*]] = fir.allocmem f64
-// CHECK: %[[EMBOX:.*]] = fir.embox %[[SCALAR]] : (!fir.heap<f64>) -> !fir.box<!fir.heap<f64>>
+// CHECK: %[[PRIVATE_ALLOC:.*]] = fir.if {{.*}} -> (!fir.heap<f64>) {
+// CHECK: %[[SCALAR:.*]] = fir.allocmem f64
+// CHECK: fir.result %[[SCALAR]] : !fir.heap<f64>
+// CHECK: } else {
+// CHECK: %[[NULL_ALLOC:.*]] = fir.zero_bits !fir.heap<f64>
+// CHECK: fir.result %[[NULL_ALLOC]] : !fir.heap<f64>
+// CHECK: }
+// CHECK: %[[EMBOX:.*]] = fir.embox %[[PRIVATE_ALLOC]] : (!fir.heap<f64>) -> !fir.box<!fir.heap<f64>>
// CHECK: %[[BOXALLOC:.*]] = fir.alloca !fir.box<!fir.heap<f64>>
// 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: acc.yield %[[BOXALLOC]], %[[PRIVATE_ALLOC]] : !fir.ref<!fir.box<!fir.heap<f64>>>, !fir.heap<f64>
// CHECK: } destroy {
-// 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: ^bb0(%{{.*}}: !fir.ref<!fir.box<!fir.heap<f64>>>, %{{.*}}: !fir.ref<!fir.box<!fir.heap<f64>>>, %[[PRIVATE_ALLOC:.*]]: !fir.heap<f64>):
+// CHECK-NOT: fir.box_addr
+// CHECK: fir.if {{.*}} {
+// CHECK: fir.freemem %[[PRIVATE_ALLOC]] : !fir.heap<f64>
+// CHECK: }
// CHECK: acc.terminator
// CHECK: }
@@ -163,16 +171,23 @@ func.func @test_box_ptr_scalar() {
// -----
-// Test box type with 1D heap array (needs destroy)
+// Test box type with 1D heap array (needs destroy). Unallocated allocatables
+// keep a null private allocation.
// CHECK: acc.private.recipe @private_box_heap_array_1d : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>> init {
// CHECK: ^bb0(%{{.*}}: !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>):
+// CHECK: %[[PRIVATE_ALLOC:.*]] = fir.if {{.*}} -> (!fir.heap<!fir.array<?xf32>>) {
+// CHECK: fir.allocmem !fir.array<?xf32>
+// CHECK: } else {
+// CHECK: fir.zero_bits !fir.heap<!fir.array<?xf32>>
+// CHECK: }
// 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: acc.yield %[[BOXALLOC]], %[[PRIVATE_ALLOC]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>, !fir.heap<!fir.array<?xf32>>
// CHECK: } destroy {
-// 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: ^bb0(%{{.*}}: !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>, %{{.*}}: !fir.ref<!fir.box<!fir.heap<!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: }
@@ -185,13 +200,22 @@ func.func @test_box_heap_array_1d() {
// -----
-// Test box type with 2D heap array (needs destroy)
+// Test box type with 2D heap array (needs destroy). Unallocated allocatables
+// keep a null private allocation.
// CHECK: acc.private.recipe @private_box_heap_array_2d : !fir.ref<!fir.box<!fir.heap<!fir.array<?x?xi64>>>> init {
// CHECK: ^bb0(%{{.*}}: !fir.ref<!fir.box<!fir.heap<!fir.array<?x?xi64>>>>):
+// CHECK: %[[PRIVATE_ALLOC:.*]] = fir.if {{.*}} -> (!fir.heap<!fir.array<?x?xi64>>) {
+// CHECK: fir.allocmem !fir.array<?x?xi64>
+// CHECK: } else {
+// CHECK: fir.zero_bits !fir.heap<!fir.array<?x?xi64>>
+// CHECK: }
// CHECK: %[[BOXALLOC:.*]] = fir.alloca !fir.box<!fir.heap<!fir.array<?x?xi64>>>
-// CHECK: acc.yield %[[BOXALLOC]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?x?xi64>>>>
+// CHECK: acc.yield %[[BOXALLOC]], %[[PRIVATE_ALLOC]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?x?xi64>>>>, !fir.heap<!fir.array<?x?xi64>>
// CHECK: } destroy {
-// CHECK: ^bb0(%{{.*}}: !fir.ref<!fir.box<!fir.heap<!fir.array<?x?xi64>>>>, %{{.*}}: !fir.ref<!fir.box<!fir.heap<!fir.array<?x?xi64>>>>):
+// CHECK: ^bb0(%{{.*}}: !fir.ref<!fir.box<!fir.heap<!fir.array<?x?xi64>>>>, %{{.*}}: !fir.ref<!fir.box<!fir.heap<!fir.array<?x?xi64>>>>, %[[PRIVATE_ALLOC:.*]]: !fir.heap<!fir.array<?x?xi64>>):
+// CHECK: fir.if {{.*}} {
+// CHECK: fir.freemem %[[PRIVATE_ALLOC]] : !fir.heap<!fir.array<?x?xi64>>
+// CHECK: }
// CHECK: acc.terminator
// CHECK: }
diff --git a/flang/test/Lower/OpenACC/acc-private.f90 b/flang/test/Lower/OpenACC/acc-private.f90
index 1e762288e94ee..6af5ef9fde44f 100644
--- a/flang/test/Lower/OpenACC/acc-private.f90
+++ b/flang/test/Lower/OpenACC/acc-private.f90
@@ -1,6 +1,7 @@
! This test checks lowering of OpenACC loop directive.
! RUN: bbc -fopenacc -emit-hlfir %s -o - | FileCheck %s
+! RUN: bbc -fopenacc -emit-hlfir %s -o - | FileCheck %s --check-prefix=SECTION
! CHECK-LABEL: acc.private.recipe @privatization_ptr_10xf32 : !fir.ptr<!fir.array<10xf32>> init {
@@ -204,17 +205,24 @@
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.box<!fir.heap<i32>>>):
! CHECK: %[[LOAD_0:.*]] = fir.load %[[VAL_0]] : !fir.ref<!fir.box<!fir.heap<i32>>>
! CHECK: %[[BOX_ADDR_0:.*]] = fir.box_addr %[[LOAD_0]] : (!fir.box<!fir.heap<i32>>) -> !fir.heap<i32>
-! CHECK: %[[ALLOCMEM_0:.*]] = fir.allocmem i32 <{bindc_name = "acc.private.init", uniq_name = ""}> {acc.var_name = #acc.var_name<"<acc.varname.placeholder>">}
-! CHECK: %[[EMBOX_0:.*]] = fir.embox %[[ALLOCMEM_0]] : (!fir.heap<i32>) -> !fir.box<!fir.heap<i32>>
+! CHECK: %[[PRIVATE_ALLOC:.*]] = fir.if {{.*}} -> (!fir.heap<i32>) {
+! CHECK: %[[ALLOCMEM_0:.*]] = fir.allocmem i32 <{bindc_name = "acc.private.init", uniq_name = ""}> {acc.var_name = #acc.var_name<"<acc.varname.placeholder>">}
+! CHECK: fir.result %[[ALLOCMEM_0]] : !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_0:.*]] = fir.embox %[[PRIVATE_ALLOC]] : (!fir.heap<i32>) -> !fir.box<!fir.heap<i32>>
! CHECK: %[[ALLOCA_0:.*]] = fir.alloca !fir.box<!fir.heap<i32>>
! CHECK: fir.store %[[EMBOX_0]] to %[[ALLOCA_0]] : !fir.ref<!fir.box<!fir.heap<i32>>>
-! CHECK: acc.yield %[[ALLOCA_0]] : !fir.ref<!fir.box<!fir.heap<i32>>>
+! CHECK: acc.yield %[[ALLOCA_0]], %[[PRIVATE_ALLOC]] : !fir.ref<!fir.box<!fir.heap<i32>>>, !fir.heap<i32>
! CHECK-LABEL: } destroy {
-! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.box<!fir.heap<i32>>>, %[[VAL_1:.*]]: !fir.ref<!fir.box<!fir.heap<i32>>>):
-! CHECK: %[[LOAD_0:.*]] = fir.load %[[VAL_1]] : !fir.ref<!fir.box<!fir.heap<i32>>>
-! CHECK: %[[BOX_ADDR_0:.*]] = fir.box_addr %[[LOAD_0]] : (!fir.box<!fir.heap<i32>>) -> !fir.heap<i32>
-! CHECK: fir.freemem %[[BOX_ADDR_0]] : !fir.heap<i32>
+! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.box<!fir.heap<i32>>>, %[[VAL_1:.*]]: !fir.ref<!fir.box<!fir.heap<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: }
@@ -225,22 +233,29 @@
! CHECK: %[[BOX_DIMS_0:.*]]:3 = fir.box_dims %[[LOAD_0]], %[[CONSTANT_0]] : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> (index, index, index)
! CHECK: %[[SHAPE_0:.*]] = fir.shape %[[BOX_DIMS_0]]#1 : (index) -> !fir.shape<1>
! CHECK: %[[SHAPE_1:.*]] = fir.shape %[[BOX_DIMS_0]]#1 : (index) -> !fir.shape<1>
-! CHECK: %[[ALLOCMEM_0:.*]] = fir.allocmem !fir.array<?xi32>, %[[BOX_DIMS_0]]#1 <{bindc_name = "acc.private.init", uniq_name = ""}> {acc.var_name = #acc.var_name<"<acc.varname.placeholder>">}
+! CHECK: %[[PRIVATE_ALLOC:.*]] = fir.if {{.*}} -> (!fir.heap<!fir.array<?xi32>>) {
+! CHECK: %[[ALLOCMEM_0:.*]] = fir.allocmem !fir.array<?xi32>, %[[BOX_DIMS_0]]#1 <{bindc_name = "acc.private.init", uniq_name = ""}> {acc.var_name = #acc.var_name<"<acc.varname.placeholder>">}
+! CHECK: fir.result %[[ALLOCMEM_0]] : !fir.heap<!fir.array<?xi32>>
+! CHECK: } else {
+! CHECK: %[[NULL_ALLOC:.*]] = fir.zero_bits !fir.heap<!fir.array<?xi32>>
+! CHECK: fir.result %[[NULL_ALLOC]] : !fir.heap<!fir.array<?xi32>>
+! CHECK: }
! CHECK: %[[CONSTANT_1:.*]] = arith.constant 0 : index
! CHECK: %[[BOX_DIMS_1:.*]]:3 = fir.box_dims %[[LOAD_0]], %[[CONSTANT_1]] : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> (index, index, index)
! CHECK: %[[CONSTANT_2:.*]] = arith.constant 0 : index
! CHECK: %[[BOX_DIMS_2:.*]]:3 = fir.box_dims %[[LOAD_0]], %[[CONSTANT_2]] : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> (index, index, index)
! CHECK: %[[SHAPE_SHIFT_0:.*]] = fir.shape_shift %[[BOX_DIMS_1]]#0, %[[BOX_DIMS_2]]#1 : (index, index) -> !fir.shapeshift<1>
-! CHECK: %[[EMBOX_0:.*]] = fir.embox %[[ALLOCMEM_0]](%[[SHAPE_SHIFT_0]]) : (!fir.heap<!fir.array<?xi32>>, !fir.shapeshift<1>) -> !fir.box<!fir.heap<!fir.array<?xi32>>>
+! CHECK: %[[EMBOX_0:.*]] = fir.embox %[[PRIVATE_ALLOC]](%[[SHAPE_SHIFT_0]]) : (!fir.heap<!fir.array<?xi32>>, !fir.shapeshift<1>) -> !fir.box<!fir.heap<!fir.array<?xi32>>>
! CHECK: %[[ALLOCA_0:.*]] = fir.alloca !fir.box<!fir.heap<!fir.array<?xi32>>>
! CHECK: fir.store %[[EMBOX_0]] to %[[ALLOCA_0]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
-! CHECK: acc.yield %[[ALLOCA_0]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+! CHECK: acc.yield %[[ALLOCA_0]], %[[PRIVATE_ALLOC]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.heap<!fir.array<?xi32>>
! CHECK-LABEL: } destroy {
-! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, %[[VAL_1:.*]]: !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>):
-! CHECK: %[[LOAD_0:.*]] = fir.load %[[VAL_1]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
-! CHECK: %[[BOX_ADDR_0:.*]] = fir.box_addr %[[LOAD_0]] : (!fir.box<!fir.heap<!fir.array<?xi32>>>) -> !fir.heap<!fir.array<?xi32>>
-! CHECK: fir.freemem %[[BOX_ADDR_0]] : !fir.heap<!fir.array<?xi32>>
+! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, %[[VAL_1:.*]]: !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, %[[PRIVATE_ALLOC:.*]]: !fir.heap<!fir.array<?xi32>>):
+! CHECK-NOT: fir.box_addr
+! CHECK: fir.if {{.*}} {
+! CHECK: fir.freemem %[[PRIVATE_ALLOC]] : !fir.heap<!fir.array<?xi32>>
+! CHECK: }
! CHECK: acc.terminator
! CHECK: }
@@ -625,3 +640,26 @@ subroutine acc_private_use()
! CHECK: %[[DECL_PRIV_I:.*]]:2 = hlfir.declare %[[PRIV_I]] uniq_name("_QFacc_private_useEi") : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
! CHECK: fir.store %[[IV0]] to %[[DECL_PRIV_I]]#0 : !fir.ref<i32>
! CHECK: %{{.*}} = fir.load %[[DECL_PRIV_I]]#0 : !fir.ref<i32>
+
+! A section of an allocatable still carries bounds when the allocatable is
+! unallocated. The copy must test the base address before designating it.
+! SECTION-LABEL: acc.firstprivate.recipe @"firstprivatization_section_?_ref_box_heap_Uxi32"
+! SECTION: } copy {
+! SECTION: fir.box_addr
+! SECTION: arith.cmpi ne
+! SECTION: fir.if {{.*}} weights([1, 0]) {
+! SECTION: hlfir.designate
+! SECTION: hlfir.assign {{.*}} temporary_lhs
+! SECTION: }
+! SECTION-NOT: hlfir.assign
+! SECTION: acc.terminator
+! SECTION: } destroy {
+
+subroutine acc_firstprivate_unalloc_allocatable_section(n)
+ integer :: n, i
+ integer, allocatable :: a(:)
+ !$acc parallel loop firstprivate(a(1:n))
+ do i = 1, n
+ a(i) = i
+ end do
+end subroutine
diff --git a/flang/test/Lower/OpenACC/acc-reduction.f90 b/flang/test/Lower/OpenACC/acc-reduction.f90
index bfbf70a75d944..8ed69804bb025 100644
--- a/flang/test/Lower/OpenACC/acc-reduction.f90
+++ b/flang/test/Lower/OpenACC/acc-reduction.f90
@@ -7,9 +7,20 @@
! CHECK: %[[CONSTANT_0:.*]] = arith.constant false
! CHECK: %[[LOAD_0:.*]] = fir.load %[[VAL_0]] : !fir.ref<!fir.box<!fir.heap<!fir.logical<4>>>>
! CHECK: %[[BOX_ADDR_0:.*]] = fir.box_addr %[[LOAD_0]] : (!fir.box<!fir.heap<!fir.logical<4>>>) -> !fir.heap<!fir.logical<4>>
-! CHECK: %[[ALLOCMEM_0:.*]] = fir.allocmem !fir.logical<4> <{bindc_name = "acc.reduction.init", uniq_name = ""}> {acc.var_name = #acc.var_name<"<acc.varname.placeholder>">}
-! CHECK: hlfir.assign %[[CONSTANT_0]] to %[[ALLOCMEM_0]] temporary_lhs : i1, !fir.heap<!fir.logical<4>>
-! CHECK: %[[EMBOX_0:.*]] = fir.embox %[[ALLOCMEM_0]] : (!fir.heap<!fir.logical<4>>) -> !fir.box<!fir.heap<!fir.logical<4>>>
+! CHECK: %[[LOAD_1:.*]] = fir.load %[[VAL_0]] : !fir.ref<!fir.box<!fir.heap<!fir.logical<4>>>>
+! CHECK: %[[BOX_ADDR_1:.*]] = fir.box_addr %[[LOAD_1]] : (!fir.box<!fir.heap<!fir.logical<4>>>) -> !fir.heap<!fir.logical<4>>
+! CHECK: %[[CONVERT_0:.*]] = fir.convert %[[BOX_ADDR_1]] : (!fir.heap<!fir.logical<4>>) -> i64
+! CHECK: %[[CONSTANT_I64:.*]] = arith.constant 0 : i64
+! CHECK: %[[IS_ALLOCATED:.*]] = arith.cmpi ne, %[[CONVERT_0]], %[[CONSTANT_I64]] : i64
+! CHECK: %[[PRIVATE_ALLOC:.*]] = fir.if %[[IS_ALLOCATED]] weights([1, 0]) -> (!fir.heap<!fir.logical<4>>) {
+! CHECK: %[[ALLOCMEM_0:.*]] = fir.allocmem !fir.logical<4> <{bindc_name = "acc.reduction.init", uniq_name = ""}> {acc.var_name = #acc.var_name<"<acc.varname.placeholder>">}
+! CHECK: hlfir.assign %[[CONSTANT_0]] to %[[ALLOCMEM_0]] temporary_lhs : i1, !fir.heap<!fir.logical<4>>
+! CHECK: fir.result %[[ALLOCMEM_0]] : !fir.heap<!fir.logical<4>>
+! CHECK: } else {
+! CHECK: %[[ZERO_BITS:.*]] = fir.zero_bits !fir.heap<!fir.logical<4>>
+! CHECK: fir.result %[[ZERO_BITS]] : !fir.heap<!fir.logical<4>>
+! CHECK: }
+! CHECK: %[[EMBOX_0:.*]] = fir.embox %[[PRIVATE_ALLOC]] : (!fir.heap<!fir.logical<4>>) -> !fir.box<!fir.heap<!fir.logical<4>>>
! CHECK: %[[ALLOCA_0:.*]] = fir.alloca !fir.box<!fir.heap<!fir.logical<4>>>
! CHECK: fir.store %[[EMBOX_0]] to %[[ALLOCA_0]] : !fir.ref<!fir.box<!fir.heap<!fir.logical<4>>>>
! CHECK: acc.yield %[[ALLOCA_0]] : !fir.ref<!fir.box<!fir.heap<!fir.logical<4>>>>
@@ -30,7 +41,12 @@
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.box<!fir.heap<!fir.logical<4>>>>, %[[VAL_1:.*]]: !fir.ref<!fir.box<!fir.heap<!fir.logical<4>>>>):
! CHECK: %[[LOAD_0:.*]] = fir.load %[[VAL_1]] : !fir.ref<!fir.box<!fir.heap<!fir.logical<4>>>>
! CHECK: %[[BOX_ADDR_0:.*]] = fir.box_addr %[[LOAD_0]] : (!fir.box<!fir.heap<!fir.logical<4>>>) -> !fir.heap<!fir.logical<4>>
-! CHECK: fir.freemem %[[BOX_ADDR_0]] : !fir.heap<!fir.logical<4>>
+! CHECK: %[[CONVERT_0:.*]] = fir.convert %[[BOX_ADDR_0]] : (!fir.heap<!fir.logical<4>>) -> i64
+! CHECK: %[[CONSTANT_0:.*]] = arith.constant 0 : i64
+! CHECK: %[[IS_ALLOCATED:.*]] = arith.cmpi ne, %[[CONVERT_0]], %[[CONSTANT_0]] : i64
+! CHECK: fir.if %[[IS_ALLOCATED]] {
+! CHECK: fir.freemem %[[BOX_ADDR_0]] : !fir.heap<!fir.logical<4>>
+! CHECK: }
! CHECK: acc.terminator
! CHECK: }
@@ -134,22 +150,22 @@
! CHECK: %[[CONVERT_0:.*]] = fir.convert %[[BOX_ADDR_0]] : (!fir.ptr<!fir.array<?xf32>>) -> i64
! CHECK: %[[CONSTANT_I64:.*]] = arith.constant 0 : i64
! CHECK: %[[IS_ASSOCIATED:.*]] = arith.cmpi ne, %[[CONVERT_0]], %[[CONSTANT_I64]] : i64
-! CHECK: %[[PRIVATE_ALLOC:.*]] = fir.if %[[IS_ASSOCIATED]] -> (!fir.heap<!fir.array<?xf32>>) {
+! CHECK: %[[PRIVATE_ALLOC:.*]] = fir.if %[[IS_ASSOCIATED]] weights([1, 0]) -> (!fir.heap<!fir.array<?xf32>>) {
! CHECK: %[[ALLOCMEM_0:.*]] = fir.allocmem !fir.array<?xf32>, %[[BOX_DIMS_0]]#1 <{bindc_name = "acc.reduction.init", uniq_name = ""}> {acc.var_name = #acc.var_name<"<acc.varname.placeholder>">}
+! CHECK: %[[EMBOX_0:.*]] = fir.embox %[[ALLOCMEM_0]](%[[SHAPE_1]]) : (!fir.heap<!fir.array<?xf32>>, !fir.shape<1>) -> !fir.box<!fir.array<?xf32>>
+! CHECK: %[[CONSTANT_2:.*]] = arith.constant 0 : index
+! CHECK: %[[BOX_DIMS_1:.*]]:3 = fir.box_dims %[[EMBOX_0]], %[[CONSTANT_2]] : (!fir.box<!fir.array<?xf32>>, index) -> (index, index, index)
+! CHECK: %[[SHAPE_2:.*]] = fir.shape %[[BOX_DIMS_1]]#1 : (index) -> !fir.shape<1>
+! CHECK: %[[CONSTANT_3:.*]] = arith.constant 1 : index
+! CHECK: fir.do_loop %[[VAL_1:.*]] = %[[CONSTANT_3]] to %[[BOX_DIMS_1]]#1 step %[[CONSTANT_3]] unordered {
+! CHECK: %[[DESIGNATE_0:.*]] = hlfir.designate %[[EMBOX_0]] (%[[VAL_1]]) : (!fir.box<!fir.array<?xf32>>, index) -> !fir.ref<f32>
+! CHECK: hlfir.assign %[[CONSTANT_0]] to %[[DESIGNATE_0]] temporary_lhs : f32, !fir.ref<f32>
+! CHECK: }
! CHECK: fir.result %[[ALLOCMEM_0]] : !fir.heap<!fir.array<?xf32>>
! CHECK: } else {
! CHECK: %[[ZERO_BITS:.*]] = fir.zero_bits !fir.heap<!fir.array<?xf32>>
! CHECK: fir.result %[[ZERO_BITS]] : !fir.heap<!fir.array<?xf32>>
! CHECK: }
-! CHECK: %[[EMBOX_0:.*]] = fir.embox %[[PRIVATE_ALLOC]](%[[SHAPE_1]]) : (!fir.heap<!fir.array<?xf32>>, !fir.shape<1>) -> !fir.box<!fir.array<?xf32>>
-! CHECK: %[[CONSTANT_2:.*]] = arith.constant 0 : index
-! CHECK: %[[BOX_DIMS_1:.*]]:3 = fir.box_dims %[[EMBOX_0]], %[[CONSTANT_2]] : (!fir.box<!fir.array<?xf32>>, index) -> (index, index, index)
-! CHECK: %[[SHAPE_2:.*]] = fir.shape %[[BOX_DIMS_1]]#1 : (index) -> !fir.shape<1>
-! CHECK: %[[CONSTANT_3:.*]] = arith.constant 1 : index
-! CHECK: fir.do_loop %[[VAL_1:.*]] = %[[CONSTANT_3]] to %[[BOX_DIMS_1]]#1 step %[[CONSTANT_3]] unordered {
-! CHECK: %[[DESIGNATE_0:.*]] = hlfir.designate %[[EMBOX_0]] (%[[VAL_1]]) : (!fir.box<!fir.array<?xf32>>, index) -> !fir.ref<f32>
-! CHECK: hlfir.assign %[[CONSTANT_0]] to %[[DESIGNATE_0]] temporary_lhs : f32, !fir.ref<f32>
-! CHECK: }
! CHECK: %[[CONSTANT_4:.*]] = arith.constant 0 : index
! CHECK: %[[BOX_DIMS_2:.*]]:3 = fir.box_dims %[[LOAD_0]], %[[CONSTANT_4]] : (!fir.box<!fir.ptr<!fir.array<?xf32>>>, index) -> (index, index, index)
! CHECK: %[[CONSTANT_5:.*]] = arith.constant 0 : index
@@ -158,7 +174,7 @@
! CHECK: %[[EMBOX_1:.*]] = fir.embox %[[PRIVATE_ALLOC]](%[[SHAPE_SHIFT_0]]) : (!fir.heap<!fir.array<?xf32>>, !fir.shapeshift<1>) -> !fir.box<!fir.ptr<!fir.array<?xf32>>>
! CHECK: %[[ALLOCA_0:.*]] = fir.alloca !fir.box<!fir.ptr<!fir.array<?xf32>>>
! CHECK: fir.store %[[EMBOX_1]] to %[[ALLOCA_0]] : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>
-! CHECK: acc.yield %[[ALLOCA_0]], %[[PRIVATE_ALLOC]] : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>, !fir.heap<!fir.array<?xf32>>
+! CHECK: acc.yield %[[ALLOCA_0]] : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>
! CHECK-LABEL: } combiner {
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>, %[[VAL_1:.*]]: !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>):
@@ -193,12 +209,15 @@
! CHECK: acc.yield %[[VAL_0]] : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>
! CHECK-LABEL: } destroy {
-! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>, %[[VAL_1:.*]]: !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>, %[[PRIVATE_ALLOC:.*]]: !fir.heap<!fir.array<?xf32>>):
-! CHECK: %[[CONVERT_0:.*]] = fir.convert %[[PRIVATE_ALLOC]] : (!fir.heap<!fir.array<?xf32>>) -> i64
+! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>, %[[VAL_1:.*]]: !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>):
+! CHECK: %[[LOAD_0:.*]] = fir.load %[[VAL_1]] : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>
+! CHECK: %[[BOX_ADDR_0:.*]] = fir.box_addr %[[LOAD_0]] : (!fir.box<!fir.ptr<!fir.array<?xf32>>>) -> !fir.ptr<!fir.array<?xf32>>
+! CHECK: %[[CONVERT_0:.*]] = fir.convert %[[BOX_ADDR_0]] : (!fir.ptr<!fir.array<?xf32>>) -> i64
! CHECK: %[[CONSTANT_0:.*]] = arith.constant 0 : i64
! CHECK: %[[IS_ALLOCATED:.*]] = arith.cmpi ne, %[[CONVERT_0]], %[[CONSTANT_0]] : i64
! CHECK: fir.if %[[IS_ALLOCATED]] {
-! CHECK: fir.freemem %[[PRIVATE_ALLOC]] : !fir.heap<!fir.array<?xf32>>
+! CHECK: %[[CONVERT_1:.*]] = fir.convert %[[BOX_ADDR_0]] : (!fir.ptr<!fir.array<?xf32>>) -> !fir.heap<!fir.array<?xf32>>
+! CHECK: fir.freemem %[[CONVERT_1]] : !fir.heap<!fir.array<?xf32>>
! CHECK: }
! CHECK: acc.terminator
! CHECK: }
@@ -211,22 +230,33 @@
! CHECK: %[[BOX_DIMS_0:.*]]:3 = fir.box_dims %[[LOAD_0]], %[[CONSTANT_1]] : (!fir.box<!fir.heap<!fir.array<?xf32>>>, index) -> (index, index, index)
! CHECK: %[[SHAPE_0:.*]] = fir.shape %[[BOX_DIMS_0]]#1 : (index) -> !fir.shape<1>
! CHECK: %[[SHAPE_1:.*]] = fir.shape %[[BOX_DIMS_0]]#1 : (index) -> !fir.shape<1>
-! CHECK: %[[ALLOCMEM_0:.*]] = fir.allocmem !fir.array<?xf32>, %[[BOX_DIMS_0]]#1 <{bindc_name = "acc.reduction.init", uniq_name = ""}> {acc.var_name = #acc.var_name<"<acc.varname.placeholder>">}
-! CHECK: %[[EMBOX_0:.*]] = fir.embox %[[ALLOCMEM_0]](%[[SHAPE_1]]) : (!fir.heap<!fir.array<?xf32>>, !fir.shape<1>) -> !fir.box<!fir.array<?xf32>>
-! CHECK: %[[CONSTANT_2:.*]] = arith.constant 0 : index
-! CHECK: %[[BOX_DIMS_1:.*]]:3 = fir.box_dims %[[EMBOX_0]], %[[CONSTANT_2]] : (!fir.box<!fir.array<?xf32>>, index) -> (index, index, index)
-! CHECK: %[[SHAPE_2:.*]] = fir.shape %[[BOX_DIMS_1]]#1 : (index) -> !fir.shape<1>
-! CHECK: %[[CONSTANT_3:.*]] = arith.constant 1 : index
-! CHECK: fir.do_loop %[[VAL_1:.*]] = %[[CONSTANT_3]] to %[[BOX_DIMS_1]]#1 step %[[CONSTANT_3]] unordered {
-! CHECK: %[[DESIGNATE_0:.*]] = hlfir.designate %[[EMBOX_0]] (%[[VAL_1]]) : (!fir.box<!fir.array<?xf32>>, index) -> !fir.ref<f32>
-! CHECK: hlfir.assign %[[CONSTANT_0]] to %[[DESIGNATE_0]] temporary_lhs : f32, !fir.ref<f32>
+! CHECK: %[[LOAD_1:.*]] = fir.load %[[VAL_0]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>
+! CHECK: %[[BOX_ADDR_0:.*]] = fir.box_addr %[[LOAD_1]] : (!fir.box<!fir.heap<!fir.array<?xf32>>>) -> !fir.heap<!fir.array<?xf32>>
+! CHECK: %[[CONVERT_0:.*]] = fir.convert %[[BOX_ADDR_0]] : (!fir.heap<!fir.array<?xf32>>) -> i64
+! CHECK: %[[CONSTANT_I64:.*]] = arith.constant 0 : i64
+! CHECK: %[[IS_ALLOCATED:.*]] = arith.cmpi ne, %[[CONVERT_0]], %[[CONSTANT_I64]] : i64
+! CHECK: %[[PRIVATE_ALLOC:.*]] = fir.if %[[IS_ALLOCATED]] weights([1, 0]) -> (!fir.heap<!fir.array<?xf32>>) {
+! CHECK: %[[ALLOCMEM_0:.*]] = fir.allocmem !fir.array<?xf32>, %[[BOX_DIMS_0]]#1 <{bindc_name = "acc.reduction.init", uniq_name = ""}> {acc.var_name = #acc.var_name<"<acc.varname.placeholder>">}
+! CHECK: %[[EMBOX_0:.*]] = fir.embox %[[ALLOCMEM_0]](%[[SHAPE_1]]) : (!fir.heap<!fir.array<?xf32>>, !fir.shape<1>) -> !fir.box<!fir.array<?xf32>>
+! CHECK: %[[CONSTANT_2:.*]] = arith.constant 0 : index
+! CHECK: %[[BOX_DIMS_1:.*]]:3 = fir.box_dims %[[EMBOX_0]], %[[CONSTANT_2]] : (!fir.box<!fir.array<?xf32>>, index) -> (index, index, index)
+! CHECK: %[[SHAPE_2:.*]] = fir.shape %[[BOX_DIMS_1]]#1 : (index) -> !fir.shape<1>
+! CHECK: %[[CONSTANT_3:.*]] = arith.constant 1 : index
+! CHECK: fir.do_loop %[[VAL_1:.*]] = %[[CONSTANT_3]] to %[[BOX_DIMS_1]]#1 step %[[CONSTANT_3]] unordered {
+! CHECK: %[[DESIGNATE_0:.*]] = hlfir.designate %[[EMBOX_0]] (%[[VAL_1]]) : (!fir.box<!fir.array<?xf32>>, index) -> !fir.ref<f32>
+! CHECK: hlfir.assign %[[CONSTANT_0]] to %[[DESIGNATE_0]] temporary_lhs : f32, !fir.ref<f32>
+! CHECK: }
+! CHECK: fir.result %[[ALLOCMEM_0]] : !fir.heap<!fir.array<?xf32>>
+! CHECK: } else {
+! CHECK: %[[ZERO_BITS:.*]] = fir.zero_bits !fir.heap<!fir.array<?xf32>>
+! CHECK: fir.result %[[ZERO_BITS]] : !fir.heap<!fir.array<?xf32>>
! CHECK: }
! CHECK: %[[CONSTANT_4:.*]] = arith.constant 0 : index
! CHECK: %[[BOX_DIMS_2:.*]]:3 = fir.box_dims %[[LOAD_0]], %[[CONSTANT_4]] : (!fir.box<!fir.heap<!fir.array<?xf32>>>, index) -> (index, index, index)
! CHECK: %[[CONSTANT_5:.*]] = arith.constant 0 : index
! CHECK: %[[BOX_DIMS_3:.*]]:3 = fir.box_dims %[[LOAD_0]], %[[CONSTANT_5]] : (!fir.box<!fir.heap<!fir.array<?xf32>>>, index) -> (index, index, index)
! CHECK: %[[SHAPE_SHIFT_0:.*]] = fir.shape_shift %[[BOX_DIMS_2]]#0, %[[BOX_DIMS_3]]#1 : (index, index) -> !fir.shapeshift<1>
-! CHECK: %[[EMBOX_1:.*]] = fir.embox %[[ALLOCMEM_0]](%[[SHAPE_SHIFT_0]]) : (!fir.heap<!fir.array<?xf32>>, !fir.shapeshift<1>) -> !fir.box<!fir.heap<!fir.array<?xf32>>>
+! CHECK: %[[EMBOX_1:.*]] = fir.embox %[[PRIVATE_ALLOC]](%[[SHAPE_SHIFT_0]]) : (!fir.heap<!fir.array<?xf32>>, !fir.shapeshift<1>) -> !fir.box<!fir.heap<!fir.array<?xf32>>>
! CHECK: %[[ALLOCA_0:.*]] = fir.alloca !fir.box<!fir.heap<!fir.array<?xf32>>>
! CHECK: fir.store %[[EMBOX_1]] to %[[ALLOCA_0]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>
! CHECK: acc.yield %[[ALLOCA_0]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>
@@ -267,7 +297,12 @@
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>, %[[VAL_1:.*]]: !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>):
! CHECK: %[[LOAD_0:.*]] = fir.load %[[VAL_1]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>
! CHECK: %[[BOX_ADDR_0:.*]] = fir.box_addr %[[LOAD_0]] : (!fir.box<!fir.heap<!fir.array<?xf32>>>) -> !fir.heap<!fir.array<?xf32>>
-! CHECK: fir.freemem %[[BOX_ADDR_0]] : !fir.heap<!fir.array<?xf32>>
+! CHECK: %[[CONVERT_0:.*]] = fir.convert %[[BOX_ADDR_0]] : (!fir.heap<!fir.array<?xf32>>) -> i64
+! CHECK: %[[CONSTANT_0:.*]] = arith.constant 0 : i64
+! CHECK: %[[IS_ALLOCATED:.*]] = arith.cmpi ne, %[[CONVERT_0]], %[[CONSTANT_0]] : i64
+! CHECK: fir.if %[[IS_ALLOCATED]] {
+! CHECK: fir.freemem %[[BOX_ADDR_0]] : !fir.heap<!fir.array<?xf32>>
+! CHECK: }
! CHECK: acc.terminator
! CHECK: }
@@ -564,18 +599,18 @@
! CHECK: %[[CONVERT_0:.*]] = fir.convert %[[BOX_ADDR_1]] : (!fir.ptr<i32>) -> i64
! CHECK: %[[CONSTANT_I64:.*]] = arith.constant 0 : i64
! CHECK: %[[IS_ASSOCIATED:.*]] = arith.cmpi ne, %[[CONVERT_0]], %[[CONSTANT_I64]] : i64
-! CHECK: %[[PRIVATE_ALLOC:.*]] = fir.if %[[IS_ASSOCIATED]] -> (!fir.heap<i32>) {
+! CHECK: %[[PRIVATE_ALLOC:.*]] = fir.if %[[IS_ASSOCIATED]] weights([1, 0]) -> (!fir.heap<i32>) {
! CHECK: %[[ALLOCMEM_0:.*]] = fir.allocmem i32 <{bindc_name = "acc.reduction.init", uniq_name = ""}> {acc.var_name = #acc.var_name<"<acc.varname.placeholder>">}
+! CHECK: hlfir.assign %[[CONSTANT_0]] to %[[ALLOCMEM_0]] temporary_lhs : i32, !fir.heap<i32>
! CHECK: fir.result %[[ALLOCMEM_0]] : !fir.heap<i32>
! CHECK: } else {
! CHECK: %[[ZERO_BITS:.*]] = fir.zero_bits !fir.heap<i32>
! CHECK: fir.result %[[ZERO_BITS]] : !fir.heap<i32>
! CHECK: }
-! CHECK: hlfir.assign %[[CONSTANT_0]] to %[[PRIVATE_ALLOC]] temporary_lhs : i32, !fir.heap<i32>
! CHECK: %[[EMBOX_0:.*]] = fir.embox %[[PRIVATE_ALLOC]] : (!fir.heap<i32>) -> !fir.box<!fir.ptr<i32>>
! CHECK: %[[ALLOCA_0:.*]] = fir.alloca !fir.box<!fir.ptr<i32>>
! CHECK: fir.store %[[EMBOX_0]] to %[[ALLOCA_0]] : !fir.ref<!fir.box<!fir.ptr<i32>>>
-! CHECK: acc.yield %[[ALLOCA_0]], %[[PRIVATE_ALLOC]] : !fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.heap<i32>
+! CHECK: acc.yield %[[ALLOCA_0]] : !fir.ref<!fir.box<!fir.ptr<i32>>>
! CHECK-LABEL: } combiner {
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.box<!fir.ptr<i32>>>, %[[VAL_1:.*]]: !fir.ref<!fir.box<!fir.ptr<i32>>>):
@@ -587,12 +622,15 @@
! CHECK: acc.yield %[[VAL_0]] : !fir.ref<!fir.box<!fir.ptr<i32>>>
! CHECK-LABEL: } destroy {
-! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.box<!fir.ptr<i32>>>, %[[VAL_1:.*]]: !fir.ref<!fir.box<!fir.ptr<i32>>>, %[[PRIVATE_ALLOC:.*]]: !fir.heap<i32>):
-! CHECK: %[[CONVERT_0:.*]] = fir.convert %[[PRIVATE_ALLOC]] : (!fir.heap<i32>) -> i64
+! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.box<!fir.ptr<i32>>>, %[[VAL_1:.*]]: !fir.ref<!fir.box<!fir.ptr<i32>>>):
+! CHECK: %[[LOAD_0:.*]] = fir.load %[[VAL_1]] : !fir.ref<!fir.box<!fir.ptr<i32>>>
+! CHECK: %[[BOX_ADDR_0:.*]] = fir.box_addr %[[LOAD_0]] : (!fir.box<!fir.ptr<i32>>) -> !fir.ptr<i32>
+! CHECK: %[[CONVERT_0:.*]] = fir.convert %[[BOX_ADDR_0]] : (!fir.ptr<i32>) -> i64
! CHECK: %[[CONSTANT_0:.*]] = arith.constant 0 : i64
! CHECK: %[[IS_ALLOCATED:.*]] = arith.cmpi ne, %[[CONVERT_0]], %[[CONSTANT_0]] : i64
! CHECK: fir.if %[[IS_ALLOCATED]] {
-! CHECK: fir.freemem %[[PRIVATE_ALLOC]] : !fir.heap<i32>
+! CHECK: %[[CONVERT_1:.*]] = fir.convert %[[BOX_ADDR_0]] : (!fir.ptr<i32>) -> !fir.heap<i32>
+! CHECK: fir.freemem %[[CONVERT_1]] : !fir.heap<i32>
! CHECK: }
! CHECK: acc.terminator
! CHECK: }
@@ -602,9 +640,20 @@
! CHECK: %[[CONSTANT_0:.*]] = arith.constant 0 : i32
! CHECK: %[[LOAD_0:.*]] = fir.load %[[VAL_0]] : !fir.ref<!fir.box<!fir.heap<i32>>>
! CHECK: %[[BOX_ADDR_0:.*]] = fir.box_addr %[[LOAD_0]] : (!fir.box<!fir.heap<i32>>) -> !fir.heap<i32>
-! CHECK: %[[ALLOCMEM_0:.*]] = fir.allocmem i32 <{bindc_name = "acc.reduction.init", uniq_name = ""}> {acc.var_name = #acc.var_name<"<acc.varname.placeholder>">}
-! CHECK: hlfir.assign %[[CONSTANT_0]] to %[[ALLOCMEM_0]] temporary_lhs : i32, !fir.heap<i32>
-! CHECK: %[[EMBOX_0:.*]] = fir.embox %[[ALLOCMEM_0]] : (!fir.heap<i32>) -> !fir.box<!fir.heap<i32>>
+! CHECK: %[[LOAD_1:.*]] = fir.load %[[VAL_0]] : !fir.ref<!fir.box<!fir.heap<i32>>>
+! CHECK: %[[BOX_ADDR_1:.*]] = fir.box_addr %[[LOAD_1]] : (!fir.box<!fir.heap<i32>>) -> !fir.heap<i32>
+! CHECK: %[[CONVERT_0:.*]] = fir.convert %[[BOX_ADDR_1]] : (!fir.heap<i32>) -> i64
+! CHECK: %[[CONSTANT_I64:.*]] = arith.constant 0 : i64
+! CHECK: %[[IS_ALLOCATED:.*]] = arith.cmpi ne, %[[CONVERT_0]], %[[CONSTANT_I64]] : i64
+! CHECK: %[[PRIVATE_ALLOC:.*]] = fir.if %[[IS_ALLOCATED]] weights([1, 0]) -> (!fir.heap<i32>) {
+! CHECK: %[[ALLOCMEM_0:.*]] = fir.allocmem i32 <{bindc_name = "acc.reduction.init", uniq_name = ""}> {acc.var_name = #acc.var_name<"<acc.varname.placeholder>">}
+! CHECK: hlfir.assign %[[CONSTANT_0]] to %[[ALLOCMEM_0]] temporary_lhs : i32, !fir.heap<i32>
+! CHECK: fir.result %[[ALLOCMEM_0]] : !fir.heap<i32>
+! CHECK: } else {
+! CHECK: %[[ZERO_BITS:.*]] = fir.zero_bits !fir.heap<i32>
+! CHECK: fir.result %[[ZERO_BITS]] : !fir.heap<i32>
+! CHECK: }
+! CHECK: %[[EMBOX_0:.*]] = fir.embox %[[PRIVATE_ALLOC]] : (!fir.heap<i32>) -> !fir.box<!fir.heap<i32>>
! CHECK: %[[ALLOCA_0:.*]] = fir.alloca !fir.box<!fir.heap<i32>>
! CHECK: fir.store %[[EMBOX_0]] to %[[ALLOCA_0]] : !fir.ref<!fir.box<!fir.heap<i32>>>
! CHECK: acc.yield %[[ALLOCA_0]] : !fir.ref<!fir.box<!fir.heap<i32>>>
@@ -622,7 +671,12 @@
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.box<!fir.heap<i32>>>, %[[VAL_1:.*]]: !fir.ref<!fir.box<!fir.heap<i32>>>):
! CHECK: %[[LOAD_0:.*]] = fir.load %[[VAL_1]] : !fir.ref<!fir.box<!fir.heap<i32>>>
! CHECK: %[[BOX_ADDR_0:.*]] = fir.box_addr %[[LOAD_0]] : (!fir.box<!fir.heap<i32>>) -> !fir.heap<i32>
-! CHECK: fir.freemem %[[BOX_ADDR_0]] : !fir.heap<i32>
+! CHECK: %[[CONVERT_0:.*]] = fir.convert %[[BOX_ADDR_0]] : (!fir.heap<i32>) -> i64
+! CHECK: %[[CONSTANT_0:.*]] = arith.constant 0 : i64
+! CHECK: %[[IS_ALLOCATED:.*]] = arith.cmpi ne, %[[CONVERT_0]], %[[CONSTANT_0]] : i64
+! CHECK: fir.if %[[IS_ALLOCATED]] {
+! CHECK: fir.freemem %[[BOX_ADDR_0]] : !fir.heap<i32>
+! CHECK: }
! CHECK: acc.terminator
! CHECK: }
More information about the flang-commits
mailing list