1! This test checks lowering of atomic and atomic update constructs
2! RUN: bbc -fopenmp -emit-fir %s -o - | FileCheck %s
3! RUN: %flang_fc1 -emit-fir -fopenmp %s -o - | FileCheck %s
4
5program OmpAtomicUpdate
6    use omp_lib
7    integer :: x, y, z
8    integer, pointer :: a, b
9    integer, target :: c, d
10    a=>c
11    b=>d
12
13!CHECK: func.func @_QQmain() {
14!CHECK: %[[A:.*]] = fir.alloca !fir.box<!fir.ptr<i32>> {bindc_name = "a", uniq_name = "_QFEa"}
15!CHECK: %[[A_ADDR:.*]] = fir.alloca !fir.ptr<i32> {uniq_name = "_QFEa.addr"}
16!CHECK: %{{.*}} = fir.zero_bits !fir.ptr<i32>
17!CHECK: fir.store %{{.*}} to %[[A_ADDR]] : !fir.ref<!fir.ptr<i32>>
18!CHECK: %[[B:.*]] = fir.alloca !fir.box<!fir.ptr<i32>> {bindc_name = "b", uniq_name = "_QFEb"}
19!CHECK: %[[B_ADDR:.*]] = fir.alloca !fir.ptr<i32> {uniq_name = "_QFEb.addr"}
20!CHECK: %{{.*}} = fir.zero_bits !fir.ptr<i32>
21!CHECK: fir.store %{{.*}} to %[[B_ADDR]] : !fir.ref<!fir.ptr<i32>>
22!CHECK: %[[C_ADDR:.*]] = fir.address_of(@_QFEc) : !fir.ref<i32>
23!CHECK: %[[D_ADDR:.*]] = fir.address_of(@_QFEd) : !fir.ref<i32>
24!CHECK: %[[X:.*]] = fir.alloca i32 {bindc_name = "x", uniq_name = "_QFEx"}
25!CHECK: %[[Y:.*]] = fir.alloca i32 {bindc_name = "y", uniq_name = "_QFEy"}
26!CHECK: %[[Z:.*]] = fir.alloca i32 {bindc_name = "z", uniq_name = "_QFEz"}
27!CHECK: %{{.*}} = fir.convert %[[C_ADDR]] : (!fir.ref<i32>) -> !fir.ptr<i32>
28!CHECK: fir.store %{{.*}} to %[[A_ADDR]] : !fir.ref<!fir.ptr<i32>>
29!CHECK: %{{.*}} = fir.convert %[[D_ADDR]] : (!fir.ref<i32>) -> !fir.ptr<i32>
30!CHECK: fir.store {{.*}} to %[[B_ADDR]] : !fir.ref<!fir.ptr<i32>>
31!CHECK: %[[LOADED_A:.*]] = fir.load %[[A_ADDR]] : !fir.ref<!fir.ptr<i32>>
32!CHECK:  omp.atomic.update   %[[LOADED_A]] : !fir.ptr<i32> {
33!CHECK:  ^bb0(%[[ARG:.*]]: i32):
34!CHECK:    %[[LOADED_B:.*]] = fir.load %[[B_ADDR]] : !fir.ref<!fir.ptr<i32>>
35!CHECK:    %{{.*}} = fir.load %[[LOADED_B]] : !fir.ptr<i32>
36!CHECK:    %[[RESULT:.*]] = arith.addi %[[ARG]], %{{.*}} : i32
37!CHECK:    omp.yield(%[[RESULT]] : i32)
38!CHECK: }
39    !$omp atomic update
40        a = a + b
41
42!CHECK: omp.atomic.update   %[[Y]] : !fir.ref<i32> {
43!CHECK:  ^bb0(%[[ARG:.*]]: i32):
44!CHECK:    {{.*}} = arith.constant 1 : i32
45!CHECK:    %[[RESULT:.*]] = arith.addi %[[ARG]], {{.*}} : i32
46!CHECK:    omp.yield(%[[RESULT]] : i32)
47!CHECK:  }
48!CHECK:  omp.atomic.update   %[[Z]] : !fir.ref<i32> {
49!CHECK:  ^bb0(%[[ARG:.*]]: i32):
50!CHECK:    %[[LOADED_X:.*]] = fir.load %[[X]] : !fir.ref<i32>
51!CHECK:    %[[RESULT:.*]] = arith.muli %[[LOADED_X]], %[[ARG]] : i32
52!CHECK:    omp.yield(%[[RESULT]] : i32)
53!CHECK:  }
54    !$omp atomic
55        y = y + 1
56    !$omp atomic update
57        z = x * z
58
59!CHECK:  omp.atomic.update   memory_order(relaxed) hint(uncontended) %[[X]] : !fir.ref<i32> {
60!CHECK:  ^bb0(%[[ARG:.*]]: i32):
61!CHECK:    %{{.*}} = arith.constant 1 : i32
62!CHECK:    %[[RESULT:.*]] = arith.subi %[[ARG]], {{.*}} : i32
63!CHECK:    omp.yield(%[[RESULT]] : i32)
64!CHECK:  }
65!CHECK:  omp.atomic.update   memory_order(relaxed) %[[Y]] : !fir.ref<i32> {
66!CHECK:  ^bb0(%[[ARG:.*]]: i32):
67!CHECK:    %[[LOADED_X:.*]] = fir.load %[[X]] : !fir.ref<i32>
68!CHECK:    %[[LOADED_Z:.*]] = fir.load %[[Z]] : !fir.ref<i32>
69!CHECK:    %{{.*}} = arith.cmpi sgt, %[[LOADED_X]], %[[ARG]] : i32
70!CHECK:    %{{.*}} = arith.select %{{.*}}, %[[LOADED_X]], %[[ARG]] : i32
71!CHECK:    %{{.*}} = arith.cmpi sgt, %{{.*}}, %[[LOADED_Z]] : i32
72!CHECK:    %[[RESULT:.*]] = arith.select %{{.*}}, %{{.*}}, %[[LOADED_Z]] : i32
73!CHECK:    omp.yield(%[[RESULT]] : i32)
74!CHECK:  }
75!CHECK:  omp.atomic.update   memory_order(relaxed) hint(contended) %[[Z]] : !fir.ref<i32> {
76!CHECK:  ^bb0(%[[ARG:.*]]: i32):
77!CHECK:    %[[LOADED_X:.*]] = fir.load %[[X]] : !fir.ref<i32>
78!CHECK:    %[[RESULT:.*]] = arith.addi %[[ARG]], %[[LOADED_X]] : i32
79!CHECK:    omp.yield(%[[RESULT]] : i32)
80!CHECK:  }
81    !$omp atomic relaxed update hint(omp_sync_hint_uncontended)
82        x = x - 1
83    !$omp atomic update relaxed
84        y = max(x, y, z)
85    !$omp atomic relaxed hint(omp_sync_hint_contended)
86        z = z + x
87
88!CHECK:  omp.atomic.update   memory_order(release) hint(contended) %[[Z]] : !fir.ref<i32> {
89!CHECK:  ^bb0(%[[ARG:.*]]: i32):
90!CHECK:    %{{.*}} = arith.constant 10 : i32
91!CHECK:   %[[RESULT:.*]] = arith.muli {{.*}}, %[[ARG]] : i32
92!CHECK:    omp.yield(%[[RESULT]] : i32)
93!CHECK:  }
94!CHECK:  omp.atomic.update   memory_order(release) hint(speculative) %[[X]] : !fir.ref<i32> {
95!CHECK:  ^bb0(%[[ARG:.*]]: i32):
96!CHECK:    %[[LOADED_Z:.*]] = fir.load %[[Z]] : !fir.ref<i32>
97!CHECK:    %[[RESULT:.*]] = arith.divsi %[[ARG]], %[[LOADED_Z]] : i32
98!CHECK:    omp.yield(%[[RESULT]] : i32)
99!CHECK:  }
100
101    !$omp atomic release update hint(omp_lock_hint_contended)
102        z = z * 10
103    !$omp atomic hint(omp_lock_hint_speculative) update release
104        x = x / z
105
106!CHECK:  omp.atomic.update   memory_order(seq_cst) hint(nonspeculative) %[[Y]] : !fir.ref<i32> {
107!CHECK:  ^bb0(%[[ARG:.*]]: i32):
108!CHECK:    %{{.*}} = arith.constant 10 : i32
109!CHECK:    %[[RESULT:.*]] = arith.addi %{{.*}}, %[[ARG]] : i32
110!CHECK:   omp.yield(%[[RESULT]] : i32)
111!CHECK:  }
112!CHECK:  omp.atomic.update   memory_order(seq_cst) %[[Z]] : !fir.ref<i32> {
113!CHECK:  ^bb0(%[[ARG:.*]]: i32):
114!CHECK:    %[[LOADED_Y:.*]] = fir.load %[[Y]] : !fir.ref<i32>
115!CHECK:    %[[RESULT:.*]] = arith.addi %[[LOADED_Y]], %[[ARG]] : i32
116!CHECK:    omp.yield(%[[RESULT]] : i32)
117!CHECK:  }
118!CHECK:  return
119!CHECK: }
120    !$omp atomic hint(omp_sync_hint_nonspeculative) seq_cst
121        y = 10 + y
122    !$omp atomic seq_cst update
123        z = y + z
124end program OmpAtomicUpdate
125