CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
216 lines
8.8 KiB
Plaintext
216 lines
8.8 KiB
Plaintext
// RUN: fir-opt -flang-licm='hoist-from-nested-regions=aggressive' --split-input-file %s | FileCheck %s
|
|
|
|
// Tests for the "aggressive" nested hoisting mode, which hoists all safe
|
|
// invariant operations from nested regions (not just fir.convert).
|
|
|
|
// Test that pure ops (arith, fir.shape, fir.convert) inside scf.if are all
|
|
// hoisted out of the loop in aggressive mode.
|
|
// CHECK-LABEL: func.func @test_aggressive_pure_ops(
|
|
// CHECK-SAME: %[[ARG0:.*]]: !fir.ref<!fir.array<10xf32>>)
|
|
// CHECK-DAG: %[[C5:.*]] = arith.constant 5 : index
|
|
// CHECK-DAG: %[[C10:.*]] = arith.constant 10 : index
|
|
// CHECK: %[[CVT:.*]] = fir.convert %[[ARG0]]
|
|
// CHECK: %[[SHP:.*]] = fir.shape %[[C10]]
|
|
// CHECK: %[[IDX:.*]] = arith.addi %{{.*}}, %[[C5]]
|
|
// CHECK: scf.for
|
|
// CHECK: scf.if
|
|
// CHECK-NOT: fir.convert
|
|
// CHECK-NOT: fir.shape
|
|
// CHECK-NOT: arith.addi
|
|
// CHECK: memref.store %{{.*}}, %[[CVT]][%[[IDX]]]
|
|
func.func @test_aggressive_pure_ops(%arg0: !fir.ref<!fir.array<10xf32>>) {
|
|
%c0 = arith.constant 0 : index
|
|
%c1 = arith.constant 1 : index
|
|
%c3 = arith.constant 3 : index
|
|
%c5 = arith.constant 5 : index
|
|
%c10 = arith.constant 10 : index
|
|
%cst = arith.constant 1.000000e+00 : f32
|
|
scf.for %i = %c0 to %c10 step %c1 {
|
|
%cond = arith.cmpi slt, %i, %c5 : index
|
|
scf.if %cond {
|
|
%cvt = fir.convert %arg0 : (!fir.ref<!fir.array<10xf32>>) -> memref<10xf32>
|
|
%shp = fir.shape %c10 : (index) -> !fir.shape<1>
|
|
%idx = arith.addi %c3, %c5 : index
|
|
memref.store %cst, %cvt[%idx] : memref<10xf32>
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// -----
|
|
// Test that an invariant fir.load and its dependent fir.convert chain inside
|
|
// scf.if are hoisted in aggressive mode, when the loaded memory is not
|
|
// modified inside the loop.
|
|
// CHECK-LABEL: func.func @test_aggressive_invariant_load(
|
|
// CHECK-SAME: %[[ARG0:.*]]: !fir.ref<!fir.array<10xf32>>,
|
|
// CHECK-SAME: %[[ARG1:.*]]: !fir.ref<i32> {fir.bindc_name = "n"})
|
|
// CHECK: %[[DECL:.*]] = fir.declare %[[ARG1]]
|
|
// CHECK: %[[CVT:.*]] = fir.convert %[[ARG0]]
|
|
// CHECK: %[[LOAD:.*]] = fir.load %[[DECL]]
|
|
// CHECK: %[[IDX:.*]] = fir.convert %[[LOAD]] : (i32) -> index
|
|
// CHECK: scf.for
|
|
// CHECK: scf.if
|
|
// CHECK-NOT: fir.convert
|
|
// CHECK-NOT: fir.load
|
|
// CHECK: memref.store %{{.*}}, %[[CVT]][%[[IDX]]]
|
|
func.func @test_aggressive_invariant_load(%arg0: !fir.ref<!fir.array<10xf32>>, %arg1: !fir.ref<i32> {fir.bindc_name = "n"}) {
|
|
%c0 = arith.constant 0 : index
|
|
%c1 = arith.constant 1 : index
|
|
%c5 = arith.constant 5 : index
|
|
%c10 = arith.constant 10 : index
|
|
%cst = arith.constant 1.000000e+00 : f32
|
|
%0 = fir.dummy_scope : !fir.dscope
|
|
%1 = fir.declare %arg1 dummy_scope %0 arg 2 {uniq_name = "_QFtestEn"} : (!fir.ref<i32>, !fir.dscope) -> !fir.ref<i32>
|
|
scf.for %i = %c0 to %c10 step %c1 {
|
|
%cond = arith.cmpi slt, %i, %c5 : index
|
|
scf.if %cond {
|
|
%cvt = fir.convert %arg0 : (!fir.ref<!fir.array<10xf32>>) -> memref<10xf32>
|
|
%val = fir.load %1 : !fir.ref<i32>
|
|
%idx = fir.convert %val : (i32) -> index
|
|
memref.store %cst, %cvt[%idx] : memref<10xf32>
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// -----
|
|
// Test that a fir.load inside scf.if is NOT hoisted even in aggressive mode
|
|
// when the loaded memory is modified inside the loop.
|
|
// CHECK-LABEL: func.func @test_aggressive_modified_load_not_hoisted(
|
|
// CHECK-SAME: %[[ARG0:.*]]: !fir.ref<!fir.array<10xf32>>,
|
|
// CHECK-SAME: %[[ARG1:.*]]: !fir.ref<i32>)
|
|
// CHECK: %[[CVT:.*]] = fir.convert %[[ARG0]]
|
|
// CHECK: scf.for
|
|
// CHECK: scf.if
|
|
// CHECK: fir.load %[[ARG1]]
|
|
// CHECK: fir.convert
|
|
// CHECK: memref.store
|
|
// CHECK: fir.store {{.*}} to %[[ARG1]]
|
|
func.func @test_aggressive_modified_load_not_hoisted(%arg0: !fir.ref<!fir.array<10xf32>>, %arg1: !fir.ref<i32>) {
|
|
%c0 = arith.constant 0 : index
|
|
%c1 = arith.constant 1 : index
|
|
%c5 = arith.constant 5 : index
|
|
%c10 = arith.constant 10 : index
|
|
%c1_i32 = arith.constant 1 : i32
|
|
%cst = arith.constant 1.000000e+00 : f32
|
|
scf.for %i = %c0 to %c10 step %c1 {
|
|
%cond = arith.cmpi slt, %i, %c5 : index
|
|
scf.if %cond {
|
|
%cvt = fir.convert %arg0 : (!fir.ref<!fir.array<10xf32>>) -> memref<10xf32>
|
|
%val = fir.load %arg1 : !fir.ref<i32>
|
|
%idx = fir.convert %val : (i32) -> index
|
|
memref.store %cst, %cvt[%idx] : memref<10xf32>
|
|
}
|
|
fir.store %c1_i32 to %arg1 : !fir.ref<i32>
|
|
}
|
|
return
|
|
}
|
|
|
|
// -----
|
|
// Test that aggressive mode hoists pure ops from deeply nested scf.if regions
|
|
// and through user-propagation chains.
|
|
// CHECK-LABEL: func.func @test_aggressive_deeply_nested(
|
|
// CHECK-SAME: %[[ARG0:.*]]: !fir.ref<!fir.array<10xf32>>)
|
|
// CHECK-DAG: %[[C3:.*]] = arith.constant 3 : index
|
|
// CHECK-DAG: %[[C5:.*]] = arith.constant 5 : index
|
|
// CHECK: %[[CVT:.*]] = fir.convert %[[ARG0]]
|
|
// CHECK: %[[IDX:.*]] = arith.addi %[[C3]], %[[C5]]
|
|
// CHECK: %[[SHP:.*]] = fir.shape %{{.*}}
|
|
// CHECK: scf.for
|
|
// CHECK: scf.if
|
|
// CHECK: scf.if
|
|
// CHECK-NOT: fir.convert
|
|
// CHECK-NOT: arith.addi
|
|
// CHECK-NOT: fir.shape
|
|
// CHECK: memref.store
|
|
func.func @test_aggressive_deeply_nested(%arg0: !fir.ref<!fir.array<10xf32>>) {
|
|
%c0 = arith.constant 0 : index
|
|
%c1 = arith.constant 1 : index
|
|
%c3 = arith.constant 3 : index
|
|
%c5 = arith.constant 5 : index
|
|
%c10 = arith.constant 10 : index
|
|
%cst = arith.constant 1.000000e+00 : f32
|
|
scf.for %i = %c0 to %c10 step %c1 {
|
|
%cond1 = arith.cmpi slt, %i, %c5 : index
|
|
scf.if %cond1 {
|
|
%cond2 = arith.cmpi slt, %i, %c3 : index
|
|
scf.if %cond2 {
|
|
%cvt = fir.convert %arg0 : (!fir.ref<!fir.array<10xf32>>) -> memref<10xf32>
|
|
%idx = arith.addi %c3, %c5 : index
|
|
%shp = fir.shape %c10 : (index) -> !fir.shape<1>
|
|
memref.store %cst, %cvt[%idx] : memref<10xf32>
|
|
}
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// -----
|
|
// Test that a fir.load of an OPTIONAL variable inside scf.if is NOT hoisted
|
|
// even in aggressive mode, because it is conditionally executed and
|
|
// isNonOptionalScalar fails for optional variables. The trip count shortcut
|
|
// (loop runs >= 1 iteration) cannot be used for conditionally-executed loads
|
|
// since the condition might never be true.
|
|
// CHECK-LABEL: func.func @test_aggressive_conditional_optional_load(
|
|
// CHECK-SAME: %[[ARG0:.*]]: !fir.ref<!fir.array<10xf32>>,
|
|
// CHECK-SAME: %[[ARG1:.*]]: !fir.ref<i32>)
|
|
// CHECK: %[[DECL:.*]] = fir.declare %[[ARG1]]
|
|
// CHECK: %[[CVT:.*]] = fir.convert %[[ARG0]]
|
|
// CHECK: scf.for
|
|
// CHECK: scf.if
|
|
// The fir.load must stay inside scf.if (conditionally executed + optional):
|
|
// CHECK: fir.load %[[DECL]]
|
|
// CHECK: fir.convert
|
|
// CHECK: memref.store
|
|
func.func @test_aggressive_conditional_optional_load(%arg0: !fir.ref<!fir.array<10xf32>>, %arg1: !fir.ref<i32>) {
|
|
%c0 = arith.constant 0 : index
|
|
%c1 = arith.constant 1 : index
|
|
%c5 = arith.constant 5 : index
|
|
%c10 = arith.constant 10 : index
|
|
%cst = arith.constant 1.000000e+00 : f32
|
|
%0 = fir.dummy_scope : !fir.dscope
|
|
%1 = fir.declare %arg1 dummy_scope %0 arg 2 {fortran_attrs = #fir.var_attrs<optional>, uniq_name = "_QFtestEn"} : (!fir.ref<i32>, !fir.dscope) -> !fir.ref<i32>
|
|
scf.for %i = %c0 to %c10 step %c1 {
|
|
%cond = arith.cmpi slt, %i, %c5 : index
|
|
scf.if %cond {
|
|
%cvt = fir.convert %arg0 : (!fir.ref<!fir.array<10xf32>>) -> memref<10xf32>
|
|
%val = fir.load %1 : !fir.ref<i32>
|
|
%idx = fir.convert %val : (i32) -> index
|
|
memref.store %cst, %cvt[%idx] : memref<10xf32>
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// -----
|
|
// Test that in cheap mode (default), only fir.convert is hoisted from nested
|
|
// regions, while other pure ops (arith.addi) remain inside. In aggressive mode,
|
|
// both would be hoisted.
|
|
// This test uses the default (cheap) mode as a cross-check.
|
|
// RUN: fir-opt -flang-licm %s --split-input-file 2>&1
|
|
// CHECK-LABEL: func.func @test_cheap_vs_aggressive(
|
|
// CHECK-SAME: %[[ARG0:.*]]: !fir.ref<!fir.array<10xf32>>)
|
|
// CHECK: %[[CVT:.*]] = fir.convert %[[ARG0]]
|
|
// CHECK: scf.for
|
|
// CHECK: scf.if
|
|
// In aggressive mode, arith.addi is also hoisted:
|
|
// CHECK-NOT: arith.addi
|
|
// CHECK: memref.store %{{.*}}, %[[CVT]]
|
|
func.func @test_cheap_vs_aggressive(%arg0: !fir.ref<!fir.array<10xf32>>) {
|
|
%c0 = arith.constant 0 : index
|
|
%c1 = arith.constant 1 : index
|
|
%c3 = arith.constant 3 : index
|
|
%c5 = arith.constant 5 : index
|
|
%c10 = arith.constant 10 : index
|
|
%cst = arith.constant 1.000000e+00 : f32
|
|
scf.for %i = %c0 to %c10 step %c1 {
|
|
%cond = arith.cmpi slt, %i, %c5 : index
|
|
scf.if %cond {
|
|
%cvt = fir.convert %arg0 : (!fir.ref<!fir.array<10xf32>>) -> memref<10xf32>
|
|
%idx = arith.addi %c3, %c5 : index
|
|
memref.store %cst, %cvt[%idx] : memref<10xf32>
|
|
}
|
|
}
|
|
return
|
|
}
|