diff --git a/flang/include/flang/Optimizer/HLFIR/HLFIROps.td b/flang/include/flang/Optimizer/HLFIR/HLFIROps.td index f69930d5b53b3..08cfa8168a922 100644 --- a/flang/include/flang/Optimizer/HLFIR/HLFIROps.td +++ b/flang/include/flang/Optimizer/HLFIR/HLFIROps.td @@ -758,6 +758,13 @@ def hlfir_AssociateOp : hlfir_Op<"associate", [AttrSizedOperandSegments, For expressions, this operation is an incentive to re-use the expression storage, if any, after the bufferization pass when possible (if the expression is not used afterwards). + + For aliasing purposes, hlfir.associate with the source being + a trivial FIR value is considered to be a unique allocation + that does not alias with anything else. For non-trivial cases + it may be a unique allocation or an alias for the source expression + storage, so FIR alias analysis will look through it for finding + the source. }]; let arguments = (ins diff --git a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp index cbfc8b63ab64d..73ddd1ff80126 100644 --- a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp +++ b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp @@ -540,6 +540,20 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v, v = op.getVar(); defOp = v.getDefiningOp(); }) + .Case([&](auto op) { + mlir::Value source = op.getSource(); + if (fir::isa_trivial(source.getType())) { + // Trivial values will always use distinct temp memory, + // so we can classify this as Allocate and stop. + type = SourceKind::Allocate; + breakFromLoop = true; + } else { + // AssociateOp may reuse the expression storage, + // so we have to trace further. + v = source; + defOp = v.getDefiningOp(); + } + }) .Case([&](auto op) { // Unique memory allocation. type = SourceKind::Allocate; diff --git a/flang/test/HLFIR/opt-bufferization-eval_in_mem-with-associate.fir b/flang/test/HLFIR/opt-bufferization-eval_in_mem-with-associate.fir new file mode 100644 index 0000000000000..2f5f88ff9e7e8 --- /dev/null +++ b/flang/test/HLFIR/opt-bufferization-eval_in_mem-with-associate.fir @@ -0,0 +1,30 @@ +// RUN: fir-opt --opt-bufferization %s | FileCheck %s + +// Verify that hlfir.eval_in_mem uses the LHS array instead +// of allocating a temporary. +func.func @_QPtest() { + %cst = arith.constant 1.000000e+00 : f32 + %c10 = arith.constant 10 : index + %0 = fir.dummy_scope : !fir.dscope + %1 = fir.alloca !fir.array<10xf32> {bindc_name = "x", uniq_name = "_QFtestEx"} + %2 = fir.shape %c10 : (index) -> !fir.shape<1> + %3:2 = hlfir.declare %1(%2) {uniq_name = "_QFtestEx"} : (!fir.ref>, !fir.shape<1>) -> (!fir.ref>, !fir.ref>) + %4:3 = hlfir.associate %cst {adapt.valuebyref} : (f32) -> (!fir.ref, !fir.ref, i1) + %5 = hlfir.eval_in_mem shape %2 : (!fir.shape<1>) -> !hlfir.expr<10xf32> { + ^bb0(%arg0: !fir.ref>): + %6 = fir.call @_QParray_func(%4#0) fastmath : (!fir.ref) -> !fir.array<10xf32> + fir.save_result %6 to %arg0(%2) : !fir.array<10xf32>, !fir.ref>, !fir.shape<1> + } + hlfir.assign %5 to %3#0 : !hlfir.expr<10xf32>, !fir.ref> + hlfir.end_associate %4#1, %4#2 : !fir.ref, i1 + hlfir.destroy %5 : !hlfir.expr<10xf32> + return +} +// CHECK-LABEL: func.func @_QPtest() { +// CHECK: %[[VAL_0:.*]] = arith.constant 1.000000e+00 : f32 +// CHECK: %[[VAL_3:.*]] = fir.alloca !fir.array<10xf32> {bindc_name = "x", uniq_name = "_QFtestEx"} +// CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_3]](%[[VAL_4:.*]]) {uniq_name = "_QFtestEx"} : (!fir.ref>, !fir.shape<1>) -> (!fir.ref>, !fir.ref>) +// CHECK: %[[VAL_6:.*]]:3 = hlfir.associate %[[VAL_0]] {adapt.valuebyref} : (f32) -> (!fir.ref, !fir.ref, i1) +// CHECK: %[[VAL_7:.*]] = fir.call @_QParray_func(%[[VAL_6]]#0) fastmath : (!fir.ref) -> !fir.array<10xf32> +// CHECK: fir.save_result %[[VAL_7]] to %[[VAL_5]]#0(%[[VAL_4]]) : !fir.array<10xf32>, !fir.ref>, !fir.shape<1> +// CHECK: hlfir.end_associate %[[VAL_6]]#1, %[[VAL_6]]#2 : !fir.ref, i1