diff --git a/flang/lib/Optimizer/HLFIR/Transforms/OptimizedBufferization.cpp b/flang/lib/Optimizer/HLFIR/Transforms/OptimizedBufferization.cpp --- a/flang/lib/Optimizer/HLFIR/Transforms/OptimizedBufferization.cpp +++ b/flang/lib/Optimizer/HLFIR/Transforms/OptimizedBufferization.cpp @@ -417,6 +417,102 @@ return mlir::success(); } +/// Expand hlfir.assign of array RHS to array LHS into a loop nest +/// of element-by-element assignments: +/// hlfir.assign %4 to %5 : !fir.ref>, +/// !fir.ref> +/// into: +/// fir.do_loop %arg1 = %c1 to %c3 step %c1 unordered { +/// fir.do_loop %arg2 = %c1 to %c3 step %c1 unordered { +/// %6 = hlfir.designate %4 (%arg2, %arg1) : +/// (!fir.ref>, index, index) -> !fir.ref +/// %7 = fir.load %6 : !fir.ref +/// %8 = hlfir.designate %5 (%arg2, %arg1) : +/// (!fir.ref>, index, index) -> !fir.ref +/// hlfir.assign %7 to %8 : f32, !fir.ref +/// } +/// } +/// +/// The transformation is correct only when LHS and RHS do not alias. +/// This transformation does not support runtime checking for +/// non-conforming LHS/RHS arrays' shapes currently. +class VariableAssignBufferization + : public mlir::OpRewritePattern { +private: +public: + using mlir::OpRewritePattern::OpRewritePattern; + + mlir::LogicalResult + matchAndRewrite(hlfir::AssignOp assign, + mlir::PatternRewriter &rewriter) const override; +}; + +mlir::LogicalResult VariableAssignBufferization::matchAndRewrite( + hlfir::AssignOp assign, mlir::PatternRewriter &rewriter) const { + if (assign.isAllocatableAssignment()) + return rewriter.notifyMatchFailure(assign, "AssignOp may imply allocation"); + + hlfir::Entity rhs{assign.getRhs()}; + // TODO: ExprType check is here to avoid conflicts with + // ElementalAssignBufferization pattern. We need to combine + // these matchers into a single one that applies to AssignOp. + if (rhs.getType().isa()) + return rewriter.notifyMatchFailure(assign, "RHS is not in memory"); + + if (!rhs.isArray()) + return rewriter.notifyMatchFailure(assign, + "AssignOp's RHS is not an array"); + + mlir::Type rhsEleTy = rhs.getFortranElementType(); + if (!fir::isa_trivial(rhsEleTy)) + return rewriter.notifyMatchFailure( + assign, "AssignOp's RHS data type is not trivial"); + + hlfir::Entity lhs{assign.getLhs()}; + if (!lhs.isArray()) + return rewriter.notifyMatchFailure(assign, + "AssignOp's LHS is not an array"); + + mlir::Type lhsEleTy = lhs.getFortranElementType(); + if (!fir::isa_trivial(lhsEleTy)) + return rewriter.notifyMatchFailure( + assign, "AssignOp's LHS data type is not trivial"); + + if (lhsEleTy != rhsEleTy) + return rewriter.notifyMatchFailure(assign, + "RHS/LHS element types mismatch"); + + fir::AliasAnalysis aliasAnalysis; + mlir::AliasResult aliasRes = aliasAnalysis.alias(lhs, rhs); + if (!aliasRes.isNo()) { + LLVM_DEBUG(llvm::dbgs() << "VariableAssignBufferization:\n" + << "\tLHS: " << lhs << "\n" + << "\tRHS: " << rhs << "\n" + << "\tALIAS: " << aliasRes << "\n"); + return rewriter.notifyMatchFailure(assign, "RHS/LHS may alias"); + } + + mlir::Location loc = assign->getLoc(); + fir::FirOpBuilder builder(rewriter, assign.getOperation()); + builder.setInsertionPoint(assign); + rhs = hlfir::derefPointersAndAllocatables(loc, builder, rhs); + lhs = hlfir::derefPointersAndAllocatables(loc, builder, lhs); + mlir::Value shape = hlfir::genShape(loc, builder, lhs); + llvm::SmallVector extents = + hlfir::getIndexExtents(loc, builder, shape); + hlfir::LoopNest loopNest = + hlfir::genLoopNest(loc, builder, extents, /*isUnordered=*/true); + builder.setInsertionPointToStart(loopNest.innerLoop.getBody()); + auto rhsArrayElement = + hlfir::getElementAt(loc, builder, rhs, loopNest.oneBasedIndices); + rhsArrayElement = hlfir::loadTrivialScalar(loc, builder, rhsArrayElement); + auto lhsArrayElement = + hlfir::getElementAt(loc, builder, lhs, loopNest.oneBasedIndices); + builder.create(loc, rhsArrayElement, lhsArrayElement); + rewriter.eraseOp(assign); + return mlir::success(); +} + class OptimizedBufferizationPass : public hlfir::impl::OptimizedBufferizationBase< OptimizedBufferizationPass> { @@ -438,6 +534,7 @@ // This requires small code reordering in ElementalAssignBufferization. patterns.insert(context); patterns.insert(context); + patterns.insert(context); if (mlir::failed(mlir::applyPatternsAndFoldGreedily( func, std::move(patterns), config))) { diff --git a/flang/test/HLFIR/opt-bufferization.fir b/flang/test/HLFIR/opt-bufferization.fir --- a/flang/test/HLFIR/opt-bufferization.fir +++ b/flang/test/HLFIR/opt-bufferization.fir @@ -251,7 +251,7 @@ // CHECK: %[[VAL_5B:.*]]:2 = hlfir.declare %[[ARG_1]](%[[VAL_4]]) {uniq_name = "array2"} : (!fir.ref>, !fir.shape<1>) -> (!fir.ref>, !fir.ref>) // CHECK: %[[VAL_6:.*]] = hlfir.elemental %[[VAL_4]] unordered : (!fir.shape<1>) -> !hlfir.expr<42xi32> { // CHECK: ^bb0(%[[VAL_7:.*]]: index): -// CHECK: hlfir.assign %[[VAL_5B]]#0 to %[[VAL_5]]#0 : !fir.ref>, !fir.ref> +// CHECK: hlfir.assign // CHECK: %[[VAL_8:.*]] = hlfir.designate %[[VAL_5]]#0 (%[[VAL_7]]) : (!fir.ref>, index) -> !fir.ref // CHECK: %[[VAL_9:.*]] = fir.load %[[VAL_8]] : !fir.ref // CHECK: %[[VAL_10:.*]] = arith.subi %[[VAL_9]], %[[VAL_1]] : i32 diff --git a/flang/test/HLFIR/opt-variable-assign.fir b/flang/test/HLFIR/opt-variable-assign.fir new file mode 100644 --- /dev/null +++ b/flang/test/HLFIR/opt-variable-assign.fir @@ -0,0 +1,308 @@ +// Test optimized bufferization for hlfir.assign of arrays +// variables: +// RUN: fir-opt --opt-bufferization %s | FileCheck %s + +// The two assigns come from the following source forms: +// y(:,:) = x(:,:) +// y = x +func.func @_QPtest1(%arg0: !fir.ref> {fir.bindc_name = "x"}) { + %c1 = arith.constant 1 : index + %c3 = arith.constant 3 : index + %0 = fir.shape %c3, %c3 : (index, index) -> !fir.shape<2> + %1:2 = hlfir.declare %arg0(%0) {uniq_name = "_QFtest1Ex"} : (!fir.ref>, !fir.shape<2>) -> (!fir.ref>, !fir.ref>) + %2 = fir.alloca !fir.array<3x3xf32> {bindc_name = "y", uniq_name = "_QFtest1Ey"} + %3:2 = hlfir.declare %2(%0) {uniq_name = "_QFtest1Ey"} : (!fir.ref>, !fir.shape<2>) -> (!fir.ref>, !fir.ref>) + %4 = hlfir.designate %1#0 (%c1:%c3:%c1, %c1:%c3:%c1) shape %0 : (!fir.ref>, index, index, index, index, index, index, !fir.shape<2>) -> !fir.ref> + %5 = hlfir.designate %3#0 (%c1:%c3:%c1, %c1:%c3:%c1) shape %0 : (!fir.ref>, index, index, index, index, index, index, !fir.shape<2>) -> !fir.ref> + hlfir.assign %4 to %5 : !fir.ref>, !fir.ref> + hlfir.assign %1#0 to %3#0 : !fir.ref>, !fir.ref> + return +} +// CHECK-LABEL: func.func @_QPtest1( +// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref> {fir.bindc_name = "x"}) { +// CHECK: %[[VAL_1:.*]] = arith.constant 1 : index +// CHECK: %[[VAL_2:.*]] = arith.constant 3 : index +// CHECK: %[[VAL_3:.*]] = fir.shape %[[VAL_2]], %[[VAL_2]] : (index, index) -> !fir.shape<2> +// CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %[[VAL_0]](%[[VAL_3]]) {uniq_name = "_QFtest1Ex"} : (!fir.ref>, !fir.shape<2>) -> (!fir.ref>, !fir.ref>) +// CHECK: %[[VAL_5:.*]] = fir.alloca !fir.array<3x3xf32> {bindc_name = "y", uniq_name = "_QFtest1Ey"} +// CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]](%[[VAL_3]]) {uniq_name = "_QFtest1Ey"} : (!fir.ref>, !fir.shape<2>) -> (!fir.ref>, !fir.ref>) +// CHECK: %[[VAL_7:.*]] = hlfir.designate %[[VAL_4]]#0 (%[[VAL_1]]:%[[VAL_2]]:%[[VAL_1]], %[[VAL_1]]:%[[VAL_2]]:%[[VAL_1]]) shape %[[VAL_3]] : (!fir.ref>, index, index, index, index, index, index, !fir.shape<2>) -> !fir.ref> +// CHECK: %[[VAL_8:.*]] = hlfir.designate %[[VAL_6]]#0 (%[[VAL_1]]:%[[VAL_2]]:%[[VAL_1]], %[[VAL_1]]:%[[VAL_2]]:%[[VAL_1]]) shape %[[VAL_3]] : (!fir.ref>, index, index, index, index, index, index, !fir.shape<2>) -> !fir.ref> +// CHECK: fir.do_loop %[[VAL_9:.*]] = %[[VAL_1]] to %[[VAL_2]] step %[[VAL_1]] unordered { +// CHECK: fir.do_loop %[[VAL_10:.*]] = %[[VAL_1]] to %[[VAL_2]] step %[[VAL_1]] unordered { +// CHECK: %[[VAL_11:.*]] = hlfir.designate %[[VAL_7]] (%[[VAL_10]], %[[VAL_9]]) : (!fir.ref>, index, index) -> !fir.ref +// CHECK: %[[VAL_12:.*]] = fir.load %[[VAL_11]] : !fir.ref +// CHECK: %[[VAL_13:.*]] = hlfir.designate %[[VAL_8]] (%[[VAL_10]], %[[VAL_9]]) : (!fir.ref>, index, index) -> !fir.ref +// CHECK: hlfir.assign %[[VAL_12]] to %[[VAL_13]] : f32, !fir.ref +// CHECK: } +// CHECK: } +// CHECK: fir.do_loop %[[VAL_14:.*]] = %[[VAL_1]] to %[[VAL_2]] step %[[VAL_1]] unordered { +// CHECK: fir.do_loop %[[VAL_15:.*]] = %[[VAL_1]] to %[[VAL_2]] step %[[VAL_1]] unordered { +// CHECK: %[[VAL_16:.*]] = hlfir.designate %[[VAL_4]]#0 (%[[VAL_15]], %[[VAL_14]]) : (!fir.ref>, index, index) -> !fir.ref +// CHECK: %[[VAL_17:.*]] = fir.load %[[VAL_16]] : !fir.ref +// CHECK: %[[VAL_18:.*]] = hlfir.designate %[[VAL_6]]#0 (%[[VAL_15]], %[[VAL_14]]) : (!fir.ref>, index, index) -> !fir.ref +// CHECK: hlfir.assign %[[VAL_17]] to %[[VAL_18]] : f32, !fir.ref +// CHECK: } +// CHECK: } +// CHECK: return +// CHECK: } + + +func.func @_QPtest2(%arg0: !fir.box> {fir.bindc_name = "x"}) { + %c0 = arith.constant 0 : index + %c1 = arith.constant 1 : index + %c3 = arith.constant 3 : index + %0:2 = hlfir.declare %arg0 {uniq_name = "_QFtest2Ex"} : (!fir.box>) -> (!fir.box>, !fir.box>) + %1 = fir.alloca !fir.array<3x3xf32> {bindc_name = "y", uniq_name = "_QFtest2Ey"} + %2 = fir.shape %c3, %c3 : (index, index) -> !fir.shape<2> + %3:2 = hlfir.declare %1(%2) {uniq_name = "_QFtest2Ey"} : (!fir.ref>, !fir.shape<2>) -> (!fir.ref>, !fir.ref>) + %4:3 = fir.box_dims %0#1, %c0 : (!fir.box>, index) -> (index, index, index) + %5:3 = fir.box_dims %0#1, %c1 : (!fir.box>, index) -> (index, index, index) + %6 = arith.cmpi sgt, %4#1, %c0 : index + %7 = arith.select %6, %4#1, %c0 : index + %8 = arith.cmpi sgt, %5#1, %c0 : index + %9 = arith.select %8, %5#1, %c0 : index + %10 = fir.shape %7, %9 : (index, index) -> !fir.shape<2> + %11 = hlfir.designate %0#0 (%c1:%4#1:%c1, %c1:%5#1:%c1) shape %10 : (!fir.box>, index, index, index, index, index, index, !fir.shape<2>) -> !fir.box> + %12 = hlfir.designate %3#0 (%c1:%c3:%c1, %c1:%c3:%c1) shape %2 : (!fir.ref>, index, index, index, index, index, index, !fir.shape<2>) -> !fir.ref> + hlfir.assign %11 to %12 : !fir.box>, !fir.ref> + hlfir.assign %0#0 to %3#0 : !fir.box>, !fir.ref> + return +} +// CHECK-LABEL: func.func @_QPtest2( +// CHECK-SAME: %[[VAL_0:.*]]: !fir.box> {fir.bindc_name = "x"}) { +// CHECK: %[[VAL_1:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_2:.*]] = arith.constant 1 : index +// CHECK: %[[VAL_3:.*]] = arith.constant 3 : index +// CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFtest2Ex"} : (!fir.box>) -> (!fir.box>, !fir.box>) +// CHECK: %[[VAL_5:.*]] = fir.alloca !fir.array<3x3xf32> {bindc_name = "y", uniq_name = "_QFtest2Ey"} +// CHECK: %[[VAL_6:.*]] = fir.shape %[[VAL_3]], %[[VAL_3]] : (index, index) -> !fir.shape<2> +// CHECK: %[[VAL_7:.*]]:2 = hlfir.declare %[[VAL_5]](%[[VAL_6]]) {uniq_name = "_QFtest2Ey"} : (!fir.ref>, !fir.shape<2>) -> (!fir.ref>, !fir.ref>) +// CHECK: %[[VAL_8:.*]]:3 = fir.box_dims %[[VAL_4]]#1, %[[VAL_1]] : (!fir.box>, index) -> (index, index, index) +// CHECK: %[[VAL_9:.*]]:3 = fir.box_dims %[[VAL_4]]#1, %[[VAL_2]] : (!fir.box>, index) -> (index, index, index) +// CHECK: %[[VAL_10:.*]] = arith.cmpi sgt, %[[VAL_8]]#1, %[[VAL_1]] : index +// CHECK: %[[VAL_11:.*]] = arith.select %[[VAL_10]], %[[VAL_8]]#1, %[[VAL_1]] : index +// CHECK: %[[VAL_12:.*]] = arith.cmpi sgt, %[[VAL_9]]#1, %[[VAL_1]] : index +// CHECK: %[[VAL_13:.*]] = arith.select %[[VAL_12]], %[[VAL_9]]#1, %[[VAL_1]] : index +// CHECK: %[[VAL_14:.*]] = fir.shape %[[VAL_11]], %[[VAL_13]] : (index, index) -> !fir.shape<2> +// CHECK: %[[VAL_15:.*]] = hlfir.designate %[[VAL_4]]#0 (%[[VAL_2]]:%[[VAL_8]]#1:%[[VAL_2]], %[[VAL_2]]:%[[VAL_9]]#1:%[[VAL_2]]) shape %[[VAL_14]] : (!fir.box>, index, index, index, index, index, index, !fir.shape<2>) -> !fir.box> +// CHECK: %[[VAL_16:.*]] = hlfir.designate %[[VAL_7]]#0 (%[[VAL_2]]:%[[VAL_3]]:%[[VAL_2]], %[[VAL_2]]:%[[VAL_3]]:%[[VAL_2]]) shape %[[VAL_6]] : (!fir.ref>, index, index, index, index, index, index, !fir.shape<2>) -> !fir.ref> +// CHECK: fir.do_loop %[[VAL_17:.*]] = %[[VAL_2]] to %[[VAL_3]] step %[[VAL_2]] unordered { +// CHECK: fir.do_loop %[[VAL_18:.*]] = %[[VAL_2]] to %[[VAL_3]] step %[[VAL_2]] unordered { +// CHECK: %[[VAL_19:.*]] = hlfir.designate %[[VAL_15]] (%[[VAL_18]], %[[VAL_17]]) : (!fir.box>, index, index) -> !fir.ref +// CHECK: %[[VAL_20:.*]] = fir.load %[[VAL_19]] : !fir.ref +// CHECK: %[[VAL_21:.*]] = hlfir.designate %[[VAL_16]] (%[[VAL_18]], %[[VAL_17]]) : (!fir.ref>, index, index) -> !fir.ref +// CHECK: hlfir.assign %[[VAL_20]] to %[[VAL_21]] : f32, !fir.ref +// CHECK: } +// CHECK: } +// CHECK: fir.do_loop %[[VAL_22:.*]] = %[[VAL_2]] to %[[VAL_3]] step %[[VAL_2]] unordered { +// CHECK: fir.do_loop %[[VAL_23:.*]] = %[[VAL_2]] to %[[VAL_3]] step %[[VAL_2]] unordered { +// CHECK: %[[VAL_24:.*]] = hlfir.designate %[[VAL_4]]#0 (%[[VAL_23]], %[[VAL_22]]) : (!fir.box>, index, index) -> !fir.ref +// CHECK: %[[VAL_25:.*]] = fir.load %[[VAL_24]] : !fir.ref +// CHECK: %[[VAL_26:.*]] = hlfir.designate %[[VAL_7]]#0 (%[[VAL_23]], %[[VAL_22]]) : (!fir.ref>, index, index) -> !fir.ref +// CHECK: hlfir.assign %[[VAL_25]] to %[[VAL_26]] : f32, !fir.ref +// CHECK: } +// CHECK: } +// CHECK: return +// CHECK: } + + +func.func @_QPtest3(%arg0: !fir.box> {fir.bindc_name = "x"}) { + %c0 = arith.constant 0 : index + %c1 = arith.constant 1 : index + %c3 = arith.constant 3 : index + %0:2 = hlfir.declare %arg0 {uniq_name = "_QFtest3Ex"} : (!fir.box>) -> (!fir.box>, !fir.box>) + %1 = fir.alloca !fir.array<3x3xf32> {bindc_name = "y", uniq_name = "_QFtest3Ey"} + %2 = fir.shape %c3, %c3 : (index, index) -> !fir.shape<2> + %3:2 = hlfir.declare %1(%2) {uniq_name = "_QFtest3Ey"} : (!fir.ref>, !fir.shape<2>) -> (!fir.ref>, !fir.ref>) + %4 = hlfir.designate %3#0 (%c1:%c3:%c1, %c1:%c3:%c1) shape %2 : (!fir.ref>, index, index, index, index, index, index, !fir.shape<2>) -> !fir.ref> + %5:3 = fir.box_dims %0#1, %c0 : (!fir.box>, index) -> (index, index, index) + %6:3 = fir.box_dims %0#1, %c1 : (!fir.box>, index) -> (index, index, index) + %7 = arith.cmpi sgt, %5#1, %c0 : index + %8 = arith.select %7, %5#1, %c0 : index + %9 = arith.cmpi sgt, %6#1, %c0 : index + %10 = arith.select %9, %6#1, %c0 : index + %11 = fir.shape %8, %10 : (index, index) -> !fir.shape<2> + %12 = hlfir.designate %0#0 (%c1:%5#1:%c1, %c1:%6#1:%c1) shape %11 : (!fir.box>, index, index, index, index, index, index, !fir.shape<2>) -> !fir.box> + hlfir.assign %4 to %12 : !fir.ref>, !fir.box> + hlfir.assign %3#0 to %0#0 : !fir.ref>, !fir.box> + return +} +// CHECK-LABEL: func.func @_QPtest3( +// CHECK-SAME: %[[VAL_0:.*]]: !fir.box> {fir.bindc_name = "x"}) { +// CHECK: %[[VAL_1:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_2:.*]] = arith.constant 1 : index +// CHECK: %[[VAL_3:.*]] = arith.constant 3 : index +// CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFtest3Ex"} : (!fir.box>) -> (!fir.box>, !fir.box>) +// CHECK: %[[VAL_5:.*]] = fir.alloca !fir.array<3x3xf32> {bindc_name = "y", uniq_name = "_QFtest3Ey"} +// CHECK: %[[VAL_6:.*]] = fir.shape %[[VAL_3]], %[[VAL_3]] : (index, index) -> !fir.shape<2> +// CHECK: %[[VAL_7:.*]]:2 = hlfir.declare %[[VAL_5]](%[[VAL_6]]) {uniq_name = "_QFtest3Ey"} : (!fir.ref>, !fir.shape<2>) -> (!fir.ref>, !fir.ref>) +// CHECK: %[[VAL_8:.*]] = hlfir.designate %[[VAL_7]]#0 (%[[VAL_2]]:%[[VAL_3]]:%[[VAL_2]], %[[VAL_2]]:%[[VAL_3]]:%[[VAL_2]]) shape %[[VAL_6]] : (!fir.ref>, index, index, index, index, index, index, !fir.shape<2>) -> !fir.ref> +// CHECK: %[[VAL_9:.*]]:3 = fir.box_dims %[[VAL_4]]#1, %[[VAL_1]] : (!fir.box>, index) -> (index, index, index) +// CHECK: %[[VAL_10:.*]]:3 = fir.box_dims %[[VAL_4]]#1, %[[VAL_2]] : (!fir.box>, index) -> (index, index, index) +// CHECK: %[[VAL_11:.*]] = arith.cmpi sgt, %[[VAL_9]]#1, %[[VAL_1]] : index +// CHECK: %[[VAL_12:.*]] = arith.select %[[VAL_11]], %[[VAL_9]]#1, %[[VAL_1]] : index +// CHECK: %[[VAL_13:.*]] = arith.cmpi sgt, %[[VAL_10]]#1, %[[VAL_1]] : index +// CHECK: %[[VAL_14:.*]] = arith.select %[[VAL_13]], %[[VAL_10]]#1, %[[VAL_1]] : index +// CHECK: %[[VAL_15:.*]] = fir.shape %[[VAL_12]], %[[VAL_14]] : (index, index) -> !fir.shape<2> +// CHECK: %[[VAL_16:.*]] = hlfir.designate %[[VAL_4]]#0 (%[[VAL_2]]:%[[VAL_9]]#1:%[[VAL_2]], %[[VAL_2]]:%[[VAL_10]]#1:%[[VAL_2]]) shape %[[VAL_15]] : (!fir.box>, index, index, index, index, index, index, !fir.shape<2>) -> !fir.box> +// CHECK: fir.do_loop %[[VAL_17:.*]] = %[[VAL_2]] to %[[VAL_14]] step %[[VAL_2]] unordered { +// CHECK: fir.do_loop %[[VAL_18:.*]] = %[[VAL_2]] to %[[VAL_12]] step %[[VAL_2]] unordered { +// CHECK: %[[VAL_19:.*]] = hlfir.designate %[[VAL_8]] (%[[VAL_18]], %[[VAL_17]]) : (!fir.ref>, index, index) -> !fir.ref +// CHECK: %[[VAL_20:.*]] = fir.load %[[VAL_19]] : !fir.ref +// CHECK: %[[VAL_21:.*]] = hlfir.designate %[[VAL_16]] (%[[VAL_18]], %[[VAL_17]]) : (!fir.box>, index, index) -> !fir.ref +// CHECK: hlfir.assign %[[VAL_20]] to %[[VAL_21]] : f32, !fir.ref +// CHECK: } +// CHECK: } +// CHECK: %[[VAL_22:.*]]:3 = fir.box_dims %[[VAL_4]]#0, %[[VAL_1]] : (!fir.box>, index) -> (index, index, index) +// CHECK: %[[VAL_23:.*]]:3 = fir.box_dims %[[VAL_4]]#0, %[[VAL_2]] : (!fir.box>, index) -> (index, index, index) +// CHECK: fir.do_loop %[[VAL_24:.*]] = %[[VAL_2]] to %[[VAL_23]]#1 step %[[VAL_2]] unordered { +// CHECK: fir.do_loop %[[VAL_25:.*]] = %[[VAL_2]] to %[[VAL_22]]#1 step %[[VAL_2]] unordered { +// CHECK: %[[VAL_26:.*]] = hlfir.designate %[[VAL_7]]#0 (%[[VAL_25]], %[[VAL_24]]) : (!fir.ref>, index, index) -> !fir.ref +// CHECK: %[[VAL_27:.*]] = fir.load %[[VAL_26]] : !fir.ref +// CHECK: %[[VAL_28:.*]] = hlfir.designate %[[VAL_4]]#0 (%[[VAL_25]], %[[VAL_24]]) : (!fir.box>, index, index) -> !fir.ref +// CHECK: hlfir.assign %[[VAL_27]] to %[[VAL_28]] : f32, !fir.ref +// CHECK: } +// CHECK: } +// CHECK: return +// CHECK: } + + +// The LHS is a whole allocatable, so the assignment may imply +// allocation. This is not currently supported. +func.func @_QPtest4(%arg0: !fir.ref>>> {fir.bindc_name = "x"}) { + %c3 = arith.constant 3 : index + %0:2 = hlfir.declare %arg0 {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest4Ex"} : (!fir.ref>>>) -> (!fir.ref>>>, !fir.ref>>>) + %1 = fir.alloca !fir.array<3x3xf32> {bindc_name = "y", uniq_name = "_QFtest4Ey"} + %2 = fir.shape %c3, %c3 : (index, index) -> !fir.shape<2> + %3:2 = hlfir.declare %1(%2) {uniq_name = "_QFtest4Ey"} : (!fir.ref>, !fir.shape<2>) -> (!fir.ref>, !fir.ref>) + hlfir.assign %3#0 to %0#0 realloc : !fir.ref>, !fir.ref>>> + return +} +// CHECK-LABEL: func.func @_QPtest4( +// CHECK-NOT: hlfir.assign +// CHECK: hlfir.assign %{{.*}} to %{{.*}} realloc : !fir.ref>, !fir.ref>>> +// CHECK-NOT: hlfir.assign + + +// TODO: LHS is a pointer, but RHS is a subroutine local, +// so they cannot alias. +func.func @_QPtest5(%arg0: !fir.ref>>> {fir.bindc_name = "x"}) { + %c0 = arith.constant 0 : index + %c1 = arith.constant 1 : index + %c3 = arith.constant 3 : index + %0:2 = hlfir.declare %arg0 {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest5Ex"} : (!fir.ref>>>) -> (!fir.ref>>>, !fir.ref>>>) + %1 = fir.alloca !fir.array<3x3xf32> {bindc_name = "y", uniq_name = "_QFtest5Ey"} + %2 = fir.shape %c3, %c3 : (index, index) -> !fir.shape<2> + %3:2 = hlfir.declare %1(%2) {uniq_name = "_QFtest5Ey"} : (!fir.ref>, !fir.shape<2>) -> (!fir.ref>, !fir.ref>) + %4 = hlfir.designate %3#0 (%c1:%c3:%c1, %c1:%c3:%c1) shape %2 : (!fir.ref>, index, index, index, index, index, index, !fir.shape<2>) -> !fir.ref> + %5 = fir.load %0#0 : !fir.ref>>> + %6:3 = fir.box_dims %5, %c0 : (!fir.box>>, index) -> (index, index, index) + %7:3 = fir.box_dims %5, %c1 : (!fir.box>>, index) -> (index, index, index) + %8 = arith.addi %6#0, %6#1 : index + %9 = arith.subi %8, %c1 : index + %10 = arith.addi %7#0, %7#1 : index + %11 = arith.subi %10, %c1 : index + %12 = arith.subi %9, %6#0 : index + %13 = arith.addi %12, %c1 : index + %14 = arith.cmpi sgt, %13, %c0 : index + %15 = arith.select %14, %13, %c0 : index + %16 = arith.subi %11, %7#0 : index + %17 = arith.addi %16, %c1 : index + %18 = arith.cmpi sgt, %17, %c0 : index + %19 = arith.select %18, %17, %c0 : index + %20 = fir.shape %15, %19 : (index, index) -> !fir.shape<2> + %21 = hlfir.designate %5 (%6#0:%9:%c1, %7#0:%11:%c1) shape %20 : (!fir.box>>, index, index, index, index, index, index, !fir.shape<2>) -> !fir.box> + hlfir.assign %4 to %21 : !fir.ref>, !fir.box> + %22 = fir.load %0#0 : !fir.ref>>> + hlfir.assign %3#0 to %22 : !fir.ref>, !fir.box>> + return +} +// CHECK-LABEL: func.func @_QPtest5( +// CHECK-NOT: hlfir.assign +// CHECK: hlfir.assign %{{.*}} to %{{.*}} : !fir.ref>, !fir.box> +// CHECK-NOT: hlfir.assign +// CHECK: hlfir.assign %{{.*}} to %{{.*}} : !fir.ref>, !fir.box>> +// CHECK-NOT: hlfir.assign + + +// TODO: RHS is a pointer, but LHS is a subroutine local, +// so they cannot alias. +func.func @_QPtest6(%arg0: !fir.ref>>> {fir.bindc_name = "x"}) { + %c1 = arith.constant 1 : index + %c0 = arith.constant 0 : index + %c3 = arith.constant 3 : index + %0:2 = hlfir.declare %arg0 {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest6Ex"} : (!fir.ref>>>) -> (!fir.ref>>>, !fir.ref>>>) + %1 = fir.alloca !fir.array<3x3xf32> {bindc_name = "y", uniq_name = "_QFtest6Ey"} + %2 = fir.shape %c3, %c3 : (index, index) -> !fir.shape<2> + %3:2 = hlfir.declare %1(%2) {uniq_name = "_QFtest6Ey"} : (!fir.ref>, !fir.shape<2>) -> (!fir.ref>, !fir.ref>) + %4 = fir.load %0#0 : !fir.ref>>> + %5:3 = fir.box_dims %4, %c0 : (!fir.box>>, index) -> (index, index, index) + %6:3 = fir.box_dims %4, %c1 : (!fir.box>>, index) -> (index, index, index) + %7 = arith.addi %5#0, %5#1 : index + %8 = arith.subi %7, %c1 : index + %9 = arith.addi %6#0, %6#1 : index + %10 = arith.subi %9, %c1 : index + %11 = arith.subi %8, %5#0 : index + %12 = arith.addi %11, %c1 : index + %13 = arith.cmpi sgt, %12, %c0 : index + %14 = arith.select %13, %12, %c0 : index + %15 = arith.subi %10, %6#0 : index + %16 = arith.addi %15, %c1 : index + %17 = arith.cmpi sgt, %16, %c0 : index + %18 = arith.select %17, %16, %c0 : index + %19 = fir.shape %14, %18 : (index, index) -> !fir.shape<2> + %20 = hlfir.designate %4 (%5#0:%8:%c1, %6#0:%10:%c1) shape %19 : (!fir.box>>, index, index, index, index, index, index, !fir.shape<2>) -> !fir.box> + %21 = hlfir.designate %3#0 (%c1:%c3:%c1, %c1:%c3:%c1) shape %2 : (!fir.ref>, index, index, index, index, index, index, !fir.shape<2>) -> !fir.ref> + hlfir.assign %20 to %21 : !fir.box>, !fir.ref> + %22 = fir.load %0#0 : !fir.ref>>> + hlfir.assign %22 to %3#0 : !fir.box>>, !fir.ref> + return +} +// CHECK-LABEL: func.func @_QPtest6( +// CHECK-NOT: hlfir.assign +// CHECK: hlfir.assign %{{.*}} to %{{.*}} : !fir.box>, !fir.ref> +// CHECK-NOT: hlfir.assign +// CHECK: hlfir.assign %{{.*}} to %{{.*}} : !fir.box>>, !fir.ref> +// CHECK-NOT: hlfir.assign + + +// TODO: LHS and RHS do not alias, and the assignment cannot +// allocate/reallocate LHS, so we should be able to optimize. +// The box load blocks alias analysis. +// subroutine test7(x) +// real, allocatable :: x(:,:) +// real :: y(3,3) +// x(:,:) = y(:,:) +// end subroutine test7 +func.func @_QPtest7(%arg0: !fir.ref>>> {fir.bindc_name = "x"}) { + %c0 = arith.constant 0 : index + %c1 = arith.constant 1 : index + %c3 = arith.constant 3 : index + %0:2 = hlfir.declare %arg0 {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest7Ex"} : (!fir.ref>>>) -> (!fir.ref>>>, !fir.ref>>>) + %1 = fir.alloca !fir.array<3x3xf32> {bindc_name = "y", uniq_name = "_QFtest7Ey"} + %2 = fir.shape %c3, %c3 : (index, index) -> !fir.shape<2> + %3:2 = hlfir.declare %1(%2) {uniq_name = "_QFtest7Ey"} : (!fir.ref>, !fir.shape<2>) -> (!fir.ref>, !fir.ref>) + %4 = hlfir.designate %3#0 (%c1:%c3:%c1, %c1:%c3:%c1) shape %2 : (!fir.ref>, index, index, index, index, index, index, !fir.shape<2>) -> !fir.ref> + %5 = fir.load %0#0 : !fir.ref>>> + %6:3 = fir.box_dims %5, %c0 : (!fir.box>>, index) -> (index, index, index) + %7:3 = fir.box_dims %5, %c1 : (!fir.box>>, index) -> (index, index, index) + %8 = arith.addi %6#0, %6#1 : index + %9 = arith.subi %8, %c1 : index + %10 = arith.addi %7#0, %7#1 : index + %11 = arith.subi %10, %c1 : index + %12 = arith.subi %9, %6#0 : index + %13 = arith.addi %12, %c1 : index + %14 = arith.cmpi sgt, %13, %c0 : index + %15 = arith.select %14, %13, %c0 : index + %16 = arith.subi %11, %7#0 : index + %17 = arith.addi %16, %c1 : index + %18 = arith.cmpi sgt, %17, %c0 : index + %19 = arith.select %18, %17, %c0 : index + %20 = fir.shape %15, %19 : (index, index) -> !fir.shape<2> + %21 = hlfir.designate %5 (%6#0:%9:%c1, %7#0:%11:%c1) shape %20 : (!fir.box>>, index, index, index, index, index, index, !fir.shape<2>) -> !fir.box> + hlfir.assign %4 to %21 : !fir.ref>, !fir.box> + return +} +// CHECK-LABEL: func.func @_QPtest7( +// CHECK: hlfir.assign %{{.*}} to %{{.*}} : !fir.ref>, !fir.box>