1 // RUN: mlir-translate -mlir-to-llvmir -split-input-file %s | FileCheck %s
3 // CHECK-LABEL: define void @test_stand_alone_directives()
4 llvm.func @test_stand_alone_directives() {
5 // CHECK: [[OMP_THREAD:%.*]] = call i32 @__kmpc_global_thread_num(ptr @{{[0-9]+}})
6 // CHECK-NEXT: call void @__kmpc_barrier(ptr @{{[0-9]+}}, i32 [[OMP_THREAD]])
9 // CHECK: [[OMP_THREAD1:%.*]] = call i32 @__kmpc_global_thread_num(ptr @{{[0-9]+}})
10 // CHECK-NEXT: [[RET_VAL:%.*]] = call i32 @__kmpc_omp_taskwait(ptr @{{[0-9]+}}, i32 [[OMP_THREAD1]])
13 // CHECK: [[OMP_THREAD2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @{{[0-9]+}})
14 // CHECK-NEXT: [[RET_VAL:%.*]] = call i32 @__kmpc_omp_taskyield(ptr @{{[0-9]+}}, i32 [[OMP_THREAD2]], i32 0)
17 // CHECK-NEXT: ret void
21 // CHECK-LABEL: define void @test_flush_construct(ptr %{{[0-9]+}})
22 llvm.func @test_flush_construct(%arg0: !llvm.ptr) {
23 // CHECK: call void @__kmpc_flush(ptr @{{[0-9]+}}
26 // CHECK: call void @__kmpc_flush(ptr @{{[0-9]+}}
27 omp.flush (%arg0 : !llvm.ptr)
29 // CHECK: call void @__kmpc_flush(ptr @{{[0-9]+}}
30 omp.flush (%arg0, %arg0 : !llvm.ptr, !llvm.ptr)
32 %0 = llvm.mlir.constant(1 : i64) : i64
33 // CHECK: alloca {{.*}} align 4
34 %1 = llvm.alloca %0 x i32 {in_type = i32, name = "a"} : (i64) -> !llvm.ptr
35 // CHECK: call void @__kmpc_flush(ptr @{{[0-9]+}}
37 // CHECK: load i32, ptr
38 %2 = llvm.load %1 : !llvm.ptr -> i32
40 // CHECK-NEXT: ret void
44 // CHECK-LABEL: define void @test_omp_parallel_1()
45 llvm.func @test_omp_parallel_1() -> () {
46 // CHECK: call void{{.*}}@__kmpc_fork_call{{.*}}@[[OMP_OUTLINED_FN_1:.*]])
55 // CHECK: define internal void @[[OMP_OUTLINED_FN_1]]
56 // CHECK: call void @__kmpc_barrier
60 // CHECK-LABEL: define void @test_omp_parallel_2()
61 llvm.func @test_omp_parallel_2() -> () {
62 // CHECK: call void{{.*}}@__kmpc_fork_call{{.*}}@[[OMP_OUTLINED_FN_2:.*]])
65 %0 = llvm.mlir.constant(1 : index) : i64
66 %1 = llvm.mlir.constant(42 : index) : i64
67 llvm.call @body(%0) : (i64) -> ()
68 llvm.call @body(%1) : (i64) -> ()
72 %2 = llvm.add %0, %1 : i64
73 llvm.call @body(%2) : (i64) -> ()
79 // CHECK: define internal void @[[OMP_OUTLINED_FN_2]]
80 // CHECK-LABEL: omp.par.region:
81 // CHECK: br label %omp.par.region1
82 // CHECK-LABEL: omp.par.region1:
83 // CHECK: call void @body(i64 1)
84 // CHECK: call void @body(i64 42)
85 // CHECK: br label %omp.par.region2
86 // CHECK-LABEL: omp.par.region2:
87 // CHECK: call void @body(i64 43)
88 // CHECK: br label %omp.par.pre_finalize
90 // CHECK: define void @test_omp_parallel_num_threads_1(i32 %[[NUM_THREADS_VAR_1:.*]])
91 llvm.func @test_omp_parallel_num_threads_1(%arg0: i32) -> () {
92 // CHECK: %[[GTN_NUM_THREADS_VAR_1:.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GTN_SI_VAR_1:.*]])
93 // CHECK: call void @__kmpc_push_num_threads(ptr @[[GTN_SI_VAR_1]], i32 %[[GTN_NUM_THREADS_VAR_1]], i32 %[[NUM_THREADS_VAR_1]])
94 // CHECK: call void{{.*}}@__kmpc_fork_call{{.*}}@[[OMP_OUTLINED_FN_NUM_THREADS_1:.*]])
95 omp.parallel num_threads(%arg0: i32) {
103 // CHECK: define internal void @[[OMP_OUTLINED_FN_NUM_THREADS_1]]
104 // CHECK: call void @__kmpc_barrier
106 // CHECK: define void @test_omp_parallel_num_threads_2()
107 llvm.func @test_omp_parallel_num_threads_2() -> () {
108 %0 = llvm.mlir.constant(4 : index) : i32
109 // CHECK: %[[GTN_NUM_THREADS_VAR_2:.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GTN_SI_VAR_2:.*]])
110 // CHECK: call void @__kmpc_push_num_threads(ptr @[[GTN_SI_VAR_2]], i32 %[[GTN_NUM_THREADS_VAR_2]], i32 4)
111 // CHECK: call void{{.*}}@__kmpc_fork_call{{.*}}@[[OMP_OUTLINED_FN_NUM_THREADS_2:.*]])
112 omp.parallel num_threads(%0: i32) {
120 // CHECK: define internal void @[[OMP_OUTLINED_FN_NUM_THREADS_2]]
121 // CHECK: call void @__kmpc_barrier
123 // CHECK: define void @test_omp_parallel_num_threads_3()
124 llvm.func @test_omp_parallel_num_threads_3() -> () {
125 %0 = llvm.mlir.constant(4 : index) : i32
126 // CHECK: %[[GTN_NUM_THREADS_VAR_3_1:.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GTN_SI_VAR_3_1:.*]])
127 // CHECK: call void @__kmpc_push_num_threads(ptr @[[GTN_SI_VAR_3_1]], i32 %[[GTN_NUM_THREADS_VAR_3_1]], i32 4)
128 // CHECK: call void{{.*}}@__kmpc_fork_call{{.*}}@[[OMP_OUTLINED_FN_NUM_THREADS_3_1:.*]])
129 omp.parallel num_threads(%0: i32) {
133 %1 = llvm.mlir.constant(8 : index) : i32
134 // CHECK: %[[GTN_NUM_THREADS_VAR_3_2:.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GTN_SI_VAR_3_2:.*]])
135 // CHECK: call void @__kmpc_push_num_threads(ptr @[[GTN_SI_VAR_3_2]], i32 %[[GTN_NUM_THREADS_VAR_3_2]], i32 8)
136 // CHECK: call void{{.*}}@__kmpc_fork_call{{.*}}@[[OMP_OUTLINED_FN_NUM_THREADS_3_2:.*]])
137 omp.parallel num_threads(%1: i32) {
145 // CHECK: define internal void @[[OMP_OUTLINED_FN_NUM_THREADS_3_2]]
146 // CHECK: call void @__kmpc_barrier
148 // CHECK: define internal void @[[OMP_OUTLINED_FN_NUM_THREADS_3_1]]
149 // CHECK: call void @__kmpc_barrier
151 // CHECK: define void @test_omp_parallel_if_1(i32 %[[IF_EXPR_1:.*]])
152 llvm.func @test_omp_parallel_if_1(%arg0: i32) -> () {
154 %0 = llvm.mlir.constant(0 : index) : i32
155 %1 = llvm.icmp "slt" %arg0, %0 : i32
156 // CHECK: %[[IF_COND_VAR_1:.*]] = icmp slt i32 %[[IF_EXPR_1]], 0
159 // CHECK: %[[GTN_IF_1:.*]] = call i32 @__kmpc_global_thread_num(ptr @[[SI_VAR_IF_1:.*]])
160 // CHECK: br label %[[OUTLINED_CALL_IF_BLOCK_1:.*]]
161 // CHECK: [[OUTLINED_CALL_IF_BLOCK_1]]:
162 // CHECK: %[[I32_IF_COND_VAR_1:.*]] = sext i1 %[[IF_COND_VAR_1]] to i32
163 // CHECK: call void @__kmpc_fork_call_if(ptr @[[SI_VAR_IF_1]], i32 0, ptr @[[OMP_OUTLINED_FN_IF_1:.*]], i32 %[[I32_IF_COND_VAR_1]], ptr null)
164 // CHECK: br label %[[OUTLINED_EXIT_IF_1:.*]]
165 // CHECK: [[OUTLINED_EXIT_IF_1]]:
166 // CHECK: br label %[[RETURN_BLOCK_IF_1:.*]]
167 omp.parallel if(%1) {
172 // CHECK: [[RETURN_BLOCK_IF_1]]:
177 // CHECK: define internal void @[[OMP_OUTLINED_FN_IF_1]]
178 // CHECK: call void @__kmpc_barrier
182 // CHECK-LABEL: define void @test_omp_parallel_attrs()
183 llvm.func @test_omp_parallel_attrs() -> () attributes {
184 target_cpu = "x86-64",
185 target_features = #llvm.target_features<["+mmx", "+sse"]>
187 // CHECK: call void{{.*}}@__kmpc_fork_call{{.*}}@[[OMP_OUTLINED_FN:.*]])
196 // CHECK: define {{.*}} @[[OMP_OUTLINED_FN]]{{.*}} #[[ATTRS:[0-9]+]]
197 // CHECK: attributes #[[ATTRS]] = {
198 // CHECK-SAME: "target-cpu"="x86-64"
199 // CHECK-SAME: "target-features"="+mmx,+sse"
203 // CHECK-LABEL: define void @test_omp_parallel_3()
204 llvm.func @test_omp_parallel_3() -> () {
205 // CHECK: [[OMP_THREAD_3_1:%.*]] = call i32 @__kmpc_global_thread_num(ptr @{{[0-9]+}})
206 // CHECK: call void @__kmpc_push_proc_bind(ptr @{{[0-9]+}}, i32 [[OMP_THREAD_3_1]], i32 2)
207 // CHECK: call void{{.*}}@__kmpc_fork_call{{.*}}@[[OMP_OUTLINED_FN_3_1:.*]])
208 omp.parallel proc_bind(master) {
212 // CHECK: [[OMP_THREAD_3_2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @{{[0-9]+}})
213 // CHECK: call void @__kmpc_push_proc_bind(ptr @{{[0-9]+}}, i32 [[OMP_THREAD_3_2]], i32 3)
214 // CHECK: call void{{.*}}@__kmpc_fork_call{{.*}}@[[OMP_OUTLINED_FN_3_2:.*]])
215 omp.parallel proc_bind(close) {
219 // CHECK: [[OMP_THREAD_3_3:%.*]] = call i32 @__kmpc_global_thread_num(ptr @{{[0-9]+}})
220 // CHECK: call void @__kmpc_push_proc_bind(ptr @{{[0-9]+}}, i32 [[OMP_THREAD_3_3]], i32 4)
221 // CHECK: call void{{.*}}@__kmpc_fork_call{{.*}}@[[OMP_OUTLINED_FN_3_3:.*]])
222 omp.parallel proc_bind(spread) {
230 // CHECK: define internal void @[[OMP_OUTLINED_FN_3_3]]
231 // CHECK: define internal void @[[OMP_OUTLINED_FN_3_2]]
232 // CHECK: define internal void @[[OMP_OUTLINED_FN_3_1]]
234 // CHECK-LABEL: define void @test_omp_parallel_4()
235 llvm.func @test_omp_parallel_4() -> () {
236 // CHECK: call void {{.*}}@__kmpc_fork_call{{.*}} @[[OMP_OUTLINED_FN_4_1:.*]])
237 // CHECK: define internal void @[[OMP_OUTLINED_FN_4_1]]
238 // CHECK: call void @__kmpc_barrier
239 // CHECK: call void {{.*}}@__kmpc_fork_call{{.*}} @[[OMP_OUTLINED_FN_4_1_1:.*]])
240 // CHECK: call void @__kmpc_barrier
244 // CHECK: define internal void @[[OMP_OUTLINED_FN_4_1_1]]
245 // CHECK: call void @__kmpc_barrier
257 llvm.func @test_omp_parallel_5() -> () {
258 // CHECK: call void {{.*}}@__kmpc_fork_call{{.*}} @[[OMP_OUTLINED_FN_5_1:.*]])
259 // CHECK: define internal void @[[OMP_OUTLINED_FN_5_1]]
260 // CHECK: call void @__kmpc_barrier
261 // CHECK: call void {{.*}}@__kmpc_fork_call{{.*}} @[[OMP_OUTLINED_FN_5_1_1:.*]])
262 // CHECK: call void @__kmpc_barrier
266 // CHECK: define internal void @[[OMP_OUTLINED_FN_5_1_1]]
268 // CHECK: call void {{.*}}@__kmpc_fork_call{{.*}} @[[OMP_OUTLINED_FN_5_1_1_1:.*]])
269 // CHECK: define internal void @[[OMP_OUTLINED_FN_5_1_1_1]]
270 // CHECK: call void @__kmpc_barrier
284 // CHECK-LABEL: define void @test_omp_master()
285 llvm.func @test_omp_master() -> () {
286 // CHECK: call void {{.*}}@__kmpc_fork_call{{.*}} @{{.*}})
287 // CHECK: omp.par.region1:
290 // CHECK: [[OMP_THREAD_3_4:%.*]] = call i32 @__kmpc_global_thread_num(ptr @{{[0-9]+}})
291 // CHECK: {{[0-9]+}} = call i32 @__kmpc_master(ptr @{{[0-9]+}}, i32 [[OMP_THREAD_3_4]])
292 // CHECK: omp.master.region
293 // CHECK: call void @__kmpc_end_master(ptr @{{[0-9]+}}, i32 [[OMP_THREAD_3_4]])
294 // CHECK: br label %omp_region.end
313 // CHECK-LABEL: define void @test_omp_masked({{.*}})
314 llvm.func @test_omp_masked(%arg0: i32)-> () {
315 // CHECK: call void {{.*}}@__kmpc_fork_call{{.*}} @{{.*}})
316 // CHECK: omp.par.region1:
318 omp.masked filter(%arg0: i32) {
319 // CHECK: [[OMP_THREAD_3_4:%.*]] = call i32 @__kmpc_global_thread_num(ptr @{{[0-9]+}})
320 // CHECK: {{[0-9]+}} = call i32 @__kmpc_masked(ptr @{{[0-9]+}}, i32 [[OMP_THREAD_3_4]], i32 %{{[0-9]+}})
321 // CHECK: omp.masked.region
322 // CHECK: call void @__kmpc_end_masked(ptr @{{[0-9]+}}, i32 [[OMP_THREAD_3_4]])
323 // CHECK: br label %omp_region.end
333 // CHECK: %struct.ident_t = type
334 // CHECK: @[[$loc:.*]] = private unnamed_addr constant {{.*}} c";unknown;unknown;{{[0-9]+}};{{[0-9]+}};;\00"
335 // CHECK: @[[$loc_struct:.*]] = private unnamed_addr constant %struct.ident_t {{.*}} @[[$loc]] {{.*}}
337 // CHECK-LABEL: @wsloop_simple
338 llvm.func @wsloop_simple(%arg0: !llvm.ptr) {
339 %0 = llvm.mlir.constant(42 : index) : i64
340 %1 = llvm.mlir.constant(10 : index) : i64
341 %2 = llvm.mlir.constant(1 : index) : i64
344 omp.loop_nest (%arg1) : i64 = (%1) to (%0) step (%2) {
345 // The form of the emitted IR is controlled by OpenMPIRBuilder and
346 // tested there. Just check that the right functions are called.
347 // CHECK: call i32 @__kmpc_global_thread_num
348 // CHECK: call void @__kmpc_for_static_init_{{.*}}(ptr @[[$loc_struct]],
349 %3 = llvm.mlir.constant(2.000000e+00 : f32) : f32
350 %4 = llvm.getelementptr %arg0[%arg1] : (!llvm.ptr, i64) -> !llvm.ptr, f32
351 llvm.store %3, %4 : f32, !llvm.ptr
354 // CHECK: call void @__kmpc_for_static_fini(ptr @[[$loc_struct]],
363 // CHECK-LABEL: @wsloop_inclusive_1
364 llvm.func @wsloop_inclusive_1(%arg0: !llvm.ptr) {
365 %0 = llvm.mlir.constant(42 : index) : i64
366 %1 = llvm.mlir.constant(10 : index) : i64
367 %2 = llvm.mlir.constant(1 : index) : i64
368 // CHECK: store i64 31, ptr %{{.*}}upperbound
370 omp.loop_nest (%arg1) : i64 = (%1) to (%0) step (%2) {
371 %3 = llvm.mlir.constant(2.000000e+00 : f32) : f32
372 %4 = llvm.getelementptr %arg0[%arg1] : (!llvm.ptr, i64) -> !llvm.ptr, f32
373 llvm.store %3, %4 : f32, !llvm.ptr
382 // CHECK-LABEL: @wsloop_inclusive_2
383 llvm.func @wsloop_inclusive_2(%arg0: !llvm.ptr) {
384 %0 = llvm.mlir.constant(42 : index) : i64
385 %1 = llvm.mlir.constant(10 : index) : i64
386 %2 = llvm.mlir.constant(1 : index) : i64
387 // CHECK: store i64 32, ptr %{{.*}}upperbound
389 omp.loop_nest (%arg1) : i64 = (%1) to (%0) inclusive step (%2) {
390 %3 = llvm.mlir.constant(2.000000e+00 : f32) : f32
391 %4 = llvm.getelementptr %arg0[%arg1] : (!llvm.ptr, i64) -> !llvm.ptr, f32
392 llvm.store %3, %4 : f32, !llvm.ptr
403 // CHECK-LABEL: @test_omp_wsloop_static_defchunk
404 llvm.func @test_omp_wsloop_static_defchunk(%lb : i32, %ub : i32, %step : i32) -> () {
405 omp.wsloop schedule(static) {
406 omp.loop_nest (%iv) : i32 = (%lb) to (%ub) step (%step) {
407 // CHECK: call void @__kmpc_for_static_init_4u(ptr @{{.*}}, i32 %{{.*}}, i32 34, ptr %{{.*}}, ptr %{{.*}}, ptr %{{.*}}, ptr %{{.*}}, i32 1, i32 0)
408 // CHECK: call void @__kmpc_for_static_fini
409 llvm.call @body(%iv) : (i32) -> ()
420 // CHECK-LABEL: @test_omp_wsloop_static_1
421 llvm.func @test_omp_wsloop_static_1(%lb : i32, %ub : i32, %step : i32) -> () {
422 %static_chunk_size = llvm.mlir.constant(1 : i32) : i32
423 omp.wsloop schedule(static = %static_chunk_size : i32) {
424 omp.loop_nest (%iv) : i32 = (%lb) to (%ub) step (%step) {
425 // CHECK: call void @__kmpc_for_static_init_4u(ptr @{{.*}}, i32 %{{.*}}, i32 33, ptr %{{.*}}, ptr %{{.*}}, ptr %{{.*}}, ptr %{{.*}}, i32 1, i32 1)
426 // CHECK: call void @__kmpc_for_static_fini
427 llvm.call @body(%iv) : (i32) -> ()
438 // CHECK-LABEL: @test_omp_wsloop_static_2
439 llvm.func @test_omp_wsloop_static_2(%lb : i32, %ub : i32, %step : i32) -> () {
440 %static_chunk_size = llvm.mlir.constant(2 : i32) : i32
441 omp.wsloop schedule(static = %static_chunk_size : i32) {
442 omp.loop_nest (%iv) : i32 = (%lb) to (%ub) step (%step) {
443 // CHECK: call void @__kmpc_for_static_init_4u(ptr @{{.*}}, i32 %{{.*}}, i32 33, ptr %{{.*}}, ptr %{{.*}}, ptr %{{.*}}, ptr %{{.*}}, i32 1, i32 2)
444 // CHECK: call void @__kmpc_for_static_fini
445 llvm.call @body(%iv) : (i32) -> ()
456 llvm.func @test_omp_wsloop_dynamic(%lb : i64, %ub : i64, %step : i64) -> () {
457 omp.wsloop schedule(dynamic) {
458 omp.loop_nest (%iv) : i64 = (%lb) to (%ub) step (%step) {
459 // CHECK: call void @__kmpc_dispatch_init_8u
460 // CHECK: %[[continue:.*]] = call i32 @__kmpc_dispatch_next_8u
461 // CHECK: %[[cond:.*]] = icmp ne i32 %[[continue]], 0
462 // CHECK: br i1 %[[cond]], label %omp_loop.header{{.*}}, label %omp_loop.exit{{.*}}
463 llvm.call @body(%iv) : (i64) -> ()
474 llvm.func @test_omp_wsloop_dynamic_chunk_const(%lb : i64, %ub : i64, %step : i64) -> () {
475 %chunk_size_const = llvm.mlir.constant(2 : i16) : i16
476 omp.wsloop schedule(dynamic = %chunk_size_const : i16) {
477 omp.loop_nest (%iv) : i64 = (%lb) to (%ub) step (%step) {
478 // CHECK: call void @__kmpc_dispatch_init_8u(ptr @{{.*}}, i32 %{{.*}}, i32 1073741859, i64 {{.*}}, i64 %{{.*}}, i64 {{.*}}, i64 2)
479 // CHECK: %[[continue:.*]] = call i32 @__kmpc_dispatch_next_8u
480 // CHECK: %[[cond:.*]] = icmp ne i32 %[[continue]], 0
481 // CHECK: br i1 %[[cond]], label %omp_loop.header{{.*}}, label %omp_loop.exit{{.*}}
482 llvm.call @body(%iv) : (i64) -> ()
493 llvm.func @test_omp_wsloop_dynamic_chunk_var(%lb : i32, %ub : i32, %step : i32) -> () {
494 %1 = llvm.mlir.constant(1 : i64) : i64
495 %chunk_size_alloca = llvm.alloca %1 x i16 {bindc_name = "chunk_size", in_type = i16, uniq_name = "_QFsub1Echunk_size"} : (i64) -> !llvm.ptr
496 %chunk_size_var = llvm.load %chunk_size_alloca : !llvm.ptr -> i16
497 omp.wsloop schedule(dynamic = %chunk_size_var : i16) {
498 omp.loop_nest (%iv) : i32 = (%lb) to (%ub) step (%step) {
499 // CHECK: %[[CHUNK_SIZE:.*]] = sext i16 %{{.*}} to i32
500 // CHECK: call void @__kmpc_dispatch_init_4u(ptr @{{.*}}, i32 %{{.*}}, i32 1073741859, i32 {{.*}}, i32 %{{.*}}, i32 {{.*}}, i32 %[[CHUNK_SIZE]])
501 // CHECK: %[[continue:.*]] = call i32 @__kmpc_dispatch_next_4u
502 // CHECK: %[[cond:.*]] = icmp ne i32 %[[continue]], 0
503 // CHECK: br i1 %[[cond]], label %omp_loop.header{{.*}}, label %omp_loop.exit{{.*}}
504 llvm.call @body(%iv) : (i32) -> ()
515 llvm.func @test_omp_wsloop_dynamic_chunk_var2(%lb : i32, %ub : i32, %step : i32) -> () {
516 %1 = llvm.mlir.constant(1 : i64) : i64
517 %chunk_size_alloca = llvm.alloca %1 x i64 {bindc_name = "chunk_size", in_type = i64, uniq_name = "_QFsub1Echunk_size"} : (i64) -> !llvm.ptr
518 %chunk_size_var = llvm.load %chunk_size_alloca : !llvm.ptr -> i64
519 omp.wsloop schedule(dynamic = %chunk_size_var : i64) {
520 omp.loop_nest (%iv) : i32 = (%lb) to (%ub) step (%step) {
521 // CHECK: %[[CHUNK_SIZE:.*]] = trunc i64 %{{.*}} to i32
522 // CHECK: call void @__kmpc_dispatch_init_4u(ptr @{{.*}}, i32 %{{.*}}, i32 1073741859, i32 {{.*}}, i32 %{{.*}}, i32 {{.*}}, i32 %[[CHUNK_SIZE]])
523 // CHECK: %[[continue:.*]] = call i32 @__kmpc_dispatch_next_4u
524 // CHECK: %[[cond:.*]] = icmp ne i32 %[[continue]], 0
525 // CHECK: br i1 %[[cond]], label %omp_loop.header{{.*}}, label %omp_loop.exit{{.*}}
526 llvm.call @body(%iv) : (i32) -> ()
537 llvm.func @test_omp_wsloop_dynamic_chunk_var3(%lb : i32, %ub : i32, %step : i32, %chunk_size : i32) -> () {
538 omp.wsloop schedule(dynamic = %chunk_size : i32) {
539 omp.loop_nest (%iv) : i32 = (%lb) to (%ub) step (%step) {
540 // CHECK: call void @__kmpc_dispatch_init_4u(ptr @{{.*}}, i32 %{{.*}}, i32 1073741859, i32 {{.*}}, i32 %{{.*}}, i32 {{.*}}, i32 %{{.*}})
541 // CHECK: %[[continue:.*]] = call i32 @__kmpc_dispatch_next_4u
542 // CHECK: %[[cond:.*]] = icmp ne i32 %[[continue]], 0
543 // CHECK: br i1 %[[cond]], label %omp_loop.header{{.*}}, label %omp_loop.exit{{.*}}
544 llvm.call @body(%iv) : (i32) -> ()
555 llvm.func @test_omp_wsloop_auto(%lb : i64, %ub : i64, %step : i64) -> () {
556 omp.wsloop schedule(auto) {
557 omp.loop_nest (%iv) : i64 = (%lb) to (%ub) step (%step) {
558 // CHECK: call void @__kmpc_dispatch_init_8u
559 // CHECK: %[[continue:.*]] = call i32 @__kmpc_dispatch_next_8u
560 // CHECK: %[[cond:.*]] = icmp ne i32 %[[continue]], 0
561 // CHECK: br i1 %[[cond]], label %omp_loop.header{{.*}}, label %omp_loop.exit{{.*}}
562 llvm.call @body(%iv) : (i64) -> ()
573 llvm.func @test_omp_wsloop_runtime(%lb : i64, %ub : i64, %step : i64) -> () {
574 omp.wsloop schedule(runtime) {
575 omp.loop_nest (%iv) : i64 = (%lb) to (%ub) step (%step) {
576 // CHECK: call void @__kmpc_dispatch_init_8u
577 // CHECK: %[[continue:.*]] = call i32 @__kmpc_dispatch_next_8u
578 // CHECK: %[[cond:.*]] = icmp ne i32 %[[continue]], 0
579 // CHECK: br i1 %[[cond]], label %omp_loop.header{{.*}}, label %omp_loop.exit{{.*}}
580 llvm.call @body(%iv) : (i64) -> ()
591 llvm.func @test_omp_wsloop_guided(%lb : i64, %ub : i64, %step : i64) -> () {
592 omp.wsloop schedule(guided) {
593 omp.loop_nest (%iv) : i64 = (%lb) to (%ub) step (%step) {
594 // CHECK: call void @__kmpc_dispatch_init_8u
595 // CHECK: %[[continue:.*]] = call i32 @__kmpc_dispatch_next_8u
596 // CHECK: %[[cond:.*]] = icmp ne i32 %[[continue]], 0
597 // CHECK: br i1 %[[cond]], label %omp_loop.header{{.*}}, label %omp_loop.exit{{.*}}
598 llvm.call @body(%iv) : (i64) -> ()
609 llvm.func @test_omp_wsloop_dynamic_nonmonotonic(%lb : i64, %ub : i64, %step : i64) -> () {
610 omp.wsloop schedule(dynamic, nonmonotonic) {
611 omp.loop_nest (%iv) : i64 = (%lb) to (%ub) step (%step) {
612 // CHECK: call void @__kmpc_dispatch_init_8u(ptr @{{.*}}, i32 %{{.*}}, i32 1073741859
613 // CHECK: %[[continue:.*]] = call i32 @__kmpc_dispatch_next_8u
614 // CHECK: %[[cond:.*]] = icmp ne i32 %[[continue]], 0
615 // CHECK: br i1 %[[cond]], label %omp_loop.header{{.*}}, label %omp_loop.exit{{.*}}
616 llvm.call @body(%iv) : (i64) -> ()
627 llvm.func @test_omp_wsloop_dynamic_monotonic(%lb : i64, %ub : i64, %step : i64) -> () {
628 omp.wsloop schedule(dynamic, monotonic) {
629 omp.loop_nest (%iv) : i64 = (%lb) to (%ub) step (%step) {
630 // CHECK: call void @__kmpc_dispatch_init_8u(ptr @{{.*}}, i32 %{{.*}}, i32 536870947
631 // CHECK: %[[continue:.*]] = call i32 @__kmpc_dispatch_next_8u
632 // CHECK: %[[cond:.*]] = icmp ne i32 %[[continue]], 0
633 // CHECK: br i1 %[[cond]], label %omp_loop.header{{.*}}, label %omp_loop.exit{{.*}}
634 llvm.call @body(%iv) : (i64) -> ()
645 llvm.func @test_omp_wsloop_runtime_simd(%lb : i64, %ub : i64, %step : i64) -> () {
646 omp.wsloop schedule(runtime, simd) {
647 omp.loop_nest (%iv) : i64 = (%lb) to (%ub) step (%step) {
648 // CHECK: call void @__kmpc_dispatch_init_8u(ptr @{{.*}}, i32 %{{.*}}, i32 1073741871
649 // CHECK: %[[continue:.*]] = call i32 @__kmpc_dispatch_next_8u
650 // CHECK: %[[cond:.*]] = icmp ne i32 %[[continue]], 0
651 // CHECK: br i1 %[[cond]], label %omp_loop.header{{.*}}, label %omp_loop.exit{{.*}}
652 llvm.call @body(%iv) : (i64) -> ()
663 llvm.func @test_omp_wsloop_guided_simd(%lb : i64, %ub : i64, %step : i64) -> () {
664 omp.wsloop schedule(guided, simd) {
665 omp.loop_nest (%iv) : i64 = (%lb) to (%ub) step (%step) {
666 // CHECK: call void @__kmpc_dispatch_init_8u(ptr @{{.*}}, i32 %{{.*}}, i32 1073741870
667 // CHECK: %[[continue:.*]] = call i32 @__kmpc_dispatch_next_8u
668 // CHECK: %[[cond:.*]] = icmp ne i32 %[[continue]], 0
669 // CHECK: br i1 %[[cond]], label %omp_loop.header{{.*}}, label %omp_loop.exit{{.*}}
670 llvm.call @body(%iv) : (i64) -> ()
679 // CHECK-LABEL: @simd_simple
680 llvm.func @simd_simple(%lb : i64, %ub : i64, %step : i64, %arg0: !llvm.ptr) {
682 omp.loop_nest (%iv) : i64 = (%lb) to (%ub) step (%step) {
683 %3 = llvm.mlir.constant(2.000000e+00 : f32) : f32
684 // The form of the emitted IR is controlled by OpenMPIRBuilder and
685 // tested there. Just check that the right metadata is added.
686 // CHECK: llvm.access.group
687 %4 = llvm.getelementptr %arg0[%iv] : (!llvm.ptr, i64) -> !llvm.ptr, f32
688 llvm.store %3, %4 : f32, !llvm.ptr
695 // CHECK: llvm.loop.parallel_accesses
696 // CHECK-NEXT: llvm.loop.vectorize.enable
700 // CHECK-LABEL: @simd_simple_multiple
701 llvm.func @simd_simple_multiple(%lb1 : i64, %ub1 : i64, %step1 : i64, %lb2 : i64, %ub2 : i64, %step2 : i64, %arg0: !llvm.ptr, %arg1: !llvm.ptr) {
703 omp.loop_nest (%iv1, %iv2) : i64 = (%lb1, %lb2) to (%ub1, %ub2) step (%step1, %step2) {
704 %3 = llvm.mlir.constant(2.000000e+00 : f32) : f32
705 // The form of the emitted IR is controlled by OpenMPIRBuilder and
706 // tested there. Just check that the right metadata is added and collapsed
707 // loop bound is generated (Collapse clause is represented as a loop with
708 // list of indices, bounds and steps where the size of the list is equal
709 // to the collapse value.)
710 // CHECK: icmp slt i64
711 // CHECK-COUNT-3: select
712 // CHECK: %[[TRIPCOUNT0:.*]] = select
713 // CHECK: br label %[[PREHEADER:.*]]
714 // CHECK: [[PREHEADER]]:
715 // CHECK: icmp slt i64
716 // CHECK-COUNT-3: select
717 // CHECK: %[[TRIPCOUNT1:.*]] = select
718 // CHECK: mul nuw i64 %[[TRIPCOUNT0]], %[[TRIPCOUNT1]]
719 // CHECK: br label %[[COLLAPSED_PREHEADER:.*]]
720 // CHECK: [[COLLAPSED_PREHEADER]]:
721 // CHECK: br label %[[COLLAPSED_HEADER:.*]]
722 // CHECK: llvm.access.group
723 // CHECK-NEXT: llvm.access.group
724 %4 = llvm.getelementptr %arg0[%iv1] : (!llvm.ptr, i64) -> !llvm.ptr, f32
725 %5 = llvm.getelementptr %arg1[%iv2] : (!llvm.ptr, i64) -> !llvm.ptr, f32
726 llvm.store %3, %4 : f32, !llvm.ptr
727 llvm.store %3, %5 : f32, !llvm.ptr
733 // CHECK: llvm.loop.parallel_accesses
734 // CHECK-NEXT: llvm.loop.vectorize.enable
738 // CHECK-LABEL: @simd_simple_multiple_simdlen
739 llvm.func @simd_simple_multiple_simdlen(%lb1 : i64, %ub1 : i64, %step1 : i64, %lb2 : i64, %ub2 : i64, %step2 : i64, %arg0: !llvm.ptr, %arg1: !llvm.ptr) {
740 omp.simd simdlen(2) {
741 omp.loop_nest (%iv1, %iv2) : i64 = (%lb1, %lb2) to (%ub1, %ub2) step (%step1, %step2) {
742 %3 = llvm.mlir.constant(2.000000e+00 : f32) : f32
743 // The form of the emitted IR is controlled by OpenMPIRBuilder and
744 // tested there. Just check that the right metadata is added.
745 // CHECK: llvm.access.group
746 // CHECK-NEXT: llvm.access.group
747 %4 = llvm.getelementptr %arg0[%iv1] : (!llvm.ptr, i64) -> !llvm.ptr, f32
748 %5 = llvm.getelementptr %arg1[%iv2] : (!llvm.ptr, i64) -> !llvm.ptr, f32
749 llvm.store %3, %4 : f32, !llvm.ptr
750 llvm.store %3, %5 : f32, !llvm.ptr
756 // CHECK: llvm.loop.parallel_accesses
757 // CHECK-NEXT: llvm.loop.vectorize.enable
758 // CHECK-NEXT: llvm.loop.vectorize.width{{.*}}i64 2
762 // CHECK-LABEL: @simd_simple_multiple_safelen
763 llvm.func @simd_simple_multiple_safelen(%lb1 : i64, %ub1 : i64, %step1 : i64, %lb2 : i64, %ub2 : i64, %step2 : i64, %arg0: !llvm.ptr, %arg1: !llvm.ptr) {
764 omp.simd safelen(2) {
765 omp.loop_nest (%iv1, %iv2) : i64 = (%lb1, %lb2) to (%ub1, %ub2) step (%step1, %step2) {
766 %3 = llvm.mlir.constant(2.000000e+00 : f32) : f32
767 %4 = llvm.getelementptr %arg0[%iv1] : (!llvm.ptr, i64) -> !llvm.ptr, f32
768 %5 = llvm.getelementptr %arg1[%iv2] : (!llvm.ptr, i64) -> !llvm.ptr, f32
769 llvm.store %3, %4 : f32, !llvm.ptr
770 llvm.store %3, %5 : f32, !llvm.ptr
776 // CHECK: llvm.loop.vectorize.enable
777 // CHECK-NEXT: llvm.loop.vectorize.width{{.*}}i64 2
781 // CHECK-LABEL: @simd_simple_multiple_simdlen_safelen
782 llvm.func @simd_simple_multiple_simdlen_safelen(%lb1 : i64, %ub1 : i64, %step1 : i64, %lb2 : i64, %ub2 : i64, %step2 : i64, %arg0: !llvm.ptr, %arg1: !llvm.ptr) {
783 omp.simd simdlen(1) safelen(2) {
784 omp.loop_nest (%iv1, %iv2) : i64 = (%lb1, %lb2) to (%ub1, %ub2) step (%step1, %step2) {
785 %3 = llvm.mlir.constant(2.000000e+00 : f32) : f32
786 %4 = llvm.getelementptr %arg0[%iv1] : (!llvm.ptr, i64) -> !llvm.ptr, f32
787 %5 = llvm.getelementptr %arg1[%iv2] : (!llvm.ptr, i64) -> !llvm.ptr, f32
788 llvm.store %3, %4 : f32, !llvm.ptr
789 llvm.store %3, %5 : f32, !llvm.ptr
795 // CHECK: llvm.loop.vectorize.enable
796 // CHECK-NEXT: llvm.loop.vectorize.width{{.*}}i64 1
800 // CHECK-LABEL: @simd_if
801 llvm.func @simd_if(%arg0: !llvm.ptr {fir.bindc_name = "n"}, %arg1: !llvm.ptr {fir.bindc_name = "threshold"}) {
802 %0 = llvm.mlir.constant(1 : i64) : i64
803 %1 = llvm.alloca %0 x i32 {adapt.valuebyref, in_type = i32, operandSegmentSizes = array<i32: 0, 0>} : (i64) -> !llvm.ptr
804 %2 = llvm.mlir.constant(1 : i64) : i64
805 %3 = llvm.alloca %2 x i32 {bindc_name = "i", in_type = i32, operandSegmentSizes = array<i32: 0, 0>, uniq_name = "_QFtest_simdEi"} : (i64) -> !llvm.ptr
806 %4 = llvm.mlir.constant(0 : i32) : i32
807 %5 = llvm.load %arg0 : !llvm.ptr -> i32
808 %6 = llvm.mlir.constant(1 : i32) : i32
809 %7 = llvm.load %arg0 : !llvm.ptr -> i32
810 %8 = llvm.load %arg1 : !llvm.ptr -> i32
811 %9 = llvm.icmp "sge" %7, %8 : i32
813 omp.loop_nest (%arg2) : i32 = (%4) to (%5) inclusive step (%6) {
814 // The form of the emitted IR is controlled by OpenMPIRBuilder and
815 // tested there. Just check that the right metadata is added.
816 // CHECK: llvm.access.group
817 llvm.store %arg2, %1 : i32, !llvm.ptr
823 // Be sure that llvm.loop.vectorize.enable metadata appears twice
824 // CHECK: llvm.loop.parallel_accesses
825 // CHECK-NEXT: llvm.loop.vectorize.enable
826 // CHECK: llvm.loop.vectorize.enable
830 // CHECK-LABEL: @simd_order
831 llvm.func @simd_order() {
832 %0 = llvm.mlir.constant(10 : i64) : i64
833 %1 = llvm.mlir.constant(1 : i64) : i64
834 %2 = llvm.alloca %1 x i64 : (i64) -> !llvm.ptr
835 omp.simd order(concurrent) safelen(2) {
836 omp.loop_nest (%arg0) : i64 = (%1) to (%0) inclusive step (%1) {
837 llvm.store %arg0, %2 : i64, !llvm.ptr
843 // If clause order(concurrent) is specified then the memory instructions
844 // are marked parallel even if 'safelen' is finite.
845 // CHECK: llvm.loop.parallel_accesses
846 // CHECK-NEXT: llvm.loop.vectorize.enable
847 // CHECK-NEXT: llvm.loop.vectorize.width{{.*}}i64 2
852 llvm.func @test_omp_wsloop_ordered(%lb : i64, %ub : i64, %step : i64) -> () {
853 omp.wsloop ordered(0) {
854 omp.loop_nest (%iv) : i64 = (%lb) to (%ub) step (%step) {
855 // CHECK: call void @__kmpc_dispatch_init_8u(ptr @{{.*}}, i32 %{{.*}}, i32 66, i64 1, i64 %{{.*}}, i64 1, i64 1)
856 // CHECK: call void @__kmpc_dispatch_fini_8u
857 // CHECK: %[[continue:.*]] = call i32 @__kmpc_dispatch_next_8u
858 // CHECK: %[[cond:.*]] = icmp ne i32 %[[continue]], 0
859 // CHECK: br i1 %[[cond]], label %omp_loop.header{{.*}}, label %omp_loop.exit{{.*}}
860 llvm.call @body(%iv) : (i64) -> ()
871 llvm.func @test_omp_wsloop_static_ordered(%lb : i64, %ub : i64, %step : i64) -> () {
872 omp.wsloop schedule(static) ordered(0) {
873 omp.loop_nest (%iv) : i64 = (%lb) to (%ub) step (%step) {
874 // CHECK: call void @__kmpc_dispatch_init_8u(ptr @{{.*}}, i32 %{{.*}}, i32 66, i64 1, i64 %{{.*}}, i64 1, i64 1)
875 // CHECK: call void @__kmpc_dispatch_fini_8u
876 // CHECK: %[[continue:.*]] = call i32 @__kmpc_dispatch_next_8u
877 // CHECK: %[[cond:.*]] = icmp ne i32 %[[continue]], 0
878 // CHECK: br i1 %[[cond]], label %omp_loop.header{{.*}}, label %omp_loop.exit{{.*}}
879 llvm.call @body(%iv) : (i64) -> ()
890 llvm.func @test_omp_wsloop_static_chunk_ordered(%lb : i32, %ub : i32, %step : i32) -> () {
891 %static_chunk_size = llvm.mlir.constant(1 : i32) : i32
892 omp.wsloop schedule(static = %static_chunk_size : i32) ordered(0) {
893 omp.loop_nest (%iv) : i32 = (%lb) to (%ub) step (%step) {
894 // CHECK: call void @__kmpc_dispatch_init_4u(ptr @{{.*}}, i32 %{{.*}}, i32 65, i32 1, i32 %{{.*}}, i32 1, i32 1)
895 // CHECK: call void @__kmpc_dispatch_fini_4u
896 // CHECK: %[[continue:.*]] = call i32 @__kmpc_dispatch_next_4u
897 // CHECK: %[[cond:.*]] = icmp ne i32 %[[continue]], 0
898 // CHECK: br i1 %[[cond]], label %omp_loop.header{{.*}}, label %omp_loop.exit{{.*}}
899 llvm.call @body(%iv) : (i32) -> ()
910 llvm.func @test_omp_wsloop_dynamic_ordered(%lb : i64, %ub : i64, %step : i64) -> () {
911 omp.wsloop schedule(dynamic) ordered(0) {
912 omp.loop_nest (%iv) : i64 = (%lb) to (%ub) step (%step) {
913 // CHECK: call void @__kmpc_dispatch_init_8u(ptr @{{.*}}, i32 %{{.*}}, i32 67, i64 1, i64 %{{.*}}, i64 1, i64 1)
914 // CHECK: call void @__kmpc_dispatch_fini_8u
915 // CHECK: %[[continue:.*]] = call i32 @__kmpc_dispatch_next_8u
916 // CHECK: %[[cond:.*]] = icmp ne i32 %[[continue]], 0
917 // CHECK: br i1 %[[cond]], label %omp_loop.header{{.*}}, label %omp_loop.exit{{.*}}
918 llvm.call @body(%iv) : (i64) -> ()
929 llvm.func @test_omp_wsloop_auto_ordered(%lb : i64, %ub : i64, %step : i64) -> () {
930 omp.wsloop schedule(auto) ordered(0) {
931 omp.loop_nest (%iv) : i64 = (%lb) to (%ub) step (%step) {
932 // CHECK: call void @__kmpc_dispatch_init_8u(ptr @{{.*}}, i32 %{{.*}}, i32 70, i64 1, i64 %{{.*}}, i64 1, i64 1)
933 // CHECK: call void @__kmpc_dispatch_fini_8u
934 // CHECK: %[[continue:.*]] = call i32 @__kmpc_dispatch_next_8u
935 // CHECK: %[[cond:.*]] = icmp ne i32 %[[continue]], 0
936 // CHECK: br i1 %[[cond]], label %omp_loop.header{{.*}}, label %omp_loop.exit{{.*}}
937 llvm.call @body(%iv) : (i64) -> ()
948 llvm.func @test_omp_wsloop_runtime_ordered(%lb : i64, %ub : i64, %step : i64) -> () {
949 omp.wsloop schedule(runtime) ordered(0) {
950 omp.loop_nest (%iv) : i64 = (%lb) to (%ub) step (%step) {
951 // CHECK: call void @__kmpc_dispatch_init_8u(ptr @{{.*}}, i32 %{{.*}}, i32 69, i64 1, i64 %{{.*}}, i64 1, i64 1)
952 // CHECK: call void @__kmpc_dispatch_fini_8u
953 // CHECK: %[[continue:.*]] = call i32 @__kmpc_dispatch_next_8u
954 // CHECK: %[[cond:.*]] = icmp ne i32 %[[continue]], 0
955 // CHECK: br i1 %[[cond]], label %omp_loop.header{{.*}}, label %omp_loop.exit{{.*}}
956 llvm.call @body(%iv) : (i64) -> ()
967 llvm.func @test_omp_wsloop_guided_ordered(%lb : i64, %ub : i64, %step : i64) -> () {
968 omp.wsloop schedule(guided) ordered(0) {
969 omp.loop_nest (%iv) : i64 = (%lb) to (%ub) step (%step) {
970 // CHECK: call void @__kmpc_dispatch_init_8u(ptr @{{.*}}, i32 %{{.*}}, i32 68, i64 1, i64 %{{.*}}, i64 1, i64 1)
971 // CHECK: call void @__kmpc_dispatch_fini_8u
972 // CHECK: %[[continue:.*]] = call i32 @__kmpc_dispatch_next_8u
973 // CHECK: %[[cond:.*]] = icmp ne i32 %[[continue]], 0
974 // CHECK: br i1 %[[cond]], label %omp_loop.header{{.*}}, label %omp_loop.exit{{.*}}
975 llvm.call @body(%iv) : (i64) -> ()
986 llvm.func @test_omp_wsloop_dynamic_nonmonotonic_ordered(%lb : i64, %ub : i64, %step : i64) -> () {
987 omp.wsloop schedule(dynamic, nonmonotonic) ordered(0) {
988 omp.loop_nest (%iv) : i64 = (%lb) to (%ub) step (%step) {
989 // CHECK: call void @__kmpc_dispatch_init_8u(ptr @{{.*}}, i32 %{{.*}}, i32 1073741891, i64 1, i64 %{{.*}}, i64 1, i64 1)
990 // CHECK: call void @__kmpc_dispatch_fini_8u
991 // CHECK: %[[continue:.*]] = call i32 @__kmpc_dispatch_next_8u
992 // CHECK: %[[cond:.*]] = icmp ne i32 %[[continue]], 0
993 // CHECK: br i1 %[[cond]], label %omp_loop.header{{.*}}, label %omp_loop.exit{{.*}}
994 llvm.call @body(%iv) : (i64) -> ()
1003 llvm.func @body(i64)
1005 llvm.func @test_omp_wsloop_dynamic_monotonic_ordered(%lb : i64, %ub : i64, %step : i64) -> () {
1006 omp.wsloop schedule(dynamic, monotonic) ordered(0) {
1007 omp.loop_nest (%iv) : i64 = (%lb) to (%ub) step (%step) {
1008 // CHECK: call void @__kmpc_dispatch_init_8u(ptr @{{.*}}, i32 %{{.*}}, i32 536870979, i64 1, i64 %{{.*}}, i64 1, i64 1)
1009 // CHECK: call void @__kmpc_dispatch_fini_8u
1010 // CHECK: %[[continue:.*]] = call i32 @__kmpc_dispatch_next_8u
1011 // CHECK: %[[cond:.*]] = icmp ne i32 %[[continue]], 0
1012 // CHECK: br i1 %[[cond]], label %omp_loop.header{{.*}}, label %omp_loop.exit{{.*}}
1013 llvm.call @body(%iv) : (i64) -> ()
1022 omp.critical.declare @mutex_none hint(none) // 0
1023 omp.critical.declare @mutex_uncontended hint(uncontended) // 1
1024 omp.critical.declare @mutex_contended hint(contended) // 2
1025 omp.critical.declare @mutex_nonspeculative hint(nonspeculative) // 4
1026 omp.critical.declare @mutex_nonspeculative_uncontended hint(nonspeculative, uncontended) // 5
1027 omp.critical.declare @mutex_nonspeculative_contended hint(nonspeculative, contended) // 6
1028 omp.critical.declare @mutex_speculative hint(speculative) // 8
1029 omp.critical.declare @mutex_speculative_uncontended hint(speculative, uncontended) // 9
1030 omp.critical.declare @mutex_speculative_contended hint(speculative, contended) // 10
1032 // CHECK-LABEL: @omp_critical
1033 llvm.func @omp_critical(%x : !llvm.ptr, %xval : i32) -> () {
1034 // CHECK: call void @__kmpc_critical({{.*}}critical_user_.var{{.*}})
1035 // CHECK: br label %omp.critical.region
1036 // CHECK: omp.critical.region
1039 llvm.store %xval, %x : i32, !llvm.ptr
1042 // CHECK: call void @__kmpc_end_critical({{.*}}critical_user_.var{{.*}})
1044 // CHECK: call void @__kmpc_critical_with_hint({{.*}}critical_user_mutex_none.var{{.*}}, i32 0)
1045 // CHECK: br label %omp.critical.region
1046 // CHECK: omp.critical.region
1047 omp.critical(@mutex_none) {
1049 llvm.store %xval, %x : i32, !llvm.ptr
1052 // CHECK: call void @__kmpc_end_critical({{.*}}critical_user_mutex_none.var{{.*}})
1054 // CHECK: call void @__kmpc_critical_with_hint({{.*}}critical_user_mutex_uncontended.var{{.*}}, i32 1)
1055 // CHECK: br label %omp.critical.region
1056 // CHECK: omp.critical.region
1057 omp.critical(@mutex_uncontended) {
1059 llvm.store %xval, %x : i32, !llvm.ptr
1062 // CHECK: call void @__kmpc_end_critical({{.*}}critical_user_mutex_uncontended.var{{.*}})
1064 // CHECK: call void @__kmpc_critical_with_hint({{.*}}critical_user_mutex_contended.var{{.*}}, i32 2)
1065 // CHECK: br label %omp.critical.region
1066 // CHECK: omp.critical.region
1067 omp.critical(@mutex_contended) {
1069 llvm.store %xval, %x : i32, !llvm.ptr
1072 // CHECK: call void @__kmpc_end_critical({{.*}}critical_user_mutex_contended.var{{.*}})
1074 // CHECK: call void @__kmpc_critical_with_hint({{.*}}critical_user_mutex_nonspeculative.var{{.*}}, i32 4)
1075 // CHECK: br label %omp.critical.region
1076 // CHECK: omp.critical.region
1077 omp.critical(@mutex_nonspeculative) {
1079 llvm.store %xval, %x : i32, !llvm.ptr
1082 // CHECK: call void @__kmpc_end_critical({{.*}}critical_user_mutex_nonspeculative.var{{.*}})
1084 // CHECK: call void @__kmpc_critical_with_hint({{.*}}critical_user_mutex_nonspeculative_uncontended.var{{.*}}, i32 5)
1085 // CHECK: br label %omp.critical.region
1086 // CHECK: omp.critical.region
1087 omp.critical(@mutex_nonspeculative_uncontended) {
1089 llvm.store %xval, %x : i32, !llvm.ptr
1092 // CHECK: call void @__kmpc_end_critical({{.*}}critical_user_mutex_nonspeculative_uncontended.var{{.*}})
1094 // CHECK: call void @__kmpc_critical_with_hint({{.*}}critical_user_mutex_nonspeculative_contended.var{{.*}}, i32 6)
1095 // CHECK: br label %omp.critical.region
1096 // CHECK: omp.critical.region
1097 omp.critical(@mutex_nonspeculative_contended) {
1099 llvm.store %xval, %x : i32, !llvm.ptr
1102 // CHECK: call void @__kmpc_end_critical({{.*}}critical_user_mutex_nonspeculative_contended.var{{.*}})
1104 // CHECK: call void @__kmpc_critical_with_hint({{.*}}critical_user_mutex_speculative.var{{.*}}, i32 8)
1105 // CHECK: br label %omp.critical.region
1106 // CHECK: omp.critical.region
1107 omp.critical(@mutex_speculative) {
1109 llvm.store %xval, %x : i32, !llvm.ptr
1112 // CHECK: call void @__kmpc_end_critical({{.*}}critical_user_mutex_speculative.var{{.*}})
1114 // CHECK: call void @__kmpc_critical_with_hint({{.*}}critical_user_mutex_speculative_uncontended.var{{.*}}, i32 9)
1115 // CHECK: br label %omp.critical.region
1116 // CHECK: omp.critical.region
1117 omp.critical(@mutex_speculative_uncontended) {
1119 llvm.store %xval, %x : i32, !llvm.ptr
1122 // CHECK: call void @__kmpc_end_critical({{.*}}critical_user_mutex_speculative_uncontended.var{{.*}})
1124 // CHECK: call void @__kmpc_critical_with_hint({{.*}}critical_user_mutex_speculative_contended.var{{.*}}, i32 10)
1125 // CHECK: br label %omp.critical.region
1126 // CHECK: omp.critical.region
1127 omp.critical(@mutex_speculative_contended) {
1129 llvm.store %xval, %x : i32, !llvm.ptr
1132 // CHECK: call void @__kmpc_end_critical({{.*}}critical_user_mutex_speculative_contended.var{{.*}})
1138 // Check that the loop bounds are emitted in the correct location in case of
1139 // collapse. This only checks the overall shape of the IR, detailed checking
1140 // is done by the OpenMPIRBuilder.
1142 // CHECK-LABEL: @collapse_wsloop
1143 // CHECK: ptr noalias %[[TIDADDR:[0-9A-Za-z.]*]]
1144 // CHECK: load i32, ptr %[[TIDADDR]]
1147 // CHECK: %[[LB0:.*]] = load i32
1148 // CHECK: %[[UB0:.*]] = load i32
1149 // CHECK: %[[STEP0:.*]] = load i32
1150 // CHECK: %[[LB1:.*]] = load i32
1151 // CHECK: %[[UB1:.*]] = load i32
1152 // CHECK: %[[STEP1:.*]] = load i32
1153 // CHECK: %[[LB2:.*]] = load i32
1154 // CHECK: %[[UB2:.*]] = load i32
1155 // CHECK: %[[STEP2:.*]] = load i32
1156 llvm.func @collapse_wsloop(
1157 %0: i32, %1: i32, %2: i32,
1158 %3: i32, %4: i32, %5: i32,
1159 %6: i32, %7: i32, %8: i32,
1162 // CHECK: icmp slt i32 %[[LB0]], 0
1163 // CHECK-COUNT-4: select
1164 // CHECK: %[[TRIPCOUNT0:.*]] = select
1165 // CHECK: br label %[[PREHEADER:.*]]
1167 // CHECK: [[PREHEADER]]:
1168 // CHECK: icmp slt i32 %[[LB1]], 0
1169 // CHECK-COUNT-4: select
1170 // CHECK: %[[TRIPCOUNT1:.*]] = select
1171 // CHECK: icmp slt i32 %[[LB2]], 0
1172 // CHECK-COUNT-4: select
1173 // CHECK: %[[TRIPCOUNT2:.*]] = select
1174 // CHECK: %[[PROD:.*]] = mul nuw i32 %[[TRIPCOUNT0]], %[[TRIPCOUNT1]]
1175 // CHECK: %[[TOTAL:.*]] = mul nuw i32 %[[PROD]], %[[TRIPCOUNT2]]
1176 // CHECK: br label %[[COLLAPSED_PREHEADER:.*]]
1178 // CHECK: [[COLLAPSED_PREHEADER]]:
1179 // CHECK: store i32 0, ptr
1180 // CHECK: %[[TOTAL_SUB_1:.*]] = sub i32 %[[TOTAL]], 1
1181 // CHECK: store i32 %[[TOTAL_SUB_1]], ptr
1182 // CHECK: call void @__kmpc_for_static_init_4u
1184 omp.loop_nest (%arg0, %arg1, %arg2) : i32 = (%0, %1, %2) to (%3, %4, %5) step (%6, %7, %8) {
1185 %31 = llvm.load %20 : !llvm.ptr -> i32
1186 %32 = llvm.add %31, %arg0 : i32
1187 %33 = llvm.add %32, %arg1 : i32
1188 %34 = llvm.add %33, %arg2 : i32
1189 llvm.store %34, %20 : i32, !llvm.ptr
1200 // Check that the loop bounds are emitted in the correct location in case of
1201 // collapse for dynamic schedule. This only checks the overall shape of the IR,
1202 // detailed checking is done by the OpenMPIRBuilder.
1204 // CHECK-LABEL: @collapse_wsloop_dynamic
1205 // CHECK: ptr noalias %[[TIDADDR:[0-9A-Za-z.]*]]
1206 // CHECK: load i32, ptr %[[TIDADDR]]
1209 // CHECK: %[[LB0:.*]] = load i32
1210 // CHECK: %[[UB0:.*]] = load i32
1211 // CHECK: %[[STEP0:.*]] = load i32
1212 // CHECK: %[[LB1:.*]] = load i32
1213 // CHECK: %[[UB1:.*]] = load i32
1214 // CHECK: %[[STEP1:.*]] = load i32
1215 // CHECK: %[[LB2:.*]] = load i32
1216 // CHECK: %[[UB2:.*]] = load i32
1217 // CHECK: %[[STEP2:.*]] = load i32
1219 llvm.func @collapse_wsloop_dynamic(
1220 %0: i32, %1: i32, %2: i32,
1221 %3: i32, %4: i32, %5: i32,
1222 %6: i32, %7: i32, %8: i32,
1225 // CHECK: icmp slt i32 %[[LB0]], 0
1226 // CHECK-COUNT-4: select
1227 // CHECK: %[[TRIPCOUNT0:.*]] = select
1228 // CHECK: br label %[[PREHEADER:.*]]
1230 // CHECK: [[PREHEADER]]:
1231 // CHECK: icmp slt i32 %[[LB1]], 0
1232 // CHECK-COUNT-4: select
1233 // CHECK: %[[TRIPCOUNT1:.*]] = select
1234 // CHECK: icmp slt i32 %[[LB2]], 0
1235 // CHECK-COUNT-4: select
1236 // CHECK: %[[TRIPCOUNT2:.*]] = select
1237 // CHECK: %[[PROD:.*]] = mul nuw i32 %[[TRIPCOUNT0]], %[[TRIPCOUNT1]]
1238 // CHECK: %[[TOTAL:.*]] = mul nuw i32 %[[PROD]], %[[TRIPCOUNT2]]
1239 // CHECK: br label %[[COLLAPSED_PREHEADER:.*]]
1241 // CHECK: [[COLLAPSED_PREHEADER]]:
1242 // CHECK: store i32 1, ptr
1243 // CHECK: store i32 %[[TOTAL]], ptr
1244 // CHECK: call void @__kmpc_dispatch_init_4u
1245 omp.wsloop schedule(dynamic) {
1246 omp.loop_nest (%arg0, %arg1, %arg2) : i32 = (%0, %1, %2) to (%3, %4, %5) step (%6, %7, %8) {
1247 %31 = llvm.load %20 : !llvm.ptr -> i32
1248 %32 = llvm.add %31, %arg0 : i32
1249 %33 = llvm.add %32, %arg1 : i32
1250 %34 = llvm.add %33, %arg2 : i32
1251 llvm.store %34, %20 : i32, !llvm.ptr
1262 // CHECK-LABEL: @omp_ordered
1263 llvm.func @omp_ordered(%arg0 : i32, %arg1 : i32, %arg2 : i32, %arg3 : i64,
1264 %arg4: i64, %arg5: i64, %arg6: i64) -> () {
1265 // CHECK: [[ADDR9:%.*]] = alloca [2 x i64], align 8
1266 // CHECK: [[ADDR7:%.*]] = alloca [2 x i64], align 8
1267 // CHECK: [[ADDR5:%.*]] = alloca [2 x i64], align 8
1268 // CHECK: [[ADDR3:%.*]] = alloca [1 x i64], align 8
1269 // CHECK: [[ADDR:%.*]] = alloca [1 x i64], align 8
1271 // CHECK: [[OMP_THREAD:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1:[0-9]+]])
1272 // CHECK-NEXT: call void @__kmpc_ordered(ptr @[[GLOB1]], i32 [[OMP_THREAD]])
1273 omp.ordered.region {
1275 // CHECK: call void @__kmpc_end_ordered(ptr @[[GLOB1]], i32 [[OMP_THREAD]])
1278 omp.wsloop ordered(0) {
1279 omp.loop_nest (%arg7) : i32 = (%arg0) to (%arg1) step (%arg2) {
1280 // CHECK: call void @__kmpc_ordered(ptr @[[GLOB3:[0-9]+]], i32 [[OMP_THREAD2:%.*]])
1281 omp.ordered.region {
1283 // CHECK: call void @__kmpc_end_ordered(ptr @[[GLOB3]], i32 [[OMP_THREAD2]])
1289 omp.wsloop ordered(1) {
1290 omp.loop_nest (%arg7) : i32 = (%arg0) to (%arg1) step (%arg2) {
1291 // CHECK: [[TMP:%.*]] = getelementptr inbounds [1 x i64], ptr [[ADDR]], i64 0, i64 0
1292 // CHECK: store i64 [[ARG0:%.*]], ptr [[TMP]], align 8
1293 // CHECK: [[TMP2:%.*]] = getelementptr inbounds [1 x i64], ptr [[ADDR]], i64 0, i64 0
1294 // CHECK: [[OMP_THREAD2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB3:[0-9]+]])
1295 // CHECK: call void @__kmpc_doacross_wait(ptr @[[GLOB3]], i32 [[OMP_THREAD2]], ptr [[TMP2]])
1296 omp.ordered depend_type(dependsink) depend_vec(%arg3 : i64) {doacross_num_loops = 1 : i64}
1298 // CHECK: [[TMP3:%.*]] = getelementptr inbounds [1 x i64], ptr [[ADDR3]], i64 0, i64 0
1299 // CHECK: store i64 [[ARG0]], ptr [[TMP3]], align 8
1300 // CHECK: [[TMP4:%.*]] = getelementptr inbounds [1 x i64], ptr [[ADDR3]], i64 0, i64 0
1301 // CHECK: [[OMP_THREAD4:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB5:[0-9]+]])
1302 // CHECK: call void @__kmpc_doacross_post(ptr @[[GLOB5]], i32 [[OMP_THREAD4]], ptr [[TMP4]])
1303 omp.ordered depend_type(dependsource) depend_vec(%arg3 : i64) {doacross_num_loops = 1 : i64}
1309 omp.wsloop ordered(2) {
1310 omp.loop_nest (%arg7) : i32 = (%arg0) to (%arg1) step (%arg2) {
1311 // CHECK: [[TMP5:%.*]] = getelementptr inbounds [2 x i64], ptr [[ADDR5]], i64 0, i64 0
1312 // CHECK: store i64 [[ARG0]], ptr [[TMP5]], align 8
1313 // CHECK: [[TMP6:%.*]] = getelementptr inbounds [2 x i64], ptr [[ADDR5]], i64 0, i64 1
1314 // CHECK: store i64 [[ARG1:%.*]], ptr [[TMP6]], align 8
1315 // CHECK: [[TMP7:%.*]] = getelementptr inbounds [2 x i64], ptr [[ADDR5]], i64 0, i64 0
1316 // CHECK: [[OMP_THREAD6:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB7:[0-9]+]])
1317 // CHECK: call void @__kmpc_doacross_wait(ptr @[[GLOB7]], i32 [[OMP_THREAD6]], ptr [[TMP7]])
1318 // CHECK: [[TMP8:%.*]] = getelementptr inbounds [2 x i64], ptr [[ADDR7]], i64 0, i64 0
1319 // CHECK: store i64 [[ARG2:%.*]], ptr [[TMP8]], align 8
1320 // CHECK: [[TMP9:%.*]] = getelementptr inbounds [2 x i64], ptr [[ADDR7]], i64 0, i64 1
1321 // CHECK: store i64 [[ARG3:%.*]], ptr [[TMP9]], align 8
1322 // CHECK: [[TMP10:%.*]] = getelementptr inbounds [2 x i64], ptr [[ADDR7]], i64 0, i64 0
1323 // CHECK: [[OMP_THREAD8:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB7]])
1324 // CHECK: call void @__kmpc_doacross_wait(ptr @[[GLOB7]], i32 [[OMP_THREAD8]], ptr [[TMP10]])
1325 omp.ordered depend_type(dependsink) depend_vec(%arg3, %arg4, %arg5, %arg6 : i64, i64, i64, i64) {doacross_num_loops = 2 : i64}
1327 // CHECK: [[TMP11:%.*]] = getelementptr inbounds [2 x i64], ptr [[ADDR9]], i64 0, i64 0
1328 // CHECK: store i64 [[ARG0]], ptr [[TMP11]], align 8
1329 // CHECK: [[TMP12:%.*]] = getelementptr inbounds [2 x i64], ptr [[ADDR9]], i64 0, i64 1
1330 // CHECK: store i64 [[ARG1]], ptr [[TMP12]], align 8
1331 // CHECK: [[TMP13:%.*]] = getelementptr inbounds [2 x i64], ptr [[ADDR9]], i64 0, i64 0
1332 // CHECK: [[OMP_THREAD10:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB9:[0-9]+]])
1333 // CHECK: call void @__kmpc_doacross_post(ptr @[[GLOB9]], i32 [[OMP_THREAD10]], ptr [[TMP13]])
1334 omp.ordered depend_type(dependsource) depend_vec(%arg3, %arg4 : i64, i64) {doacross_num_loops = 2 : i64}
1345 // CHECK-LABEL: @omp_atomic_read
1346 // CHECK-SAME: (ptr %[[ARG0:.*]], ptr %[[ARG1:.*]])
1347 llvm.func @omp_atomic_read(%arg0 : !llvm.ptr, %arg1 : !llvm.ptr) -> () {
1349 // CHECK: %[[X1:.*]] = load atomic i32, ptr %[[ARG0]] monotonic, align 4
1350 // CHECK: store i32 %[[X1]], ptr %[[ARG1]], align 4
1351 omp.atomic.read %arg1 = %arg0 : !llvm.ptr, !llvm.ptr, i32
1353 // CHECK: %[[X2:.*]] = load atomic i32, ptr %[[ARG0]] seq_cst, align 4
1354 // CHECK: call void @__kmpc_flush(ptr @{{.*}})
1355 // CHECK: store i32 %[[X2]], ptr %[[ARG1]], align 4
1356 omp.atomic.read %arg1 = %arg0 memory_order(seq_cst) : !llvm.ptr, !llvm.ptr, i32
1358 // CHECK: %[[X3:.*]] = load atomic i32, ptr %[[ARG0]] acquire, align 4
1359 // CHECK: call void @__kmpc_flush(ptr @{{.*}})
1360 // CHECK: store i32 %[[X3]], ptr %[[ARG1]], align 4
1361 omp.atomic.read %arg1 = %arg0 memory_order(acquire) : !llvm.ptr, !llvm.ptr, i32
1363 // CHECK: %[[X4:.*]] = load atomic i32, ptr %[[ARG0]] monotonic, align 4
1364 // CHECK: store i32 %[[X4]], ptr %[[ARG1]], align 4
1365 omp.atomic.read %arg1 = %arg0 memory_order(relaxed) : !llvm.ptr, !llvm.ptr, i32
1371 // CHECK-LABEL: @omp_atomic_read_implicit_cast
1372 llvm.func @omp_atomic_read_implicit_cast () {
1373 //CHECK: %[[Z:.*]] = alloca float, i64 1, align 4
1374 //CHECK: %[[Y:.*]] = alloca double, i64 1, align 8
1375 //CHECK: %[[X:.*]] = alloca [2 x { float, float }], i64 1, align 8
1376 //CHECK: %[[W:.*]] = alloca i32, i64 1, align 4
1377 //CHECK: %[[X_ELEMENT:.*]] = getelementptr { float, float }, ptr %3, i64 0
1378 %0 = llvm.mlir.constant(1 : i64) : i64
1379 %1 = llvm.alloca %0 x f32 {bindc_name = "z"} : (i64) -> !llvm.ptr
1380 %2 = llvm.mlir.constant(1 : i64) : i64
1381 %3 = llvm.alloca %2 x f64 {bindc_name = "y"} : (i64) -> !llvm.ptr
1382 %4 = llvm.mlir.constant(1 : i64) : i64
1383 %5 = llvm.alloca %4 x !llvm.array<2 x struct<(f32, f32)>> {bindc_name = "x"} : (i64) -> !llvm.ptr
1384 %6 = llvm.mlir.constant(1 : i64) : i64
1385 %7 = llvm.alloca %6 x i32 {bindc_name = "w"} : (i64) -> !llvm.ptr
1386 %8 = llvm.mlir.constant(1 : index) : i64
1387 %9 = llvm.mlir.constant(2 : index) : i64
1388 %10 = llvm.mlir.constant(1 : i64) : i64
1389 %11 = llvm.mlir.constant(0 : i64) : i64
1390 %12 = llvm.sub %8, %10 overflow<nsw> : i64
1391 %13 = llvm.mul %12, %10 overflow<nsw> : i64
1392 %14 = llvm.mul %13, %10 overflow<nsw> : i64
1393 %15 = llvm.add %14, %11 overflow<nsw> : i64
1394 %16 = llvm.mul %10, %9 overflow<nsw> : i64
1395 %17 = llvm.getelementptr %5[%15] : (!llvm.ptr, i64) -> !llvm.ptr, !llvm.struct<(f32, f32)>
1397 //CHECK: %[[ATOMIC_LOAD_TEMP:.*]] = alloca { float, float }, align 8
1398 //CHECK: call void @__atomic_load(i64 8, ptr %[[X_ELEMENT]], ptr %[[ATOMIC_LOAD_TEMP]], i32 0)
1399 //CHECK: %[[LOAD:.*]] = load { float, float }, ptr %[[ATOMIC_LOAD_TEMP]], align 8
1400 //CHECK: %[[EXT:.*]] = extractvalue { float, float } %[[LOAD]], 0
1401 //CHECK: store float %[[EXT]], ptr %[[Y]], align 4
1402 omp.atomic.read %3 = %17 : !llvm.ptr, !llvm.ptr, !llvm.struct<(f32, f32)>
1404 //CHECK: %[[ATOMIC_LOAD_TEMP:.*]] = load atomic i32, ptr %[[Z]] monotonic, align 4
1405 //CHECK: %[[CAST:.*]] = bitcast i32 %[[ATOMIC_LOAD_TEMP]] to float
1406 //CHECK: %[[LOAD:.*]] = fpext float %[[CAST]] to double
1407 //CHECK: store double %[[LOAD]], ptr %[[Y]], align 8
1408 omp.atomic.read %3 = %1 : !llvm.ptr, !llvm.ptr, f32
1410 //CHECK: %[[ATOMIC_LOAD_TEMP:.*]] = load atomic i32, ptr %[[W]] monotonic, align 4
1411 //CHECK: %[[LOAD:.*]] = sitofp i32 %[[ATOMIC_LOAD_TEMP]] to double
1412 //CHECK: store double %[[LOAD]], ptr %[[Y]], align 8
1413 omp.atomic.read %3 = %7 : !llvm.ptr, !llvm.ptr, i32
1415 //CHECK: %[[ATOMIC_LOAD_TEMP:.*]] = load atomic i64, ptr %[[Y]] monotonic, align 4
1416 //CHECK: %[[CAST:.*]] = bitcast i64 %[[ATOMIC_LOAD_TEMP]] to double
1417 //CHECK: %[[LOAD:.*]] = fptrunc double %[[CAST]] to float
1418 //CHECK: store float %[[LOAD]], ptr %[[Z]], align 4
1419 omp.atomic.read %1 = %3 : !llvm.ptr, !llvm.ptr, f64
1421 //CHECK: %[[ATOMIC_LOAD_TEMP:.*]] = load atomic i32, ptr %[[W]] monotonic, align 4
1422 //CHECK: %[[LOAD:.*]] = sitofp i32 %[[ATOMIC_LOAD_TEMP]] to float
1423 //CHECK: store float %[[LOAD]], ptr %[[Z]], align 4
1424 omp.atomic.read %1 = %7 : !llvm.ptr, !llvm.ptr, i32
1426 //CHECK: %[[ATOMIC_LOAD_TEMP:.*]] = load atomic i64, ptr %[[Y]] monotonic, align 4
1427 //CHECK: %[[CAST:.*]] = bitcast i64 %[[ATOMIC_LOAD_TEMP]] to double
1428 //CHECK: %[[LOAD:.*]] = fptosi double %[[CAST]] to i32
1429 //CHECK: store i32 %[[LOAD]], ptr %[[W]], align 4
1430 omp.atomic.read %7 = %3 : !llvm.ptr, !llvm.ptr, f64
1432 //CHECK: %[[ATOMIC_LOAD_TEMP:.*]] = load atomic i32, ptr %[[Z]] monotonic, align 4
1433 //CHECK: %[[CAST:.*]] = bitcast i32 %[[ATOMIC_LOAD_TEMP]] to float
1434 //CHECK: %[[LOAD:.*]] = fptosi float %[[CAST]] to i32
1435 //CHECK: store i32 %[[LOAD]], ptr %[[W]], align 4
1436 omp.atomic.read %7 = %1 : !llvm.ptr, !llvm.ptr, f32
1442 // CHECK-LABEL: @omp_atomic_write
1443 // CHECK-SAME: (ptr %[[x:.*]], i32 %[[expr:.*]])
1444 llvm.func @omp_atomic_write(%x: !llvm.ptr, %expr: i32) -> () {
1445 // CHECK: store atomic i32 %[[expr]], ptr %[[x]] monotonic, align 4
1446 omp.atomic.write %x = %expr : !llvm.ptr, i32
1447 // CHECK: store atomic i32 %[[expr]], ptr %[[x]] seq_cst, align 4
1448 // CHECK: call void @__kmpc_flush(ptr @{{.*}})
1449 omp.atomic.write %x = %expr memory_order(seq_cst) : !llvm.ptr, i32
1450 // CHECK: store atomic i32 %[[expr]], ptr %[[x]] release, align 4
1451 // CHECK: call void @__kmpc_flush(ptr @{{.*}})
1452 omp.atomic.write %x = %expr memory_order(release) : !llvm.ptr, i32
1453 // CHECK: store atomic i32 %[[expr]], ptr %[[x]] monotonic, align 4
1454 omp.atomic.write %x = %expr memory_order(relaxed) : !llvm.ptr, i32
1460 // Checking simple atomicrmw and cmpxchg based translation. This also checks for
1461 // ambigous alloca insert point by putting llvm.mul as the first update operation.
1462 // CHECK-LABEL: @omp_atomic_update
1463 // CHECK-SAME: (ptr %[[x:.*]], i32 %[[expr:.*]], ptr %[[xbool:.*]], i1 %[[exprbool:.*]])
1464 llvm.func @omp_atomic_update(%x:!llvm.ptr, %expr: i32, %xbool: !llvm.ptr, %exprbool: i1) {
1465 // CHECK: %[[t1:.*]] = mul i32 %[[x_old:.*]], %[[expr]]
1466 // CHECK: store i32 %[[t1]], ptr %[[x_new:.*]]
1467 // CHECK: %[[t2:.*]] = load i32, ptr %[[x_new]]
1468 // CHECK: cmpxchg ptr %[[x]], i32 %[[x_old]], i32 %[[t2]]
1469 omp.atomic.update %x : !llvm.ptr {
1471 %newval = llvm.mul %xval, %expr : i32
1472 omp.yield(%newval : i32)
1474 // CHECK: atomicrmw add ptr %[[x]], i32 %[[expr]] monotonic
1475 omp.atomic.update %x : !llvm.ptr {
1477 %newval = llvm.add %xval, %expr : i32
1478 omp.yield(%newval : i32)
1485 //CHECK: %[[X_NEW_VAL:.*]] = alloca { float, float }, align 8
1486 //CHECK: {{.*}} = alloca { float, float }, i64 1, align 8
1487 //CHECK: %[[ORIG_VAL:.*]] = alloca { float, float }, i64 1, align 8
1489 //CHECK: br label %entry
1492 //CHECK: %[[ATOMIC_TEMP_LOAD:.*]] = alloca { float, float }, align 8
1493 //CHECK: call void @__atomic_load(i64 8, ptr %[[ORIG_VAL]], ptr %[[ATOMIC_TEMP_LOAD]], i32 0)
1494 //CHECK: %[[PHI_NODE_ENTRY_1:.*]] = load { float, float }, ptr %[[ATOMIC_TEMP_LOAD]], align 8
1495 //CHECK: br label %.atomic.cont
1497 //CHECK: .atomic.cont
1498 //CHECK: %[[VAL_4:.*]] = phi { float, float } [ %[[PHI_NODE_ENTRY_1]], %entry ], [ %{{.*}}, %.atomic.cont ]
1499 //CHECK: %[[VAL_5:.*]] = extractvalue { float, float } %[[VAL_4]], 0
1500 //CHECK: %[[VAL_6:.*]] = extractvalue { float, float } %[[VAL_4]], 1
1501 //CHECK: %[[VAL_7:.*]] = fadd contract float %[[VAL_5]], 1.000000e+00
1502 //CHECK: %[[VAL_8:.*]] = fadd contract float %[[VAL_6]], 1.000000e+00
1503 //CHECK: %[[VAL_9:.*]] = insertvalue { float, float } undef, float %[[VAL_7]], 0
1504 //CHECK: %[[VAL_10:.*]] = insertvalue { float, float } %[[VAL_9]], float %[[VAL_8]], 1
1505 //CHECK: store { float, float } %[[VAL_10]], ptr %[[X_NEW_VAL]], align 4
1506 //CHECK: %[[VAL_11:.*]] = call i1 @__atomic_compare_exchange(i64 8, ptr %[[ORIG_VAL]], ptr %[[ATOMIC_TEMP_LOAD]], ptr %[[X_NEW_VAL]], i32 2, i32 2)
1507 //CHECK: %[[VAL_12:.*]] = load { float, float }, ptr %[[ATOMIC_TEMP_LOAD]], align 4
1508 //CHECK: br i1 %[[VAL_11]], label %.atomic.exit, label %.atomic.cont
1510 llvm.func @_QPomp_atomic_update_complex() {
1511 %0 = llvm.mlir.constant(1 : i64) : i64
1512 %1 = llvm.alloca %0 x !llvm.struct<(f32, f32)> {bindc_name = "ib"} : (i64) -> !llvm.ptr
1513 %2 = llvm.mlir.constant(1 : i64) : i64
1514 %3 = llvm.alloca %2 x !llvm.struct<(f32, f32)> {bindc_name = "ia"} : (i64) -> !llvm.ptr
1515 %4 = llvm.mlir.constant(1.000000e+00 : f32) : f32
1516 %5 = llvm.mlir.undef : !llvm.struct<(f32, f32)>
1517 %6 = llvm.insertvalue %4, %5[0] : !llvm.struct<(f32, f32)>
1518 %7 = llvm.insertvalue %4, %6[1] : !llvm.struct<(f32, f32)>
1519 omp.atomic.update %3 : !llvm.ptr {
1520 ^bb0(%arg0: !llvm.struct<(f32, f32)>):
1521 %8 = llvm.extractvalue %arg0[0] : !llvm.struct<(f32, f32)>
1522 %9 = llvm.extractvalue %arg0[1] : !llvm.struct<(f32, f32)>
1523 %10 = llvm.extractvalue %7[0] : !llvm.struct<(f32, f32)>
1524 %11 = llvm.extractvalue %7[1] : !llvm.struct<(f32, f32)>
1525 %12 = llvm.fadd %8, %10 {fastmathFlags = #llvm.fastmath<contract>} : f32
1526 %13 = llvm.fadd %9, %11 {fastmathFlags = #llvm.fastmath<contract>} : f32
1527 %14 = llvm.mlir.undef : !llvm.struct<(f32, f32)>
1528 %15 = llvm.insertvalue %12, %14[0] : !llvm.struct<(f32, f32)>
1529 %16 = llvm.insertvalue %13, %15[1] : !llvm.struct<(f32, f32)>
1530 omp.yield(%16 : !llvm.struct<(f32, f32)>)
1537 //CHECK: %[[X_NEW_VAL:.*]] = alloca { float, float }, align 8
1538 //CHECK: %[[VAL_1:.*]] = alloca { float, float }, i64 1, align 8
1539 //CHECK: %[[ORIG_VAL:.*]] = alloca { float, float }, i64 1, align 8
1540 //CHECK: store { float, float } { float 2.000000e+00, float 2.000000e+00 }, ptr %[[ORIG_VAL]], align 4
1541 //CHECK: br label %entry
1543 //CHECK: entry: ; preds = %0
1544 //CHECK: %[[ATOMIC_TEMP_LOAD:.*]] = alloca { float, float }, align 8
1545 //CHECK: call void @__atomic_load(i64 8, ptr %[[ORIG_VAL]], ptr %[[ATOMIC_TEMP_LOAD]], i32 0)
1546 //CHECK: %[[PHI_NODE_ENTRY_1:.*]] = load { float, float }, ptr %[[ATOMIC_TEMP_LOAD]], align 8
1547 //CHECK: br label %.atomic.cont
1549 //CHECK: .atomic.cont
1550 //CHECK: %[[VAL_4:.*]] = phi { float, float } [ %[[PHI_NODE_ENTRY_1]], %entry ], [ %{{.*}}, %.atomic.cont ]
1551 //CHECK: %[[VAL_5:.*]] = extractvalue { float, float } %[[VAL_4]], 0
1552 //CHECK: %[[VAL_6:.*]] = extractvalue { float, float } %[[VAL_4]], 1
1553 //CHECK: %[[VAL_7:.*]] = fadd contract float %[[VAL_5]], 1.000000e+00
1554 //CHECK: %[[VAL_8:.*]] = fadd contract float %[[VAL_6]], 1.000000e+00
1555 //CHECK: %[[VAL_9:.*]] = insertvalue { float, float } undef, float %[[VAL_7]], 0
1556 //CHECK: %[[VAL_10:.*]] = insertvalue { float, float } %[[VAL_9]], float %[[VAL_8]], 1
1557 //CHECK: store { float, float } %[[VAL_10]], ptr %[[X_NEW_VAL]], align 4
1558 //CHECK: %[[VAL_11:.*]] = call i1 @__atomic_compare_exchange(i64 8, ptr %[[ORIG_VAL]], ptr %[[ATOMIC_TEMP_LOAD]], ptr %[[X_NEW_VAL]], i32 2, i32 2)
1559 //CHECK: %[[VAL_12:.*]] = load { float, float }, ptr %[[ATOMIC_TEMP_LOAD]], align 4
1560 //CHECK: br i1 %[[VAL_11]], label %.atomic.exit, label %.atomic.cont
1561 //CHECK: .atomic.exit
1562 //CHECK: store { float, float } %[[VAL_10]], ptr %[[VAL_1]], align 4
1564 llvm.func @_QPomp_atomic_capture_complex() {
1565 %0 = llvm.mlir.constant(1 : i64) : i64
1566 %1 = llvm.alloca %0 x !llvm.struct<(f32, f32)> {bindc_name = "ib"} : (i64) -> !llvm.ptr
1567 %2 = llvm.mlir.constant(1 : i64) : i64
1568 %3 = llvm.alloca %2 x !llvm.struct<(f32, f32)> {bindc_name = "ia"} : (i64) -> !llvm.ptr
1569 %4 = llvm.mlir.constant(1.000000e+00 : f32) : f32
1570 %5 = llvm.mlir.constant(2.000000e+00 : f32) : f32
1571 %6 = llvm.mlir.undef : !llvm.struct<(f32, f32)>
1572 %7 = llvm.insertvalue %5, %6[0] : !llvm.struct<(f32, f32)>
1573 %8 = llvm.insertvalue %5, %7[1] : !llvm.struct<(f32, f32)>
1574 llvm.store %8, %3 : !llvm.struct<(f32, f32)>, !llvm.ptr
1575 %9 = llvm.mlir.undef : !llvm.struct<(f32, f32)>
1576 %10 = llvm.insertvalue %4, %9[0] : !llvm.struct<(f32, f32)>
1577 %11 = llvm.insertvalue %4, %10[1] : !llvm.struct<(f32, f32)>
1578 omp.atomic.capture {
1579 omp.atomic.update %3 : !llvm.ptr {
1580 ^bb0(%arg0: !llvm.struct<(f32, f32)>):
1581 %12 = llvm.extractvalue %arg0[0] : !llvm.struct<(f32, f32)>
1582 %13 = llvm.extractvalue %arg0[1] : !llvm.struct<(f32, f32)>
1583 %14 = llvm.extractvalue %11[0] : !llvm.struct<(f32, f32)>
1584 %15 = llvm.extractvalue %11[1] : !llvm.struct<(f32, f32)>
1585 %16 = llvm.fadd %12, %14 {fastmathFlags = #llvm.fastmath<contract>} : f32
1586 %17 = llvm.fadd %13, %15 {fastmathFlags = #llvm.fastmath<contract>} : f32
1587 %18 = llvm.mlir.undef : !llvm.struct<(f32, f32)>
1588 %19 = llvm.insertvalue %16, %18[0] : !llvm.struct<(f32, f32)>
1589 %20 = llvm.insertvalue %17, %19[1] : !llvm.struct<(f32, f32)>
1590 omp.yield(%20 : !llvm.struct<(f32, f32)>)
1592 omp.atomic.read %1 = %3 : !llvm.ptr, !llvm.ptr, !llvm.struct<(f32, f32)>
1599 // CHECK-LABEL: define void @omp_atomic_read_complex() {
1600 llvm.func @omp_atomic_read_complex(){
1602 // CHECK: %[[a:.*]] = alloca { float, float }, i64 1, align 8
1603 // CHECK: %[[b:.*]] = alloca { float, float }, i64 1, align 8
1604 // CHECK: %[[ATOMIC_TEMP_LOAD:.*]] = alloca { float, float }, align 8
1605 // CHECK: call void @__atomic_load(i64 8, ptr %[[b]], ptr %[[ATOMIC_TEMP_LOAD]], i32 0)
1606 // CHECK: %[[LOADED_VAL:.*]] = load { float, float }, ptr %[[ATOMIC_TEMP_LOAD]], align 8
1607 // CHECK: store { float, float } %[[LOADED_VAL]], ptr %[[a]], align 4
1611 %0 = llvm.mlir.constant(1 : i64) : i64
1612 %1 = llvm.alloca %0 x !llvm.struct<(f32, f32)> {bindc_name = "ib"} : (i64) -> !llvm.ptr
1613 %2 = llvm.mlir.constant(1 : i64) : i64
1614 %3 = llvm.alloca %2 x !llvm.struct<(f32, f32)> {bindc_name = "ia"} : (i64) -> !llvm.ptr
1615 omp.atomic.read %1 = %3 : !llvm.ptr, !llvm.ptr, !llvm.struct<(f32, f32)>
1621 // Checking an order-dependent operation when the order is `expr binop x`
1622 // CHECK-LABEL: @omp_atomic_update_ordering
1623 // CHECK-SAME: (ptr %[[x:.*]], i32 %[[expr:.*]])
1624 llvm.func @omp_atomic_update_ordering(%x:!llvm.ptr, %expr: i32) {
1625 // CHECK: %[[t1:.*]] = shl i32 %[[expr]], %[[x_old:[^ ,]*]]
1626 // CHECK: store i32 %[[t1]], ptr %[[x_new:.*]]
1627 // CHECK: %[[t2:.*]] = load i32, ptr %[[x_new]]
1628 // CHECK: cmpxchg ptr %[[x]], i32 %[[x_old]], i32 %[[t2]]
1629 omp.atomic.update %x : !llvm.ptr {
1631 %newval = llvm.shl %expr, %xval : i32
1632 omp.yield(%newval : i32)
1639 // Checking an order-dependent operation when the order is `x binop expr`
1640 // CHECK-LABEL: @omp_atomic_update_ordering
1641 // CHECK-SAME: (ptr %[[x:.*]], i32 %[[expr:.*]])
1642 llvm.func @omp_atomic_update_ordering(%x:!llvm.ptr, %expr: i32) {
1643 // CHECK: %[[t1:.*]] = shl i32 %[[x_old:.*]], %[[expr]]
1644 // CHECK: store i32 %[[t1]], ptr %[[x_new:.*]]
1645 // CHECK: %[[t2:.*]] = load i32, ptr %[[x_new]]
1646 // CHECK: cmpxchg ptr %[[x]], i32 %[[x_old]], i32 %[[t2]] monotonic
1647 omp.atomic.update %x : !llvm.ptr {
1649 %newval = llvm.shl %xval, %expr : i32
1650 omp.yield(%newval : i32)
1657 // Checking intrinsic translation.
1658 // CHECK-LABEL: @omp_atomic_update_intrinsic
1659 // CHECK-SAME: (ptr %[[x:.*]], i32 %[[expr:.*]])
1660 llvm.func @omp_atomic_update_intrinsic(%x:!llvm.ptr, %expr: i32) {
1661 // CHECK: %[[t1:.*]] = call i32 @llvm.smax.i32(i32 %[[x_old:.*]], i32 %[[expr]])
1662 // CHECK: store i32 %[[t1]], ptr %[[x_new:.*]]
1663 // CHECK: %[[t2:.*]] = load i32, ptr %[[x_new]]
1664 // CHECK: cmpxchg ptr %[[x]], i32 %[[x_old]], i32 %[[t2]]
1665 omp.atomic.update %x : !llvm.ptr {
1667 %newval = "llvm.intr.smax"(%xval, %expr) : (i32, i32) -> i32
1668 omp.yield(%newval : i32)
1670 // CHECK: %[[t1:.*]] = call i32 @llvm.umax.i32(i32 %[[x_old:.*]], i32 %[[expr]])
1671 // CHECK: store i32 %[[t1]], ptr %[[x_new:.*]]
1672 // CHECK: %[[t2:.*]] = load i32, ptr %[[x_new]]
1673 // CHECK: cmpxchg ptr %[[x]], i32 %[[x_old]], i32 %[[t2]]
1674 omp.atomic.update %x : !llvm.ptr {
1676 %newval = "llvm.intr.umax"(%xval, %expr) : (i32, i32) -> i32
1677 omp.yield(%newval : i32)
1684 // CHECK-LABEL: @atomic_update_cmpxchg
1685 // CHECK-SAME: (ptr %[[X:.*]], ptr %[[EXPR:.*]]) {
1686 // CHECK: %[[AT_LOAD_VAL:.*]] = load atomic i32, ptr %[[X]] monotonic, align 4
1687 // CHECK: %[[LOAD_VAL_PHI:.*]] = phi i32 [ %[[AT_LOAD_VAL]], %entry ], [ %[[LOAD_VAL:.*]], %.atomic.cont ]
1688 // CHECK: %[[VAL_SUCCESS:.*]] = cmpxchg ptr %[[X]], i32 %[[LOAD_VAL_PHI]], i32 %{{.*}} monotonic monotonic, align 4
1689 // CHECK: %[[LOAD_VAL]] = extractvalue { i32, i1 } %[[VAL_SUCCESS]], 0
1690 // CHECK: br i1 %{{.*}}, label %.atomic.exit, label %.atomic.cont
1692 llvm.func @atomic_update_cmpxchg(%arg0: !llvm.ptr, %arg1: !llvm.ptr) {
1693 %0 = llvm.load %arg1 : !llvm.ptr -> f32
1694 omp.atomic.update %arg0 : !llvm.ptr {
1696 %1 = llvm.sitofp %arg2 : i32 to f32
1697 %2 = llvm.fadd %1, %0 : f32
1698 %3 = llvm.fptosi %2 : f32 to i32
1706 // CHECK-LABEL: @omp_atomic_capture_prefix_update
1707 // CHECK-SAME: (ptr %[[x:.*]], ptr %[[v:.*]], i32 %[[expr:.*]], ptr %[[xf:.*]], ptr %[[vf:.*]], float %[[exprf:.*]])
1708 llvm.func @omp_atomic_capture_prefix_update(
1709 %x: !llvm.ptr, %v: !llvm.ptr, %expr: i32,
1710 %xf: !llvm.ptr, %vf: !llvm.ptr, %exprf: f32) -> () {
1711 // CHECK: %[[res:.*]] = atomicrmw add ptr %[[x]], i32 %[[expr]] monotonic
1712 // CHECK-NEXT: %[[newval:.*]] = add i32 %[[res]], %[[expr]]
1713 // CHECK: store i32 %[[newval]], ptr %[[v]]
1714 omp.atomic.capture {
1715 omp.atomic.update %x : !llvm.ptr {
1717 %newval = llvm.add %xval, %expr : i32
1718 omp.yield(%newval : i32)
1720 omp.atomic.read %v = %x : !llvm.ptr, !llvm.ptr, i32
1723 // CHECK: %[[res:.*]] = atomicrmw sub ptr %[[x]], i32 %[[expr]] monotonic
1724 // CHECK-NEXT: %[[newval:.*]] = sub i32 %[[res]], %[[expr]]
1725 // CHECK: store i32 %[[newval]], ptr %[[v]]
1726 omp.atomic.capture {
1727 omp.atomic.update %x : !llvm.ptr {
1729 %newval = llvm.sub %xval, %expr : i32
1730 omp.yield(%newval : i32)
1732 omp.atomic.read %v = %x : !llvm.ptr, !llvm.ptr, i32
1735 // CHECK: %[[res:.*]] = atomicrmw and ptr %[[x]], i32 %[[expr]] monotonic
1736 // CHECK-NEXT: %[[newval:.*]] = and i32 %[[res]], %[[expr]]
1737 // CHECK: store i32 %[[newval]], ptr %[[v]]
1738 omp.atomic.capture {
1739 omp.atomic.update %x : !llvm.ptr {
1741 %newval = llvm.and %xval, %expr : i32
1742 omp.yield(%newval : i32)
1744 omp.atomic.read %v = %x : !llvm.ptr, !llvm.ptr, i32
1747 // CHECK: %[[res:.*]] = atomicrmw or ptr %[[x]], i32 %[[expr]] monotonic
1748 // CHECK-NEXT: %[[newval:.*]] = or i32 %[[res]], %[[expr]]
1749 // CHECK: store i32 %[[newval]], ptr %[[v]]
1750 omp.atomic.capture {
1751 omp.atomic.update %x : !llvm.ptr {
1753 %newval = llvm.or %xval, %expr : i32
1754 omp.yield(%newval : i32)
1756 omp.atomic.read %v = %x : !llvm.ptr, !llvm.ptr, i32
1759 // CHECK: %[[res:.*]] = atomicrmw xor ptr %[[x]], i32 %[[expr]] monotonic
1760 // CHECK-NEXT: %[[newval:.*]] = xor i32 %[[res]], %[[expr]]
1761 // CHECK: store i32 %[[newval]], ptr %[[v]]
1762 omp.atomic.capture {
1763 omp.atomic.update %x : !llvm.ptr {
1765 %newval = llvm.xor %xval, %expr : i32
1766 omp.yield(%newval : i32)
1768 omp.atomic.read %v = %x : !llvm.ptr, !llvm.ptr, i32
1771 // CHECK: %[[xval:.*]] = phi i32
1772 // CHECK-NEXT: %[[newval:.*]] = mul i32 %[[xval]], %[[expr]]
1773 // CHECK-NEXT: store i32 %[[newval]], ptr %{{.*}}
1774 // CHECK-NEXT: %[[newval_:.*]] = load i32, ptr %{{.*}}
1775 // CHECK-NEXT: %{{.*}} = cmpxchg ptr %[[x]], i32 %[[xval]], i32 %[[newval_]] monotonic monotonic
1776 // CHECK: store i32 %[[newval]], ptr %[[v]]
1777 omp.atomic.capture {
1778 omp.atomic.update %x : !llvm.ptr {
1780 %newval = llvm.mul %xval, %expr : i32
1781 omp.yield(%newval : i32)
1783 omp.atomic.read %v = %x : !llvm.ptr, !llvm.ptr, i32
1786 // CHECK: %[[xval:.*]] = phi i32
1787 // CHECK-NEXT: %[[newval:.*]] = sdiv i32 %[[xval]], %[[expr]]
1788 // CHECK-NEXT: store i32 %[[newval]], ptr %{{.*}}
1789 // CHECK-NEXT: %[[newval_:.*]] = load i32, ptr %{{.*}}
1790 // CHECK-NEXT: %{{.*}} = cmpxchg ptr %[[x]], i32 %[[xval]], i32 %[[newval_]] monotonic monotonic
1791 // CHECK: store i32 %[[newval]], ptr %[[v]]
1792 omp.atomic.capture {
1793 omp.atomic.update %x : !llvm.ptr {
1795 %newval = llvm.sdiv %xval, %expr : i32
1796 omp.yield(%newval : i32)
1798 omp.atomic.read %v = %x : !llvm.ptr, !llvm.ptr, i32
1801 // CHECK: %[[xval:.*]] = phi i32
1802 // CHECK-NEXT: %[[newval:.*]] = udiv i32 %[[xval]], %[[expr]]
1803 // CHECK-NEXT: store i32 %[[newval]], ptr %{{.*}}
1804 // CHECK-NEXT: %[[newval_:.*]] = load i32, ptr %{{.*}}
1805 // CHECK-NEXT: %{{.*}} = cmpxchg ptr %[[x]], i32 %[[xval]], i32 %[[newval_]] monotonic monotonic
1806 // CHECK: store i32 %[[newval]], ptr %[[v]]
1807 omp.atomic.capture {
1808 omp.atomic.update %x : !llvm.ptr {
1810 %newval = llvm.udiv %xval, %expr : i32
1811 omp.yield(%newval : i32)
1813 omp.atomic.read %v = %x : !llvm.ptr, !llvm.ptr, i32
1816 // CHECK: %[[xval:.*]] = phi i32
1817 // CHECK-NEXT: %[[newval:.*]] = shl i32 %[[xval]], %[[expr]]
1818 // CHECK-NEXT: store i32 %[[newval]], ptr %{{.*}}
1819 // CHECK-NEXT: %[[newval_:.*]] = load i32, ptr %{{.*}}
1820 // CHECK-NEXT: %{{.*}} = cmpxchg ptr %[[x]], i32 %[[xval]], i32 %[[newval_]] monotonic monotonic
1821 // CHECK: store i32 %[[newval]], ptr %[[v]]
1822 omp.atomic.capture {
1823 omp.atomic.update %x : !llvm.ptr {
1825 %newval = llvm.shl %xval, %expr : i32
1826 omp.yield(%newval : i32)
1828 omp.atomic.read %v = %x : !llvm.ptr, !llvm.ptr, i32
1831 // CHECK: %[[xval:.*]] = phi i32
1832 // CHECK-NEXT: %[[newval:.*]] = lshr i32 %[[xval]], %[[expr]]
1833 // CHECK-NEXT: store i32 %[[newval]], ptr %{{.*}}
1834 // CHECK-NEXT: %[[newval_:.*]] = load i32, ptr %{{.*}}
1835 // CHECK-NEXT: %{{.*}} = cmpxchg ptr %[[x]], i32 %[[xval]], i32 %[[newval_]] monotonic monotonic
1836 // CHECK: store i32 %[[newval]], ptr %[[v]]
1837 omp.atomic.capture {
1838 omp.atomic.update %x : !llvm.ptr {
1840 %newval = llvm.lshr %xval, %expr : i32
1841 omp.yield(%newval : i32)
1843 omp.atomic.read %v = %x : !llvm.ptr, !llvm.ptr, i32
1846 // CHECK: %[[xval:.*]] = phi i32
1847 // CHECK-NEXT: %[[newval:.*]] = ashr i32 %[[xval]], %[[expr]]
1848 // CHECK-NEXT: store i32 %[[newval]], ptr %{{.*}}
1849 // CHECK-NEXT: %[[newval_:.*]] = load i32, ptr %{{.*}}
1850 // CHECK-NEXT: %{{.*}} = cmpxchg ptr %[[x]], i32 %[[xval]], i32 %[[newval_]] monotonic monotonic
1851 // CHECK: store i32 %[[newval]], ptr %[[v]]
1852 omp.atomic.capture {
1853 omp.atomic.update %x : !llvm.ptr {
1855 %newval = llvm.ashr %xval, %expr : i32
1856 omp.yield(%newval : i32)
1858 omp.atomic.read %v = %x : !llvm.ptr, !llvm.ptr, i32
1861 // CHECK: %[[xval:.*]] = phi i32
1862 // CHECK-NEXT: %[[newval:.*]] = call i32 @llvm.smax.i32(i32 %[[xval]], i32 %[[expr]])
1863 // CHECK-NEXT: store i32 %[[newval]], ptr %{{.*}}
1864 // CHECK-NEXT: %[[newval_:.*]] = load i32, ptr %{{.*}}
1865 // CHECK-NEXT: %{{.*}} = cmpxchg ptr %[[x]], i32 %[[xval]], i32 %[[newval_]] monotonic monotonic
1866 // CHECK: store i32 %[[newval]], ptr %[[v]]
1867 omp.atomic.capture {
1868 omp.atomic.update %x : !llvm.ptr {
1870 %newval = "llvm.intr.smax"(%xval, %expr) : (i32, i32) -> i32
1871 omp.yield(%newval : i32)
1873 omp.atomic.read %v = %x : !llvm.ptr, !llvm.ptr, i32
1876 // CHECK: %[[xval:.*]] = phi i32
1877 // CHECK-NEXT: %[[newval:.*]] = call i32 @llvm.smin.i32(i32 %[[xval]], i32 %[[expr]])
1878 // CHECK-NEXT: store i32 %[[newval]], ptr %{{.*}}
1879 // CHECK-NEXT: %[[newval_:.*]] = load i32, ptr %{{.*}}
1880 // CHECK-NEXT: %{{.*}} = cmpxchg ptr %[[x]], i32 %[[xval]], i32 %[[newval_]] monotonic monotonic
1881 // CHECK: store i32 %[[newval]], ptr %[[v]]
1882 omp.atomic.capture {
1883 omp.atomic.update %x : !llvm.ptr {
1885 %newval = "llvm.intr.smin"(%xval, %expr) : (i32, i32) -> i32
1886 omp.yield(%newval : i32)
1888 omp.atomic.read %v = %x : !llvm.ptr, !llvm.ptr, i32
1891 // CHECK: %[[xval:.*]] = phi i32
1892 // CHECK-NEXT: %[[newval:.*]] = call i32 @llvm.umax.i32(i32 %[[xval]], i32 %[[expr]])
1893 // CHECK-NEXT: store i32 %[[newval]], ptr %{{.*}}
1894 // CHECK-NEXT: %[[newval_:.*]] = load i32, ptr %{{.*}}
1895 // CHECK-NEXT: %{{.*}} = cmpxchg ptr %[[x]], i32 %[[xval]], i32 %[[newval_]] monotonic monotonic
1896 // CHECK: store i32 %[[newval]], ptr %[[v]]
1897 omp.atomic.capture {
1898 omp.atomic.update %x : !llvm.ptr {
1900 %newval = "llvm.intr.umax"(%xval, %expr) : (i32, i32) -> i32
1901 omp.yield(%newval : i32)
1903 omp.atomic.read %v = %x : !llvm.ptr, !llvm.ptr, i32
1906 // CHECK: %[[xval:.*]] = phi i32
1907 // CHECK-NEXT: %[[newval:.*]] = call i32 @llvm.umin.i32(i32 %[[xval]], i32 %[[expr]])
1908 // CHECK-NEXT: store i32 %[[newval]], ptr %{{.*}}
1909 // CHECK-NEXT: %[[newval_:.*]] = load i32, ptr %{{.*}}
1910 // CHECK-NEXT: %{{.*}} = cmpxchg ptr %[[x]], i32 %[[xval]], i32 %[[newval_]] monotonic monotonic
1911 // CHECK: store i32 %[[newval]], ptr %[[v]]
1912 omp.atomic.capture {
1913 omp.atomic.update %x : !llvm.ptr {
1915 %newval = "llvm.intr.umin"(%xval, %expr) : (i32, i32) -> i32
1916 omp.yield(%newval : i32)
1918 omp.atomic.read %v = %x : !llvm.ptr, !llvm.ptr, i32
1921 // CHECK: %[[xval:.*]] = phi i32
1922 // CHECK: %[[newval:.*]] = fadd float %{{.*}}, %[[exprf]]
1923 // CHECK: store float %[[newval]], ptr %{{.*}}
1924 // CHECK: %[[newval_:.*]] = load i32, ptr %{{.*}}
1925 // CHECK: %{{.*}} = cmpxchg ptr %[[xf]], i32 %[[xval]], i32 %[[newval_]] monotonic monotonic
1926 // CHECK: store float %[[newval]], ptr %[[vf]]
1927 omp.atomic.capture {
1928 omp.atomic.update %xf : !llvm.ptr {
1930 %newval = llvm.fadd %xval, %exprf : f32
1931 omp.yield(%newval : f32)
1933 omp.atomic.read %vf = %xf : !llvm.ptr, !llvm.ptr, f32
1936 // CHECK: %[[xval:.*]] = phi i32
1937 // CHECK: %[[newval:.*]] = fsub float %{{.*}}, %[[exprf]]
1938 // CHECK: store float %[[newval]], ptr %{{.*}}
1939 // CHECK: %[[newval_:.*]] = load i32, ptr %{{.*}}
1940 // CHECK: %{{.*}} = cmpxchg ptr %[[xf]], i32 %[[xval]], i32 %[[newval_]] monotonic monotonic
1941 // CHECK: store float %[[newval]], ptr %[[vf]]
1942 omp.atomic.capture {
1943 omp.atomic.update %xf : !llvm.ptr {
1945 %newval = llvm.fsub %xval, %exprf : f32
1946 omp.yield(%newval : f32)
1948 omp.atomic.read %vf = %xf : !llvm.ptr, !llvm.ptr, f32
1956 // CHECK-LABEL: @omp_atomic_capture_postfix_update
1957 // CHECK-SAME: (ptr %[[x:.*]], ptr %[[v:.*]], i32 %[[expr:.*]], ptr %[[xf:.*]], ptr %[[vf:.*]], float %[[exprf:.*]])
1958 llvm.func @omp_atomic_capture_postfix_update(
1959 %x: !llvm.ptr, %v: !llvm.ptr, %expr: i32,
1960 %xf: !llvm.ptr, %vf: !llvm.ptr, %exprf: f32) -> () {
1961 // CHECK: %[[res:.*]] = atomicrmw add ptr %[[x]], i32 %[[expr]] monotonic
1962 // CHECK: store i32 %[[res]], ptr %[[v]]
1963 omp.atomic.capture {
1964 omp.atomic.read %v = %x : !llvm.ptr, !llvm.ptr, i32
1965 omp.atomic.update %x : !llvm.ptr {
1967 %newval = llvm.add %xval, %expr : i32
1968 omp.yield(%newval : i32)
1972 // CHECK: %[[res:.*]] = atomicrmw sub ptr %[[x]], i32 %[[expr]] monotonic
1973 // CHECK: store i32 %[[res]], ptr %[[v]]
1974 omp.atomic.capture {
1975 omp.atomic.read %v = %x : !llvm.ptr, !llvm.ptr, i32
1976 omp.atomic.update %x : !llvm.ptr {
1978 %newval = llvm.sub %xval, %expr : i32
1979 omp.yield(%newval : i32)
1983 // CHECK: %[[res:.*]] = atomicrmw and ptr %[[x]], i32 %[[expr]] monotonic
1984 // CHECK: store i32 %[[res]], ptr %[[v]]
1985 omp.atomic.capture {
1986 omp.atomic.read %v = %x : !llvm.ptr, !llvm.ptr, i32
1987 omp.atomic.update %x : !llvm.ptr {
1989 %newval = llvm.and %xval, %expr : i32
1990 omp.yield(%newval : i32)
1994 // CHECK: %[[res:.*]] = atomicrmw or ptr %[[x]], i32 %[[expr]] monotonic
1995 // CHECK: store i32 %[[res]], ptr %[[v]]
1996 omp.atomic.capture {
1997 omp.atomic.read %v = %x : !llvm.ptr, !llvm.ptr, i32
1998 omp.atomic.update %x : !llvm.ptr {
2000 %newval = llvm.or %xval, %expr : i32
2001 omp.yield(%newval : i32)
2005 // CHECK: %[[res:.*]] = atomicrmw xor ptr %[[x]], i32 %[[expr]] monotonic
2006 // CHECK: store i32 %[[res]], ptr %[[v]]
2007 omp.atomic.capture {
2008 omp.atomic.read %v = %x : !llvm.ptr, !llvm.ptr, i32
2009 omp.atomic.update %x : !llvm.ptr {
2011 %newval = llvm.xor %xval, %expr : i32
2012 omp.yield(%newval : i32)
2016 // CHECK: %[[xval:.*]] = phi i32
2017 // CHECK-NEXT: %[[newval:.*]] = mul i32 %[[xval]], %[[expr]]
2018 // CHECK-NEXT: store i32 %[[newval]], ptr %{{.*}}
2019 // CHECK-NEXT: %[[newval_:.*]] = load i32, ptr %{{.*}}
2020 // CHECK-NEXT: %{{.*}} = cmpxchg ptr %[[x]], i32 %[[xval]], i32 %[[newval_]] monotonic monotonic
2021 // CHECK: store i32 %[[xval]], ptr %[[v]]
2022 omp.atomic.capture {
2023 omp.atomic.read %v = %x : !llvm.ptr, !llvm.ptr, i32
2024 omp.atomic.update %x : !llvm.ptr {
2026 %newval = llvm.mul %xval, %expr : i32
2027 omp.yield(%newval : i32)
2031 // CHECK: %[[xval:.*]] = phi i32
2032 // CHECK-NEXT: %[[newval:.*]] = sdiv i32 %[[xval]], %[[expr]]
2033 // CHECK-NEXT: store i32 %[[newval]], ptr %{{.*}}
2034 // CHECK-NEXT: %[[newval_:.*]] = load i32, ptr %{{.*}}
2035 // CHECK-NEXT: %{{.*}} = cmpxchg ptr %[[x]], i32 %[[xval]], i32 %[[newval_]] monotonic monotonic
2036 // CHECK: store i32 %[[xval]], ptr %[[v]]
2037 omp.atomic.capture {
2038 omp.atomic.read %v = %x : !llvm.ptr, !llvm.ptr, i32
2039 omp.atomic.update %x : !llvm.ptr {
2041 %newval = llvm.sdiv %xval, %expr : i32
2042 omp.yield(%newval : i32)
2046 // CHECK: %[[xval:.*]] = phi i32
2047 // CHECK-NEXT: %[[newval:.*]] = udiv i32 %[[xval]], %[[expr]]
2048 // CHECK-NEXT: store i32 %[[newval]], ptr %{{.*}}
2049 // CHECK-NEXT: %[[newval_:.*]] = load i32, ptr %{{.*}}
2050 // CHECK-NEXT: %{{.*}} = cmpxchg ptr %[[x]], i32 %[[xval]], i32 %[[newval_]] monotonic monotonic
2051 // CHECK: store i32 %[[xval]], ptr %[[v]]
2052 omp.atomic.capture {
2053 omp.atomic.read %v = %x : !llvm.ptr, !llvm.ptr, i32
2054 omp.atomic.update %x : !llvm.ptr {
2056 %newval = llvm.udiv %xval, %expr : i32
2057 omp.yield(%newval : i32)
2061 // CHECK: %[[xval:.*]] = phi i32
2062 // CHECK-NEXT: %[[newval:.*]] = shl i32 %[[xval]], %[[expr]]
2063 // CHECK-NEXT: store i32 %[[newval]], ptr %{{.*}}
2064 // CHECK-NEXT: %[[newval_:.*]] = load i32, ptr %{{.*}}
2065 // CHECK-NEXT: %{{.*}} = cmpxchg ptr %[[x]], i32 %[[xval]], i32 %[[newval_]] monotonic monotonic
2066 // CHECK: store i32 %[[xval]], ptr %[[v]]
2067 omp.atomic.capture {
2068 omp.atomic.read %v = %x : !llvm.ptr, !llvm.ptr, i32
2069 omp.atomic.update %x : !llvm.ptr {
2071 %newval = llvm.shl %xval, %expr : i32
2072 omp.yield(%newval : i32)
2076 // CHECK: %[[xval:.*]] = phi i32
2077 // CHECK-NEXT: %[[newval:.*]] = lshr i32 %[[xval]], %[[expr]]
2078 // CHECK-NEXT: store i32 %[[newval]], ptr %{{.*}}
2079 // CHECK-NEXT: %[[newval_:.*]] = load i32, ptr %{{.*}}
2080 // CHECK-NEXT: %{{.*}} = cmpxchg ptr %[[x]], i32 %[[xval]], i32 %[[newval_]] monotonic monotonic
2081 // CHECK: store i32 %[[xval]], ptr %[[v]]
2082 omp.atomic.capture {
2083 omp.atomic.read %v = %x : !llvm.ptr, !llvm.ptr, i32
2084 omp.atomic.update %x : !llvm.ptr {
2086 %newval = llvm.lshr %xval, %expr : i32
2087 omp.yield(%newval : i32)
2091 // CHECK: %[[xval:.*]] = phi i32
2092 // CHECK-NEXT: %[[newval:.*]] = ashr i32 %[[xval]], %[[expr]]
2093 // CHECK-NEXT: store i32 %[[newval]], ptr %{{.*}}
2094 // CHECK-NEXT: %[[newval_:.*]] = load i32, ptr %{{.*}}
2095 // CHECK-NEXT: %{{.*}} = cmpxchg ptr %[[x]], i32 %[[xval]], i32 %[[newval_]] monotonic monotonic
2096 // CHECK: store i32 %[[xval]], ptr %[[v]]
2097 omp.atomic.capture {
2098 omp.atomic.read %v = %x : !llvm.ptr, !llvm.ptr, i32
2099 omp.atomic.update %x : !llvm.ptr {
2101 %newval = llvm.ashr %xval, %expr : i32
2102 omp.yield(%newval : i32)
2106 // CHECK: %[[xval:.*]] = phi i32
2107 // CHECK-NEXT: %[[newval:.*]] = call i32 @llvm.smax.i32(i32 %[[xval]], i32 %[[expr]])
2108 // CHECK-NEXT: store i32 %[[newval]], ptr %{{.*}}
2109 // CHECK-NEXT: %[[newval_:.*]] = load i32, ptr %{{.*}}
2110 // CHECK-NEXT: %{{.*}} = cmpxchg ptr %[[x]], i32 %[[xval]], i32 %[[newval_]] monotonic monotonic
2111 // CHECK: store i32 %[[xval]], ptr %[[v]]
2112 omp.atomic.capture {
2113 omp.atomic.read %v = %x : !llvm.ptr, !llvm.ptr, i32
2114 omp.atomic.update %x : !llvm.ptr {
2116 %newval = "llvm.intr.smax"(%xval, %expr) : (i32, i32) -> i32
2117 omp.yield(%newval : i32)
2121 // CHECK: %[[xval:.*]] = phi i32
2122 // CHECK-NEXT: %[[newval:.*]] = call i32 @llvm.smin.i32(i32 %[[xval]], i32 %[[expr]])
2123 // CHECK-NEXT: store i32 %[[newval]], ptr %{{.*}}
2124 // CHECK-NEXT: %[[newval_:.*]] = load i32, ptr %{{.*}}
2125 // CHECK-NEXT: %{{.*}} = cmpxchg ptr %[[x]], i32 %[[xval]], i32 %[[newval_]] monotonic monotonic
2126 // CHECK: store i32 %[[xval]], ptr %[[v]]
2127 omp.atomic.capture {
2128 omp.atomic.read %v = %x : !llvm.ptr, !llvm.ptr, i32
2129 omp.atomic.update %x : !llvm.ptr {
2131 %newval = "llvm.intr.smin"(%xval, %expr) : (i32, i32) -> i32
2132 omp.yield(%newval : i32)
2136 // CHECK: %[[xval:.*]] = phi i32
2137 // CHECK-NEXT: %[[newval:.*]] = call i32 @llvm.umax.i32(i32 %[[xval]], i32 %[[expr]])
2138 // CHECK-NEXT: store i32 %[[newval]], ptr %{{.*}}
2139 // CHECK-NEXT: %[[newval_:.*]] = load i32, ptr %{{.*}}
2140 // CHECK-NEXT: %{{.*}} = cmpxchg ptr %[[x]], i32 %[[xval]], i32 %[[newval_]] monotonic monotonic
2141 // CHECK: store i32 %[[xval]], ptr %[[v]]
2142 omp.atomic.capture {
2143 omp.atomic.read %v = %x : !llvm.ptr, !llvm.ptr, i32
2144 omp.atomic.update %x : !llvm.ptr {
2146 %newval = "llvm.intr.umax"(%xval, %expr) : (i32, i32) -> i32
2147 omp.yield(%newval : i32)
2151 // CHECK: %[[xval:.*]] = phi i32
2152 // CHECK-NEXT: %[[newval:.*]] = call i32 @llvm.umin.i32(i32 %[[xval]], i32 %[[expr]])
2153 // CHECK-NEXT: store i32 %[[newval]], ptr %{{.*}}
2154 // CHECK-NEXT: %[[newval_:.*]] = load i32, ptr %{{.*}}
2155 // CHECK-NEXT: %{{.*}} = cmpxchg ptr %[[x]], i32 %[[xval]], i32 %[[newval_]] monotonic monotonic
2156 // CHECK: store i32 %[[xval]], ptr %[[v]]
2157 omp.atomic.capture {
2158 omp.atomic.read %v = %x : !llvm.ptr, !llvm.ptr, i32
2159 omp.atomic.update %x : !llvm.ptr {
2161 %newval = "llvm.intr.umin"(%xval, %expr) : (i32, i32) -> i32
2162 omp.yield(%newval : i32)
2166 // CHECK: %[[xval:.*]] = phi i32
2167 // CHECK: %[[xvalf:.*]] = bitcast i32 %[[xval]] to float
2168 // CHECK: %[[newval:.*]] = fadd float %{{.*}}, %[[exprf]]
2169 // CHECK: store float %[[newval]], ptr %{{.*}}
2170 // CHECK: %[[newval_:.*]] = load i32, ptr %{{.*}}
2171 // CHECK: %{{.*}} = cmpxchg ptr %[[xf]], i32 %[[xval]], i32 %[[newval_]] monotonic monotonic
2172 // CHECK: store float %[[xvalf]], ptr %[[vf]]
2173 omp.atomic.capture {
2174 omp.atomic.read %vf = %xf : !llvm.ptr, !llvm.ptr, f32
2175 omp.atomic.update %xf : !llvm.ptr {
2177 %newval = llvm.fadd %xval, %exprf : f32
2178 omp.yield(%newval : f32)
2182 // CHECK: %[[xval:.*]] = phi i32
2183 // CHECK: %[[xvalf:.*]] = bitcast i32 %[[xval]] to float
2184 // CHECK: %[[newval:.*]] = fsub float %{{.*}}, %[[exprf]]
2185 // CHECK: store float %[[newval]], ptr %{{.*}}
2186 // CHECK: %[[newval_:.*]] = load i32, ptr %{{.*}}
2187 // CHECK: %{{.*}} = cmpxchg ptr %[[xf]], i32 %[[xval]], i32 %[[newval_]] monotonic monotonic
2188 // CHECK: store float %[[xvalf]], ptr %[[vf]]
2189 omp.atomic.capture {
2190 omp.atomic.read %vf = %xf : !llvm.ptr, !llvm.ptr, f32
2191 omp.atomic.update %xf : !llvm.ptr {
2193 %newval = llvm.fsub %xval, %exprf : f32
2194 omp.yield(%newval : f32)
2202 // CHECK-LABEL: @omp_atomic_capture_misc
2203 // CHECK-SAME: (ptr %[[x:.*]], ptr %[[v:.*]], i32 %[[expr:.*]], ptr %[[xf:.*]], ptr %[[vf:.*]], float %[[exprf:.*]])
2204 llvm.func @omp_atomic_capture_misc(
2205 %x: !llvm.ptr, %v: !llvm.ptr, %expr: i32,
2206 %xf: !llvm.ptr, %vf: !llvm.ptr, %exprf: f32) -> () {
2207 // CHECK: %[[xval:.*]] = atomicrmw xchg ptr %[[x]], i32 %[[expr]] monotonic
2208 // CHECK: store i32 %[[xval]], ptr %[[v]]
2210 omp.atomic.read %v = %x : !llvm.ptr, !llvm.ptr, i32
2211 omp.atomic.write %x = %expr : !llvm.ptr, i32
2214 // CHECK: %[[xval:.*]] = phi i32
2215 // CHECK: %[[xvalf:.*]] = bitcast i32 %[[xval]] to float
2216 // CHECK: store float %[[exprf]], ptr %{{.*}}
2217 // CHECK: %[[newval_:.*]] = load i32, ptr %{{.*}}
2218 // CHECK: %{{.*}} = cmpxchg ptr %[[xf]], i32 %[[xval]], i32 %[[newval_]] monotonic monotonic
2219 // CHECK: store float %[[xvalf]], ptr %[[vf]]
2221 omp.atomic.read %vf = %xf : !llvm.ptr, !llvm.ptr, f32
2222 omp.atomic.write %xf = %exprf : !llvm.ptr, f32
2225 // CHECK: %[[res:.*]] = atomicrmw add ptr %[[x]], i32 %[[expr]] seq_cst
2226 // CHECK: store i32 %[[res]], ptr %[[v]]
2227 omp.atomic.capture memory_order(seq_cst) {
2228 omp.atomic.read %v = %x : !llvm.ptr, !llvm.ptr, i32
2229 omp.atomic.update %x : !llvm.ptr {
2231 %newval = llvm.add %xval, %expr : i32
2232 omp.yield(%newval : i32)
2236 // CHECK: %[[res:.*]] = atomicrmw add ptr %[[x]], i32 %[[expr]] acquire
2237 // CHECK: store i32 %[[res]], ptr %[[v]]
2238 omp.atomic.capture memory_order(acquire) {
2239 omp.atomic.read %v = %x : !llvm.ptr, !llvm.ptr, i32
2240 omp.atomic.update %x : !llvm.ptr {
2242 %newval = llvm.add %xval, %expr : i32
2243 omp.yield(%newval : i32)
2247 // CHECK: %[[res:.*]] = atomicrmw add ptr %[[x]], i32 %[[expr]] release
2248 // CHECK: store i32 %[[res]], ptr %[[v]]
2249 omp.atomic.capture memory_order(release) {
2250 omp.atomic.read %v = %x : !llvm.ptr, !llvm.ptr, i32
2251 omp.atomic.update %x : !llvm.ptr {
2253 %newval = llvm.add %xval, %expr : i32
2254 omp.yield(%newval : i32)
2258 // CHECK: %[[res:.*]] = atomicrmw add ptr %[[x]], i32 %[[expr]] monotonic
2259 // CHECK: store i32 %[[res]], ptr %[[v]]
2260 omp.atomic.capture memory_order(relaxed) {
2261 omp.atomic.read %v = %x : !llvm.ptr, !llvm.ptr, i32
2262 omp.atomic.update %x : !llvm.ptr {
2264 %newval = llvm.add %xval, %expr : i32
2265 omp.yield(%newval : i32)
2269 // CHECK: %[[res:.*]] = atomicrmw add ptr %[[x]], i32 %[[expr]] acq_rel
2270 // CHECK: store i32 %[[res]], ptr %[[v]]
2271 omp.atomic.capture memory_order(acq_rel) {
2272 omp.atomic.read %v = %x : !llvm.ptr, !llvm.ptr, i32
2273 omp.atomic.update %x : !llvm.ptr {
2275 %newval = llvm.add %xval, %expr : i32
2276 omp.yield(%newval : i32)
2285 // CHECK-LABEL: @omp_sections_empty
2286 llvm.func @omp_sections_empty() -> () {
2290 // CHECK-NEXT: br label %entry
2292 // CHECK-NEXT: ret void
2298 // Check IR generation for simple empty sections. This only checks the overall
2299 // shape of the IR, detailed checking is done by the OpenMPIRBuilder.
2301 // CHECK-LABEL: @omp_sections_trivial
2302 llvm.func @omp_sections_trivial() -> () {
2303 // CHECK: br label %[[ENTRY:[a-zA-Z_.]+]]
2305 // CHECK: [[ENTRY]]:
2306 // CHECK: br label %[[PREHEADER:.*]]
2308 // CHECK: [[PREHEADER]]:
2309 // CHECK: %{{.*}} = call i32 @__kmpc_global_thread_num({{.*}})
2310 // CHECK: call void @__kmpc_for_static_init_4u({{.*}})
2311 // CHECK: br label %[[HEADER:.*]]
2313 // CHECK: [[HEADER]]:
2314 // CHECK: br label %[[COND:.*]]
2317 // CHECK: br i1 %{{.*}}, label %[[BODY:.*]], label %[[EXIT:.*]]
2319 // CHECK: switch i32 %{{.*}}, label %[[INC:.*]] [
2320 // CHECK-NEXT: i32 0, label %[[SECTION1:.*]]
2321 // CHECK-NEXT: i32 1, label %[[SECTION2:.*]]
2326 // CHECK: [[SECTION1]]:
2327 // CHECK-NEXT: br label %[[SECTION1_REGION1:[^ ,]*]]
2329 // CHECK-NEXT: [[SECTION1_REGION1]]:
2330 // CHECK-NEXT: br label %[[SECTION1_REGION2:[^ ,]*]]
2332 // CHECK-NEXT: [[SECTION1_REGION2]]:
2333 // CHECK-NEXT: br label %[[INC]]
2337 // CHECK: [[SECTION2]]:
2338 // CHECK: br label %[[INC]]
2345 // CHECK: %{{.*}} = add {{.*}}, 1
2346 // CHECK: br label %[[HEADER]]
2349 // CHECK: call void @__kmpc_for_static_fini({{.*}})
2350 // CHECK: call void @__kmpc_barrier({{.*}})
2351 // CHECK: br label %[[AFTER:.*]]
2353 // CHECK: [[AFTER]]:
2360 // CHECK: declare void @foo()
2363 // CHECK: declare void @bar(i32)
2364 llvm.func @bar(%arg0 : i32)
2366 // CHECK-LABEL: @omp_sections
2367 llvm.func @omp_sections(%arg0 : i32, %arg1 : i32, %arg2 : !llvm.ptr) -> () {
2369 // CHECK: switch i32 %{{.*}}, label %{{.*}} [
2370 // CHECK-NEXT: i32 0, label %[[SECTION1:.*]]
2371 // CHECK-NEXT: i32 1, label %[[SECTION2:.*]]
2372 // CHECK-NEXT: i32 2, label %[[SECTION3:.*]]
2376 // CHECK: [[SECTION1]]:
2377 // CHECK: br label %[[REGION1:[^ ,]*]]
2378 // CHECK: [[REGION1]]:
2379 // CHECK: call void @foo()
2380 // CHECK: br label %{{.*}}
2381 llvm.call @foo() : () -> ()
2385 // CHECK: [[SECTION2]]:
2386 // CHECK: br label %[[REGION2:[^ ,]*]]
2387 // CHECK: [[REGION2]]:
2388 // CHECK: call void @bar(i32 %{{.*}})
2389 // CHECK: br label %{{.*}}
2390 llvm.call @bar(%arg0) : (i32) -> ()
2394 // CHECK: [[SECTION3]]:
2395 // CHECK: br label %[[REGION3:[^ ,]*]]
2396 // CHECK: [[REGION3]]:
2397 // CHECK: %11 = add i32 %{{.*}}, %{{.*}}
2398 %add = llvm.add %arg0, %arg1 : i32
2399 // CHECK: store i32 %{{.*}}, ptr %{{.*}}, align 4
2400 // CHECK: br label %{{.*}}
2401 llvm.store %add, %arg2 : i32, !llvm.ptr
2413 // CHECK-LABEL: @omp_sections_with_clauses
2414 llvm.func @omp_sections_with_clauses() -> () {
2415 // CHECK-NOT: call void @__kmpc_barrier
2416 omp.sections nowait {
2418 llvm.call @foo() : () -> ()
2422 llvm.call @foo() : () -> ()
2432 // Check that translation doesn't crash in presence of repeated successor
2433 // blocks with different arguments within OpenMP operations: LLVM cannot
2434 // represent this and a dummy block will be introduced for forwarding. The
2435 // introduction mechanism itself is tested elsewhere.
2436 // CHECK-LABEL: @repeated_successor
2437 llvm.func @repeated_successor(%arg0: i64, %arg1: i64, %arg2: i64, %arg3: i1) {
2439 omp.loop_nest (%arg4) : i64 = (%arg0) to (%arg1) step (%arg2) {
2440 llvm.cond_br %arg3, ^bb1(%arg0 : i64), ^bb1(%arg1 : i64)
2441 ^bb1(%0: i64): // 2 preds: ^bb0, ^bb0
2450 // CHECK-LABEL: @single
2451 // CHECK-SAME: (i32 %[[x:.*]], i32 %[[y:.*]], ptr %[[zaddr:.*]])
2452 llvm.func @single(%x: i32, %y: i32, %zaddr: !llvm.ptr) {
2453 // CHECK: %[[a:.*]] = sub i32 %[[x]], %[[y]]
2454 %a = llvm.sub %x, %y : i32
2455 // CHECK: store i32 %[[a]], ptr %[[zaddr]]
2456 llvm.store %a, %zaddr : i32, !llvm.ptr
2457 // CHECK: call i32 @__kmpc_single
2459 // CHECK: %[[z:.*]] = add i32 %[[x]], %[[y]]
2460 %z = llvm.add %x, %y : i32
2461 // CHECK: store i32 %[[z]], ptr %[[zaddr]]
2462 llvm.store %z, %zaddr : i32, !llvm.ptr
2463 // CHECK: call void @__kmpc_end_single
2464 // CHECK: call void @__kmpc_barrier
2467 // CHECK: %[[b:.*]] = mul i32 %[[x]], %[[y]]
2468 %b = llvm.mul %x, %y : i32
2469 // CHECK: store i32 %[[b]], ptr %[[zaddr]]
2470 llvm.store %b, %zaddr : i32, !llvm.ptr
2477 // CHECK-LABEL: @single_nowait
2478 // CHECK-SAME: (i32 %[[x:.*]], i32 %[[y:.*]], ptr %[[zaddr:.*]])
2479 llvm.func @single_nowait(%x: i32, %y: i32, %zaddr: !llvm.ptr) {
2480 // CHECK: %[[a:.*]] = sub i32 %[[x]], %[[y]]
2481 %a = llvm.sub %x, %y : i32
2482 // CHECK: store i32 %[[a]], ptr %[[zaddr]]
2483 llvm.store %a, %zaddr : i32, !llvm.ptr
2484 // CHECK: call i32 @__kmpc_single
2486 // CHECK: %[[z:.*]] = add i32 %[[x]], %[[y]]
2487 %z = llvm.add %x, %y : i32
2488 // CHECK: store i32 %[[z]], ptr %[[zaddr]]
2489 llvm.store %z, %zaddr : i32, !llvm.ptr
2490 // CHECK: call void @__kmpc_end_single
2491 // CHECK-NOT: call void @__kmpc_barrier
2494 // CHECK: %[[t:.*]] = mul i32 %[[x]], %[[y]]
2495 %t = llvm.mul %x, %y : i32
2496 // CHECK: store i32 %[[t]], ptr %[[zaddr]]
2497 llvm.store %t, %zaddr : i32, !llvm.ptr
2504 llvm.func @copy_i32(!llvm.ptr, !llvm.ptr)
2505 llvm.func @copy_f32(!llvm.ptr, !llvm.ptr)
2507 // CHECK-LABEL: @single_copyprivate
2508 // CHECK-SAME: (ptr %[[ip:.*]], ptr %[[fp:.*]])
2509 llvm.func @single_copyprivate(%ip: !llvm.ptr, %fp: !llvm.ptr) {
2510 // CHECK: %[[didit_addr:.*]] = alloca i32
2511 // CHECK: store i32 0, ptr %[[didit_addr]]
2512 // CHECK: call i32 @__kmpc_single
2513 omp.single copyprivate(%ip -> @copy_i32 : !llvm.ptr, %fp -> @copy_f32 : !llvm.ptr) {
2514 // CHECK: %[[i:.*]] = load i32, ptr %[[ip]]
2515 %i = llvm.load %ip : !llvm.ptr -> i32
2516 // CHECK: %[[i2:.*]] = add i32 %[[i]], %[[i]]
2517 %i2 = llvm.add %i, %i : i32
2518 // CHECK: store i32 %[[i2]], ptr %[[ip]]
2519 llvm.store %i2, %ip : i32, !llvm.ptr
2520 // CHECK: %[[f:.*]] = load float, ptr %[[fp]]
2521 %f = llvm.load %fp : !llvm.ptr -> f32
2522 // CHECK: %[[f2:.*]] = fadd float %[[f]], %[[f]]
2523 %f2 = llvm.fadd %f, %f : f32
2524 // CHECK: store float %[[f2]], ptr %[[fp]]
2525 llvm.store %f2, %fp : f32, !llvm.ptr
2526 // CHECK: store i32 1, ptr %[[didit_addr]]
2527 // CHECK: call void @__kmpc_end_single
2528 // CHECK: %[[didit:.*]] = load i32, ptr %[[didit_addr]]
2529 // CHECK: call void @__kmpc_copyprivate({{.*}}, ptr %[[ip]], ptr @copy_i32, i32 %[[didit]])
2530 // CHECK: %[[didit2:.*]] = load i32, ptr %[[didit_addr]]
2531 // CHECK: call void @__kmpc_copyprivate({{.*}}, ptr %[[fp]], ptr @copy_f32, i32 %[[didit2]])
2532 // CHECK-NOT: call void @__kmpc_barrier
2541 // CHECK: @_QFsubEx = internal global i32 undef
2542 // CHECK: @_QFsubEx.cache = common global ptr null
2544 // CHECK-LABEL: @omp_threadprivate
2545 llvm.func @omp_threadprivate() {
2546 // CHECK: [[THREAD:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB:[0-9]+]])
2547 // CHECK: [[TMP1:%.*]] = call ptr @__kmpc_threadprivate_cached(ptr @[[GLOB]], i32 [[THREAD]], ptr @_QFsubEx, i64 4, ptr @_QFsubEx.cache)
2548 // CHECK: store i32 1, ptr [[TMP1]], align 4
2549 // CHECK: store i32 3, ptr [[TMP1]], align 4
2551 // CHECK-LABEL: omp.par.region{{.*}}
2552 // CHECK: [[THREAD2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB2:[0-9]+]])
2553 // CHECK: [[TMP3:%.*]] = call ptr @__kmpc_threadprivate_cached(ptr @[[GLOB2]], i32 [[THREAD2]], ptr @_QFsubEx, i64 4, ptr @_QFsubEx.cache)
2554 // CHECK: store i32 2, ptr [[TMP3]], align 4
2556 %0 = llvm.mlir.constant(1 : i32) : i32
2557 %1 = llvm.mlir.constant(2 : i32) : i32
2558 %2 = llvm.mlir.constant(3 : i32) : i32
2560 %3 = llvm.mlir.addressof @_QFsubEx : !llvm.ptr
2561 %4 = omp.threadprivate %3 : !llvm.ptr -> !llvm.ptr
2563 llvm.store %0, %4 : i32, !llvm.ptr
2566 %5 = omp.threadprivate %3 : !llvm.ptr -> !llvm.ptr
2567 llvm.store %1, %5 : i32, !llvm.ptr
2571 llvm.store %2, %4 : i32, !llvm.ptr
2575 llvm.mlir.global internal @_QFsubEx() : i32
2579 // CHECK-LABEL: define void @omp_task_detach
2580 // CHECK-SAME: (ptr %[[event_handle:.*]])
2581 llvm.func @omp_task_detach(%event_handle : !llvm.ptr){
2582 // CHECK: %[[omp_global_thread_num:.+]] = call i32 @__kmpc_global_thread_num({{.+}})
2583 // CHECK: %[[task_data:.+]] = call ptr @__kmpc_omp_task_alloc
2584 // CHECK: %[[return_val:.*]] = call ptr @__kmpc_task_allow_completion_event(ptr {{.*}}, i32 %[[omp_global_thread_num]], ptr %[[task_data]])
2585 // CHECK: %[[conv:.*]] = ptrtoint ptr %[[return_val]] to i64
2586 // CHECK: store i64 %[[conv]], ptr %[[event_handle]], align 4
2587 // CHECK: call i32 @__kmpc_omp_task(ptr @{{.+}}, i32 %[[omp_global_thread_num]], ptr %[[task_data]])
2588 omp.task detach(%event_handle : !llvm.ptr){
2596 // CHECK-LABEL: define void @omp_task
2597 // CHECK-SAME: (i32 %[[x:.+]], i32 %[[y:.+]], ptr %[[zaddr:.+]])
2598 llvm.func @omp_task(%x: i32, %y: i32, %zaddr: !llvm.ptr) {
2599 // CHECK: %[[omp_global_thread_num:.+]] = call i32 @__kmpc_global_thread_num({{.+}})
2600 // CHECK: %[[task_data:.+]] = call ptr @__kmpc_omp_task_alloc
2601 // CHECK-SAME: (ptr @{{.+}}, i32 %[[omp_global_thread_num]], i32 1, i64 40,
2602 // CHECK-SAME: i64 0, ptr @[[outlined_fn:.+]])
2603 // CHECK: call i32 @__kmpc_omp_task(ptr @{{.+}}, i32 %[[omp_global_thread_num]], ptr %[[task_data]])
2605 %n = llvm.mlir.constant(1 : i64) : i64
2606 %valaddr = llvm.alloca %n x i32 : (i64) -> !llvm.ptr
2607 %val = llvm.load %valaddr : !llvm.ptr -> i32
2608 %double = llvm.add %val, %val : i32
2609 llvm.store %double, %valaddr : i32, !llvm.ptr
2615 // CHECK: define internal void @[[outlined_fn]](i32 %[[global_tid:[^ ,]+]])
2616 // CHECK: task.alloca{{.*}}:
2617 // CHECK: br label %[[task_body:[^, ]+]]
2618 // CHECK: [[task_body]]:
2619 // CHECK: br label %[[task_region:[^, ]+]]
2620 // CHECK: [[task_region]]:
2621 // CHECK: %[[alloca:.+]] = alloca i32, i64 1
2622 // CHECK: %[[val:.+]] = load i32, ptr %[[alloca]]
2623 // CHECK: %[[newval:.+]] = add i32 %[[val]], %[[val]]
2624 // CHECK: store i32 %[[newval]], ptr %{{[^, ]+}}
2625 // CHECK: br label %[[exit_stub:[^, ]+]]
2626 // CHECK: [[exit_stub]]:
2631 // CHECK-LABEL: define void @omp_task_attrs()
2632 llvm.func @omp_task_attrs() -> () attributes {
2633 target_cpu = "x86-64",
2634 target_features = #llvm.target_features<["+mmx", "+sse"]>
2636 // CHECK: %[[task_data:.*]] = call {{.*}}@__kmpc_omp_task_alloc{{.*}}@[[outlined_fn:.*]])
2637 // CHECK: call {{.*}}@__kmpc_omp_task(
2638 // CHECK-SAME: ptr %[[task_data]]
2646 // CHECK: define {{.*}} @[[outlined_fn]]{{.*}} #[[attrs:[0-9]+]]
2647 // CHECK: attributes #[[attrs]] = {
2648 // CHECK-SAME: "target-cpu"="x86-64"
2649 // CHECK-SAME: "target-features"="+mmx,+sse"
2653 // CHECK-LABEL: define void @omp_task_with_deps
2654 // CHECK-SAME: (ptr %[[zaddr:.+]])
2655 // CHECK: %[[dep_arr_addr:.+]] = alloca [1 x %struct.kmp_dep_info], align 8
2656 // CHECK: %[[dep_arr_addr_0:.+]] = getelementptr inbounds [1 x %struct.kmp_dep_info], ptr %[[dep_arr_addr]], i64 0, i64 0
2657 // CHECK: %[[dep_arr_addr_0_val:.+]] = getelementptr inbounds nuw %struct.kmp_dep_info, ptr %[[dep_arr_addr_0]], i32 0, i32 0
2658 // CHECK: %[[dep_arr_addr_0_val_int:.+]] = ptrtoint ptr %0 to i64
2659 // CHECK: store i64 %[[dep_arr_addr_0_val_int]], ptr %[[dep_arr_addr_0_val]], align 4
2660 // CHECK: %[[dep_arr_addr_0_size:.+]] = getelementptr inbounds nuw %struct.kmp_dep_info, ptr %[[dep_arr_addr_0]], i32 0, i32 1
2661 // CHECK: store i64 8, ptr %[[dep_arr_addr_0_size]], align 4
2662 // CHECK: %[[dep_arr_addr_0_kind:.+]] = getelementptr inbounds nuw %struct.kmp_dep_info, ptr %[[dep_arr_addr_0]], i32 0, i32 2
2663 // CHECK: store i8 1, ptr %[[dep_arr_addr_0_kind]], align 1
2665 // dependence_type: Out
2666 // CHECK: %[[DEP_ARR_ADDR1:.+]] = alloca [1 x %struct.kmp_dep_info], align 8
2667 // CHECK: %[[DEP_ARR_ADDR_1:.+]] = getelementptr inbounds [1 x %struct.kmp_dep_info], ptr %[[DEP_ARR_ADDR1]], i64 0, i64 0
2669 // CHECK: %[[DEP_TYPE_1:.+]] = getelementptr inbounds nuw %struct.kmp_dep_info, ptr %[[DEP_ARR_ADDR_1]], i32 0, i32 2
2670 // CHECK: store i8 3, ptr %[[DEP_TYPE_1]], align 1
2672 // dependence_type: Inout
2673 // CHECK: %[[DEP_ARR_ADDR2:.+]] = alloca [1 x %struct.kmp_dep_info], align 8
2674 // CHECK: %[[DEP_ARR_ADDR_2:.+]] = getelementptr inbounds [1 x %struct.kmp_dep_info], ptr %[[DEP_ARR_ADDR2]], i64 0, i64 0
2676 // CHECK: %[[DEP_TYPE_2:.+]] = getelementptr inbounds nuw %struct.kmp_dep_info, ptr %[[DEP_ARR_ADDR_2]], i32 0, i32 2
2677 // CHECK: store i8 3, ptr %[[DEP_TYPE_2]], align 1
2679 // dependence_type: Mutexinoutset
2680 // CHECK: %[[DEP_ARR_ADDR3:.+]] = alloca [1 x %struct.kmp_dep_info], align 8
2681 // CHECK: %[[DEP_ARR_ADDR_3:.+]] = getelementptr inbounds [1 x %struct.kmp_dep_info], ptr %[[DEP_ARR_ADDR3]], i64 0, i64 0
2683 // CHECK: %[[DEP_TYPE_3:.+]] = getelementptr inbounds nuw %struct.kmp_dep_info, ptr %[[DEP_ARR_ADDR_3]], i32 0, i32 2
2684 // CHECK: store i8 4, ptr %[[DEP_TYPE_3]], align 1
2686 // dependence_type: Inoutset
2687 // CHECK: %[[DEP_ARR_ADDR4:.+]] = alloca [1 x %struct.kmp_dep_info], align 8
2688 // CHECK: %[[DEP_ARR_ADDR_4:.+]] = getelementptr inbounds [1 x %struct.kmp_dep_info], ptr %[[DEP_ARR_ADDR4]], i64 0, i64 0
2690 // CHECK: %[[DEP_TYPE_4:.+]] = getelementptr inbounds nuw %struct.kmp_dep_info, ptr %[[DEP_ARR_ADDR_4]], i32 0, i32 2
2691 // CHECK: store i8 8, ptr %[[DEP_TYPE_4]], align 1
2692 llvm.func @omp_task_with_deps(%zaddr: !llvm.ptr) {
2693 // CHECK: %[[omp_global_thread_num:.+]] = call i32 @__kmpc_global_thread_num({{.+}})
2694 // CHECK: %[[task_data:.+]] = call ptr @__kmpc_omp_task_alloc
2695 // CHECK-SAME: (ptr @{{.+}}, i32 %[[omp_global_thread_num]], i32 1, i64 40,
2696 // CHECK-SAME: i64 0, ptr @[[outlined_fn:.+]])
2697 // CHECK: call i32 @__kmpc_omp_task_with_deps(ptr @{{.+}}, i32 %[[omp_global_thread_num]], ptr %[[task_data]], {{.*}})
2698 omp.task depend(taskdependin -> %zaddr : !llvm.ptr) {
2699 %n = llvm.mlir.constant(1 : i64) : i64
2700 %valaddr = llvm.alloca %n x i32 : (i64) -> !llvm.ptr
2701 %val = llvm.load %valaddr : !llvm.ptr -> i32
2702 %double = llvm.add %val, %val : i32
2703 llvm.store %double, %valaddr : i32, !llvm.ptr
2706 omp.task depend(taskdependout -> %zaddr : !llvm.ptr) {
2709 omp.task depend(taskdependinout -> %zaddr : !llvm.ptr) {
2712 omp.task depend(taskdependmutexinoutset -> %zaddr : !llvm.ptr) {
2715 omp.task depend(taskdependinoutset -> %zaddr : !llvm.ptr) {
2721 // CHECK: define internal void @[[outlined_fn]](i32 %[[global_tid:[^ ,]+]])
2722 // CHECK: task.alloca{{.*}}:
2723 // CHECK: br label %[[task_body:[^, ]+]]
2724 // CHECK: [[task_body]]:
2725 // CHECK: br label %[[task_region:[^, ]+]]
2726 // CHECK: [[task_region]]:
2727 // CHECK: %[[alloca:.+]] = alloca i32, i64 1
2728 // CHECK: %[[val:.+]] = load i32, ptr %[[alloca]]
2729 // CHECK: %[[newval:.+]] = add i32 %[[val]], %[[val]]
2730 // CHECK: store i32 %[[newval]], ptr %{{[^, ]+}}
2731 // CHECK: br label %[[exit_stub:[^, ]+]]
2732 // CHECK: [[exit_stub]]:
2737 // CHECK-LABEL: define void @omp_task
2738 // CHECK-SAME: (i32 %[[x:.+]], i32 %[[y:.+]], ptr %[[zaddr:.+]])
2739 module attributes {llvm.target_triple = "x86_64-unknown-linux-gnu"} {
2740 llvm.func @omp_task(%x: i32, %y: i32, %zaddr: !llvm.ptr) {
2741 // CHECK: %[[diff:.+]] = sub i32 %[[x]], %[[y]]
2742 %diff = llvm.sub %x, %y : i32
2743 // CHECK: store i32 %[[diff]], ptr %2
2744 llvm.store %diff, %zaddr : i32, !llvm.ptr
2745 // CHECK: %[[omp_global_thread_num:.+]] = call i32 @__kmpc_global_thread_num({{.+}})
2746 // CHECK: %[[task_data:.+]] = call ptr @__kmpc_omp_task_alloc
2747 // CHECK-SAME: (ptr @{{.+}}, i32 %[[omp_global_thread_num]], i32 1, i64 40, i64 16,
2748 // CHECK-SAME: ptr @[[outlined_fn:.+]])
2749 // CHECK: %[[shareds:.+]] = load ptr, ptr %[[task_data]]
2750 // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr {{.+}} %[[shareds]], ptr {{.+}}, i64 16, i1 false)
2751 // CHECK: call i32 @__kmpc_omp_task(ptr @{{.+}}, i32 %[[omp_global_thread_num]], ptr %[[task_data]])
2753 %z = llvm.add %x, %y : i32
2754 llvm.store %z, %zaddr : i32, !llvm.ptr
2757 // CHECK: %[[prod:.+]] = mul i32 %[[x]], %[[y]]
2758 %b = llvm.mul %x, %y : i32
2759 // CHECK: store i32 %[[prod]], ptr %[[zaddr]]
2760 llvm.store %b, %zaddr : i32, !llvm.ptr
2765 // CHECK: define internal void @[[outlined_fn]](i32 %[[global_tid:[^ ,]+]], ptr %[[task_data:.+]])
2766 // CHECK: task.alloca{{.*}}:
2767 // CHECK: %[[shareds:.+]] = load ptr, ptr %[[task_data]]
2768 // CHECK: br label %[[task_body:[^, ]+]]
2769 // CHECK: [[task_body]]:
2770 // CHECK: br label %[[task_region:[^, ]+]]
2771 // CHECK: [[task_region]]:
2772 // CHECK: %[[sum:.+]] = add i32 %{{.+}}, %{{.+}}
2773 // CHECK: store i32 %[[sum]], ptr %{{.+}}
2774 // CHECK: br label %[[exit_stub:[^, ]+]]
2775 // CHECK: [[exit_stub]]:
2780 llvm.func @par_task_(%arg0: !llvm.ptr {fir.bindc_name = "a"}) {
2781 %0 = llvm.mlir.constant(1 : i32) : i32
2784 llvm.store %0, %arg0 : i32, !llvm.ptr
2792 // CHECK-LABEL: @par_task_
2793 // CHECK: %[[TASK_ALLOC:.*]] = call ptr @__kmpc_omp_task_alloc({{.*}}ptr @[[task_outlined_fn:.+]])
2794 // CHECK: call i32 @__kmpc_omp_task({{.*}}, ptr %[[TASK_ALLOC]])
2795 // CHECK: define internal void @[[task_outlined_fn]]
2796 // CHECK: %[[ARG_ALLOC:.*]] = alloca { ptr }, align 8
2797 // CHECK: call void ({{.*}}) @__kmpc_fork_call({{.*}}, ptr @[[parallel_outlined_fn:.+]], ptr %[[ARG_ALLOC]])
2798 // CHECK: define internal void @[[parallel_outlined_fn]]
2801 llvm.func @foo(!llvm.ptr) -> ()
2802 llvm.func @destroy(!llvm.ptr) -> ()
2804 omp.private {type = firstprivate} @privatizer : i32 copy {
2805 ^bb0(%arg0: !llvm.ptr, %arg1: !llvm.ptr):
2806 %0 = llvm.load %arg0 : !llvm.ptr -> i32
2807 llvm.store %0, %arg1 : i32, !llvm.ptr
2808 omp.yield(%arg1 : !llvm.ptr)
2810 ^bb0(%arg0 : !llvm.ptr):
2811 llvm.call @destroy(%arg0) : (!llvm.ptr) -> ()
2815 llvm.func @task(%arg0 : !llvm.ptr) {
2816 omp.task private(@privatizer %arg0 -> %arg1 : !llvm.ptr) {
2817 llvm.call @foo(%arg1) : (!llvm.ptr) -> ()
2822 // CHECK-LABEL: @task..omp_par
2823 // CHECK: task.alloca:
2824 // CHECK: %[[VAL_11:.*]] = load ptr, ptr %[[VAL_12:.*]], align 8
2825 // CHECK: %[[VAL_13:.*]] = getelementptr { ptr }, ptr %[[VAL_11]], i32 0, i32 0
2826 // CHECK: %[[VAL_14:.*]] = load ptr, ptr %[[VAL_13]], align 8
2827 // CHECK: %[[VAL_15:.*]] = alloca i32, align 4
2828 // CHECK: br label %omp.private.init
2829 // CHECK: omp.private.init: ; preds = %task.alloca
2830 // CHECK: br label %omp.private.copy
2831 // CHECK: omp.private.copy: ; preds = %omp.private.init
2832 // CHECK: %[[VAL_19:.*]] = load i32, ptr %[[VAL_14]], align 4
2833 // CHECK: store i32 %[[VAL_19]], ptr %[[VAL_15]], align 4
2834 // CHECK: br label %[[VAL_20:.*]]
2835 // CHECK: [[VAL_20]]:
2836 // CHECK: br label %task.body
2837 // CHECK: task.body: ; preds = %[[VAL_20]]
2838 // CHECK: br label %omp.task.region
2839 // CHECK: omp.task.region: ; preds = %task.body
2840 // CHECK: call void @foo(ptr %[[VAL_15]])
2841 // CHECK: br label %omp.region.cont
2842 // CHECK: omp.region.cont: ; preds = %omp.task.region
2843 // CHECK: call void @destroy(ptr %[[VAL_15]])
2844 // CHECK: br label %task.exit.exitStub
2845 // CHECK: task.exit.exitStub: ; preds = %omp.region.cont
2849 llvm.func @foo() -> ()
2851 llvm.func @omp_taskgroup(%x: i32, %y: i32, %zaddr: !llvm.ptr) {
2853 llvm.call @foo() : () -> ()
2859 // CHECK-LABEL: define void @omp_taskgroup(
2860 // CHECK-SAME: i32 %[[x:.+]], i32 %[[y:.+]], ptr %[[zaddr:.+]])
2861 // CHECK: br label %[[entry:[^,]+]]
2862 // CHECK: [[entry]]:
2863 // CHECK: %[[omp_global_thread_num:.+]] = call i32 @__kmpc_global_thread_num(ptr @{{.+}})
2864 // CHECK: call void @__kmpc_taskgroup(ptr @{{.+}}, i32 %[[omp_global_thread_num]])
2865 // CHECK: br label %[[omp_taskgroup_region:[^,]+]]
2866 // CHECK: [[omp_taskgroup_region]]:
2867 // CHECK: call void @foo()
2868 // CHECK: br label %[[omp_region_cont:[^,]+]]
2869 // CHECK: [[omp_region_cont]]:
2870 // CHECK: br label %[[taskgroup_exit:[^,]+]]
2871 // CHECK: [[taskgroup_exit]]:
2872 // CHECK: call void @__kmpc_end_taskgroup(ptr @{{.+}}, i32 %[[omp_global_thread_num]])
2877 llvm.func @foo() -> ()
2878 llvm.func @bar(i32, i32, !llvm.ptr) -> ()
2880 llvm.func @omp_taskgroup_task(%x: i32, %y: i32, %zaddr: !llvm.ptr) {
2882 %c1 = llvm.mlir.constant(1) : i32
2883 %ptr1 = llvm.alloca %c1 x i8 : (i32) -> !llvm.ptr
2885 llvm.call @foo() : () -> ()
2889 llvm.call @bar(%x, %y, %zaddr) : (i32, i32, !llvm.ptr) -> ()
2894 llvm.call @foo() : () -> ()
2900 // CHECK-LABEL: define void @omp_taskgroup_task(
2901 // CHECK-SAME: i32 %[[x:.+]], i32 %[[y:.+]], ptr %[[zaddr:.+]])
2902 // CHECK: %[[structArg:.+]] = alloca { i32, i32, ptr }, align 8
2903 // CHECK: br label %[[entry:[^,]+]]
2904 // CHECK: [[entry]]: ; preds = %3
2905 // CHECK: %[[omp_global_thread_num:.+]] = call i32 @__kmpc_global_thread_num(ptr @{{.+}})
2906 // CHECK: call void @__kmpc_taskgroup(ptr @{{.+}}, i32 %[[omp_global_thread_num]])
2907 // CHECK: br label %[[omp_taskgroup_region:[^,]+]]
2908 // CHECK: [[omp_taskgroup_region1:.+]]:
2909 // CHECK: call void @foo()
2910 // CHECK: br label %[[omp_region_cont:[^,]+]]
2911 // CHECK: [[omp_taskgroup_region]]:
2912 // CHECK: %{{.+}} = alloca i8, align 1
2913 // CHECK: br label %[[codeRepl:[^,]+]]
2914 // CHECK: [[codeRepl]]:
2915 // CHECK: %[[omp_global_thread_num_t1:.+]] = call i32 @__kmpc_global_thread_num(ptr @{{.+}})
2916 // CHECK: %[[t1_alloc:.+]] = call ptr @__kmpc_omp_task_alloc(ptr @{{.+}}, i32 %[[omp_global_thread_num_t1]], i32 1, i64 40, i64 0, ptr @[[outlined_task_fn:.+]])
2917 // CHECK: %{{.+}} = call i32 @__kmpc_omp_task(ptr @{{.+}}, i32 %[[omp_global_thread_num_t1]], ptr %[[t1_alloc]])
2918 // CHECK: br label %[[task_exit:[^,]+]]
2919 // CHECK: [[task_exit]]:
2920 // CHECK: br label %[[codeRepl9:[^,]+]]
2921 // CHECK: [[codeRepl9]]:
2922 // CHECK: %[[gep1:.+]] = getelementptr { i32, i32, ptr }, ptr %[[structArg]], i32 0, i32 0
2923 // CHECK: store i32 %[[x]], ptr %[[gep1]], align 4
2924 // CHECK: %[[gep2:.+]] = getelementptr { i32, i32, ptr }, ptr %[[structArg]], i32 0, i32 1
2925 // CHECK: store i32 %[[y]], ptr %[[gep2]], align 4
2926 // CHECK: %[[gep3:.+]] = getelementptr { i32, i32, ptr }, ptr %[[structArg]], i32 0, i32 2
2927 // CHECK: store ptr %[[zaddr]], ptr %[[gep3]], align 8
2928 // CHECK: %[[omp_global_thread_num_t2:.+]] = call i32 @__kmpc_global_thread_num(ptr @{{.+}})
2929 // CHECK: %[[t2_alloc:.+]] = call ptr @__kmpc_omp_task_alloc(ptr @{{.+}}, i32 %[[omp_global_thread_num_t2]], i32 1, i64 40, i64 16, ptr @[[outlined_task_fn:.+]])
2930 // CHECK: %[[shareds:.+]] = load ptr, ptr %[[t2_alloc]]
2931 // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 1 %[[shareds]], ptr align 1 %[[structArg]], i64 16, i1 false)
2932 // CHECK: %{{.+}} = call i32 @__kmpc_omp_task(ptr @{{.+}}, i32 %[[omp_global_thread_num_t2]], ptr %[[t2_alloc]])
2933 // CHECK: br label %[[task_exit3:[^,]+]]
2934 // CHECK: [[task_exit3]]:
2935 // CHECK: br label %[[omp_taskgroup_region1]]
2936 // CHECK: [[omp_region_cont]]:
2937 // CHECK: br label %[[taskgroup_exit:[^,]+]]
2938 // CHECK: [[taskgroup_exit]]:
2939 // CHECK: call void @__kmpc_end_taskgroup(ptr @{{.+}}, i32 %[[omp_global_thread_num]])
2945 llvm.func @test_01() attributes {sym_visibility = "private"}
2946 llvm.func @test_02() attributes {sym_visibility = "private"}
2947 // CHECK-LABEL: define void @_QPomp_task_priority() {
2948 llvm.func @_QPomp_task_priority() {
2949 %0 = llvm.mlir.constant(1 : i64) : i64
2950 %1 = llvm.alloca %0 x i32 {bindc_name = "x"} : (i64) -> !llvm.ptr
2951 %2 = llvm.mlir.constant(4 : i32) : i32
2952 %3 = llvm.mlir.constant(true) : i1
2953 %4 = llvm.load %1 : !llvm.ptr -> i32
2954 // CHECK: %[[GID_01:.*]] = call i32 @__kmpc_global_thread_num(ptr {{.*}})
2955 // CHECK: %[[I_01:.*]] = call ptr @__kmpc_omp_task_alloc(ptr {{.*}}, i32 %[[GID_01]], i32 33, i64 40, i64 0, ptr @{{.*}})
2956 // CHECK: %[[I_02:.*]] = getelementptr inbounds { ptr }, ptr %[[I_01]], i32 0, i32 0
2957 // CHECK: %[[I_03:.*]] = getelementptr inbounds { ptr, ptr, i32, ptr, ptr }, ptr %[[I_02]], i32 0, i32 4
2958 // CHECK: %[[I_04:.*]] = getelementptr inbounds { ptr, ptr }, ptr %[[I_03]], i32 0, i32 0
2959 // CHECK: store i32 {{.*}}, ptr %[[I_04]], align 4
2960 // CHECK: %{{.*}} = call i32 @__kmpc_omp_task(ptr {{.*}}, i32 %[[GID_01]], ptr %[[I_01]])
2961 omp.task priority(%4 : i32) {
2962 llvm.call @test_01() : () -> ()
2965 // CHECK: %[[GID_02:.*]] = call i32 @__kmpc_global_thread_num(ptr {{.*}})
2966 // CHECK: %[[I_05:.*]] = call ptr @__kmpc_omp_task_alloc(ptr {{.*}}, i32 %[[GID_02]], i32 35, i64 40, i64 0, ptr @{{.*}})
2967 // CHECK: %[[I_06:.*]] = getelementptr inbounds { ptr }, ptr %[[I_05]], i32 0, i32 0
2968 // CHECK: %[[I_07:.*]] = getelementptr inbounds { ptr, ptr, i32, ptr, ptr }, ptr %[[I_06]], i32 0, i32 4
2969 // CHECK: %[[I_08:.*]] = getelementptr inbounds { ptr, ptr }, ptr %[[I_07]], i32 0, i32 0
2970 // CHECK: store i32 4, ptr %[[I_08]], align 4
2971 // CHECK: %{{.*}} = call i32 @__kmpc_omp_task(ptr {{.*}}, i32 %[[GID_02]], ptr %[[I_05]])
2972 omp.task final(%3) priority(%2 : i32) {
2973 llvm.call @test_02() : () -> ()
2983 // CHECK-LABEL: @omp_opaque_pointers
2984 // CHECK-SAME: (ptr %[[ARG0:.*]], ptr %[[ARG1:.*]], i32 %[[EXPR:.*]])
2985 llvm.func @omp_opaque_pointers(%arg0 : !llvm.ptr, %arg1: !llvm.ptr, %expr: i32) -> () {
2986 // CHECK: %[[X1:.*]] = load atomic i32, ptr %[[ARG0]] monotonic, align 4
2987 // CHECK: store i32 %[[X1]], ptr %[[ARG1]], align 4
2988 omp.atomic.read %arg1 = %arg0 : !llvm.ptr, !llvm.ptr, i32
2990 // CHECK: %[[RES:.*]] = atomicrmw add ptr %[[ARG1]], i32 %[[EXPR]] acq_rel
2991 // CHECK: store i32 %[[RES]], ptr %[[ARG0]]
2992 omp.atomic.capture memory_order(acq_rel) {
2993 omp.atomic.read %arg0 = %arg1 : !llvm.ptr, !llvm.ptr, i32
2994 omp.atomic.update %arg1 : !llvm.ptr {
2996 %newval = llvm.add %xval, %expr : i32
2997 omp.yield(%newval : i32)
3005 // CHECK: @__omp_rtl_debug_kind = weak_odr hidden constant i32 1
3006 // CHECK: @__omp_rtl_assume_teams_oversubscription = weak_odr hidden constant i32 1
3007 // CHECK: @__omp_rtl_assume_threads_oversubscription = weak_odr hidden constant i32 1
3008 // CHECK: @__omp_rtl_assume_no_thread_state = weak_odr hidden constant i32 1
3009 // CHECK: @__omp_rtl_assume_no_nested_parallelism = weak_odr hidden constant i32 1
3010 module attributes {omp.flags = #omp.flags<debug_kind = 1, assume_teams_oversubscription = true,
3011 assume_threads_oversubscription = true, assume_no_thread_state = true,
3012 assume_no_nested_parallelism = true>} {}
3015 // CHECK: @__omp_rtl_debug_kind = weak_odr hidden constant i32 0
3016 // CHECK: @__omp_rtl_assume_teams_oversubscription = weak_odr hidden constant i32 0
3017 // CHECK: @__omp_rtl_assume_threads_oversubscription = weak_odr hidden constant i32 0
3018 // CHECK: @__omp_rtl_assume_no_thread_state = weak_odr hidden constant i32 0
3019 // CHECK: @__omp_rtl_assume_no_nested_parallelism = weak_odr hidden constant i32 0
3020 // CHECK: [[META0:![0-9]+]] = !{i32 7, !"openmp-device", i32 50}
3021 module attributes {omp.flags = #omp.flags<>} {}
3025 // CHECK: @__omp_rtl_debug_kind = weak_odr hidden constant i32 0
3026 // CHECK: @__omp_rtl_assume_teams_oversubscription = weak_odr hidden constant i32 0
3027 // CHECK: @__omp_rtl_assume_threads_oversubscription = weak_odr hidden constant i32 0
3028 // CHECK: @__omp_rtl_assume_no_thread_state = weak_odr hidden constant i32 0
3029 // CHECK: @__omp_rtl_assume_no_nested_parallelism = weak_odr hidden constant i32 0
3030 // CHECK: [[META0:![0-9]+]] = !{i32 7, !"openmp-device", i32 51}
3031 module attributes {omp.flags = #omp.flags<openmp_device_version = 51>} {}
3035 // CHECK: @__omp_rtl_debug_kind = weak_odr hidden constant i32 0
3036 // CHECK: @__omp_rtl_assume_teams_oversubscription = weak_odr hidden constant i32 0
3037 // CHECK: @__omp_rtl_assume_threads_oversubscription = weak_odr hidden constant i32 0
3038 // CHECK: @__omp_rtl_assume_no_thread_state = weak_odr hidden constant i32 0
3039 // CHECK: @__omp_rtl_assume_no_nested_parallelism = weak_odr hidden constant i32 0
3040 // CHECK: [[META0:![0-9]+]] = !{i32 7, !"openmp-device", i32 50}
3041 // CHECK: [[META0:![0-9]+]] = !{i32 7, !"openmp", i32 50}
3042 module attributes {omp.version = #omp.version<version = 50>, omp.flags = #omp.flags<>} {}
3046 // CHECK: [[META0:![0-9]+]] = !{i32 7, !"openmp", i32 51}
3047 // CHECK-NOT: [[META0:![0-9]+]] = !{i32 7, !"openmp-device", i32 50}
3048 module attributes {omp.version = #omp.version<version = 51>} {}
3051 // CHECK: @__omp_rtl_debug_kind = weak_odr hidden constant i32 0
3052 // CHECK: @__omp_rtl_assume_teams_oversubscription = weak_odr hidden constant i32 0
3053 // CHECK: @__omp_rtl_assume_threads_oversubscription = weak_odr hidden constant i32 0
3054 // CHECK: @__omp_rtl_assume_no_thread_state = weak_odr hidden constant i32 0
3055 // CHECK: @__omp_rtl_assume_no_nested_parallelism = weak_odr hidden constant i32 0
3056 module attributes {omp.flags = #omp.flags<debug_kind = 0, assume_teams_oversubscription = false,
3057 assume_threads_oversubscription = false, assume_no_thread_state = false,
3058 assume_no_nested_parallelism = false>} {}
3062 // CHECK: @__omp_rtl_debug_kind = weak_odr hidden constant i32 0
3063 // CHECK: @__omp_rtl_assume_teams_oversubscription = weak_odr hidden constant i32 1
3064 // CHECK: @__omp_rtl_assume_threads_oversubscription = weak_odr hidden constant i32 0
3065 // CHECK: @__omp_rtl_assume_no_thread_state = weak_odr hidden constant i32 1
3066 // CHECK: @__omp_rtl_assume_no_nested_parallelism = weak_odr hidden constant i32 0
3067 module attributes {omp.flags = #omp.flags<assume_teams_oversubscription = true, assume_no_thread_state = true>} {}
3071 // CHECK-NOT: @__omp_rtl_debug_kind = weak_odr hidden constant i32 0
3072 // CHECK-NOT: @__omp_rtl_assume_teams_oversubscription = weak_odr hidden constant i32 1
3073 // CHECK-NOT: @__omp_rtl_assume_threads_oversubscription = weak_odr hidden constant i32 0
3074 // CHECK-NOT: @__omp_rtl_assume_no_thread_state = weak_odr hidden constant i32 1
3075 // CHECK-NOT: @__omp_rtl_assume_no_nested_parallelism = weak_odr hidden constant i32 0
3076 module attributes {omp.flags = #omp.flags<assume_teams_oversubscription = true, assume_no_thread_state = true,
3077 no_gpu_lib=true>} {}
3081 module attributes {omp.is_target_device = false} {
3082 // CHECK: define void @filter_nohost
3083 llvm.func @filter_nohost() -> ()
3085 omp.declare_target =
3086 #omp.declaretarget<device_type = (nohost), capture_clause = (to)>
3091 // CHECK: define void @filter_host
3092 llvm.func @filter_host() -> ()
3094 omp.declare_target =
3095 #omp.declaretarget<device_type = (host), capture_clause = (to)>
3103 module attributes {omp.is_target_device = false} {
3104 // CHECK: define void @filter_nohost
3105 llvm.func @filter_nohost() -> ()
3107 omp.declare_target =
3108 #omp.declaretarget<device_type = (nohost), capture_clause = (enter)>
3113 // CHECK: define void @filter_host
3114 llvm.func @filter_host() -> ()
3116 omp.declare_target =
3117 #omp.declaretarget<device_type = (host), capture_clause = (enter)>
3125 module attributes {omp.is_target_device = true} {
3126 // CHECK: define void @filter_nohost
3127 llvm.func @filter_nohost() -> ()
3129 omp.declare_target =
3130 #omp.declaretarget<device_type = (nohost), capture_clause = (to)>
3135 // CHECK-NOT: define void @filter_host
3136 llvm.func @filter_host() -> ()
3138 omp.declare_target =
3139 #omp.declaretarget<device_type = (host), capture_clause = (to)>
3147 module attributes {omp.is_target_device = true} {
3148 // CHECK: define void @filter_nohost
3149 llvm.func @filter_nohost() -> ()
3151 omp.declare_target =
3152 #omp.declaretarget<device_type = (nohost), capture_clause = (enter)>
3157 // CHECK-NOT: define void @filter_host
3158 llvm.func @filter_host() -> ()
3160 omp.declare_target =
3161 #omp.declaretarget<device_type = (host), capture_clause = (enter)>
3169 llvm.func @omp_task_untied() {
3170 // The third argument is 0: which signifies the untied task
3171 // CHECK: {{.*}} = call ptr @__kmpc_omp_task_alloc(ptr @1, i32 %{{.*}}, i32 0,
3172 // CHECK-SAME: i64 40, i64 0, ptr @{{.*}})
3181 // Third argument is 5: essentially (4 || 1)
3182 // signifying this task is TIED and MERGEABLE
3184 // CHECK: {{.*}} = call ptr @__kmpc_omp_task_alloc(ptr @1, i32 %omp_global_thread_num, i32 5, i64 40, i64 0, ptr @omp_task_mergeable..omp_par)
3185 llvm.func @omp_task_mergeable() {
3186 omp.task mergeable {
3194 llvm.func external @foo_before() -> ()
3195 llvm.func external @foo() -> ()
3196 llvm.func external @foo_after() -> ()
3198 llvm.func @omp_task_final(%boolexpr: i1) {
3199 llvm.call @foo_before() : () -> ()
3200 omp.task final(%boolexpr) {
3201 llvm.call @foo() : () -> ()
3204 llvm.call @foo_after() : () -> ()
3208 // CHECK-LABEL: define void @omp_task_final(
3209 // CHECK-SAME: i1 %[[boolexpr:.+]]) {
3210 // CHECK: call void @foo_before()
3211 // CHECK: br label %[[entry:[^,]+]]
3212 // CHECK: [[entry]]:
3213 // CHECK: br label %[[codeRepl:[^,]+]]
3214 // CHECK: [[codeRepl]]: ; preds = %entry
3215 // CHECK: %[[omp_global_thread_num:.+]] = call i32 @__kmpc_global_thread_num(ptr @{{.+}})
3216 // CHECK: %[[final_flag:.+]] = select i1 %[[boolexpr]], i32 2, i32 0
3217 // CHECK: %[[task_flags:.+]] = or i32 %[[final_flag]], 1
3218 // CHECK: %[[task_data:.+]] = call ptr @__kmpc_omp_task_alloc(ptr @{{.+}}, i32 %[[omp_global_thread_num]], i32 %[[task_flags]], i64 40, i64 0, ptr @[[task_outlined_fn:.+]])
3219 // CHECK: %{{.+}} = call i32 @__kmpc_omp_task(ptr @{{.+}}, i32 %[[omp_global_thread_num]], ptr %[[task_data]])
3220 // CHECK: br label %[[task_exit:[^,]+]]
3221 // CHECK: [[task_exit]]:
3222 // CHECK: call void @foo_after()
3227 llvm.func external @foo_before() -> ()
3228 llvm.func external @foo() -> ()
3229 llvm.func external @foo_after() -> ()
3231 llvm.func @omp_task_if(%boolexpr: i1) {
3232 llvm.call @foo_before() : () -> ()
3233 omp.task if(%boolexpr) {
3234 llvm.call @foo() : () -> ()
3237 llvm.call @foo_after() : () -> ()
3241 // CHECK-LABEL: define void @omp_task_if(
3242 // CHECK-SAME: i1 %[[boolexpr:.+]]) {
3243 // CHECK: call void @foo_before()
3244 // CHECK: br label %[[entry:[^,]+]]
3245 // CHECK: [[entry]]:
3246 // CHECK: br label %[[codeRepl:[^,]+]]
3247 // CHECK: [[codeRepl]]:
3248 // CHECK: %[[omp_global_thread_num:.+]] = call i32 @__kmpc_global_thread_num(ptr @{{.+}})
3249 // CHECK: %[[task_data:.+]] = call ptr @__kmpc_omp_task_alloc(ptr @{{.+}}, i32 %[[omp_global_thread_num]], i32 1, i64 40, i64 0, ptr @[[task_outlined_fn:.+]])
3250 // CHECK: br i1 %[[boolexpr]], label %[[true_label:[^,]+]], label %[[false_label:[^,]+]]
3251 // CHECK: [[true_label]]:
3252 // CHECK: %{{.+}} = call i32 @__kmpc_omp_task(ptr @{{.+}}, i32 %[[omp_global_thread_num]], ptr %[[task_data]])
3253 // CHECK: br label %[[if_else_exit:[^,]+]]
3254 // CHECK: [[false_label:[^,]+]]: ; preds = %codeRepl
3255 // CHECK: call void @__kmpc_omp_task_begin_if0(ptr @{{.+}}, i32 %[[omp_global_thread_num]], ptr %[[task_data]])
3256 // CHECK: call void @[[task_outlined_fn]](i32 %[[omp_global_thread_num]])
3257 // CHECK: call void @__kmpc_omp_task_complete_if0(ptr @{{.+}}, i32 %[[omp_global_thread_num]], ptr %[[task_data]])
3258 // CHECK: br label %[[if_else_exit]]
3259 // CHECK: [[if_else_exit]]:
3260 // CHECK: br label %[[task_exit:[^,]+]]
3261 // CHECK: [[task_exit]]:
3262 // CHECK: call void @foo_after()
3267 module attributes {omp.requires = #omp<clause_requires reverse_offload|unified_shared_memory>} {}