llvm-project/flang/test/Lower/OpenMP/FIR/atomic-update.f90
Kiran Chandramohan 25d0f9fc3b
[Flang][OpenMP][OpenACC] Hoist nonAtomic Expr in atomic intrinsics (#72131)
Hoist non-atomic expressions in atomic intrinsics. Use a list to collect
the non-atomic expressions since the max and min intrinsics can have
more than two operands.

Hoisting makes the lowering to LLVMIR of iand,ior,ieor intrinsics
trivial. For max and min this still results in multiple instructions in
the atomic region but the loads are removed, which should help improve
performance.
2023-11-16 13:22:26 +00:00

140 lines
6.0 KiB
Fortran

! This test checks lowering of atomic and atomic update constructs
! RUN: bbc --use-desc-for-alloc=false -fopenmp -emit-fir -hlfir=false %s -o - | FileCheck %s
! RUN: %flang_fc1 -mllvm --use-desc-for-alloc=false -emit-fir -flang-deprecated-no-hlfir -fopenmp %s -o - | FileCheck %s
program OmpAtomicUpdate
use omp_lib
integer :: x, y, z
integer, pointer :: a, b
integer, target :: c, d
integer(1) :: i1
a=>c
b=>d
!CHECK: func.func @_QQmain() attributes {fir.bindc_name = "ompatomicupdate"} {
!CHECK: %[[A:.*]] = fir.alloca !fir.box<!fir.ptr<i32>> {bindc_name = "a", uniq_name = "_QFEa"}
!CHECK: %[[A_ADDR:.*]] = fir.alloca !fir.ptr<i32> {uniq_name = "_QFEa.addr"}
!CHECK: %{{.*}} = fir.zero_bits !fir.ptr<i32>
!CHECK: fir.store %{{.*}} to %[[A_ADDR]] : !fir.ref<!fir.ptr<i32>>
!CHECK: %[[B:.*]] = fir.alloca !fir.box<!fir.ptr<i32>> {bindc_name = "b", uniq_name = "_QFEb"}
!CHECK: %[[B_ADDR:.*]] = fir.alloca !fir.ptr<i32> {uniq_name = "_QFEb.addr"}
!CHECK: %{{.*}} = fir.zero_bits !fir.ptr<i32>
!CHECK: fir.store %{{.*}} to %[[B_ADDR]] : !fir.ref<!fir.ptr<i32>>
!CHECK: %[[C_ADDR:.*]] = fir.address_of(@_QFEc) : !fir.ref<i32>
!CHECK: %[[D_ADDR:.*]] = fir.address_of(@_QFEd) : !fir.ref<i32>
!CHECK: %[[I1:.*]] = fir.alloca i8 {bindc_name = "i1", uniq_name = "_QFEi1"}
!CHECK: %[[X:.*]] = fir.alloca i32 {bindc_name = "x", uniq_name = "_QFEx"}
!CHECK: %[[Y:.*]] = fir.alloca i32 {bindc_name = "y", uniq_name = "_QFEy"}
!CHECK: %[[Z:.*]] = fir.alloca i32 {bindc_name = "z", uniq_name = "_QFEz"}
!CHECK: %{{.*}} = fir.convert %[[C_ADDR]] : (!fir.ref<i32>) -> !fir.ptr<i32>
!CHECK: fir.store %{{.*}} to %[[A_ADDR]] : !fir.ref<!fir.ptr<i32>>
!CHECK: %{{.*}} = fir.convert %[[D_ADDR]] : (!fir.ref<i32>) -> !fir.ptr<i32>
!CHECK: fir.store {{.*}} to %[[B_ADDR]] : !fir.ref<!fir.ptr<i32>>
!CHECK: %[[LOADED_A:.*]] = fir.load %[[A_ADDR]] : !fir.ref<!fir.ptr<i32>>
!CHECK: %[[LOADED_B:.*]] = fir.load %[[B_ADDR]] : !fir.ref<!fir.ptr<i32>>
!CHECK: %{{.*}} = fir.load %[[LOADED_B]] : !fir.ptr<i32>
!CHECK: omp.atomic.update %[[LOADED_A]] : !fir.ptr<i32> {
!CHECK: ^bb0(%[[ARG:.*]]: i32):
!CHECK: %[[RESULT:.*]] = arith.addi %[[ARG]], %{{.*}} : i32
!CHECK: omp.yield(%[[RESULT]] : i32)
!CHECK: }
!$omp atomic update
a = a + b
!CHECK: {{.*}} = arith.constant 1 : i32
!CHECK: omp.atomic.update %[[Y]] : !fir.ref<i32> {
!CHECK: ^bb0(%[[ARG:.*]]: i32):
!CHECK: %[[RESULT:.*]] = arith.addi %[[ARG]], {{.*}} : i32
!CHECK: omp.yield(%[[RESULT]] : i32)
!CHECK: }
!CHECK: %[[LOADED_X:.*]] = fir.load %[[X]] : !fir.ref<i32>
!CHECK: omp.atomic.update %[[Z]] : !fir.ref<i32> {
!CHECK: ^bb0(%[[ARG:.*]]: i32):
!CHECK: %[[RESULT:.*]] = arith.muli %[[LOADED_X]], %[[ARG]] : i32
!CHECK: omp.yield(%[[RESULT]] : i32)
!CHECK: }
!$omp atomic
y = y + 1
!$omp atomic update
z = x * z
!CHECK: %{{.*}} = arith.constant 1 : i32
!CHECK: omp.atomic.update memory_order(relaxed) hint(uncontended) %[[X]] : !fir.ref<i32> {
!CHECK: ^bb0(%[[ARG:.*]]: i32):
!CHECK: %[[RESULT:.*]] = arith.subi %[[ARG]], {{.*}} : i32
!CHECK: omp.yield(%[[RESULT]] : i32)
!CHECK: }
!CHECK: %[[LOADED_X:.*]] = fir.load %[[X]] : !fir.ref<i32>
!CHECK: %[[LOADED_Z:.*]] = fir.load %[[Z]] : !fir.ref<i32>
!CHECK: omp.atomic.update memory_order(relaxed) %[[Y]] : !fir.ref<i32> {
!CHECK: ^bb0(%[[ARG:.*]]: i32):
!CHECK: %{{.*}} = arith.cmpi sgt, %[[ARG]], %[[LOADED_X]] : i32
!CHECK: %{{.*}} = arith.select %{{.*}}, %[[ARG]], %[[LOADED_X]] : i32
!CHECK: %{{.*}} = arith.cmpi sgt, %{{.*}}, %[[LOADED_Z]] : i32
!CHECK: %[[RESULT:.*]] = arith.select %{{.*}}, %{{.*}}, %[[LOADED_Z]] : i32
!CHECK: omp.yield(%[[RESULT]] : i32)
!CHECK: }
!CHECK: %[[LOADED_X:.*]] = fir.load %[[X]] : !fir.ref<i32>
!CHECK: omp.atomic.update memory_order(relaxed) hint(contended) %[[Z]] : !fir.ref<i32> {
!CHECK: ^bb0(%[[ARG:.*]]: i32):
!CHECK: %[[RESULT:.*]] = arith.addi %[[ARG]], %[[LOADED_X]] : i32
!CHECK: omp.yield(%[[RESULT]] : i32)
!CHECK: }
!$omp atomic relaxed update hint(omp_sync_hint_uncontended)
x = x - 1
!$omp atomic update relaxed
y = max(y, x, z)
!$omp atomic relaxed hint(omp_sync_hint_contended)
z = z + x
!CHECK: %{{.*}} = arith.constant 10 : i32
!CHECK: omp.atomic.update memory_order(release) hint(contended) %[[Z]] : !fir.ref<i32> {
!CHECK: ^bb0(%[[ARG:.*]]: i32):
!CHECK: %[[RESULT:.*]] = arith.muli {{.*}}, %[[ARG]] : i32
!CHECK: omp.yield(%[[RESULT]] : i32)
!CHECK: }
!CHECK: %[[LOADED_Z:.*]] = fir.load %[[Z]] : !fir.ref<i32>
!CHECK: omp.atomic.update memory_order(release) hint(speculative) %[[X]] : !fir.ref<i32> {
!CHECK: ^bb0(%[[ARG:.*]]: i32):
!CHECK: %[[RESULT:.*]] = arith.divsi %[[ARG]], %[[LOADED_Z]] : i32
!CHECK: omp.yield(%[[RESULT]] : i32)
!CHECK: }
!$omp atomic release update hint(omp_lock_hint_contended)
z = z * 10
!$omp atomic hint(omp_lock_hint_speculative) update release
x = x / z
!CHECK: %{{.*}} = arith.constant 10 : i32
!CHECK: omp.atomic.update memory_order(seq_cst) hint(nonspeculative) %[[Y]] : !fir.ref<i32> {
!CHECK: ^bb0(%[[ARG:.*]]: i32):
!CHECK: %[[RESULT:.*]] = arith.addi %{{.*}}, %[[ARG]] : i32
!CHECK: omp.yield(%[[RESULT]] : i32)
!CHECK: }
!CHECK: %[[LOADED_Y:.*]] = fir.load %[[Y]] : !fir.ref<i32>
!CHECK: omp.atomic.update memory_order(seq_cst) %[[Z]] : !fir.ref<i32> {
!CHECK: ^bb0(%[[ARG:.*]]: i32):
!CHECK: %[[RESULT:.*]] = arith.addi %[[LOADED_Y]], %[[ARG]] : i32
!CHECK: omp.yield(%[[RESULT]] : i32)
!CHECK: }
!$omp atomic hint(omp_sync_hint_nonspeculative) seq_cst
y = 10 + y
!$omp atomic seq_cst update
z = y + z
!CHECK: %[[C1_VAL:.*]] = arith.constant 1 : i32
!CHECK: omp.atomic.update %[[I1]] : !fir.ref<i8> {
!CHECK: ^bb0(%[[VAL:.*]]: i8):
!CHECK: %[[CVT_VAL:.*]] = fir.convert %[[VAL]] : (i8) -> i32
!CHECK: %[[ADD_VAL:.*]] = arith.addi %[[CVT_VAL]], %[[C1_VAL]] : i32
!CHECK: %[[UPDATED_VAL:.*]] = fir.convert %[[ADD_VAL]] : (i32) -> i8
!CHECK: omp.yield(%[[UPDATED_VAL]] : i8)
!CHECK: }
!$omp atomic
i1 = i1 + 1
!$omp end atomic
!CHECK: return
!CHECK: }
end program OmpAtomicUpdate