diff --git a/flang/lib/Optimizer/HLFIR/Transforms/InlineElementals.cpp b/flang/lib/Optimizer/HLFIR/Transforms/InlineElementals.cpp --- a/flang/lib/Optimizer/HLFIR/Transforms/InlineElementals.cpp +++ b/flang/lib/Optimizer/HLFIR/Transforms/InlineElementals.cpp @@ -74,9 +74,17 @@ mlir::PatternRewriter &rewriter) const override { std::optional> maybeTuple = getTwoUses(elemental); - if (!maybeTuple) { - return rewriter.notifyMatchFailure(elemental.getLoc(), - [](mlir::Diagnostic &) {}); + if (!maybeTuple) + return rewriter.notifyMatchFailure( + elemental, "hlfir.elemental does not have two uses"); + + if (elemental.isOrdered()) { + // We can only inline the ordered elemental into a loop-like + // construct that processes the indices in-order and does not + // have the side effects itself. Adhere to conservative behavior + // for the time being. + return rewriter.notifyMatchFailure(elemental, + "hlfir.elemental is ordered"); } auto [apply, destroy] = *maybeTuple; diff --git a/flang/test/HLFIR/inline-elemental.fir b/flang/test/HLFIR/inline-elemental.fir --- a/flang/test/HLFIR/inline-elemental.fir +++ b/flang/test/HLFIR/inline-elemental.fir @@ -10,7 +10,7 @@ %c0 = arith.constant 0 : index %4:3 = fir.box_dims %1#0, %c0 : (!fir.box>, index) -> (index, index, index) %5 = fir.shape %4#1 : (index) -> !fir.shape<1> - %6 = hlfir.elemental %5 : (!fir.shape<1>) -> !hlfir.expr { + %6 = hlfir.elemental %5 unordered : (!fir.shape<1>) -> !hlfir.expr { ^bb0(%arg4: index): %8 = hlfir.designate %1#0 (%arg4) : (!fir.box>, index) -> !fir.ref %9 = hlfir.designate %2#0 (%arg4) : (!fir.box>, index) -> !fir.ref @@ -72,7 +72,7 @@ %c0 = arith.constant 0 : index %4:3 = fir.box_dims %1#0, %c0 : (!fir.box>, index) -> (index, index, index) %5 = fir.shape %4#1 : (index) -> !fir.shape<1> - %6 = hlfir.elemental %5 : (!fir.shape<1>) -> !hlfir.expr { + %6 = hlfir.elemental %5 unordered : (!fir.shape<1>) -> !hlfir.expr { ^bb0(%arg4: index): %8 = hlfir.designate %1#0 (%arg4) : (!fir.box>, index) -> !fir.ref %9 = hlfir.designate %2#0 (%arg4) : (!fir.box>, index) -> !fir.ref @@ -137,7 +137,7 @@ %c0 = arith.constant 0 : index %4:3 = fir.box_dims %1#0, %c0 : (!fir.box>, index) -> (index, index, index) %5 = fir.shape %4#1 : (index) -> !fir.shape<1> - %6 = hlfir.elemental %5 : (!fir.shape<1>) -> !hlfir.expr { + %6 = hlfir.elemental %5 unordered : (!fir.shape<1>) -> !hlfir.expr { ^bb0(%arg4: index): %8 = hlfir.designate %1#0 (%arg4) : (!fir.box>, index) -> !fir.ref %9 = hlfir.designate %2#0 (%arg4) : (!fir.box>, index) -> !fir.ref @@ -182,14 +182,14 @@ %c0 = arith.constant 0 : index %1:3 = fir.box_dims %0#0, %c0 : (!fir.box>, index) -> (index, index, index) %2 = fir.shape %1#1 : (index) -> !fir.shape<1> - %3 = hlfir.elemental %2 : (!fir.shape<1>) -> !hlfir.expr { + %3 = hlfir.elemental %2 unordered : (!fir.shape<1>) -> !hlfir.expr { ^bb0(%arg1: index): %9 = hlfir.designate %0#0 (%arg1) : (!fir.box>, index) -> !fir.ref %10 = fir.load %9 : !fir.ref %11 = arith.subf %10, %cst fastmath : f32 hlfir.yield_element %11 : f32 } - %4 = hlfir.elemental %2 : (!fir.shape<1>) -> !hlfir.expr { + %4 = hlfir.elemental %2 unordered : (!fir.shape<1>) -> !hlfir.expr { ^bb0(%arg1: index): %9 = hlfir.apply %3, %arg1 : (!hlfir.expr, index) -> f32 %10 = hlfir.no_reassoc %9 : f32 @@ -198,7 +198,7 @@ %c0_0 = arith.constant 0 : index %5:3 = fir.box_dims %0#0, %c0_0 : (!fir.box>, index) -> (index, index, index) %6 = fir.shape %5#1 : (index) -> !fir.shape<1> - %7 = hlfir.elemental %6 : (!fir.shape<1>) -> !hlfir.expr { + %7 = hlfir.elemental %6 unordered : (!fir.shape<1>) -> !hlfir.expr { ^bb0(%arg1: index): %9 = hlfir.designate %0#0 (%arg1) : (!fir.box>, index) -> !fir.ref %10 = hlfir.apply %4, %arg1 : (!hlfir.expr, index) -> f32 @@ -243,3 +243,70 @@ // CHECK-NEXT: hlfir.destroy %[[EXPR]] // CHECK-NEXT: return // CHECK-NEXT: } + +// Check that the ordered elemental is not inlined into another: +// a = b + c + d +func.func @noinline_ordered(%arg0: !fir.box> {fir.bindc_name = "a"}, %arg1: !fir.box> {fir.bindc_name = "b"}, %arg2: !fir.box> {fir.bindc_name = "c"}, %arg3: !fir.box> {fir.bindc_name = "d"}) { + %0:2 = hlfir.declare %arg0 {uniq_name = "a"} : (!fir.box>) -> (!fir.box>, !fir.box>) + %1:2 = hlfir.declare %arg1 {uniq_name = "b"} : (!fir.box>) -> (!fir.box>, !fir.box>) + %2:2 = hlfir.declare %arg2 {uniq_name = "c"} : (!fir.box>) -> (!fir.box>, !fir.box>) + %3:2 = hlfir.declare %arg3 {uniq_name = "d"} : (!fir.box>) -> (!fir.box>, !fir.box>) + %c0 = arith.constant 0 : index + %4:3 = fir.box_dims %1#0, %c0 : (!fir.box>, index) -> (index, index, index) + %5 = fir.shape %4#1 : (index) -> !fir.shape<1> + %6 = hlfir.elemental %5 : (!fir.shape<1>) -> !hlfir.expr { + ^bb0(%arg4: index): + %8 = hlfir.designate %1#0 (%arg4) : (!fir.box>, index) -> !fir.ref + %9 = hlfir.designate %2#0 (%arg4) : (!fir.box>, index) -> !fir.ref + %10 = fir.load %8 : !fir.ref + %11 = fir.load %9 : !fir.ref + %12 = arith.muli %10, %11 : i32 + hlfir.yield_element %12 : i32 + } + %7 = hlfir.elemental %5 unordered : (!fir.shape<1>) -> !hlfir.expr { + ^bb0(%arg4: index): + %8 = hlfir.apply %6, %arg4 : (!hlfir.expr, index) -> i32 + %9 = hlfir.designate %3#0 (%arg4) : (!fir.box>, index) -> !fir.ref + %10 = fir.load %9 : !fir.ref + %11 = arith.addi %8, %10 : i32 + hlfir.yield_element %11 : i32 + } + hlfir.assign %7 to %0#0 : !hlfir.expr, !fir.box> + hlfir.destroy %7 : !hlfir.expr + hlfir.destroy %6 : !hlfir.expr + return +} +// CHECK-LABEL: func.func @noinline_ordered( +// CHECK-SAME: %[[VAL_0:.*]]: !fir.box> {fir.bindc_name = "a"}, +// CHECK-SAME: %[[VAL_1:.*]]: !fir.box> {fir.bindc_name = "b"}, +// CHECK-SAME: %[[VAL_2:.*]]: !fir.box> {fir.bindc_name = "c"}, +// CHECK-SAME: %[[VAL_3:.*]]: !fir.box> {fir.bindc_name = "d"}) { +// CHECK: %[[VAL_4:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "a"} : (!fir.box>) -> (!fir.box>, !fir.box>) +// CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_1]] {uniq_name = "b"} : (!fir.box>) -> (!fir.box>, !fir.box>) +// CHECK: %[[VAL_7:.*]]:2 = hlfir.declare %[[VAL_2]] {uniq_name = "c"} : (!fir.box>) -> (!fir.box>, !fir.box>) +// CHECK: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_3]] {uniq_name = "d"} : (!fir.box>) -> (!fir.box>, !fir.box>) +// CHECK: %[[VAL_9:.*]]:3 = fir.box_dims %[[VAL_6]]#0, %[[VAL_4]] : (!fir.box>, index) -> (index, index, index) +// CHECK: %[[VAL_10:.*]] = fir.shape %[[VAL_9]]#1 : (index) -> !fir.shape<1> +// CHECK: %[[VAL_11:.*]] = hlfir.elemental %[[VAL_10]] : (!fir.shape<1>) -> !hlfir.expr { +// CHECK: ^bb0(%[[VAL_12:.*]]: index): +// CHECK: %[[VAL_13:.*]] = hlfir.designate %[[VAL_6]]#0 (%[[VAL_12]]) : (!fir.box>, index) -> !fir.ref +// CHECK: %[[VAL_14:.*]] = hlfir.designate %[[VAL_7]]#0 (%[[VAL_12]]) : (!fir.box>, index) -> !fir.ref +// CHECK: %[[VAL_15:.*]] = fir.load %[[VAL_13]] : !fir.ref +// CHECK: %[[VAL_16:.*]] = fir.load %[[VAL_14]] : !fir.ref +// CHECK: %[[VAL_17:.*]] = arith.muli %[[VAL_15]], %[[VAL_16]] : i32 +// CHECK: hlfir.yield_element %[[VAL_17]] : i32 +// CHECK: } +// CHECK: %[[VAL_18:.*]] = hlfir.elemental %[[VAL_10]] unordered : (!fir.shape<1>) -> !hlfir.expr { +// CHECK: ^bb0(%[[VAL_19:.*]]: index): +// CHECK: %[[VAL_20:.*]] = hlfir.apply %[[VAL_21:.*]], %[[VAL_19]] : (!hlfir.expr, index) -> i32 +// CHECK: %[[VAL_22:.*]] = hlfir.designate %[[VAL_8]]#0 (%[[VAL_19]]) : (!fir.box>, index) -> !fir.ref +// CHECK: %[[VAL_23:.*]] = fir.load %[[VAL_22]] : !fir.ref +// CHECK: %[[VAL_24:.*]] = arith.addi %[[VAL_20]], %[[VAL_23]] : i32 +// CHECK: hlfir.yield_element %[[VAL_24]] : i32 +// CHECK: } +// CHECK: hlfir.assign %[[VAL_25:.*]] to %[[VAL_5]]#0 : !hlfir.expr, !fir.box> +// CHECK: hlfir.destroy %[[VAL_25]] : !hlfir.expr +// CHECK: hlfir.destroy %[[VAL_26:.*]] : !hlfir.expr +// CHECK: return +// CHECK: }