diff options
author | Slava Zakharin <szakharin@nvidia.com> | 2023-07-19 10:03:27 -0700 |
---|---|---|
committer | Slava Zakharin <szakharin@nvidia.com> | 2023-07-19 14:38:31 -0700 |
commit | b9e435cbe494c919e8edc973e696e88e08e0dace (patch) | |
tree | ca6c0e600f83a7799fb8c70e372f37b4e60ee7f5 /flang | |
parent | b63698727d84a84f2163386aa3209ab28cc73c7e (diff) | |
download | llvm-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.td | 2 | ||||
-rw-r--r-- | flang/lib/Lower/ConvertArrayConstructor.cpp | 20 | ||||
-rw-r--r-- | flang/test/Lower/HLFIR/array-ctor-as-elemental.f90 | 29 |
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]] |