diff --git a/flang/include/flang/Optimizer/Dialect/FIROps.td b/flang/include/flang/Optimizer/Dialect/FIROps.td index 610084d5fdbf..d9c59b6f4343 100644 --- a/flang/include/flang/Optimizer/Dialect/FIROps.td +++ b/flang/include/flang/Optimizer/Dialect/FIROps.td @@ -2289,9 +2289,9 @@ def fir_LenParamIndexOp : fir_OneResultOp<"len_param_index", [NoMemoryEffect]> { // Fortran loops //===----------------------------------------------------------------------===// -def fir_ResultOp : fir_Op<"result", - [NoMemoryEffect, ReturnLike, Terminator, - ParentOneOf<["IfOp", "DoLoopOp", "IterWhileOp"]>]> { +def fir_ResultOp + : fir_Op<"result", [Pure, ReturnLike, Terminator, + ParentOneOf<["IfOp", "DoLoopOp", "IterWhileOp"]>]> { let summary = "special terminator for use in fir region operations"; let description = [{ diff --git a/flang/test/Transforms/licm.fir b/flang/test/Transforms/licm.fir index d7f405ffb05f..fbcb928620b3 100644 --- a/flang/test/Transforms/licm.fir +++ b/flang/test/Transforms/licm.fir @@ -1325,6 +1325,7 @@ func.func @_QPtest_dummy_scalar_pointer_optional(%arg0: !fir.ref> {fir.bindc_n return } +// ----- // Check that a load of scalar defined as associate(c => b(10)) // is not hoisted, because it is actually an access of array // and it may be out of bounds. @@ -1444,6 +1447,7 @@ func.func @_QPtest_associated_array_access(%arg0: !fir.ref> {f return } +// ----- // 'b' can be hoisted. // subroutine test_common_scalar(a,n) // common /blk/ b,c @@ -1504,6 +1508,7 @@ func.func @_QPtest_common_scalar(%arg0: !fir.ref> {fir.bindc_n return } +// ----- // 'm' can be hoisted, and 'c(m)' cannot. // subroutine test_common_array(a,n,m) // common /blk/ b,c @@ -1574,3 +1579,83 @@ func.func @_QPtest_common_array(%arg0: !fir.ref> {fir.bindc_na fir.store %19 to %13 : !fir.ref return } + +// ----- +// Same example as test_dummy_scalar with manually added fir.if inside the loop. +// Check that the invariant fir.if is hoisted: +// CHECK-LABEL: func.func @test_if_hoisting( +// CHECK-SAME: %[[ARG0:.*]]: !fir.ref> {fir.bindc_name = "r"}, +// CHECK-SAME: %[[ARG1:.*]]: !fir.ref {fir.bindc_name = "x"}, +// CHECK-SAME: %[[ARG2:.*]]: !fir.ref {fir.bindc_name = "n"}, +// CHECK-SAME: %[[ARG3:.*]]: i1) { +// CHECK: %[[CONSTANT_0:.*]] = arith.constant 1 : index +// CHECK: %[[DUMMY_SCOPE_0:.*]] = fir.dummy_scope : !fir.dscope +// CHECK: %[[ALLOCA_0:.*]] = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFtest_dummy_scalarEi"} +// CHECK: %[[DECLARE_0:.*]] = fir.declare %[[ALLOCA_0]] {uniq_name = "_QFtest_dummy_scalarEi"} : (!fir.ref) -> !fir.ref +// CHECK: %[[DECLARE_1:.*]] = fir.declare %[[ARG2]] dummy_scope %[[DUMMY_SCOPE_0]] arg 3 {uniq_name = "_QFtest_dummy_scalarEn"} : (!fir.ref, !fir.dscope) -> !fir.ref +// CHECK: %[[ASSUMED_SIZE_EXTENT_0:.*]] = fir.assumed_size_extent : index +// CHECK: %[[SHAPE_0:.*]] = fir.shape %[[ASSUMED_SIZE_EXTENT_0]] : (index) -> !fir.shape<1> +// CHECK: %[[DECLARE_2:.*]] = fir.declare %[[ARG0]](%[[SHAPE_0]]) dummy_scope %[[DUMMY_SCOPE_0]] arg 1 {uniq_name = "_QFtest_dummy_scalarEr"} : (!fir.ref>, !fir.shape<1>, !fir.dscope) -> !fir.ref> +// CHECK: %[[DECLARE_3:.*]] = fir.declare %[[ARG1]] dummy_scope %[[DUMMY_SCOPE_0]] arg 2 {uniq_name = "_QFtest_dummy_scalarEx"} : (!fir.ref, !fir.dscope) -> !fir.ref +// CHECK: %[[LOAD_0:.*]] = fir.load %[[DECLARE_1]] : !fir.ref +// CHECK: %[[CONVERT_0:.*]] = fir.convert %[[LOAD_0]] : (i32) -> index +// CHECK: %[[CONVERT_1:.*]] = fir.convert %[[CONSTANT_0]] : (index) -> i32 +// CHECK: %[[IF_0:.*]] = fir.if %[[ARG3]] -> (i32) { +// CHECK: %[[LOAD_1:.*]] = fir.load %[[DECLARE_3]] : !fir.ref +// CHECK: fir.result %[[LOAD_1]] : i32 +// CHECK: } else { +// CHECK: %[[CONSTANT_1:.*]] = arith.constant 1 : i32 +// CHECK: %[[LOAD_2:.*]] = fir.load %[[DECLARE_3]] : !fir.ref +// CHECK: %[[ADDI_0:.*]] = arith.addi %[[LOAD_2]], %[[CONSTANT_1]] : i32 +// CHECK: fir.result %[[ADDI_0]] : i32 +// CHECK: } +// CHECK: %[[DO_LOOP_0:.*]] = fir.do_loop %[[VAL_0:.*]] = %[[CONSTANT_0]] to %[[CONVERT_0]] step %[[CONSTANT_0]] iter_args(%[[VAL_1:.*]] = %[[CONVERT_1]]) -> (i32) { +// CHECK: fir.store %[[VAL_1]] to %[[DECLARE_0]] : !fir.ref +// CHECK: %[[LOAD_3:.*]] = fir.load %[[DECLARE_0]] : !fir.ref +// CHECK: %[[CONVERT_2:.*]] = fir.convert %[[LOAD_3]] : (i32) -> i64 +// CHECK: %[[ARRAY_COOR_0:.*]] = fir.array_coor %[[DECLARE_2]](%[[SHAPE_0]]) %[[CONVERT_2]] : (!fir.ref>, !fir.shape<1>, i64) -> !fir.ref +// CHECK: fir.store %[[IF_0]] to %[[ARRAY_COOR_0]] : !fir.ref +// CHECK: fir.call @_QPexternal_sub() : () -> () +// CHECK: %[[LOAD_4:.*]] = fir.load %[[DECLARE_0]] : !fir.ref +// CHECK: %[[ADDI_1:.*]] = arith.addi %[[LOAD_4]], %[[CONVERT_1]] overflow : i32 +// CHECK: fir.result %[[ADDI_1]] : i32 +// CHECK: } +// CHECK: fir.store %[[DO_LOOP_0]] to %[[DECLARE_0]] : !fir.ref +// CHECK: return +// CHECK: } +func.func @test_if_hoisting(%arg0: !fir.ref> {fir.bindc_name = "r"}, %arg1: !fir.ref {fir.bindc_name = "x"}, %arg2: !fir.ref {fir.bindc_name = "n"}, %cond : i1) { + %c1 = arith.constant 1 : index + %0 = fir.dummy_scope : !fir.dscope + %1 = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFtest_dummy_scalarEi"} + %2 = fir.declare %1 {uniq_name = "_QFtest_dummy_scalarEi"} : (!fir.ref) -> !fir.ref + %3 = fir.declare %arg2 dummy_scope %0 arg 3 {uniq_name = "_QFtest_dummy_scalarEn"} : (!fir.ref, !fir.dscope) -> !fir.ref + %4 = fir.assumed_size_extent : index + %5 = fir.shape %4 : (index) -> !fir.shape<1> + %6 = fir.declare %arg0(%5) dummy_scope %0 arg 1 {uniq_name = "_QFtest_dummy_scalarEr"} : (!fir.ref>, !fir.shape<1>, !fir.dscope) -> !fir.ref> + %7 = fir.declare %arg1 dummy_scope %0 arg 2 {uniq_name = "_QFtest_dummy_scalarEx"} : (!fir.ref, !fir.dscope) -> !fir.ref + %8 = fir.load %3 : !fir.ref + %9 = fir.convert %8 : (i32) -> index + %10 = fir.convert %c1 : (index) -> i32 + %11 = fir.do_loop %arg3 = %c1 to %9 step %c1 iter_args(%arg4 = %10) -> (i32) { + fir.store %arg4 to %2 : !fir.ref + %12 = fir.if %cond -> i32 { + %orig = fir.load %7 : !fir.ref + fir.result %orig : i32 + } else { + %c1_i32 = arith.constant 1 : i32 + %orig = fir.load %7 : !fir.ref + %new = arith.addi %orig, %c1_i32 : i32 + fir.result %new : i32 + } + %13 = fir.load %2 : !fir.ref + %14 = fir.convert %13 : (i32) -> i64 + %15 = fir.array_coor %6(%5) %14 : (!fir.ref>, !fir.shape<1>, i64) -> !fir.ref + fir.store %12 to %15 : !fir.ref + fir.call @_QPexternal_sub() : () -> () + %16 = fir.load %2 : !fir.ref + %17 = arith.addi %16, %10 overflow : i32 + fir.result %17 : i32 + } + fir.store %11 to %2 : !fir.ref + return +}