aboutsummaryrefslogtreecommitdiff
path: root/flang
diff options
context:
space:
mode:
authorSlava Zakharin <szakharin@nvidia.com>2023-07-19 10:03:27 -0700
committerSlava Zakharin <szakharin@nvidia.com>2023-07-19 14:38:31 -0700
commitb9e435cbe494c919e8edc973e696e88e08e0dace (patch)
treeca6c0e600f83a7799fb8c70e372f37b4e60ee7f5 /flang
parentb63698727d84a84f2163386aa3209ab28cc73c7e (diff)
downloadllvm-b9e435cbe494c919e8edc973e696e88e08e0dace.zip
llvm-b9e435cbe494c919e8edc973e696e88e08e0dace.tar.gz
llvm-b9e435cbe494c919e8edc973e696e88e08e0dace.tar.bz2
[flang][hlfir] Removed incorrect clean-up in the implied-do lowering.
The lowering of calls/expressions unconditionally inserts DestroyOp clean-up for hlfir.expr values, which is wrong in the case where the value is used as a result of the elemental operation created during the implied-do lowering. A cleaner fix could be to avoid DestroyOp insertion at all, but I have not figure out an easy way to do it. The DestroyOp look-up I used seems to be quite reliable, so it should just work. Reviewed By: clementval Differential Revision: https://reviews.llvm.org/D155665
Diffstat (limited to 'flang')
-rw-r--r--flang/include/flang/Optimizer/HLFIR/HLFIROps.td2
-rw-r--r--flang/lib/Lower/ConvertArrayConstructor.cpp20
-rw-r--r--flang/test/Lower/HLFIR/array-ctor-as-elemental.f9029
3 files changed, 50 insertions, 1 deletions
diff --git a/flang/include/flang/Optimizer/HLFIR/HLFIROps.td b/flang/include/flang/Optimizer/HLFIR/HLFIROps.td
index 704a745..d5114ec 100644
--- a/flang/include/flang/Optimizer/HLFIR/HLFIROps.td
+++ b/flang/include/flang/Optimizer/HLFIR/HLFIROps.td
@@ -894,7 +894,7 @@ def hlfir_DestroyOp : hlfir_Op<"destroy", [MemoryEffects<[MemFree]>]> {
buffer of an hlfir.expr, if any, will be deallocated if it was heap
allocated.
It is not required to create an hlfir.destroy operation for and hlfir.expr
- created inside an hlfir.elemental an returned in the hlfir.yield_element.
+ created inside an hlfir.elemental and returned in the hlfir.yield_element.
The last use of such expression is implicit and an hlfir.destroy could
not be emitted after the hlfir.yield_element since it is a terminator.
diff --git a/flang/lib/Lower/ConvertArrayConstructor.cpp b/flang/lib/Lower/ConvertArrayConstructor.cpp
index b028201..2ef500e 100644
--- a/flang/lib/Lower/ConvertArrayConstructor.cpp
+++ b/flang/lib/Lower/ConvertArrayConstructor.cpp
@@ -241,6 +241,26 @@ public:
// right now.
stmtCtx.finalizeAndPop();
+ // This is a hacky way to get rid of the DestroyOp clean-up
+ // associated with the final ac-value result if it is hlfir.expr.
+ // Example:
+ // ... = (/(REPEAT(REPEAT(CHAR(i),2),2),i=1,n)/)
+ // Each intrinsic call lowering will produce hlfir.expr result
+ // with the associated clean-up, but only the last of them
+ // is wrong. It is wrong because the value is used in hlfir.yield_element,
+ // so it cannot be destroyed.
+ mlir::Operation *destroyOp = nullptr;
+ for (mlir::Operation *useOp : elementResult.getUsers())
+ if (mlir::isa<hlfir::DestroyOp>(useOp)) {
+ if (destroyOp)
+ fir::emitFatalError(loc,
+ "multiple DestroyOp's for ac-value expression");
+ destroyOp = useOp;
+ }
+
+ if (destroyOp)
+ destroyOp->erase();
+
builder.create<hlfir::YieldElementOp>(loc, elementResult);
}
diff --git a/flang/test/Lower/HLFIR/array-ctor-as-elemental.f90 b/flang/test/Lower/HLFIR/array-ctor-as-elemental.f90
index 35b60a4..b7faa71 100644
--- a/flang/test/Lower/HLFIR/array-ctor-as-elemental.f90
+++ b/flang/test/Lower/HLFIR/array-ctor-as-elemental.f90
@@ -128,3 +128,32 @@ subroutine test_with_impure_call(n)
end subroutine
! CHECK-NOT: hlfir.elemental
! CHECK: return
+
+! Test that the hlfir.expr result of the outer intrinsic call
+! is not destructed.
+subroutine test_hlfir_expr_result_destruction
+ character(4) :: a(21)
+ a = (/ (repeat(repeat(char(i),2),2),i=1,n) /)
+end subroutine
+! CHECK-LABEL: func.func @_QPtest_hlfir_expr_result_destruction() {
+! CHECK: %[[VAL_36:.*]] = hlfir.elemental %{{.*}} typeparams %{{.*}} unordered : (!fir.shape<1>, index) -> !hlfir.expr<?x!fir.char<1,?>> {
+! CHECK: %[[VAL_48:.*]] = hlfir.as_expr %{{.*}} move %{{.*}} : (!fir.ref<!fir.char<1>>, i1) -> !hlfir.expr<!fir.char<1>>
+! CHECK: %[[VAL_51:.*]]:3 = hlfir.associate %[[VAL_48]] typeparams %{{.*}} {uniq_name = "adapt.valuebyref"} : (!hlfir.expr<!fir.char<1>>, index) -> (!fir.ref<!fir.char<1>>, !fir.ref<!fir.char<1>>, i1)
+! CHECK: %[[VAL_64:.*]]:2 = hlfir.declare %{{.*}} typeparams %{{.*}} {uniq_name = ".tmp.intrinsic_result"} : (!fir.heap<!fir.char<1,2>>, index) -> (!fir.heap<!fir.char<1,2>>, !fir.heap<!fir.char<1,2>>)
+! CHECK: %[[VAL_66:.*]] = hlfir.as_expr %[[VAL_64]]#0 move %{{.*}} : (!fir.heap<!fir.char<1,2>>, i1) -> !hlfir.expr<!fir.char<1,2>>
+! CHECK: %[[VAL_68:.*]]:3 = hlfir.associate %[[VAL_66]] typeparams %{{.*}} {uniq_name = "adapt.valuebyref"} : (!hlfir.expr<!fir.char<1,2>>, index) -> (!fir.ref<!fir.char<1,2>>, !fir.ref<!fir.char<1,2>>, i1)
+! CHECK: %[[VAL_81:.*]]:2 = hlfir.declare %{{.*}} typeparams %{{.*}} {uniq_name = ".tmp.intrinsic_result"} : (!fir.heap<!fir.char<1,4>>, index) -> (!fir.heap<!fir.char<1,4>>, !fir.heap<!fir.char<1,4>>)
+! CHECK: %[[VAL_83:.*]] = hlfir.as_expr %[[VAL_81]]#0 move %{{.*}} : (!fir.heap<!fir.char<1,4>>, i1) -> !hlfir.expr<!fir.char<1,4>>
+! CHECK-NOT: hlfir.destroy %[[VAL_83]]
+! CHECK: hlfir.end_associate %[[VAL_68]]#1, %[[VAL_68]]#2 : !fir.ref<!fir.char<1,2>>, i1
+! CHECK-NOT: hlfir.destroy %[[VAL_83]]
+! CHECK: hlfir.destroy %[[VAL_66]] : !hlfir.expr<!fir.char<1,2>>
+! CHECK-NOT: hlfir.destroy %[[VAL_83]]
+! CHECK: hlfir.end_associate %[[VAL_51]]#1, %[[VAL_51]]#2 : !fir.ref<!fir.char<1>>, i1
+! CHECK-NOT: hlfir.destroy %[[VAL_83]]
+! CHECK: hlfir.destroy %[[VAL_48]] : !hlfir.expr<!fir.char<1>>
+! CHECK-NOT: hlfir.destroy %[[VAL_83]]
+! CHECK: hlfir.yield_element %[[VAL_83]] : !hlfir.expr<!fir.char<1,4>>
+! CHECK-NOT: hlfir.destroy %[[VAL_83]]
+! CHECK: }
+! CHECK-NOT: hlfir.destroy %[[VAL_83]]