// RUN: fir-opt -flang-licm --split-input-file %s | FileCheck %s // Verify that Pure fir.convert operations with !fir.ref operands // are not hoisted by LICM out of cuf.kernel. // CHECK-LABEL: func.func @_QPtest( // CHECK-SAME: %[[ARG0:.*]]: !fir.ref> {cuf.data_attr = #cuf.cuda, fir.bindc_name = "a"}, // CHECK-SAME: %[[ARG1:.*]]: !fir.ref> {cuf.data_attr = #cuf.cuda, fir.bindc_name = "ra"}) { // CHECK: %[[CONSTANT_0:.*]] = arith.constant 1.000000e+00 : f32 // CHECK: %[[CONSTANT_1:.*]] = arith.constant 1 : index // CHECK: %[[CONSTANT_2:.*]] = arith.constant 10 : index // CHECK: %[[ALLOC_0:.*]] = cuf.alloc !fir.box>> {data_attr = #cuf.cuda} -> !fir.ref>>> // CHECK: %[[DUMMY_SCOPE_0:.*]] = fir.dummy_scope : !fir.dscope // CHECK: %[[SHAPE_0:.*]] = fir.shape %[[CONSTANT_2]] : (index) -> !fir.shape<1> // CHECK: %[[DECLARE_0:.*]] = fir.declare %[[ARG0]](%[[SHAPE_0]]) dummy_scope %[[DUMMY_SCOPE_0]] arg 1 {data_attr = #cuf.cuda, uniq_name = "_QFtestEa"} : (!fir.ref>, !fir.shape<1>, !fir.dscope) -> !fir.ref> // CHECK: %[[ALLOCA_0:.*]] = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFtestEi"} // CHECK: %[[DECLARE_1:.*]] = fir.declare %[[ALLOCA_0]] {uniq_name = "_QFtestEi"} : (!fir.ref) -> !fir.ref // CHECK: %[[ALLOCA_1:.*]] = fir.alloca i64 {bindc_name = "pa", uniq_name = "_QFtestEpa"} // CHECK: %[[DECLARE_2:.*]] = fir.declare %[[ALLOCA_1]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtestEpa"} : (!fir.ref) -> !fir.ref // CHECK: %[[DECLARE_3:.*]] = fir.declare %[[ALLOC_0]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtestEra"} : (!fir.ref>>>) -> !fir.ref>>> // CHECK: %[[ZERO_BITS_0:.*]] = fir.zero_bits !fir.ptr> // CHECK: %[[EMBOX_0:.*]] = fir.embox %[[ZERO_BITS_0]](%[[SHAPE_0]]) : (!fir.ptr>, !fir.shape<1>) -> !fir.box>> // CHECK: fir.store %[[EMBOX_0]] to %[[DECLARE_3]] : !fir.ref>>> // CHECK: %[[CONVERT_0:.*]] = fir.convert %[[DECLARE_0]] : (!fir.ref>) -> i64 // CHECK: fir.store %[[CONVERT_0]] to %[[DECLARE_2]] : !fir.ref // CHECK: %[[CONSTANT_3:.*]] = arith.constant 0 : index // CHECK: cuf.kernel<<<*, *>>> (%[[VAL_0:.*]] : index) = (%[[CONSTANT_1]] : index) to (%[[CONSTANT_2]] : index) step (%[[CONSTANT_1]] : index) { // CHECK: %[[CONVERT_1:.*]] = fir.convert %[[VAL_0]] : (index) -> i32 // CHECK: fir.store %[[CONVERT_1]] to %[[DECLARE_1]] : !fir.ref // CHECK: %[[CONVERT_2:.*]] = fir.convert %[[DECLARE_2]] : (!fir.ref) -> !fir.ref> // CHECK: %[[LOAD_0:.*]] = fir.load %[[CONVERT_2]] : !fir.ref> // CHECK: %[[CONVERT_3:.*]] = fir.convert %[[DECLARE_3]] : (!fir.ref>>>) -> !fir.ref> // CHECK: %[[CONVERT_4:.*]] = fir.convert %[[LOAD_0]] : (!fir.ptr) -> !fir.llvm_ptr // CHECK: fir.call @_FortranAPointerAssociateScalar(%[[CONVERT_3]], %[[CONVERT_4]]) fastmath : (!fir.ref>, !fir.llvm_ptr) -> () // CHECK: %[[LOAD_1:.*]] = fir.load %[[DECLARE_3]] : !fir.ref>>> // CHECK: %[[LOAD_2:.*]] = fir.load %[[DECLARE_1]] : !fir.ref // CHECK: %[[CONVERT_5:.*]] = fir.convert %[[LOAD_2]] : (i32) -> i64 // CHECK: %[[BOX_DIMS_0:.*]]:3 = fir.box_dims %[[LOAD_1]], %[[CONSTANT_3]] : (!fir.box>>, index) -> (index, index, index) // CHECK: %[[SHIFT_0:.*]] = fir.shift %[[BOX_DIMS_0]]#0 : (index) -> !fir.shift<1> // CHECK: %[[ARRAY_COOR_0:.*]] = fir.array_coor %[[LOAD_1]](%[[SHIFT_0]]) %[[CONVERT_5]] : (!fir.box>>, !fir.shift<1>, i64) -> !fir.ref // CHECK: fir.store %[[CONSTANT_0]] to %[[ARRAY_COOR_0]] : !fir.ref // CHECK: "fir.end"() : () -> () // CHECK: } // CHECK: return // CHECK: } func.func @_QPtest(%arg0: !fir.ref> {cuf.data_attr = #cuf.cuda, fir.bindc_name = "a"}, %arg1: !fir.ref> {cuf.data_attr = #cuf.cuda, fir.bindc_name = "ra"}) { %cst = arith.constant 1.000000e+00 : f32 %c1 = arith.constant 1 : index %c10 = arith.constant 10 : index %0 = cuf.alloc !fir.box>> {data_attr = #cuf.cuda} -> !fir.ref>>> %1 = fir.dummy_scope : !fir.dscope %2 = fir.shape %c10 : (index) -> !fir.shape<1> %3 = fir.declare %arg0(%2) dummy_scope %1 arg 1 {data_attr = #cuf.cuda, uniq_name = "_QFtestEa"} : (!fir.ref>, !fir.shape<1>, !fir.dscope) -> !fir.ref> %4 = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFtestEi"} %5 = fir.declare %4 {uniq_name = "_QFtestEi"} : (!fir.ref) -> !fir.ref %6 = fir.alloca i64 {bindc_name = "pa", uniq_name = "_QFtestEpa"} %7 = fir.declare %6 {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtestEpa"} : (!fir.ref) -> !fir.ref %8 = fir.declare %0 {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtestEra"} : (!fir.ref>>>) -> !fir.ref>>> %9 = fir.zero_bits !fir.ptr> %10 = fir.embox %9(%2) : (!fir.ptr>, !fir.shape<1>) -> !fir.box>> fir.store %10 to %8 : !fir.ref>>> %11 = fir.convert %3 : (!fir.ref>) -> i64 fir.store %11 to %7 : !fir.ref cuf.kernel<<<*, *>>> (%arg2 : index) = (%c1 : index) to (%c10 : index) step (%c1 : index) { %12 = fir.convert %arg2 : (index) -> i32 fir.store %12 to %5 : !fir.ref %13 = fir.convert %7 : (!fir.ref) -> !fir.ref> %14 = fir.load %13 : !fir.ref> %15 = fir.convert %8 : (!fir.ref>>>) -> !fir.ref> %16 = fir.convert %14 : (!fir.ptr) -> !fir.llvm_ptr fir.call @_FortranAPointerAssociateScalar(%15, %16) fastmath : (!fir.ref>, !fir.llvm_ptr) -> () %17 = fir.load %8 : !fir.ref>>> %18 = fir.load %5 : !fir.ref %19 = fir.convert %18 : (i32) -> i64 %c0 = arith.constant 0 : index %20:3 = fir.box_dims %17, %c0 : (!fir.box>>, index) -> (index, index, index) %21 = fir.shift %20#0 : (index) -> !fir.shift<1> %22 = fir.array_coor %17(%21) %19 : (!fir.box>>, !fir.shift<1>, i64) -> !fir.ref fir.store %cst to %22 : !fir.ref "fir.end"() : () -> () } return } // ----- // Verify that scf.if containing fir.convert with !fir.ref operand is NOT // hoisted out of cuf.kernel as a whole. The canMoveOutOf restriction must // be checked transitively for all nested operations of the candidate, // not just the candidate itself. fir.convert can convert !fir.ref to i64, // so scf.if may yield an integer result produced from a !fir.ref. // CHECK-LABEL: func.func @transitive_canMoveOutOf( // CHECK-SAME: %[[ARG0:.*]]: !fir.ref> // CHECK-SAME: %[[COND:.*]]: i1) // CHECK: cuf.kernel // CHECK: %[[ADDR:.*]] = scf.if %[[COND]] -> (i64) // CHECK: fir.convert %[[ARG0]] // CHECK: %[[REF:.*]] = fir.convert %[[ADDR]] : (i64) -> !fir.ref // CHECK: fir.store %{{.*}} to %[[REF]] func.func @transitive_canMoveOutOf(%arg0: !fir.ref> {cuf.data_attr = #cuf.cuda}, %cond: i1) { %c0_i64 = arith.constant 0 : i64 %c1 = arith.constant 1 : index %c10 = arith.constant 10 : index %cst = arith.constant 1.000000e+00 : f32 cuf.kernel<<<*, *>>> (%arg2 : index) = (%c1 : index) to (%c10 : index) step (%c1 : index) { %addr = scf.if %cond -> (i64) { %ptr = fir.convert %arg0 : (!fir.ref>) -> i64 scf.yield %ptr : i64 } else { scf.yield %c0_i64 : i64 } %ref = fir.convert %addr : (i64) -> !fir.ref fir.store %cst to %ref : !fir.ref "fir.end"() : () -> () } return } // ----- // Verify that Pure fir.address_of operation is not hoisted by LICM // out of cuf.kernel. // CHECK-LABEL: func.func @_QQmain() { // CHECK-NOT: fir.address_of // CHECK: cuf.kernel func.func @_QQmain() { %c100 = arith.constant 100 : index %c4_i32 = arith.constant 4 : i32 %c6_i32 = arith.constant 6 : i32 %c1 = arith.constant 1 : index %0 = fir.dummy_scope : !fir.dscope %1 = cuf.alloc i32 {bindc_name = "a", data_attr = #cuf.cuda, uniq_name = "_QFEa"} -> !fir.ref %2 = fir.declare %1 {data_attr = #cuf.cuda, uniq_name = "_QFEa"} : (!fir.ref) -> !fir.ref %3 = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFEi"} %4 = fir.declare %3 {uniq_name = "_QFEi"} : (!fir.ref) -> !fir.ref cuf.kernel<<<*, *>>> (%arg0 : index) = (%c1 : index) to (%c100 : index) step (%c1 : index) { %5 = fir.convert %arg0 : (index) -> i32 fir.store %5 to %4 : !fir.ref %6 = fir.address_of(@_QQclXb12241cc4e2d1775ec743d7d1b7d73f7) : !fir.ref> %7 = fir.convert %6 : (!fir.ref>) -> !fir.ref %8 = fir.call @_FortranAioBeginExternalListOutput(%c6_i32, %7, %c4_i32) fastmath : (i32, !fir.ref, i32) -> !fir.ref %9 = fir.load %2 : !fir.ref %10 = fir.call @_FortranAioOutputInteger32(%8, %9) fastmath : (!fir.ref, i32) -> i1 %11 = fir.call @_FortranAioEndIoStatement(%8) fastmath : (!fir.ref) -> i32 "fir.end"() : () -> () } return }