This PR adds an initial implementation for the map modifiers close, present and ompx_hold, primarily just required adding the appropriate map type flags to the map type bits. In the case of ompx_hold it required adding the map type to the OpenMP dialect. Close has a bit of a problem when utilised with the ALWAYS map type on descriptors, so it is likely we'll have to make sure close and always are not applied to the descriptor simultaneously in the future when we apply always to the descriptors to facilitate movement of descriptor information to device for consistency, however, we may find an alternative to this with further investigation. For the moment, it is a TODO/Note to keep track of it.
2990 lines
106 KiB
MLIR
2990 lines
106 KiB
MLIR
// RUN: mlir-opt %s | mlir-opt | FileCheck %s
|
|
|
|
func.func @omp_barrier() -> () {
|
|
// CHECK: omp.barrier
|
|
omp.barrier
|
|
return
|
|
}
|
|
|
|
func.func @omp_master() -> () {
|
|
// CHECK: omp.master
|
|
omp.master {
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: omp_masked
|
|
func.func @omp_masked(%filtered_thread_id : i32) -> () {
|
|
// CHECK: omp.masked filter(%{{.*}} : i32)
|
|
"omp.masked" (%filtered_thread_id) ({
|
|
omp.terminator
|
|
}) : (i32) -> ()
|
|
|
|
// CHECK: omp.masked
|
|
"omp.masked" () ({
|
|
omp.terminator
|
|
}) : () -> ()
|
|
return
|
|
}
|
|
|
|
func.func @omp_taskwait() -> () {
|
|
// CHECK: omp.taskwait
|
|
omp.taskwait
|
|
return
|
|
}
|
|
|
|
func.func @omp_taskyield() -> () {
|
|
// CHECK: omp.taskyield
|
|
omp.taskyield
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: func @omp_flush
|
|
// CHECK-SAME: ([[ARG0:%.*]]: memref<i32>) {
|
|
func.func @omp_flush(%arg0 : memref<i32>) -> () {
|
|
// Test without data var
|
|
// CHECK: omp.flush
|
|
omp.flush
|
|
|
|
// Test with one data var
|
|
// CHECK: omp.flush([[ARG0]] : memref<i32>)
|
|
omp.flush(%arg0 : memref<i32>)
|
|
|
|
// Test with two data var
|
|
// CHECK: omp.flush([[ARG0]], [[ARG0]] : memref<i32>, memref<i32>)
|
|
omp.flush(%arg0, %arg0: memref<i32>, memref<i32>)
|
|
|
|
return
|
|
}
|
|
|
|
func.func @omp_terminator() -> () {
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
|
|
func.func @omp_parallel(%data_var : memref<i32>, %if_cond : i1, %num_threads : i32, %idx : index) -> () {
|
|
// CHECK: omp.parallel allocate(%{{.*}} : memref<i32> -> %{{.*}} : memref<i32>) if(%{{.*}}) num_threads(%{{.*}} : i32)
|
|
"omp.parallel" (%data_var, %data_var, %if_cond, %num_threads) ({
|
|
|
|
// test without if condition
|
|
// CHECK: omp.parallel allocate(%{{.*}} : memref<i32> -> %{{.*}} : memref<i32>) num_threads(%{{.*}} : i32)
|
|
"omp.parallel"(%data_var, %data_var, %num_threads) ({
|
|
omp.terminator
|
|
}) {operandSegmentSizes = array<i32: 1,1,0,1,0,0>} : (memref<i32>, memref<i32>, i32) -> ()
|
|
|
|
// CHECK: omp.barrier
|
|
omp.barrier
|
|
|
|
// test without num_threads
|
|
// CHECK: omp.parallel allocate(%{{.*}} : memref<i32> -> %{{.*}} : memref<i32>) if(%{{.*}})
|
|
"omp.parallel"(%data_var, %data_var, %if_cond) ({
|
|
omp.terminator
|
|
}) {operandSegmentSizes = array<i32: 1,1,1,0,0,0>} : (memref<i32>, memref<i32>, i1) -> ()
|
|
|
|
// test without allocate
|
|
// CHECK: omp.parallel if(%{{.*}}) num_threads(%{{.*}} : i32)
|
|
"omp.parallel"(%if_cond, %num_threads) ({
|
|
omp.terminator
|
|
}) {operandSegmentSizes = array<i32: 0,0,1,1,0,0>} : (i1, i32) -> ()
|
|
|
|
omp.terminator
|
|
}) {operandSegmentSizes = array<i32: 1,1,1,1,0,0>, proc_bind_kind = #omp<procbindkind spread>} : (memref<i32>, memref<i32>, i1, i32) -> ()
|
|
|
|
// test with multiple parameters for single variadic argument
|
|
// CHECK: omp.parallel allocate(%{{.*}} : memref<i32> -> %{{.*}} : memref<i32>)
|
|
"omp.parallel" (%data_var, %data_var) ({
|
|
omp.terminator
|
|
}) {operandSegmentSizes = array<i32: 1,1,0,0,0,0>} : (memref<i32>, memref<i32>) -> ()
|
|
|
|
// CHECK: omp.parallel
|
|
omp.parallel {
|
|
// CHECK-NOT: omp.terminator
|
|
// CHECK: omp.distribute
|
|
omp.distribute {
|
|
// CHECK-NEXT: omp.wsloop
|
|
omp.wsloop {
|
|
// CHECK-NEXT: omp.loop_nest
|
|
omp.loop_nest (%iv) : index = (%idx) to (%idx) step (%idx) {
|
|
omp.yield
|
|
}
|
|
} {omp.composite}
|
|
} {omp.composite}
|
|
omp.terminator
|
|
} {omp.composite}
|
|
|
|
// CHECK: omp.parallel
|
|
omp.parallel {
|
|
// CHECK-NOT: omp.terminator
|
|
// CHECK: omp.distribute
|
|
omp.distribute {
|
|
// CHECK-NEXT: omp.wsloop
|
|
omp.wsloop {
|
|
// CHECK-NEXT: omp.simd
|
|
omp.simd {
|
|
// CHECK-NEXT: omp.loop_nest
|
|
omp.loop_nest (%iv) : index = (%idx) to (%idx) step (%idx) {
|
|
omp.yield
|
|
}
|
|
} {omp.composite}
|
|
} {omp.composite}
|
|
} {omp.composite}
|
|
omp.terminator
|
|
} {omp.composite}
|
|
|
|
return
|
|
}
|
|
|
|
func.func @omp_parallel_pretty(%data_var : memref<i32>, %if_cond : i1, %num_threads : i32, %allocator : si32) -> () {
|
|
// CHECK: omp.parallel
|
|
omp.parallel {
|
|
omp.terminator
|
|
}
|
|
|
|
// CHECK: omp.parallel num_threads(%{{.*}} : i32)
|
|
omp.parallel num_threads(%num_threads : i32) {
|
|
omp.terminator
|
|
}
|
|
|
|
%n_index = arith.constant 2 : index
|
|
// CHECK: omp.parallel num_threads(%{{.*}} : index)
|
|
omp.parallel num_threads(%n_index : index) {
|
|
omp.terminator
|
|
}
|
|
|
|
%n_i64 = arith.constant 4 : i64
|
|
// CHECK: omp.parallel num_threads(%{{.*}} : i64)
|
|
omp.parallel num_threads(%n_i64 : i64) {
|
|
omp.terminator
|
|
}
|
|
|
|
// CHECK: omp.parallel allocate(%{{.*}} : memref<i32> -> %{{.*}} : memref<i32>)
|
|
omp.parallel allocate(%data_var : memref<i32> -> %data_var : memref<i32>) {
|
|
omp.terminator
|
|
}
|
|
|
|
// CHECK: omp.parallel
|
|
// CHECK-NEXT: omp.parallel if(%{{.*}})
|
|
omp.parallel {
|
|
omp.parallel if(%if_cond) {
|
|
omp.terminator
|
|
}
|
|
omp.terminator
|
|
}
|
|
|
|
// CHECK: omp.parallel if(%{{.*}}) num_threads(%{{.*}} : i32) proc_bind(close)
|
|
omp.parallel num_threads(%num_threads : i32) if(%if_cond) proc_bind(close) {
|
|
omp.terminator
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: omp_loop_nest
|
|
func.func @omp_loop_nest(%lb : index, %ub : index, %step : index) -> () {
|
|
omp.wsloop {
|
|
// CHECK: omp.loop_nest
|
|
// CHECK-SAME: (%{{.*}}) : index =
|
|
// CHECK-SAME: (%{{.*}}) to (%{{.*}}) step (%{{.*}})
|
|
"omp.loop_nest" (%lb, %ub, %step) ({
|
|
^bb0(%iv: index):
|
|
omp.yield
|
|
}) : (index, index, index) -> ()
|
|
}
|
|
|
|
omp.wsloop {
|
|
// CHECK: omp.loop_nest
|
|
// CHECK-SAME: (%{{.*}}) : index =
|
|
// CHECK-SAME: (%{{.*}}) to (%{{.*}}) inclusive step (%{{.*}})
|
|
"omp.loop_nest" (%lb, %ub, %step) ({
|
|
^bb0(%iv: index):
|
|
omp.yield
|
|
}) {loop_inclusive} : (index, index, index) -> ()
|
|
}
|
|
|
|
omp.wsloop {
|
|
// CHECK: omp.loop_nest
|
|
// CHECK-SAME: (%{{.*}}, %{{.*}}) : index =
|
|
// CHECK-SAME: (%{{.*}}, %{{.*}}) to (%{{.*}}, %{{.*}}) step (%{{.*}}, %{{.*}})
|
|
"omp.loop_nest" (%lb, %lb, %ub, %ub, %step, %step) ({
|
|
^bb0(%iv: index, %iv3: index):
|
|
omp.yield
|
|
}) : (index, index, index, index, index, index) -> ()
|
|
}
|
|
|
|
omp.wsloop {
|
|
// CHECK: omp.loop_nest
|
|
// CHECK-SAME: (%{{.*}}) : index =
|
|
// CHECK-SAME: (%{{.*}}) to (%{{.*}}) step (%{{.*}})
|
|
"omp.loop_nest" (%lb, %ub, %step) ({
|
|
^bb0(%iv: index):
|
|
// CHECK: test.op1
|
|
"test.op1"(%lb) : (index) -> ()
|
|
// CHECK: test.op2
|
|
"test.op2"() : () -> ()
|
|
// CHECK: omp.yield
|
|
omp.yield
|
|
}) : (index, index, index) -> ()
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: omp_loop_nest_pretty
|
|
func.func @omp_loop_nest_pretty(%lb : index, %ub : index, %step : index) -> () {
|
|
omp.wsloop {
|
|
// CHECK: omp.loop_nest
|
|
// CHECK-SAME: (%{{.*}}) : index =
|
|
// CHECK-SAME: (%{{.*}}) to (%{{.*}}) step (%{{.*}})
|
|
omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
|
|
omp.yield
|
|
}
|
|
}
|
|
|
|
omp.wsloop {
|
|
// CHECK: omp.loop_nest
|
|
// CHECK-SAME: (%{{.*}}) : index =
|
|
// CHECK-SAME: (%{{.*}}) to (%{{.*}}) inclusive step (%{{.*}})
|
|
omp.loop_nest (%iv) : index = (%lb) to (%ub) inclusive step (%step) {
|
|
omp.yield
|
|
}
|
|
}
|
|
|
|
omp.wsloop {
|
|
// CHECK: omp.loop_nest
|
|
// CHECK-SAME: (%{{.*}}) : index =
|
|
// CHECK-SAME: (%{{.*}}, %{{.*}}) to (%{{.*}}, %{{.*}}) step (%{{.*}}, %{{.*}})
|
|
omp.loop_nest (%iv1, %iv2) : index = (%lb, %lb) to (%ub, %ub) step (%step, %step) {
|
|
omp.yield
|
|
}
|
|
}
|
|
|
|
omp.wsloop {
|
|
// CHECK: omp.loop_nest
|
|
// CHECK-SAME: (%{{.*}}) : index =
|
|
// CHECK-SAME: (%{{.*}}) to (%{{.*}}) step (%{{.*}})
|
|
omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
|
|
// CHECK: test.op1
|
|
"test.op1"(%lb) : (index) -> ()
|
|
// CHECK: test.op2
|
|
"test.op2"() : () -> ()
|
|
// CHECK: omp.yield
|
|
omp.yield
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: omp_loop_nest_pretty_multi_block
|
|
func.func @omp_loop_nest_pretty_multi_block(%lb : index, %ub : index,
|
|
%step : index, %data1 : memref<?xi32>, %data2 : memref<?xi32>) -> () {
|
|
|
|
omp.wsloop {
|
|
// CHECK: omp.loop_nest (%{{.*}}) : index = (%{{.*}}) to (%{{.*}}) step (%{{.*}})
|
|
omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
|
|
%1 = "test.payload"(%iv) : (index) -> (i32)
|
|
cf.br ^bb1(%1: i32)
|
|
^bb1(%arg: i32):
|
|
memref.store %arg, %data1[%iv] : memref<?xi32>
|
|
omp.yield
|
|
}
|
|
}
|
|
|
|
omp.wsloop {
|
|
// CHECK: omp.loop_nest (%{{.*}}) : index = (%{{.*}}) to (%{{.*}}) step (%{{.*}})
|
|
omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
|
|
%c = "test.condition"(%iv) : (index) -> (i1)
|
|
%v1 = "test.payload"(%iv) : (index) -> (i32)
|
|
cf.cond_br %c, ^bb1(%v1: i32), ^bb2(%v1: i32)
|
|
^bb1(%arg0: i32):
|
|
memref.store %arg0, %data1[%iv] : memref<?xi32>
|
|
cf.br ^bb3
|
|
^bb2(%arg1: i32):
|
|
memref.store %arg1, %data2[%iv] : memref<?xi32>
|
|
cf.br ^bb3
|
|
^bb3:
|
|
omp.yield
|
|
}
|
|
}
|
|
|
|
omp.wsloop {
|
|
// CHECK: omp.loop_nest (%{{.*}}) : index = (%{{.*}}) to (%{{.*}}) step (%{{.*}})
|
|
omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
|
|
%c = "test.condition"(%iv) : (index) -> (i1)
|
|
%v1 = "test.payload"(%iv) : (index) -> (i32)
|
|
cf.cond_br %c, ^bb1(%v1: i32), ^bb2(%v1: i32)
|
|
^bb1(%arg0: i32):
|
|
memref.store %arg0, %data1[%iv] : memref<?xi32>
|
|
omp.yield
|
|
^bb2(%arg1: i32):
|
|
memref.store %arg1, %data2[%iv] : memref<?xi32>
|
|
omp.yield
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: omp_loop_nest_pretty_non_index
|
|
func.func @omp_loop_nest_pretty_non_index(%lb1 : i32, %ub1 : i32, %step1 : i32,
|
|
%lb2 : i64, %ub2 : i64, %step2 : i64, %data1 : memref<?xi32>,
|
|
%data2 : memref<?xi64>) -> () {
|
|
|
|
omp.wsloop {
|
|
// CHECK: omp.loop_nest (%{{.*}}) : i32 = (%{{.*}}) to (%{{.*}}) step (%{{.*}})
|
|
omp.loop_nest (%iv1) : i32 = (%lb1) to (%ub1) step (%step1) {
|
|
%1 = "test.payload"(%iv1) : (i32) -> (index)
|
|
cf.br ^bb1(%1: index)
|
|
^bb1(%arg1: index):
|
|
memref.store %iv1, %data1[%arg1] : memref<?xi32>
|
|
omp.yield
|
|
}
|
|
}
|
|
|
|
omp.wsloop {
|
|
// CHECK: omp.loop_nest (%{{.*}}) : i64 = (%{{.*}}) to (%{{.*}}) step (%{{.*}})
|
|
omp.loop_nest (%iv) : i64 = (%lb2) to (%ub2) step (%step2) {
|
|
%2 = "test.payload"(%iv) : (i64) -> (index)
|
|
cf.br ^bb1(%2: index)
|
|
^bb1(%arg2: index):
|
|
memref.store %iv, %data2[%arg2] : memref<?xi64>
|
|
omp.yield
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: omp_loop_nest_pretty_multiple
|
|
func.func @omp_loop_nest_pretty_multiple(%lb1 : i32, %ub1 : i32, %step1 : i32,
|
|
%lb2 : i32, %ub2 : i32, %step2 : i32, %data1 : memref<?xi32>) -> () {
|
|
|
|
omp.wsloop {
|
|
// CHECK: omp.loop_nest (%{{.*}}, %{{.*}}) : i32 = (%{{.*}}, %{{.*}}) to (%{{.*}}, %{{.*}}) step (%{{.*}}, %{{.*}})
|
|
omp.loop_nest (%iv1, %iv2) : i32 = (%lb1, %lb2) to (%ub1, %ub2) step (%step1, %step2) {
|
|
%1 = "test.payload"(%iv1) : (i32) -> (index)
|
|
%2 = "test.payload"(%iv2) : (i32) -> (index)
|
|
memref.store %iv1, %data1[%1] : memref<?xi32>
|
|
memref.store %iv2, %data1[%2] : memref<?xi32>
|
|
omp.yield
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: omp_wsloop
|
|
func.func @omp_wsloop(%lb : index, %ub : index, %step : index, %data_var : memref<i32>, %linear_var : i32, %chunk_var : i32) -> () {
|
|
|
|
// CHECK: omp.wsloop ordered(1) {
|
|
// CHECK-NEXT: omp.loop_nest
|
|
"omp.wsloop" () ({
|
|
omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
|
|
omp.yield
|
|
}
|
|
}) {operandSegmentSizes = array<i32: 0,0,0,0,0,0,0>, ordered = 1} :
|
|
() -> ()
|
|
|
|
// CHECK: omp.wsloop linear(%{{.*}} = %{{.*}} : memref<i32>) schedule(static) {
|
|
// CHECK-NEXT: omp.loop_nest
|
|
"omp.wsloop" (%data_var, %linear_var) ({
|
|
omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
|
|
omp.yield
|
|
}
|
|
}) {operandSegmentSizes = array<i32: 0,0,1,1,0,0,0>, schedule_kind = #omp<schedulekind static>} :
|
|
(memref<i32>, i32) -> ()
|
|
|
|
// CHECK: omp.wsloop linear(%{{.*}} = %{{.*}} : memref<i32>, %{{.*}} = %{{.*}} : memref<i32>) schedule(static) {
|
|
// CHECK-NEXT: omp.loop_nest
|
|
"omp.wsloop" (%data_var, %data_var, %linear_var, %linear_var) ({
|
|
omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
|
|
omp.yield
|
|
}
|
|
}) {operandSegmentSizes = array<i32: 0,0,2,2,0,0,0>, schedule_kind = #omp<schedulekind static>} :
|
|
(memref<i32>, memref<i32>, i32, i32) -> ()
|
|
|
|
// CHECK: omp.wsloop linear(%{{.*}} = %{{.*}} : memref<i32>) ordered(2) schedule(dynamic = %{{.*}}) {
|
|
// CHECK-NEXT: omp.loop_nest
|
|
"omp.wsloop" (%data_var, %linear_var, %chunk_var) ({
|
|
omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
|
|
omp.yield
|
|
}
|
|
}) {operandSegmentSizes = array<i32: 0,0,1,1,0,0,1>, schedule_kind = #omp<schedulekind dynamic>, ordered = 2} :
|
|
(memref<i32>, i32, i32) -> ()
|
|
|
|
// CHECK: omp.wsloop nowait schedule(auto) {
|
|
// CHECK-NEXT: omp.loop_nest
|
|
"omp.wsloop" () ({
|
|
omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
|
|
omp.yield
|
|
}
|
|
}) {operandSegmentSizes = array<i32: 0,0,0,0,0,0,0>, nowait, schedule_kind = #omp<schedulekind auto>} :
|
|
() -> ()
|
|
|
|
// CHECK: omp.wsloop {
|
|
// CHECK-NEXT: omp.simd
|
|
// CHECK-NEXT: omp.loop_nest
|
|
"omp.wsloop" () ({
|
|
omp.simd {
|
|
omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
|
|
omp.yield
|
|
}
|
|
} {omp.composite}
|
|
}) {omp.composite} : () -> ()
|
|
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: omp_wsloop_pretty
|
|
func.func @omp_wsloop_pretty(%lb : index, %ub : index, %step : index, %data_var : memref<i32>, %linear_var : i32, %chunk_var : i32, %chunk_var2 : i16) -> () {
|
|
|
|
// CHECK: omp.wsloop ordered(2) {
|
|
// CHECK-NEXT: omp.loop_nest
|
|
omp.wsloop ordered(2) {
|
|
omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
|
|
omp.yield
|
|
}
|
|
}
|
|
|
|
// CHECK: omp.wsloop linear(%{{.*}} = %{{.*}} : memref<i32>) schedule(static) {
|
|
// CHECK-NEXT: omp.loop_nest
|
|
omp.wsloop schedule(static) linear(%data_var = %linear_var : memref<i32>) {
|
|
omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
|
|
omp.yield
|
|
}
|
|
}
|
|
|
|
// CHECK: omp.wsloop linear(%{{.*}} = %{{.*}} : memref<i32>) ordered(2) schedule(static = %{{.*}} : i32) {
|
|
// CHECK-NEXT: omp.loop_nest
|
|
omp.wsloop ordered(2) linear(%data_var = %linear_var : memref<i32>) schedule(static = %chunk_var : i32) {
|
|
omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
|
|
omp.yield
|
|
}
|
|
}
|
|
|
|
// CHECK: omp.wsloop linear(%{{.*}} = %{{.*}} : memref<i32>) ordered(2) schedule(dynamic = %{{.*}} : i32, nonmonotonic) {
|
|
// CHECK-NEXT: omp.loop_nest
|
|
omp.wsloop ordered(2) linear(%data_var = %linear_var : memref<i32>) schedule(dynamic = %chunk_var : i32, nonmonotonic) {
|
|
omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
|
|
omp.yield
|
|
}
|
|
}
|
|
|
|
// CHECK: omp.wsloop linear(%{{.*}} = %{{.*}} : memref<i32>) ordered(2) schedule(dynamic = %{{.*}} : i16, monotonic) {
|
|
// CHECK-NEXT: omp.loop_nest
|
|
omp.wsloop ordered(2) linear(%data_var = %linear_var : memref<i32>) schedule(dynamic = %chunk_var2 : i16, monotonic) {
|
|
omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
|
|
omp.yield
|
|
}
|
|
}
|
|
|
|
// CHECK: omp.wsloop {
|
|
// CHECK-NEXT: omp.loop_nest
|
|
omp.wsloop {
|
|
omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
|
|
omp.yield
|
|
}
|
|
}
|
|
|
|
// CHECK: omp.wsloop nowait {
|
|
// CHECK-NEXT: omp.loop_nest
|
|
omp.wsloop nowait {
|
|
omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
|
|
omp.yield
|
|
}
|
|
}
|
|
|
|
// CHECK: omp.wsloop nowait order(concurrent) {
|
|
// CHECK-NEXT: omp.loop_nest
|
|
omp.wsloop order(concurrent) nowait {
|
|
omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
|
|
omp.yield
|
|
}
|
|
}
|
|
|
|
// CHECK: omp.wsloop nowait order(reproducible:concurrent) {
|
|
// CHECK-NEXT: omp.loop_nest
|
|
omp.wsloop order(reproducible:concurrent) nowait {
|
|
omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
|
|
omp.yield
|
|
}
|
|
}
|
|
// CHECK: omp.wsloop nowait order(unconstrained:concurrent) {
|
|
// CHECK-NEXT: omp.loop_nest
|
|
omp.wsloop order(unconstrained:concurrent) nowait {
|
|
omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
|
|
omp.yield
|
|
}
|
|
}
|
|
// CHECK: omp.wsloop {
|
|
// CHECK-NEXT: omp.simd
|
|
// CHECK-NEXT: omp.loop_nest
|
|
omp.wsloop {
|
|
omp.simd {
|
|
omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
|
|
omp.yield
|
|
}
|
|
} {omp.composite}
|
|
} {omp.composite}
|
|
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: omp_simd
|
|
func.func @omp_simd(%lb : index, %ub : index, %step : index) -> () {
|
|
// CHECK: omp.simd
|
|
omp.simd {
|
|
"omp.loop_nest" (%lb, %ub, %step) ({
|
|
^bb1(%iv2: index):
|
|
"omp.yield"() : () -> ()
|
|
}) : (index, index, index) -> ()
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: omp_simd_aligned_list
|
|
func.func @omp_simd_aligned_list(%arg0 : index, %arg1 : index, %arg2 : index,
|
|
%arg3 : memref<i32>, %arg4 : memref<i32>) -> () {
|
|
// CHECK: omp.simd aligned(
|
|
// CHECK-SAME: %{{.*}} : memref<i32> -> 32 : i64,
|
|
// CHECK-SAME: %{{.*}} : memref<i32> -> 128 : i64)
|
|
"omp.simd"(%arg3, %arg4) ({
|
|
"omp.loop_nest" (%arg0, %arg1, %arg2) ({
|
|
^bb1(%iv2: index):
|
|
"omp.yield"() : () -> ()
|
|
}) : (index, index, index) -> ()
|
|
}) {alignments = [32, 128],
|
|
operandSegmentSizes = array<i32: 2, 0, 0, 0, 0, 0, 0>} : (memref<i32>, memref<i32>) -> ()
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: omp_simd_aligned_single
|
|
func.func @omp_simd_aligned_single(%arg0 : index, %arg1 : index, %arg2 : index,
|
|
%arg3 : memref<i32>, %arg4 : memref<i32>) -> () {
|
|
// CHECK: omp.simd aligned(%{{.*}} : memref<i32> -> 32 : i64)
|
|
"omp.simd"(%arg3) ({
|
|
"omp.loop_nest" (%arg0, %arg1, %arg2) ({
|
|
^bb1(%iv2: index):
|
|
"omp.yield"() : () -> ()
|
|
}) : (index, index, index) -> ()
|
|
}) {alignments = [32],
|
|
operandSegmentSizes = array<i32: 1, 0, 0, 0, 0, 0, 0>} : (memref<i32>) -> ()
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: omp_simd_nontemporal_list
|
|
func.func @omp_simd_nontemporal_list(%arg0 : index, %arg1 : index,
|
|
%arg2 : index, %arg3 : memref<i32>,
|
|
%arg4 : memref<i64>) -> () {
|
|
// CHECK: omp.simd nontemporal(%{{.*}}, %{{.*}} : memref<i32>, memref<i64>)
|
|
"omp.simd"(%arg3, %arg4) ({
|
|
"omp.loop_nest" (%arg0, %arg1, %arg2) ({
|
|
^bb1(%iv2: index):
|
|
"omp.yield"() : () -> ()
|
|
}) : (index, index, index) -> ()
|
|
}) {operandSegmentSizes = array<i32: 0, 0, 0, 0, 2, 0, 0>} : (memref<i32>, memref<i64>) -> ()
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: omp_simd_nontemporal_single
|
|
func.func @omp_simd_nontemporal_single(%arg0 : index, %arg1 : index,
|
|
%arg2 : index, %arg3 : memref<i32>,
|
|
%arg4 : memref<i64>) -> () {
|
|
// CHECK: omp.simd nontemporal(%{{.*}} : memref<i32>)
|
|
"omp.simd"(%arg3) ({
|
|
"omp.loop_nest" (%arg0, %arg1, %arg2) ({
|
|
^bb1(%iv2: index):
|
|
"omp.yield"() : () -> ()
|
|
}) : (index, index, index) -> ()
|
|
}) {operandSegmentSizes = array<i32: 0, 0, 0, 0, 1, 0, 0>} : (memref<i32>) -> ()
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: omp_simd_pretty
|
|
func.func @omp_simd_pretty(%lb : index, %ub : index, %step : index) -> () {
|
|
// CHECK: omp.simd {
|
|
omp.simd {
|
|
omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
|
|
omp.yield
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: func.func @omp_simd_pretty_aligned(
|
|
func.func @omp_simd_pretty_aligned(%lb : index, %ub : index, %step : index,
|
|
%data_var : memref<i32>,
|
|
%data_var1 : memref<i32>) -> () {
|
|
// CHECK: omp.simd aligned(
|
|
// CHECK-SAME: %{{.*}} : memref<i32> -> 32 : i64,
|
|
// CHECK-SAME: %{{.*}} : memref<i32> -> 128 : i64)
|
|
omp.simd aligned(%data_var : memref<i32> -> 32, %data_var1 : memref<i32> -> 128) {
|
|
omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
|
|
omp.yield
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: omp_simd_pretty_if
|
|
func.func @omp_simd_pretty_if(%lb : index, %ub : index, %step : index, %if_cond : i1) -> () {
|
|
// CHECK: omp.simd if(%{{.*}})
|
|
omp.simd if(%if_cond) {
|
|
omp.loop_nest (%iv): index = (%lb) to (%ub) step (%step) {
|
|
omp.yield
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: func.func @omp_simd_pretty_nontemporal
|
|
func.func @omp_simd_pretty_nontemporal(%lb : index, %ub : index, %step : index,
|
|
%data_var : memref<i32>,
|
|
%data_var1 : memref<i32>) -> () {
|
|
// CHECK: omp.simd nontemporal(%{{.*}}, %{{.*}} : memref<i32>, memref<i32>)
|
|
omp.simd nontemporal(%data_var, %data_var1 : memref<i32>, memref<i32>) {
|
|
omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
|
|
omp.yield
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: omp_simd_pretty_order
|
|
func.func @omp_simd_pretty_order(%lb : index, %ub : index, %step : index) -> () {
|
|
// CHECK: omp.simd order(concurrent)
|
|
omp.simd order(concurrent) {
|
|
omp.loop_nest (%iv): index = (%lb) to (%ub) step (%step) {
|
|
omp.yield
|
|
}
|
|
}
|
|
// CHECK: omp.simd order(reproducible:concurrent)
|
|
omp.simd order(reproducible:concurrent) {
|
|
omp.loop_nest (%iv): index = (%lb) to (%ub) step (%step) {
|
|
omp.yield
|
|
}
|
|
}
|
|
// CHECK: omp.simd order(unconstrained:concurrent)
|
|
omp.simd order(unconstrained:concurrent) {
|
|
omp.loop_nest (%iv): index = (%lb) to (%ub) step (%step) {
|
|
omp.yield
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: omp_simd_pretty_simdlen
|
|
func.func @omp_simd_pretty_simdlen(%lb : index, %ub : index, %step : index) -> () {
|
|
// CHECK: omp.simd simdlen(2)
|
|
omp.simd simdlen(2) {
|
|
omp.loop_nest (%iv): index = (%lb) to (%ub) step (%step) {
|
|
omp.yield
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: omp_simd_pretty_safelen
|
|
func.func @omp_simd_pretty_safelen(%lb : index, %ub : index, %step : index) -> () {
|
|
// CHECK: omp.simd safelen(2)
|
|
omp.simd safelen(2) {
|
|
omp.loop_nest (%iv): index = (%lb) to (%ub) step (%step) {
|
|
omp.yield
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: omp_distribute
|
|
func.func @omp_distribute(%chunk_size : i32, %data_var : memref<i32>, %arg0 : i32) -> () {
|
|
// CHECK: omp.distribute
|
|
"omp.distribute" () ({
|
|
"omp.loop_nest" (%arg0, %arg0, %arg0) ({
|
|
^bb0(%iv: i32):
|
|
"omp.yield"() : () -> ()
|
|
}) : (i32, i32, i32) -> ()
|
|
}) {} : () -> ()
|
|
// CHECK: omp.distribute
|
|
omp.distribute {
|
|
omp.loop_nest (%iv) : i32 = (%arg0) to (%arg0) step (%arg0) {
|
|
omp.yield
|
|
}
|
|
}
|
|
// CHECK: omp.distribute dist_schedule_static
|
|
omp.distribute dist_schedule_static {
|
|
omp.loop_nest (%iv) : i32 = (%arg0) to (%arg0) step (%arg0) {
|
|
omp.yield
|
|
}
|
|
}
|
|
// CHECK: omp.distribute dist_schedule_static dist_schedule_chunk_size(%{{.+}} : i32)
|
|
omp.distribute dist_schedule_static dist_schedule_chunk_size(%chunk_size : i32) {
|
|
omp.loop_nest (%iv) : i32 = (%arg0) to (%arg0) step (%arg0) {
|
|
omp.yield
|
|
}
|
|
}
|
|
// CHECK: omp.distribute order(concurrent)
|
|
omp.distribute order(concurrent) {
|
|
omp.loop_nest (%iv) : i32 = (%arg0) to (%arg0) step (%arg0) {
|
|
omp.yield
|
|
}
|
|
}
|
|
// CHECK: omp.distribute order(reproducible:concurrent)
|
|
omp.distribute order(reproducible:concurrent) {
|
|
omp.loop_nest (%iv) : i32 = (%arg0) to (%arg0) step (%arg0) {
|
|
omp.yield
|
|
}
|
|
}
|
|
// CHECK: omp.distribute order(unconstrained:concurrent)
|
|
omp.distribute order(unconstrained:concurrent) {
|
|
omp.loop_nest (%iv) : i32 = (%arg0) to (%arg0) step (%arg0) {
|
|
omp.yield
|
|
}
|
|
}
|
|
// CHECK: omp.distribute allocate(%{{.+}} : memref<i32> -> %{{.+}} : memref<i32>)
|
|
omp.distribute allocate(%data_var : memref<i32> -> %data_var : memref<i32>) {
|
|
omp.loop_nest (%iv) : i32 = (%arg0) to (%arg0) step (%arg0) {
|
|
omp.yield
|
|
}
|
|
}
|
|
// CHECK: omp.distribute
|
|
omp.distribute {
|
|
omp.simd {
|
|
omp.loop_nest (%iv) : i32 = (%arg0) to (%arg0) step (%arg0) {
|
|
omp.yield
|
|
}
|
|
} {omp.composite}
|
|
} {omp.composite}
|
|
return
|
|
}
|
|
|
|
|
|
// CHECK-LABEL: omp_target
|
|
func.func @omp_target(%if_cond : i1, %device : si32, %num_threads : i32, %device_ptr: memref<i32>, %device_addr: memref<?xi32>, %map1: memref<?xi32>, %map2: memref<?xi32>) -> () {
|
|
|
|
// Test with optional operands; if_expr, device, thread_limit, private, firstprivate and nowait.
|
|
// CHECK: omp.target device({{.*}}) if({{.*}}) nowait thread_limit({{.*}})
|
|
"omp.target"(%device, %if_cond, %num_threads) ({
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}) {nowait, operandSegmentSizes = array<i32: 0,0,0,1,0,0,1,0,0,0,0,1>} : ( si32, i1, i32 ) -> ()
|
|
|
|
// Test with optional map clause.
|
|
// CHECK: %[[MAP_A:.*]] = omp.map.info var_ptr(%[[VAL_1:.*]] : memref<?xi32>, tensor<?xi32>) map_clauses(tofrom) capture(ByRef) -> memref<?xi32> {name = ""}
|
|
// CHECK: %[[MAP_B:.*]] = omp.map.info var_ptr(%[[VAL_2:.*]] : memref<?xi32>, tensor<?xi32>) map_clauses(exit_release_or_enter_alloc) capture(ByRef) -> memref<?xi32> {name = ""}
|
|
// CHECK: omp.target has_device_addr(%[[VAL_5:.*]] : memref<?xi32>) is_device_ptr(%[[VAL_4:.*]] : memref<i32>) map_entries(%[[MAP_A]] -> {{.*}}, %[[MAP_B]] -> {{.*}} : memref<?xi32>, memref<?xi32>) {
|
|
%mapv1 = omp.map.info var_ptr(%map1 : memref<?xi32>, tensor<?xi32>) map_clauses(tofrom) capture(ByRef) -> memref<?xi32> {name = ""}
|
|
%mapv2 = omp.map.info var_ptr(%map2 : memref<?xi32>, tensor<?xi32>) map_clauses(exit_release_or_enter_alloc) capture(ByRef) -> memref<?xi32> {name = ""}
|
|
omp.target is_device_ptr(%device_ptr : memref<i32>) has_device_addr(%device_addr : memref<?xi32>) map_entries(%mapv1 -> %arg0, %mapv2 -> %arg1 : memref<?xi32>, memref<?xi32>) {
|
|
omp.terminator
|
|
}
|
|
// CHECK: %[[MAP_C:.*]] = omp.map.info var_ptr(%[[VAL_1:.*]] : memref<?xi32>, tensor<?xi32>) map_clauses(to) capture(ByRef) -> memref<?xi32> {name = ""}
|
|
// CHECK: %[[MAP_D:.*]] = omp.map.info var_ptr(%[[VAL_2:.*]] : memref<?xi32>, tensor<?xi32>) map_clauses(always, from) capture(ByRef) -> memref<?xi32> {name = ""}
|
|
// CHECK: omp.target map_entries(%[[MAP_C]] -> {{.*}}, %[[MAP_D]] -> {{.*}} : memref<?xi32>, memref<?xi32>) {
|
|
%mapv3 = omp.map.info var_ptr(%map1 : memref<?xi32>, tensor<?xi32>) map_clauses(to) capture(ByRef) -> memref<?xi32> {name = ""}
|
|
%mapv4 = omp.map.info var_ptr(%map2 : memref<?xi32>, tensor<?xi32>) map_clauses(always, from) capture(ByRef) -> memref<?xi32> {name = ""}
|
|
omp.target map_entries(%mapv3 -> %arg0, %mapv4 -> %arg1 : memref<?xi32>, memref<?xi32>) {
|
|
omp.terminator
|
|
}
|
|
// CHECK: omp.barrier
|
|
omp.barrier
|
|
|
|
return
|
|
}
|
|
|
|
func.func @omp_target_data (%if_cond : i1, %device : si32, %device_ptr: memref<i32>, %device_addr: memref<?xi32>, %map1: memref<?xi32>, %map2: memref<?xi32>) -> () {
|
|
// CHECK: %[[MAP_A:.*]] = omp.map.info var_ptr(%[[VAL_2:.*]] : memref<?xi32>, tensor<?xi32>) map_clauses(always, from) capture(ByRef) -> memref<?xi32> {name = ""}
|
|
// CHECK: omp.target_data device(%[[VAL_1:.*]] : si32) if(%[[VAL_0:.*]]) map_entries(%[[MAP_A]] : memref<?xi32>)
|
|
%mapv1 = omp.map.info var_ptr(%map1 : memref<?xi32>, tensor<?xi32>) map_clauses(always, from) capture(ByRef) -> memref<?xi32> {name = ""}
|
|
omp.target_data if(%if_cond) device(%device : si32) map_entries(%mapv1 : memref<?xi32>){}
|
|
|
|
// CHECK: %[[MAP_A:.*]] = omp.map.info var_ptr(%[[VAL_2:.*]] : memref<?xi32>, tensor<?xi32>) map_clauses(close, present, to) capture(ByRef) -> memref<?xi32> {name = ""}
|
|
// CHECK: omp.target_data map_entries(%[[MAP_A]] : memref<?xi32>) use_device_addr(%[[VAL_3:.*]] -> %{{.*}} : memref<?xi32>) use_device_ptr(%[[VAL_4:.*]] -> %{{.*}} : memref<i32>)
|
|
%mapv2 = omp.map.info var_ptr(%map1 : memref<?xi32>, tensor<?xi32>) map_clauses(close, present, to) capture(ByRef) -> memref<?xi32> {name = ""}
|
|
omp.target_data map_entries(%mapv2 : memref<?xi32>) use_device_addr(%device_addr -> %arg0 : memref<?xi32>) use_device_ptr(%device_ptr -> %arg1 : memref<i32>) {
|
|
omp.terminator
|
|
}
|
|
|
|
// CHECK: %[[MAP_A:.*]] = omp.map.info var_ptr(%[[VAL_1:.*]] : memref<?xi32>, tensor<?xi32>) map_clauses(tofrom) capture(ByRef) -> memref<?xi32> {name = ""}
|
|
// CHECK: %[[MAP_B:.*]] = omp.map.info var_ptr(%[[VAL_2:.*]] : memref<?xi32>, tensor<?xi32>) map_clauses(exit_release_or_enter_alloc) capture(ByRef) -> memref<?xi32> {name = ""}
|
|
// CHECK: omp.target_data map_entries(%[[MAP_A]], %[[MAP_B]] : memref<?xi32>, memref<?xi32>)
|
|
%mapv3 = omp.map.info var_ptr(%map1 : memref<?xi32>, tensor<?xi32>) map_clauses(tofrom) capture(ByRef) -> memref<?xi32> {name = ""}
|
|
%mapv4 = omp.map.info var_ptr(%map2 : memref<?xi32>, tensor<?xi32>) map_clauses(exit_release_or_enter_alloc) capture(ByRef) -> memref<?xi32> {name = ""}
|
|
omp.target_data map_entries(%mapv3, %mapv4 : memref<?xi32>, memref<?xi32>) {}
|
|
|
|
// CHECK: %[[MAP_A:.*]] = omp.map.info var_ptr(%[[VAL_3:.*]] : memref<?xi32>, tensor<?xi32>) map_clauses(exit_release_or_enter_alloc) capture(ByRef) -> memref<?xi32> {name = ""}
|
|
// CHECK: omp.target_enter_data device(%[[VAL_1:.*]] : si32) if(%[[VAL_0:.*]]) map_entries(%[[MAP_A]] : memref<?xi32>) nowait
|
|
%mapv5 = omp.map.info var_ptr(%map1 : memref<?xi32>, tensor<?xi32>) map_clauses(exit_release_or_enter_alloc) capture(ByRef) -> memref<?xi32> {name = ""}
|
|
omp.target_enter_data if(%if_cond) device(%device : si32) nowait map_entries(%mapv5 : memref<?xi32>)
|
|
|
|
// CHECK: %[[MAP_A:.*]] = omp.map.info var_ptr(%[[VAL_3:.*]] : memref<?xi32>, tensor<?xi32>) map_clauses(exit_release_or_enter_alloc) capture(ByRef) -> memref<?xi32> {name = ""}
|
|
// CHECK: omp.target_exit_data device(%[[VAL_1:.*]] : si32) if(%[[VAL_0:.*]]) map_entries(%[[MAP_A]] : memref<?xi32>) nowait
|
|
%mapv6 = omp.map.info var_ptr(%map2 : memref<?xi32>, tensor<?xi32>) map_clauses(exit_release_or_enter_alloc) capture(ByRef) -> memref<?xi32> {name = ""}
|
|
omp.target_exit_data if(%if_cond) device(%device : si32) nowait map_entries(%mapv6 : memref<?xi32>)
|
|
|
|
// CHECK: %[[MAP_A:.*]] = omp.map.info var_ptr(%[[VAL_2:.*]] : memref<?xi32>, tensor<?xi32>) map_clauses(ompx_hold, to) capture(ByRef) -> memref<?xi32> {name = ""}
|
|
// CHECK: omp.target_data map_entries(%[[MAP_A]] : memref<?xi32>)
|
|
%mapv7 = omp.map.info var_ptr(%map1 : memref<?xi32>, tensor<?xi32>) map_clauses(ompx_hold, to) capture(ByRef) -> memref<?xi32> {name = ""}
|
|
omp.target_data map_entries(%mapv7 : memref<?xi32>) {
|
|
omp.terminator
|
|
}
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: omp_target_pretty
|
|
func.func @omp_target_pretty(%if_cond : i1, %device : si32, %num_threads : i32) -> () {
|
|
// CHECK: omp.target device({{.*}}) if({{.*}})
|
|
omp.target if(%if_cond) device(%device : si32) {
|
|
omp.terminator
|
|
}
|
|
|
|
// CHECK: omp.target device({{.*}}) if({{.*}}) nowait
|
|
omp.target if(%if_cond) device(%device : si32) thread_limit(%num_threads : i32) nowait {
|
|
omp.terminator
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// CHECK: omp.declare_reduction
|
|
// CHECK-LABEL: @add_f32
|
|
// CHECK: : f32
|
|
// CHECK: init
|
|
// CHECK: ^{{.+}}(%{{.+}}: f32):
|
|
// CHECK: omp.yield
|
|
// CHECK: combiner
|
|
// CHECK: ^{{.+}}(%{{.+}}: f32, %{{.+}}: f32):
|
|
// CHECK: omp.yield
|
|
// CHECK: atomic
|
|
// CHECK: ^{{.+}}(%{{.+}}: !llvm.ptr, %{{.+}}: !llvm.ptr):
|
|
// CHECK: omp.yield
|
|
// CHECK: cleanup
|
|
// CHECK: omp.yield
|
|
omp.declare_reduction @add_f32 : f32
|
|
init {
|
|
^bb0(%arg: f32):
|
|
%0 = arith.constant 0.0 : f32
|
|
omp.yield (%0 : f32)
|
|
}
|
|
combiner {
|
|
^bb1(%arg0: f32, %arg1: f32):
|
|
%1 = arith.addf %arg0, %arg1 : f32
|
|
omp.yield (%1 : f32)
|
|
}
|
|
atomic {
|
|
^bb2(%arg2: !llvm.ptr, %arg3: !llvm.ptr):
|
|
%2 = llvm.load %arg3 : !llvm.ptr -> f32
|
|
llvm.atomicrmw fadd %arg2, %2 monotonic : !llvm.ptr, f32
|
|
omp.yield
|
|
}
|
|
cleanup {
|
|
^bb0(%arg: f32):
|
|
omp.yield
|
|
}
|
|
|
|
// CHECK: omp.declare_mapper @my_mapper : !llvm.struct<"my_type", (i32)>
|
|
omp.declare_mapper @my_mapper : !llvm.struct<"my_type", (i32)> {
|
|
^bb0(%arg: !llvm.ptr):
|
|
// CHECK: %[[DECL_MAP_INFO:.*]] = omp.map.info var_ptr(%{{.*}} : !llvm.ptr, !llvm.struct<"my_type", (i32)>) map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {name = ""}
|
|
%decl_map_info = omp.map.info var_ptr(%arg : !llvm.ptr, !llvm.struct<"my_type", (i32)>) map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {name = ""}
|
|
// CHECK: omp.declare_mapper.info map_entries(%[[DECL_MAP_INFO]] : !llvm.ptr)
|
|
omp.declare_mapper.info map_entries(%decl_map_info : !llvm.ptr)
|
|
}
|
|
|
|
// CHECK-LABEL: func @wsloop_reduction
|
|
func.func @wsloop_reduction(%lb : index, %ub : index, %step : index) {
|
|
%c1 = arith.constant 1 : i32
|
|
%0 = llvm.alloca %c1 x i32 : (i32) -> !llvm.ptr
|
|
// CHECK: reduction(@add_f32 %{{.+}} -> %[[PRV:.+]] : !llvm.ptr)
|
|
omp.wsloop reduction(@add_f32 %0 -> %prv : !llvm.ptr) {
|
|
omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
|
|
// CHECK: %[[CST:.+]] = arith.constant 2.0{{.*}} : f32
|
|
%cst = arith.constant 2.0 : f32
|
|
// CHECK: %[[LPRV:.+]] = llvm.load %[[PRV]] : !llvm.ptr -> f32
|
|
%lprv = llvm.load %prv : !llvm.ptr -> f32
|
|
// CHECK: %[[RES:.+]] = llvm.fadd %[[LPRV]], %[[CST]] : f32
|
|
%res = llvm.fadd %lprv, %cst: f32
|
|
// CHECK: llvm.store %[[RES]], %[[PRV]] : f32, !llvm.ptr
|
|
llvm.store %res, %prv : f32, !llvm.ptr
|
|
omp.yield
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: func @wsloop_inscan_reduction
|
|
func.func @wsloop_inscan_reduction(%lb : index, %ub : index, %step : index) {
|
|
%c1 = arith.constant 1 : i32
|
|
%0 = llvm.alloca %c1 x i32 : (i32) -> !llvm.ptr
|
|
// CHECK: reduction(mod: inscan, @add_f32 %{{.+}} -> %[[PRV:.+]] : !llvm.ptr)
|
|
omp.wsloop reduction(mod:inscan, @add_f32 %0 -> %prv : !llvm.ptr) {
|
|
omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
|
|
// CHECK: omp.scan inclusive(%{{.*}} : !llvm.ptr)
|
|
omp.scan inclusive(%prv : !llvm.ptr)
|
|
omp.yield
|
|
}
|
|
}
|
|
// CHECK: reduction(mod: inscan, @add_f32 %{{.+}} -> %[[PRV:.+]] : !llvm.ptr)
|
|
omp.wsloop reduction(mod:inscan, @add_f32 %0 -> %prv : !llvm.ptr) {
|
|
omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
|
|
// CHECK: omp.scan exclusive(%{{.*}} : !llvm.ptr)
|
|
omp.scan exclusive(%prv : !llvm.ptr)
|
|
omp.yield
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: func @wsloop_reduction_byref
|
|
func.func @wsloop_reduction_byref(%lb : index, %ub : index, %step : index) {
|
|
%c1 = arith.constant 1 : i32
|
|
%0 = llvm.alloca %c1 x i32 : (i32) -> !llvm.ptr
|
|
// CHECK: reduction(byref @add_f32 %{{.+}} -> %[[PRV:.+]] : !llvm.ptr)
|
|
omp.wsloop reduction(byref @add_f32 %0 -> %prv : !llvm.ptr) {
|
|
omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
|
|
// CHECK: %[[CST:.+]] = arith.constant 2.0{{.*}} : f32
|
|
%cst = arith.constant 2.0 : f32
|
|
// CHECK: %[[LPRV:.+]] = llvm.load %[[PRV]] : !llvm.ptr -> f32
|
|
%lprv = llvm.load %prv : !llvm.ptr -> f32
|
|
// CHECK: %[[RES:.+]] = llvm.fadd %[[LPRV]], %[[CST]] : f32
|
|
%res = llvm.fadd %lprv, %cst: f32
|
|
// CHECK: llvm.store %[[RES]], %[[PRV]] : f32, !llvm.ptr
|
|
llvm.store %res, %prv : f32, !llvm.ptr
|
|
omp.yield
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: func @parallel_reduction
|
|
func.func @parallel_reduction() {
|
|
%c1 = arith.constant 1 : i32
|
|
%0 = llvm.alloca %c1 x i32 : (i32) -> !llvm.ptr
|
|
// CHECK: omp.parallel reduction(@add_f32 {{.+}} -> {{.+}} : !llvm.ptr)
|
|
omp.parallel reduction(@add_f32 %0 -> %prv : !llvm.ptr) {
|
|
%1 = arith.constant 2.0 : f32
|
|
%2 = llvm.load %prv : !llvm.ptr -> f32
|
|
// CHECK: llvm.fadd %{{.*}}, %{{.*}} : f32
|
|
%3 = llvm.fadd %1, %2 : f32
|
|
llvm.store %3, %prv : f32, !llvm.ptr
|
|
omp.terminator
|
|
}
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: func @parallel_reduction_byref
|
|
func.func @parallel_reduction_byref() {
|
|
%c1 = arith.constant 1 : i32
|
|
%0 = llvm.alloca %c1 x i32 : (i32) -> !llvm.ptr
|
|
// CHECK: omp.parallel reduction(byref @add_f32 {{.+}} -> {{.+}} : !llvm.ptr)
|
|
omp.parallel reduction(byref @add_f32 %0 -> %prv : !llvm.ptr) {
|
|
%1 = arith.constant 2.0 : f32
|
|
%2 = llvm.load %prv : !llvm.ptr -> f32
|
|
// CHECK: llvm.fadd %{{.*}}, %{{.*}} : f32
|
|
%3 = llvm.fadd %1, %2 : f32
|
|
llvm.store %3, %prv : f32, !llvm.ptr
|
|
omp.terminator
|
|
}
|
|
return
|
|
}
|
|
|
|
// CHECK: func @parallel_wsloop_reduction
|
|
func.func @parallel_wsloop_reduction(%lb : index, %ub : index, %step : index) {
|
|
%c1 = arith.constant 1 : i32
|
|
%0 = llvm.alloca %c1 x i32 : (i32) -> !llvm.ptr
|
|
// CHECK: omp.parallel {
|
|
omp.parallel {
|
|
// CHECK: omp.wsloop reduction(@add_f32 %{{.*}} -> %{{.+}} : !llvm.ptr) {
|
|
omp.wsloop reduction(@add_f32 %0 -> %prv : !llvm.ptr) {
|
|
// CHECK: omp.loop_nest (%{{.+}}) : index = (%{{.+}}) to (%{{.+}}) step (%{{.+}}) {
|
|
omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
|
|
%1 = arith.constant 2.0 : f32
|
|
%2 = llvm.load %prv : !llvm.ptr -> f32
|
|
// CHECK: llvm.fadd %{{.+}}, %{{.+}} : f32
|
|
llvm.fadd %1, %2 : f32
|
|
// CHECK: omp.yield
|
|
omp.yield
|
|
}
|
|
}
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: omp_teams
|
|
func.func @omp_teams(%lb : i32, %ub : i32, %if_cond : i1, %num_threads : i32,
|
|
%data_var : memref<i32>) -> () {
|
|
// Test nesting inside of omp.target
|
|
omp.target {
|
|
// CHECK: omp.teams
|
|
omp.teams {
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
|
|
// CHECK: omp.teams
|
|
omp.teams {
|
|
%0 = arith.constant 1 : i32
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
|
|
// Test num teams.
|
|
// CHECK: omp.teams num_teams(%{{.+}} : i32 to %{{.+}} : i32)
|
|
omp.teams num_teams(%lb : i32 to %ub : i32) {
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
|
|
// CHECK: omp.teams num_teams( to %{{.+}} : i32)
|
|
omp.teams num_teams(to %ub : i32) {
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
|
|
// Test if.
|
|
// CHECK: omp.teams if(%{{.+}})
|
|
omp.teams if(%if_cond) {
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
|
|
// Test thread limit.
|
|
// CHECK: omp.teams thread_limit(%{{.+}} : i32)
|
|
omp.teams thread_limit(%num_threads : i32) {
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
|
|
// Test reduction.
|
|
%c1 = arith.constant 1 : i32
|
|
%0 = llvm.alloca %c1 x i32 : (i32) -> !llvm.ptr
|
|
// CHECK: omp.teams reduction(@add_f32 %{{.+}} -> %{{.+}} : !llvm.ptr) {
|
|
omp.teams reduction(@add_f32 %0 -> %arg0 : !llvm.ptr) {
|
|
%1 = arith.constant 2.0 : f32
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
|
|
// Test reduction byref
|
|
// CHECK: omp.teams reduction(byref @add_f32 %{{.+}} -> %{{.+}} : !llvm.ptr) {
|
|
omp.teams reduction(byref @add_f32 %0 -> %arg0 : !llvm.ptr) {
|
|
%1 = arith.constant 2.0 : f32
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
|
|
// Test allocate.
|
|
// CHECK: omp.teams allocate(%{{.+}} : memref<i32> -> %{{.+}} : memref<i32>)
|
|
omp.teams allocate(%data_var : memref<i32> -> %data_var : memref<i32>) {
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: func @sections_reduction
|
|
func.func @sections_reduction() {
|
|
%c1 = arith.constant 1 : i32
|
|
%0 = llvm.alloca %c1 x i32 : (i32) -> !llvm.ptr
|
|
// CHECK: omp.sections reduction(@add_f32 %{{.+}} -> {{.+}} : !llvm.ptr)
|
|
omp.sections reduction(@add_f32 %0 -> %arg0 : !llvm.ptr) {
|
|
// CHECK: omp.section
|
|
omp.section {
|
|
^bb0(%arg1 : !llvm.ptr):
|
|
%1 = arith.constant 2.0 : f32
|
|
omp.terminator
|
|
}
|
|
// CHECK: omp.section
|
|
omp.section {
|
|
^bb0(%arg1 : !llvm.ptr):
|
|
%1 = arith.constant 3.0 : f32
|
|
omp.terminator
|
|
}
|
|
omp.terminator
|
|
}
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: func @sections_reduction_byref
|
|
func.func @sections_reduction_byref() {
|
|
%c1 = arith.constant 1 : i32
|
|
%0 = llvm.alloca %c1 x i32 : (i32) -> !llvm.ptr
|
|
// CHECK: omp.sections reduction(byref @add_f32 %{{.+}} -> {{.+}} : !llvm.ptr)
|
|
omp.sections reduction(byref @add_f32 %0 -> %arg0 : !llvm.ptr) {
|
|
// CHECK: omp.section
|
|
omp.section {
|
|
^bb0(%arg1 : !llvm.ptr):
|
|
%1 = arith.constant 2.0 : f32
|
|
omp.terminator
|
|
}
|
|
// CHECK: omp.section
|
|
omp.section {
|
|
^bb0(%arg1 : !llvm.ptr):
|
|
%1 = arith.constant 3.0 : f32
|
|
omp.terminator
|
|
}
|
|
omp.terminator
|
|
}
|
|
return
|
|
}
|
|
|
|
// CHECK: omp.declare_reduction
|
|
// CHECK-LABEL: @add2_f32
|
|
omp.declare_reduction @add2_f32 : f32
|
|
// CHECK: init
|
|
init {
|
|
^bb0(%arg: f32):
|
|
%0 = arith.constant 0.0 : f32
|
|
omp.yield (%0 : f32)
|
|
}
|
|
// CHECK: combiner
|
|
combiner {
|
|
^bb1(%arg0: f32, %arg1: f32):
|
|
%1 = arith.addf %arg0, %arg1 : f32
|
|
omp.yield (%1 : f32)
|
|
}
|
|
// CHECK-NOT: atomic
|
|
// CHECK-NOT: cleanup
|
|
|
|
// CHECK-LABEL: func @wsloop_reduction2
|
|
func.func @wsloop_reduction2(%lb : index, %ub : index, %step : index) {
|
|
%0 = memref.alloca() : memref<1xf32>
|
|
// CHECK: omp.wsloop reduction(@add2_f32 %{{.+}} -> %{{.+}} : memref<1xf32>) {
|
|
omp.wsloop reduction(@add2_f32 %0 -> %prv : memref<1xf32>) {
|
|
omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
|
|
%1 = arith.constant 2.0 : f32
|
|
%2 = arith.constant 0 : index
|
|
%3 = memref.load %prv[%2] : memref<1xf32>
|
|
// CHECK: llvm.fadd
|
|
%4 = llvm.fadd %1, %3 : f32
|
|
memref.store %4, %prv[%2] : memref<1xf32>
|
|
omp.yield
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: func @parallel_reduction2
|
|
func.func @parallel_reduction2() {
|
|
%0 = memref.alloca() : memref<1xf32>
|
|
// CHECK: omp.parallel reduction(@add2_f32 %{{.+}} -> %{{.+}} : memref<1xf32>)
|
|
omp.parallel reduction(@add2_f32 %0 -> %prv : memref<1xf32>) {
|
|
%1 = arith.constant 2.0 : f32
|
|
%2 = arith.constant 0 : index
|
|
%3 = memref.load %prv[%2] : memref<1xf32>
|
|
// CHECK: llvm.fadd
|
|
%4 = llvm.fadd %1, %3 : f32
|
|
memref.store %4, %prv[%2] : memref<1xf32>
|
|
omp.terminator
|
|
}
|
|
return
|
|
}
|
|
|
|
// CHECK: func @parallel_wsloop_reduction2
|
|
func.func @parallel_wsloop_reduction2(%lb : index, %ub : index, %step : index) {
|
|
%c1 = arith.constant 1 : i32
|
|
%0 = llvm.alloca %c1 x i32 : (i32) -> !llvm.ptr
|
|
// CHECK: omp.parallel {
|
|
omp.parallel {
|
|
// CHECK: omp.wsloop reduction(@add2_f32 %{{.*}} -> %{{.+}} : !llvm.ptr) {
|
|
omp.wsloop reduction(@add2_f32 %0 -> %prv : !llvm.ptr) {
|
|
// CHECK: omp.loop_nest (%{{.+}}) : index = (%{{.+}}) to (%{{.+}}) step (%{{.+}}) {
|
|
omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
|
|
%1 = arith.constant 2.0 : f32
|
|
%2 = llvm.load %prv : !llvm.ptr -> f32
|
|
// CHECK: llvm.fadd %{{.+}}, %{{.+}} : f32
|
|
%3 = llvm.fadd %1, %2 : f32
|
|
// CHECK: omp.yield
|
|
omp.yield
|
|
}
|
|
}
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: func @sections_reduction2
|
|
func.func @sections_reduction2() {
|
|
%0 = memref.alloca() : memref<1xf32>
|
|
// CHECK: omp.sections reduction(@add2_f32 %{{.+}} -> %{{.+}} : memref<1xf32>)
|
|
omp.sections reduction(@add2_f32 %0 -> %arg0 : memref<1xf32>) {
|
|
omp.section {
|
|
^bb0(%arg1 : !llvm.ptr):
|
|
%1 = arith.constant 2.0 : f32
|
|
omp.terminator
|
|
}
|
|
omp.section {
|
|
^bb0(%arg1 : !llvm.ptr):
|
|
%1 = arith.constant 2.0 : f32
|
|
omp.terminator
|
|
}
|
|
omp.terminator
|
|
}
|
|
return
|
|
}
|
|
|
|
// CHECK: omp.critical.declare @mutex1 hint(uncontended)
|
|
omp.critical.declare @mutex1 hint(uncontended)
|
|
// CHECK: omp.critical.declare @mutex2 hint(contended)
|
|
omp.critical.declare @mutex2 hint(contended)
|
|
// CHECK: omp.critical.declare @mutex3 hint(nonspeculative)
|
|
omp.critical.declare @mutex3 hint(nonspeculative)
|
|
// CHECK: omp.critical.declare @mutex4 hint(speculative)
|
|
omp.critical.declare @mutex4 hint(speculative)
|
|
// CHECK: omp.critical.declare @mutex5 hint(uncontended, nonspeculative)
|
|
omp.critical.declare @mutex5 hint(uncontended, nonspeculative)
|
|
// CHECK: omp.critical.declare @mutex6 hint(contended, nonspeculative)
|
|
omp.critical.declare @mutex6 hint(contended, nonspeculative)
|
|
// CHECK: omp.critical.declare @mutex7 hint(uncontended, speculative)
|
|
omp.critical.declare @mutex7 hint(uncontended, speculative)
|
|
// CHECK: omp.critical.declare @mutex8 hint(contended, speculative)
|
|
omp.critical.declare @mutex8 hint(contended, speculative)
|
|
// CHECK: omp.critical.declare @mutex9
|
|
omp.critical.declare @mutex9 hint(none)
|
|
// CHECK: omp.critical.declare @mutex10
|
|
omp.critical.declare @mutex10
|
|
|
|
|
|
// CHECK-LABEL: omp_critical
|
|
func.func @omp_critical() -> () {
|
|
// CHECK: omp.critical
|
|
omp.critical {
|
|
omp.terminator
|
|
}
|
|
|
|
// CHECK: omp.critical(@{{.*}})
|
|
omp.critical(@mutex1) {
|
|
omp.terminator
|
|
}
|
|
return
|
|
}
|
|
|
|
func.func @omp_ordered(%arg1 : i32, %arg2 : i32, %arg3 : i32,
|
|
%vec0 : i64, %vec1 : i64, %vec2 : i64, %vec3 : i64) -> () {
|
|
// CHECK: omp.ordered.region
|
|
omp.ordered.region {
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
|
|
omp.wsloop ordered(0) {
|
|
omp.loop_nest (%0) : i32 = (%arg1) to (%arg2) step (%arg3) {
|
|
// CHECK: omp.ordered.region
|
|
omp.ordered.region {
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
omp.yield
|
|
}
|
|
}
|
|
|
|
omp.wsloop ordered(1) {
|
|
omp.loop_nest (%0) : i32 = (%arg1) to (%arg2) step (%arg3) {
|
|
// Only one DEPEND(SINK: vec) clause
|
|
// CHECK: omp.ordered depend_type(dependsink) depend_vec(%{{.*}} : i64) {doacross_num_loops = 1 : i64}
|
|
omp.ordered depend_type(dependsink) depend_vec(%vec0 : i64) {doacross_num_loops = 1 : i64}
|
|
|
|
// CHECK: omp.ordered depend_type(dependsource) depend_vec(%{{.*}} : i64) {doacross_num_loops = 1 : i64}
|
|
omp.ordered depend_type(dependsource) depend_vec(%vec0 : i64) {doacross_num_loops = 1 : i64}
|
|
|
|
omp.yield
|
|
}
|
|
}
|
|
|
|
omp.wsloop ordered(2) {
|
|
omp.loop_nest (%0) : i32 = (%arg1) to (%arg2) step (%arg3) {
|
|
// Multiple DEPEND(SINK: vec) clauses
|
|
// CHECK: omp.ordered depend_type(dependsink) depend_vec(%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}} : i64, i64, i64, i64) {doacross_num_loops = 2 : i64}
|
|
omp.ordered depend_type(dependsink) depend_vec(%vec0, %vec1, %vec2, %vec3 : i64, i64, i64, i64) {doacross_num_loops = 2 : i64}
|
|
|
|
// CHECK: omp.ordered depend_type(dependsource) depend_vec(%{{.*}}, %{{.*}} : i64, i64) {doacross_num_loops = 2 : i64}
|
|
omp.ordered depend_type(dependsource) depend_vec(%vec0, %vec1 : i64, i64) {doacross_num_loops = 2 : i64}
|
|
|
|
omp.yield
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: omp_atomic_read
|
|
// CHECK-SAME: (%[[v:.*]]: memref<i32>, %[[x:.*]]: memref<i32>)
|
|
func.func @omp_atomic_read(%v: memref<i32>, %x: memref<i32>) {
|
|
// CHECK: omp.atomic.read %[[v]] = %[[x]] : memref<i32>, memref<i32>, i32
|
|
omp.atomic.read %v = %x : memref<i32>, memref<i32>, i32
|
|
// CHECK: omp.atomic.read %[[v]] = %[[x]] memory_order(seq_cst) : memref<i32>, memref<i32>, i32
|
|
omp.atomic.read %v = %x memory_order(seq_cst) : memref<i32>, memref<i32>, i32
|
|
// CHECK: omp.atomic.read %[[v]] = %[[x]] memory_order(acquire) : memref<i32>, memref<i32>, i32
|
|
omp.atomic.read %v = %x memory_order(acquire) : memref<i32>, memref<i32>, i32
|
|
// CHECK: omp.atomic.read %[[v]] = %[[x]] memory_order(relaxed) : memref<i32>, memref<i32>, i32
|
|
omp.atomic.read %v = %x memory_order(relaxed) : memref<i32>, memref<i32>, i32
|
|
// CHECK: omp.atomic.read %[[v]] = %[[x]] hint(contended, nonspeculative) : memref<i32>, memref<i32>, i32
|
|
omp.atomic.read %v = %x hint(nonspeculative, contended) : memref<i32>, memref<i32>, i32
|
|
// CHECK: omp.atomic.read %[[v]] = %[[x]] hint(contended, speculative) memory_order(seq_cst) : memref<i32>, memref<i32>, i32
|
|
omp.atomic.read %v = %x hint(speculative, contended) memory_order(seq_cst) : memref<i32>, memref<i32>, i32
|
|
// CHECK: omp.atomic.read %[[v]] = %[[x]] memory_order(seq_cst) : memref<i32>, memref<i32>, i32
|
|
omp.atomic.read %v = %x hint(none) memory_order(seq_cst) : memref<i32>, memref<i32>, i32
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: omp_atomic_write
|
|
// CHECK-SAME: (%[[ADDR:.*]]: memref<i32>, %[[VAL:.*]]: i32)
|
|
func.func @omp_atomic_write(%addr : memref<i32>, %val : i32) {
|
|
// CHECK: omp.atomic.write %[[ADDR]] = %[[VAL]] : memref<i32>, i32
|
|
omp.atomic.write %addr = %val : memref<i32>, i32
|
|
// CHECK: omp.atomic.write %[[ADDR]] = %[[VAL]] memory_order(seq_cst) : memref<i32>, i32
|
|
omp.atomic.write %addr = %val memory_order(seq_cst) : memref<i32>, i32
|
|
// CHECK: omp.atomic.write %[[ADDR]] = %[[VAL]] memory_order(release) : memref<i32>, i32
|
|
omp.atomic.write %addr = %val memory_order(release) : memref<i32>, i32
|
|
// CHECK: omp.atomic.write %[[ADDR]] = %[[VAL]] memory_order(relaxed) : memref<i32>, i32
|
|
omp.atomic.write %addr = %val memory_order(relaxed) : memref<i32>, i32
|
|
// CHECK: omp.atomic.write %[[ADDR]] = %[[VAL]] hint(uncontended, speculative) : memref<i32>, i32
|
|
omp.atomic.write %addr = %val hint(speculative, uncontended) : memref<i32>, i32
|
|
// CHECK: omp.atomic.write %[[ADDR]] = %[[VAL]] : memref<i32>, i32
|
|
omp.atomic.write %addr = %val hint(none) : memref<i32>, i32
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: omp_atomic_update
|
|
// CHECK-SAME: (%[[X:.*]]: memref<i32>, %[[EXPR:.*]]: i32, %[[XBOOL:.*]]: memref<i1>, %[[EXPRBOOL:.*]]: i1)
|
|
func.func @omp_atomic_update(%x : memref<i32>, %expr : i32, %xBool : memref<i1>, %exprBool : i1) {
|
|
// CHECK: omp.atomic.update %[[X]] : memref<i32>
|
|
// CHECK-NEXT: (%[[XVAL:.*]]: i32):
|
|
// CHECK-NEXT: %[[NEWVAL:.*]] = llvm.add %[[XVAL]], %[[EXPR]] : i32
|
|
// CHECK-NEXT: omp.yield(%[[NEWVAL]] : i32)
|
|
omp.atomic.update %x : memref<i32> {
|
|
^bb0(%xval: i32):
|
|
%newval = llvm.add %xval, %expr : i32
|
|
omp.yield(%newval : i32)
|
|
}
|
|
// CHECK: omp.atomic.update %[[XBOOL]] : memref<i1>
|
|
// CHECK-NEXT: (%[[XVAL:.*]]: i1):
|
|
// CHECK-NEXT: %[[NEWVAL:.*]] = llvm.and %[[XVAL]], %[[EXPRBOOL]] : i1
|
|
// CHECK-NEXT: omp.yield(%[[NEWVAL]] : i1)
|
|
omp.atomic.update %xBool : memref<i1> {
|
|
^bb0(%xval: i1):
|
|
%newval = llvm.and %xval, %exprBool : i1
|
|
omp.yield(%newval : i1)
|
|
}
|
|
// CHECK: omp.atomic.update %[[X]] : memref<i32>
|
|
// CHECK-NEXT: (%[[XVAL:.*]]: i32):
|
|
// CHECK-NEXT: %[[NEWVAL:.*]] = llvm.shl %[[XVAL]], %[[EXPR]] : i32
|
|
// CHECK-NEXT: omp.yield(%[[NEWVAL]] : i32)
|
|
// CHECK-NEXT: }
|
|
omp.atomic.update %x : memref<i32> {
|
|
^bb0(%xval: i32):
|
|
%newval = llvm.shl %xval, %expr : i32
|
|
omp.yield(%newval : i32)
|
|
}
|
|
// CHECK: omp.atomic.update %[[X]] : memref<i32>
|
|
// CHECK-NEXT: (%[[XVAL:.*]]: i32):
|
|
// CHECK-NEXT: %[[NEWVAL:.*]] = llvm.intr.smax(%[[XVAL]], %[[EXPR]]) : (i32, i32) -> i32
|
|
// CHECK-NEXT: omp.yield(%[[NEWVAL]] : i32)
|
|
// CHECK-NEXT: }
|
|
omp.atomic.update %x : memref<i32> {
|
|
^bb0(%xval: i32):
|
|
%newval = llvm.intr.smax(%xval, %expr) : (i32, i32) -> i32
|
|
omp.yield(%newval : i32)
|
|
}
|
|
|
|
// CHECK: omp.atomic.update %[[XBOOL]] : memref<i1>
|
|
// CHECK-NEXT: (%[[XVAL:.*]]: i1):
|
|
// CHECK-NEXT: %[[NEWVAL:.*]] = llvm.icmp "eq" %[[XVAL]], %[[EXPRBOOL]] : i1
|
|
// CHECK-NEXT: omp.yield(%[[NEWVAL]] : i1)
|
|
// }
|
|
omp.atomic.update %xBool : memref<i1> {
|
|
^bb0(%xval: i1):
|
|
%newval = llvm.icmp "eq" %xval, %exprBool : i1
|
|
omp.yield(%newval : i1)
|
|
}
|
|
|
|
// CHECK: omp.atomic.update %[[X]] : memref<i32> {
|
|
// CHECK-NEXT: (%[[XVAL:.*]]: i32):
|
|
// CHECK-NEXT: omp.yield(%[[XVAL]] : i32)
|
|
// CHECK-NEXT: }
|
|
omp.atomic.update %x : memref<i32> {
|
|
^bb0(%xval:i32):
|
|
omp.yield(%xval:i32)
|
|
}
|
|
|
|
// CHECK: omp.atomic.update %[[X]] : memref<i32> {
|
|
// CHECK-NEXT: (%[[XVAL:.*]]: i32):
|
|
// CHECK-NEXT: omp.yield(%{{.+}} : i32)
|
|
// CHECK-NEXT: }
|
|
%const = arith.constant 42 : i32
|
|
omp.atomic.update %x : memref<i32> {
|
|
^bb0(%xval:i32):
|
|
omp.yield(%const:i32)
|
|
}
|
|
|
|
// CHECK: omp.atomic.update %[[X]] : memref<i32>
|
|
// CHECK-NEXT: (%[[XVAL:.*]]: i32):
|
|
// CHECK-NEXT: %[[NEWVAL:.*]] = llvm.add %[[XVAL]], %[[EXPR]] : i32
|
|
// CHECK-NEXT: omp.yield(%[[NEWVAL]] : i32)
|
|
omp.atomic.update hint(none) %x : memref<i32> {
|
|
^bb0(%xval: i32):
|
|
%newval = llvm.add %xval, %expr : i32
|
|
omp.yield(%newval : i32)
|
|
}
|
|
|
|
// CHECK: omp.atomic.update hint(uncontended) %[[X]] : memref<i32>
|
|
// CHECK-NEXT: (%[[XVAL:.*]]: i32):
|
|
// CHECK-NEXT: %[[NEWVAL:.*]] = llvm.add %[[XVAL]], %[[EXPR]] : i32
|
|
// CHECK-NEXT: omp.yield(%[[NEWVAL]] : i32)
|
|
omp.atomic.update hint(uncontended) %x : memref<i32> {
|
|
^bb0(%xval: i32):
|
|
%newval = llvm.add %xval, %expr : i32
|
|
omp.yield(%newval : i32)
|
|
}
|
|
|
|
// CHECK: omp.atomic.update hint(contended) %[[X]] : memref<i32>
|
|
// CHECK-NEXT: (%[[XVAL:.*]]: i32):
|
|
// CHECK-NEXT: %[[NEWVAL:.*]] = llvm.add %[[XVAL]], %[[EXPR]] : i32
|
|
// CHECK-NEXT: omp.yield(%[[NEWVAL]] : i32)
|
|
omp.atomic.update hint(contended) %x : memref<i32> {
|
|
^bb0(%xval: i32):
|
|
%newval = llvm.add %xval, %expr : i32
|
|
omp.yield(%newval : i32)
|
|
}
|
|
|
|
// CHECK: omp.atomic.update hint(nonspeculative) %[[X]] : memref<i32>
|
|
// CHECK-NEXT: (%[[XVAL:.*]]: i32):
|
|
// CHECK-NEXT: %[[NEWVAL:.*]] = llvm.add %[[XVAL]], %[[EXPR]] : i32
|
|
// CHECK-NEXT: omp.yield(%[[NEWVAL]] : i32)
|
|
omp.atomic.update hint(nonspeculative) %x : memref<i32> {
|
|
^bb0(%xval: i32):
|
|
%newval = llvm.add %xval, %expr : i32
|
|
omp.yield(%newval : i32)
|
|
}
|
|
|
|
// CHECK: omp.atomic.update hint(speculative) %[[X]] : memref<i32>
|
|
// CHECK-NEXT: (%[[XVAL:.*]]: i32):
|
|
// CHECK-NEXT: %[[NEWVAL:.*]] = llvm.add %[[XVAL]], %[[EXPR]] : i32
|
|
// CHECK-NEXT: omp.yield(%[[NEWVAL]] : i32)
|
|
omp.atomic.update hint(speculative) %x : memref<i32> {
|
|
^bb0(%xval: i32):
|
|
%newval = llvm.add %xval, %expr : i32
|
|
omp.yield(%newval : i32)
|
|
}
|
|
|
|
// CHECK: omp.atomic.update hint(uncontended, nonspeculative) %[[X]] : memref<i32>
|
|
// CHECK-NEXT: (%[[XVAL:.*]]: i32):
|
|
// CHECK-NEXT: %[[NEWVAL:.*]] = llvm.add %[[XVAL]], %[[EXPR]] : i32
|
|
// CHECK-NEXT: omp.yield(%[[NEWVAL]] : i32)
|
|
omp.atomic.update hint(uncontended, nonspeculative) %x : memref<i32> {
|
|
^bb0(%xval: i32):
|
|
%newval = llvm.add %xval, %expr : i32
|
|
omp.yield(%newval : i32)
|
|
}
|
|
|
|
// CHECK: omp.atomic.update hint(contended, nonspeculative) %[[X]] : memref<i32>
|
|
// CHECK-NEXT: (%[[XVAL:.*]]: i32):
|
|
// CHECK-NEXT: %[[NEWVAL:.*]] = llvm.add %[[XVAL]], %[[EXPR]] : i32
|
|
// CHECK-NEXT: omp.yield(%[[NEWVAL]] : i32)
|
|
omp.atomic.update hint(contended, nonspeculative) %x : memref<i32> {
|
|
^bb0(%xval: i32):
|
|
%newval = llvm.add %xval, %expr : i32
|
|
omp.yield(%newval : i32)
|
|
}
|
|
|
|
// CHECK: omp.atomic.update hint(uncontended, speculative) %[[X]] : memref<i32>
|
|
// CHECK-NEXT: (%[[XVAL:.*]]: i32):
|
|
// CHECK-NEXT: %[[NEWVAL:.*]] = llvm.add %[[XVAL]], %[[EXPR]] : i32
|
|
// CHECK-NEXT: omp.yield(%[[NEWVAL]] : i32)
|
|
omp.atomic.update hint(uncontended, speculative) %x : memref<i32> {
|
|
^bb0(%xval: i32):
|
|
%newval = llvm.add %xval, %expr : i32
|
|
omp.yield(%newval : i32)
|
|
}
|
|
|
|
// CHECK: omp.atomic.update hint(contended, speculative) %[[X]] : memref<i32>
|
|
// CHECK-NEXT: (%[[XVAL:.*]]: i32):
|
|
// CHECK-NEXT: %[[NEWVAL:.*]] = llvm.add %[[XVAL]], %[[EXPR]] : i32
|
|
// CHECK-NEXT: omp.yield(%[[NEWVAL]] : i32)
|
|
omp.atomic.update hint(contended, speculative) %x : memref<i32> {
|
|
^bb0(%xval: i32):
|
|
%newval = llvm.add %xval, %expr : i32
|
|
omp.yield(%newval : i32)
|
|
}
|
|
|
|
// CHECK: omp.atomic.update memory_order(seq_cst) %[[X]] : memref<i32>
|
|
// CHECK-NEXT: (%[[XVAL:.*]]: i32):
|
|
// CHECK-NEXT: %[[NEWVAL:.*]] = llvm.add %[[XVAL]], %[[EXPR]] : i32
|
|
// CHECK-NEXT: omp.yield(%[[NEWVAL]] : i32)
|
|
omp.atomic.update memory_order(seq_cst) %x : memref<i32> {
|
|
^bb0(%xval: i32):
|
|
%newval = llvm.add %xval, %expr : i32
|
|
omp.yield(%newval : i32)
|
|
}
|
|
|
|
// CHECK: omp.atomic.update memory_order(release) %[[X]] : memref<i32>
|
|
// CHECK-NEXT: (%[[XVAL:.*]]: i32):
|
|
// CHECK-NEXT: %[[NEWVAL:.*]] = llvm.add %[[XVAL]], %[[EXPR]] : i32
|
|
// CHECK-NEXT: omp.yield(%[[NEWVAL]] : i32)
|
|
omp.atomic.update memory_order(release) %x : memref<i32> {
|
|
^bb0(%xval: i32):
|
|
%newval = llvm.add %xval, %expr : i32
|
|
omp.yield(%newval : i32)
|
|
}
|
|
|
|
// CHECK: omp.atomic.update memory_order(relaxed) %[[X]] : memref<i32>
|
|
// CHECK-NEXT: (%[[XVAL:.*]]: i32):
|
|
// CHECK-NEXT: %[[NEWVAL:.*]] = llvm.add %[[XVAL]], %[[EXPR]] : i32
|
|
// CHECK-NEXT: omp.yield(%[[NEWVAL]] : i32)
|
|
omp.atomic.update memory_order(relaxed) %x : memref<i32> {
|
|
^bb0(%xval: i32):
|
|
%newval = llvm.add %xval, %expr : i32
|
|
omp.yield(%newval : i32)
|
|
}
|
|
|
|
// CHECK: omp.atomic.update hint(uncontended, speculative) memory_order(seq_cst) %[[X]] : memref<i32>
|
|
// CHECK-NEXT: (%[[XVAL:.*]]: i32):
|
|
// CHECK-NEXT: %[[NEWVAL:.*]] = llvm.add %[[XVAL]], %[[EXPR]] : i32
|
|
// CHECK-NEXT: omp.yield(%[[NEWVAL]] : i32)
|
|
omp.atomic.update memory_order(seq_cst) hint(uncontended, speculative) %x : memref<i32> {
|
|
^bb0(%xval: i32):
|
|
%newval = llvm.add %xval, %expr : i32
|
|
omp.yield(%newval : i32)
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: omp_atomic_capture
|
|
// CHECK-SAME: (%[[v:.*]]: memref<i32>, %[[x:.*]]: memref<i32>, %[[expr:.*]]: i32)
|
|
func.func @omp_atomic_capture(%v: memref<i32>, %x: memref<i32>, %expr: i32) {
|
|
// CHECK: omp.atomic.capture {
|
|
// CHECK-NEXT: omp.atomic.update %[[x]] : memref<i32>
|
|
// CHECK-NEXT: (%[[xval:.*]]: i32):
|
|
// CHECK-NEXT: %[[newval:.*]] = llvm.add %[[xval]], %[[expr]] : i32
|
|
// CHECK-NEXT: omp.yield(%[[newval]] : i32)
|
|
// CHECK-NEXT: }
|
|
// CHECK-NEXT: omp.atomic.read %[[v]] = %[[x]] : memref<i32>, memref<i32>, i32
|
|
// CHECK-NEXT: }
|
|
omp.atomic.capture{
|
|
omp.atomic.update %x : memref<i32> {
|
|
^bb0(%xval: i32):
|
|
%newval = llvm.add %xval, %expr : i32
|
|
omp.yield(%newval : i32)
|
|
}
|
|
omp.atomic.read %v = %x : memref<i32>, memref<i32>, i32
|
|
}
|
|
// CHECK: omp.atomic.capture {
|
|
// CHECK-NEXT: omp.atomic.read %[[v]] = %[[x]] : memref<i32>, memref<i32>, i32
|
|
// CHECK-NEXT: omp.atomic.update %[[x]] : memref<i32>
|
|
// CHECK-NEXT: (%[[xval:.*]]: i32):
|
|
// CHECK-NEXT: %[[newval:.*]] = llvm.add %[[xval]], %[[expr]] : i32
|
|
// CHECK-NEXT: omp.yield(%[[newval]] : i32)
|
|
// CHECK-NEXT: }
|
|
// CHECK-NEXT: }
|
|
omp.atomic.capture{
|
|
omp.atomic.read %v = %x : memref<i32>, memref<i32>, i32
|
|
omp.atomic.update %x : memref<i32> {
|
|
^bb0(%xval: i32):
|
|
%newval = llvm.add %xval, %expr : i32
|
|
omp.yield(%newval : i32)
|
|
}
|
|
}
|
|
// CHECK: omp.atomic.capture {
|
|
// CHECK-NEXT: omp.atomic.read %[[v]] = %[[x]] : memref<i32>, memref<i32>, i32
|
|
// CHECK-NEXT: omp.atomic.write %[[x]] = %[[expr]] : memref<i32>, i32
|
|
// CHECK-NEXT: }
|
|
omp.atomic.capture{
|
|
omp.atomic.read %v = %x : memref<i32>, memref<i32>, i32
|
|
omp.atomic.write %x = %expr : memref<i32>, i32
|
|
}
|
|
|
|
// CHECK: omp.atomic.capture {
|
|
// CHECK-NEXT: omp.atomic.update %[[x]] : memref<i32>
|
|
// CHECK-NEXT: (%[[xval:.*]]: i32):
|
|
// CHECK-NEXT: %[[newval:.*]] = llvm.add %[[xval]], %[[expr]] : i32
|
|
// CHECK-NEXT: omp.yield(%[[newval]] : i32)
|
|
// CHECK-NEXT: }
|
|
// CHECK-NEXT: omp.atomic.read %[[v]] = %[[x]] : memref<i32>, memref<i32>, i32
|
|
// CHECK-NEXT: }
|
|
omp.atomic.capture hint(none) {
|
|
omp.atomic.update %x : memref<i32> {
|
|
^bb0(%xval: i32):
|
|
%newval = llvm.add %xval, %expr : i32
|
|
omp.yield(%newval : i32)
|
|
}
|
|
omp.atomic.read %v = %x : memref<i32>, memref<i32>, i32
|
|
}
|
|
|
|
// CHECK: omp.atomic.capture hint(uncontended) {
|
|
// CHECK-NEXT: omp.atomic.update %[[x]] : memref<i32>
|
|
// CHECK-NEXT: (%[[xval:.*]]: i32):
|
|
// CHECK-NEXT: %[[newval:.*]] = llvm.add %[[xval]], %[[expr]] : i32
|
|
// CHECK-NEXT: omp.yield(%[[newval]] : i32)
|
|
// CHECK-NEXT: }
|
|
// CHECK-NEXT: omp.atomic.read %[[v]] = %[[x]] : memref<i32>, memref<i32>, i32
|
|
// CHECK-NEXT: }
|
|
omp.atomic.capture hint(uncontended) {
|
|
omp.atomic.update %x : memref<i32> {
|
|
^bb0(%xval: i32):
|
|
%newval = llvm.add %xval, %expr : i32
|
|
omp.yield(%newval : i32)
|
|
}
|
|
omp.atomic.read %v = %x : memref<i32>, memref<i32>, i32
|
|
}
|
|
|
|
// CHECK: omp.atomic.capture hint(contended) {
|
|
// CHECK-NEXT: omp.atomic.update %[[x]] : memref<i32>
|
|
// CHECK-NEXT: (%[[xval:.*]]: i32):
|
|
// CHECK-NEXT: %[[newval:.*]] = llvm.add %[[xval]], %[[expr]] : i32
|
|
// CHECK-NEXT: omp.yield(%[[newval]] : i32)
|
|
// CHECK-NEXT: }
|
|
// CHECK-NEXT: omp.atomic.read %[[v]] = %[[x]] : memref<i32>, memref<i32>, i32
|
|
// CHECK-NEXT: }
|
|
omp.atomic.capture hint(contended) {
|
|
omp.atomic.update %x : memref<i32> {
|
|
^bb0(%xval: i32):
|
|
%newval = llvm.add %xval, %expr : i32
|
|
omp.yield(%newval : i32)
|
|
}
|
|
omp.atomic.read %v = %x : memref<i32>, memref<i32>, i32
|
|
}
|
|
|
|
// CHECK: omp.atomic.capture hint(nonspeculative) {
|
|
// CHECK-NEXT: omp.atomic.update %[[x]] : memref<i32>
|
|
// CHECK-NEXT: (%[[xval:.*]]: i32):
|
|
// CHECK-NEXT: %[[newval:.*]] = llvm.add %[[xval]], %[[expr]] : i32
|
|
// CHECK-NEXT: omp.yield(%[[newval]] : i32)
|
|
// CHECK-NEXT: }
|
|
// CHECK-NEXT: omp.atomic.read %[[v]] = %[[x]] : memref<i32>, memref<i32>, i32
|
|
// CHECK-NEXT: }
|
|
omp.atomic.capture hint(nonspeculative) {
|
|
omp.atomic.update %x : memref<i32> {
|
|
^bb0(%xval: i32):
|
|
%newval = llvm.add %xval, %expr : i32
|
|
omp.yield(%newval : i32)
|
|
}
|
|
omp.atomic.read %v = %x : memref<i32>, memref<i32>, i32
|
|
}
|
|
|
|
// CHECK: omp.atomic.capture hint(speculative) {
|
|
// CHECK-NEXT: omp.atomic.update %[[x]] : memref<i32>
|
|
// CHECK-NEXT: (%[[xval:.*]]: i32):
|
|
// CHECK-NEXT: %[[newval:.*]] = llvm.add %[[xval]], %[[expr]] : i32
|
|
// CHECK-NEXT: omp.yield(%[[newval]] : i32)
|
|
// CHECK-NEXT: }
|
|
// CHECK-NEXT: omp.atomic.read %[[v]] = %[[x]] : memref<i32>, memref<i32>, i32
|
|
// CHECK-NEXT: }
|
|
omp.atomic.capture hint(speculative) {
|
|
omp.atomic.update %x : memref<i32> {
|
|
^bb0(%xval: i32):
|
|
%newval = llvm.add %xval, %expr : i32
|
|
omp.yield(%newval : i32)
|
|
}
|
|
omp.atomic.read %v = %x : memref<i32>, memref<i32>, i32
|
|
}
|
|
|
|
// CHECK: omp.atomic.capture hint(uncontended, nonspeculative) {
|
|
// CHECK-NEXT: omp.atomic.update %[[x]] : memref<i32>
|
|
// CHECK-NEXT: (%[[xval:.*]]: i32):
|
|
// CHECK-NEXT: %[[newval:.*]] = llvm.add %[[xval]], %[[expr]] : i32
|
|
// CHECK-NEXT: omp.yield(%[[newval]] : i32)
|
|
// CHECK-NEXT: }
|
|
// CHECK-NEXT: omp.atomic.read %[[v]] = %[[x]] : memref<i32>, memref<i32>, i32
|
|
// CHECK-NEXT: }
|
|
omp.atomic.capture hint(uncontended, nonspeculative) {
|
|
omp.atomic.update %x : memref<i32> {
|
|
^bb0(%xval: i32):
|
|
%newval = llvm.add %xval, %expr : i32
|
|
omp.yield(%newval : i32)
|
|
}
|
|
omp.atomic.read %v = %x : memref<i32>, memref<i32>, i32
|
|
}
|
|
|
|
// CHECK: omp.atomic.capture hint(contended, nonspeculative) {
|
|
// CHECK-NEXT: omp.atomic.update %[[x]] : memref<i32>
|
|
// CHECK-NEXT: (%[[xval:.*]]: i32):
|
|
// CHECK-NEXT: %[[newval:.*]] = llvm.add %[[xval]], %[[expr]] : i32
|
|
// CHECK-NEXT: omp.yield(%[[newval]] : i32)
|
|
// CHECK-NEXT: }
|
|
// CHECK-NEXT: omp.atomic.read %[[v]] = %[[x]] : memref<i32>, memref<i32>, i32
|
|
// CHECK-NEXT: }
|
|
omp.atomic.capture hint(contended, nonspeculative) {
|
|
omp.atomic.update %x : memref<i32> {
|
|
^bb0(%xval: i32):
|
|
%newval = llvm.add %xval, %expr : i32
|
|
omp.yield(%newval : i32)
|
|
}
|
|
omp.atomic.read %v = %x : memref<i32>, memref<i32>, i32
|
|
}
|
|
|
|
// CHECK: omp.atomic.capture hint(uncontended, speculative) {
|
|
// CHECK-NEXT: omp.atomic.update %[[x]] : memref<i32>
|
|
// CHECK-NEXT: (%[[xval:.*]]: i32):
|
|
// CHECK-NEXT: %[[newval:.*]] = llvm.add %[[xval]], %[[expr]] : i32
|
|
// CHECK-NEXT: omp.yield(%[[newval]] : i32)
|
|
// CHECK-NEXT: }
|
|
// CHECK-NEXT: omp.atomic.read %[[v]] = %[[x]] : memref<i32>, memref<i32>, i32
|
|
// CHECK-NEXT: }
|
|
omp.atomic.capture hint(uncontended, speculative) {
|
|
omp.atomic.update %x : memref<i32> {
|
|
^bb0(%xval: i32):
|
|
%newval = llvm.add %xval, %expr : i32
|
|
omp.yield(%newval : i32)
|
|
}
|
|
omp.atomic.read %v = %x : memref<i32>, memref<i32>, i32
|
|
}
|
|
|
|
// CHECK: omp.atomic.capture hint(contended, speculative) {
|
|
// CHECK-NEXT: omp.atomic.update %[[x]] : memref<i32>
|
|
// CHECK-NEXT: (%[[xval:.*]]: i32):
|
|
// CHECK-NEXT: %[[newval:.*]] = llvm.add %[[xval]], %[[expr]] : i32
|
|
// CHECK-NEXT: omp.yield(%[[newval]] : i32)
|
|
// CHECK-NEXT: }
|
|
// CHECK-NEXT: omp.atomic.read %[[v]] = %[[x]] : memref<i32>, memref<i32>, i32
|
|
// CHECK-NEXT: }
|
|
omp.atomic.capture hint(contended, speculative) {
|
|
omp.atomic.update %x : memref<i32> {
|
|
^bb0(%xval: i32):
|
|
%newval = llvm.add %xval, %expr : i32
|
|
omp.yield(%newval : i32)
|
|
}
|
|
omp.atomic.read %v = %x : memref<i32>, memref<i32>, i32
|
|
}
|
|
|
|
// CHECK: omp.atomic.capture memory_order(seq_cst) {
|
|
// CHECK-NEXT: omp.atomic.update %[[x]] : memref<i32>
|
|
// CHECK-NEXT: (%[[xval:.*]]: i32):
|
|
// CHECK-NEXT: %[[newval:.*]] = llvm.add %[[xval]], %[[expr]] : i32
|
|
// CHECK-NEXT: omp.yield(%[[newval]] : i32)
|
|
// CHECK-NEXT: }
|
|
// CHECK-NEXT: omp.atomic.read %[[v]] = %[[x]] : memref<i32>, memref<i32>, i32
|
|
// CHECK-NEXT: }
|
|
omp.atomic.capture memory_order(seq_cst) {
|
|
omp.atomic.update %x : memref<i32> {
|
|
^bb0(%xval: i32):
|
|
%newval = llvm.add %xval, %expr : i32
|
|
omp.yield(%newval : i32)
|
|
}
|
|
omp.atomic.read %v = %x : memref<i32>, memref<i32>, i32
|
|
}
|
|
|
|
// CHECK: omp.atomic.capture memory_order(acq_rel) {
|
|
// CHECK-NEXT: omp.atomic.update %[[x]] : memref<i32>
|
|
// CHECK-NEXT: (%[[xval:.*]]: i32):
|
|
// CHECK-NEXT: %[[newval:.*]] = llvm.add %[[xval]], %[[expr]] : i32
|
|
// CHECK-NEXT: omp.yield(%[[newval]] : i32)
|
|
// CHECK-NEXT: }
|
|
// CHECK-NEXT: omp.atomic.read %[[v]] = %[[x]] : memref<i32>, memref<i32>, i32
|
|
// CHECK-NEXT: }
|
|
omp.atomic.capture memory_order(acq_rel) {
|
|
omp.atomic.update %x : memref<i32> {
|
|
^bb0(%xval: i32):
|
|
%newval = llvm.add %xval, %expr : i32
|
|
omp.yield(%newval : i32)
|
|
}
|
|
omp.atomic.read %v = %x : memref<i32>, memref<i32>, i32
|
|
}
|
|
|
|
// CHECK: omp.atomic.capture memory_order(acquire) {
|
|
// CHECK-NEXT: omp.atomic.update %[[x]] : memref<i32>
|
|
// CHECK-NEXT: (%[[xval:.*]]: i32):
|
|
// CHECK-NEXT: %[[newval:.*]] = llvm.add %[[xval]], %[[expr]] : i32
|
|
// CHECK-NEXT: omp.yield(%[[newval]] : i32)
|
|
// CHECK-NEXT: }
|
|
// CHECK-NEXT: omp.atomic.read %[[v]] = %[[x]] : memref<i32>, memref<i32>, i32
|
|
// CHECK-NEXT: }
|
|
omp.atomic.capture memory_order(acquire) {
|
|
omp.atomic.update %x : memref<i32> {
|
|
^bb0(%xval: i32):
|
|
%newval = llvm.add %xval, %expr : i32
|
|
omp.yield(%newval : i32)
|
|
}
|
|
omp.atomic.read %v = %x : memref<i32>, memref<i32>, i32
|
|
}
|
|
|
|
// CHECK: omp.atomic.capture memory_order(release) {
|
|
// CHECK-NEXT: omp.atomic.update %[[x]] : memref<i32>
|
|
// CHECK-NEXT: (%[[xval:.*]]: i32):
|
|
// CHECK-NEXT: %[[newval:.*]] = llvm.add %[[xval]], %[[expr]] : i32
|
|
// CHECK-NEXT: omp.yield(%[[newval]] : i32)
|
|
// CHECK-NEXT: }
|
|
// CHECK-NEXT: omp.atomic.read %[[v]] = %[[x]] : memref<i32>, memref<i32>, i32
|
|
// CHECK-NEXT: }
|
|
omp.atomic.capture memory_order(release) {
|
|
omp.atomic.update %x : memref<i32> {
|
|
^bb0(%xval: i32):
|
|
%newval = llvm.add %xval, %expr : i32
|
|
omp.yield(%newval : i32)
|
|
}
|
|
omp.atomic.read %v = %x : memref<i32>, memref<i32>, i32
|
|
}
|
|
|
|
// CHECK: omp.atomic.capture memory_order(relaxed) {
|
|
// CHECK-NEXT: omp.atomic.update %[[x]] : memref<i32>
|
|
// CHECK-NEXT: (%[[xval:.*]]: i32):
|
|
// CHECK-NEXT: %[[newval:.*]] = llvm.add %[[xval]], %[[expr]] : i32
|
|
// CHECK-NEXT: omp.yield(%[[newval]] : i32)
|
|
// CHECK-NEXT: }
|
|
// CHECK-NEXT: omp.atomic.read %[[v]] = %[[x]] : memref<i32>, memref<i32>, i32
|
|
// CHECK-NEXT: }
|
|
omp.atomic.capture memory_order(relaxed) {
|
|
omp.atomic.update %x : memref<i32> {
|
|
^bb0(%xval: i32):
|
|
%newval = llvm.add %xval, %expr : i32
|
|
omp.yield(%newval : i32)
|
|
}
|
|
omp.atomic.read %v = %x : memref<i32>, memref<i32>, i32
|
|
}
|
|
|
|
// CHECK: omp.atomic.capture hint(contended, speculative) memory_order(seq_cst) {
|
|
// CHECK-NEXT: omp.atomic.update %[[x]] : memref<i32>
|
|
// CHECK-NEXT: (%[[xval:.*]]: i32):
|
|
// CHECK-NEXT: %[[newval:.*]] = llvm.add %[[xval]], %[[expr]] : i32
|
|
// CHECK-NEXT: omp.yield(%[[newval]] : i32)
|
|
// CHECK-NEXT: }
|
|
// CHECK-NEXT: omp.atomic.read %[[v]] = %[[x]] : memref<i32>, memref<i32>, i32
|
|
// CHECK-NEXT: }
|
|
omp.atomic.capture hint(contended, speculative) memory_order(seq_cst) {
|
|
omp.atomic.update %x : memref<i32> {
|
|
^bb0(%xval: i32):
|
|
%newval = llvm.add %xval, %expr : i32
|
|
omp.yield(%newval : i32)
|
|
}
|
|
omp.atomic.read %v = %x : memref<i32>, memref<i32>, i32
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: omp_sectionsop
|
|
func.func @omp_sectionsop(%data_var1 : memref<i32>, %data_var2 : memref<i32>,
|
|
%data_var3 : memref<i32>, %redn_var : !llvm.ptr) {
|
|
// CHECK: omp.sections allocate(%{{.*}} : memref<i32> -> %{{.*}} : memref<i32>)
|
|
"omp.sections" (%data_var1, %data_var1) ({
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}) {operandSegmentSizes = array<i32: 1,1,0,0>} : (memref<i32>, memref<i32>) -> ()
|
|
|
|
// CHECK: omp.sections reduction(@add_f32 %{{.*}} -> %{{.*}} : !llvm.ptr)
|
|
"omp.sections" (%redn_var) ({
|
|
^bb0(%arg0: !llvm.ptr):
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}) {operandSegmentSizes = array<i32: 0,0,0,1>, reduction_byref = array<i1: false>, reduction_syms=[@add_f32]} : (!llvm.ptr) -> ()
|
|
|
|
// CHECK: omp.sections nowait {
|
|
omp.sections nowait {
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
|
|
// CHECK: omp.sections reduction(@add_f32 %{{.*}} -> %{{.*}} : !llvm.ptr) {
|
|
omp.sections reduction(@add_f32 %redn_var -> %arg0 : !llvm.ptr) {
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
|
|
// CHECK: omp.sections allocate(%{{.*}} : memref<i32> -> %{{.*}} : memref<i32>)
|
|
omp.sections allocate(%data_var1 : memref<i32> -> %data_var1 : memref<i32>) {
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
|
|
// CHECK: omp.sections nowait
|
|
omp.sections nowait {
|
|
// CHECK: omp.section
|
|
omp.section {
|
|
// CHECK: %{{.*}} = "test.payload"() : () -> i32
|
|
%1 = "test.payload"() : () -> i32
|
|
// CHECK: %{{.*}} = "test.payload"() : () -> i32
|
|
%2 = "test.payload"() : () -> i32
|
|
// CHECK: %{{.*}} = "test.payload"(%{{.*}}, %{{.*}}) : (i32, i32) -> i32
|
|
%3 = "test.payload"(%1, %2) : (i32, i32) -> i32
|
|
}
|
|
// CHECK: omp.section
|
|
omp.section {
|
|
// CHECK: %{{.*}} = "test.payload"(%{{.*}}) : (!llvm.ptr) -> i32
|
|
%1 = "test.payload"(%redn_var) : (!llvm.ptr) -> i32
|
|
}
|
|
// CHECK: omp.section
|
|
omp.section {
|
|
// CHECK: "test.payload"(%{{.*}}) : (!llvm.ptr) -> ()
|
|
"test.payload"(%redn_var) : (!llvm.ptr) -> ()
|
|
}
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: func @omp_single
|
|
func.func @omp_single() {
|
|
omp.parallel {
|
|
// CHECK: omp.single {
|
|
omp.single {
|
|
"test.payload"() : () -> ()
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: func @omp_single_nowait
|
|
func.func @omp_single_nowait() {
|
|
omp.parallel {
|
|
// CHECK: omp.single nowait {
|
|
omp.single nowait {
|
|
"test.payload"() : () -> ()
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: func @omp_single_allocate
|
|
func.func @omp_single_allocate(%data_var: memref<i32>) {
|
|
omp.parallel {
|
|
// CHECK: omp.single allocate(%{{.*}} : memref<i32> -> %{{.*}} : memref<i32>) {
|
|
omp.single allocate(%data_var : memref<i32> -> %data_var : memref<i32>) {
|
|
"test.payload"() : () -> ()
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: func @omp_single_allocate_nowait
|
|
func.func @omp_single_allocate_nowait(%data_var: memref<i32>) {
|
|
omp.parallel {
|
|
// CHECK: omp.single allocate(%{{.*}} : memref<i32> -> %{{.*}} : memref<i32>) nowait {
|
|
omp.single allocate(%data_var : memref<i32> -> %data_var : memref<i32>) nowait {
|
|
"test.payload"() : () -> ()
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: func @omp_single_multiple_blocks
|
|
func.func @omp_single_multiple_blocks() {
|
|
// CHECK: omp.single {
|
|
omp.single {
|
|
cf.br ^bb2
|
|
^bb2:
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
return
|
|
}
|
|
|
|
func.func private @copy_i32(memref<i32>, memref<i32>)
|
|
|
|
// CHECK-LABEL: func @omp_single_copyprivate
|
|
func.func @omp_single_copyprivate(%data_var: memref<i32>) {
|
|
omp.parallel {
|
|
// CHECK: omp.single copyprivate(%{{.*}} -> @copy_i32 : memref<i32>) {
|
|
omp.single copyprivate(%data_var -> @copy_i32 : memref<i32>) {
|
|
"test.payload"() : () -> ()
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: @omp_task
|
|
// CHECK-SAME: (%[[bool_var:.*]]: i1, %[[i64_var:.*]]: i64, %[[i32_var:.*]]: i32, %[[data_var:.*]]: memref<i32>, %[[event_handle:.*]]: !llvm.ptr)
|
|
func.func @omp_task(%bool_var: i1, %i64_var: i64, %i32_var: i32, %data_var: memref<i32>, %event_handle : !llvm.ptr) {
|
|
|
|
// Checking simple task
|
|
// CHECK: omp.task {
|
|
omp.task {
|
|
// CHECK: "test.foo"() : () -> ()
|
|
"test.foo"() : () -> ()
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
|
|
// Checking `if` clause
|
|
// CHECK: omp.task if(%[[bool_var]]) {
|
|
omp.task if(%bool_var) {
|
|
// CHECK: "test.foo"() : () -> ()
|
|
"test.foo"() : () -> ()
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
|
|
// Checking `final` clause
|
|
// CHECK: omp.task final(%[[bool_var]]) {
|
|
omp.task final(%bool_var) {
|
|
// CHECK: "test.foo"() : () -> ()
|
|
"test.foo"() : () -> ()
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
|
|
// Checking `untied` clause
|
|
// CHECK: omp.task untied {
|
|
omp.task untied {
|
|
// CHECK: "test.foo"() : () -> ()
|
|
"test.foo"() : () -> ()
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
|
|
// Checking `in_reduction` clause
|
|
%c1 = arith.constant 1 : i32
|
|
// CHECK: %[[redn_var1:.*]] = llvm.alloca %{{.*}} x f32 : (i32) -> !llvm.ptr
|
|
%0 = llvm.alloca %c1 x f32 : (i32) -> !llvm.ptr
|
|
// CHECK: %[[redn_var2:.*]] = llvm.alloca %{{.*}} x f32 : (i32) -> !llvm.ptr
|
|
%1 = llvm.alloca %c1 x f32 : (i32) -> !llvm.ptr
|
|
// CHECK: omp.task in_reduction(@add_f32 %[[redn_var1]] -> %{{.+}}, @add_f32 %[[redn_var2]] -> %{{.+}} : !llvm.ptr, !llvm.ptr) {
|
|
omp.task in_reduction(@add_f32 %0 -> %arg0, @add_f32 %1 -> %arg1 : !llvm.ptr, !llvm.ptr) {
|
|
// CHECK: "test.foo"() : () -> ()
|
|
"test.foo"() : () -> ()
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
|
|
// Checking `in_reduction` clause (mixed) byref
|
|
// CHECK: omp.task in_reduction(byref @add_f32 %[[redn_var1]] -> %{{.+}}, @add_f32 %[[redn_var2]] -> %{{.+}} : !llvm.ptr, !llvm.ptr) {
|
|
omp.task in_reduction(byref @add_f32 %0 -> %arg0, @add_f32 %1 -> %arg1 : !llvm.ptr, !llvm.ptr) {
|
|
// CHECK: "test.foo"() : () -> ()
|
|
"test.foo"() : () -> ()
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
|
|
// Checking priority clause
|
|
// CHECK: omp.task priority(%[[i32_var]] : i32) {
|
|
omp.task priority(%i32_var : i32) {
|
|
// CHECK: "test.foo"() : () -> ()
|
|
"test.foo"() : () -> ()
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
|
|
// Checking allocate clause
|
|
// CHECK: omp.task allocate(%[[data_var]] : memref<i32> -> %[[data_var]] : memref<i32>) {
|
|
omp.task allocate(%data_var : memref<i32> -> %data_var : memref<i32>) {
|
|
// CHECK: "test.foo"() : () -> ()
|
|
"test.foo"() : () -> ()
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
// Checking detach clause
|
|
// CHECK: omp.task detach(%[[event_handle]] : !llvm.ptr)
|
|
omp.task detach(%event_handle : !llvm.ptr){
|
|
omp.terminator
|
|
}
|
|
// Checking multiple clauses
|
|
// CHECK: omp.task allocate(%[[data_var]] : memref<i32> -> %[[data_var]] : memref<i32>)
|
|
omp.task allocate(%data_var : memref<i32> -> %data_var : memref<i32>)
|
|
// CHECK-SAME: final(%[[bool_var]]) if(%[[bool_var]])
|
|
final(%bool_var) if(%bool_var)
|
|
// CHECK-SAME: priority(%[[i32_var]] : i32) untied
|
|
priority(%i32_var : i32) untied
|
|
// CHECK-SAME: in_reduction(@add_f32 %[[redn_var1]] -> %{{.+}}, byref @add_f32 %[[redn_var2]] -> %{{.+}} : !llvm.ptr, !llvm.ptr)
|
|
in_reduction(@add_f32 %0 -> %arg0, byref @add_f32 %1 -> %arg1 : !llvm.ptr, !llvm.ptr) {
|
|
// CHECK: "test.foo"() : () -> ()
|
|
"test.foo"() : () -> ()
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: @omp_task_depend
|
|
// CHECK-SAME: (%arg0: memref<i32>, %arg1: memref<i32>) {
|
|
func.func @omp_task_depend(%arg0: memref<i32>, %arg1: memref<i32>) {
|
|
// CHECK: omp.task depend(taskdependin -> %arg0 : memref<i32>, taskdependin -> %arg1 : memref<i32>, taskdependinout -> %arg0 : memref<i32>) {
|
|
omp.task depend(taskdependin -> %arg0 : memref<i32>, taskdependin -> %arg1 : memref<i32>, taskdependinout -> %arg0 : memref<i32>) {
|
|
// CHECK: "test.foo"() : () -> ()
|
|
"test.foo"() : () -> ()
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
return
|
|
}
|
|
|
|
|
|
// CHECK-LABEL: @omp_target_depend
|
|
// CHECK-SAME: (%arg0: memref<i32>, %arg1: memref<i32>) {
|
|
func.func @omp_target_depend(%arg0: memref<i32>, %arg1: memref<i32>) {
|
|
// CHECK: omp.target depend(taskdependin -> %arg0 : memref<i32>, taskdependin -> %arg1 : memref<i32>, taskdependinout -> %arg0 : memref<i32>) {
|
|
omp.target depend(taskdependin -> %arg0 : memref<i32>, taskdependin -> %arg1 : memref<i32>, taskdependinout -> %arg0 : memref<i32>) {
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
} {operandSegmentSizes = array<i32: 0,0,0,3,0,0,0,0>}
|
|
return
|
|
}
|
|
|
|
func.func @omp_threadprivate() {
|
|
%0 = arith.constant 1 : i32
|
|
%1 = arith.constant 2 : i32
|
|
%2 = arith.constant 3 : i32
|
|
|
|
// CHECK: [[ARG0:%.*]] = llvm.mlir.addressof @_QFsubEx : !llvm.ptr
|
|
// CHECK: {{.*}} = omp.threadprivate [[ARG0]] : !llvm.ptr -> !llvm.ptr
|
|
%3 = llvm.mlir.addressof @_QFsubEx : !llvm.ptr
|
|
%4 = omp.threadprivate %3 : !llvm.ptr -> !llvm.ptr
|
|
llvm.store %0, %4 : i32, !llvm.ptr
|
|
|
|
// CHECK: omp.parallel
|
|
// CHECK: {{.*}} = omp.threadprivate [[ARG0]] : !llvm.ptr -> !llvm.ptr
|
|
omp.parallel {
|
|
%5 = omp.threadprivate %3 : !llvm.ptr -> !llvm.ptr
|
|
llvm.store %1, %5 : i32, !llvm.ptr
|
|
omp.terminator
|
|
}
|
|
llvm.store %2, %4 : i32, !llvm.ptr
|
|
return
|
|
}
|
|
|
|
llvm.mlir.global internal @_QFsubEx() : i32
|
|
|
|
func.func @omp_cancel_parallel(%if_cond : i1) -> () {
|
|
// Test with optional operand; if_expr.
|
|
omp.parallel {
|
|
// CHECK: omp.cancel cancellation_construct_type(parallel) if(%{{.*}})
|
|
omp.cancel cancellation_construct_type(parallel) if(%if_cond)
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
return
|
|
}
|
|
|
|
func.func @omp_cancel_wsloop(%lb : index, %ub : index, %step : index) {
|
|
omp.wsloop {
|
|
omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
|
|
// CHECK: omp.cancel cancellation_construct_type(loop)
|
|
omp.cancel cancellation_construct_type(loop)
|
|
// CHECK: omp.yield
|
|
omp.yield
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func.func @omp_cancel_sections() -> () {
|
|
omp.sections {
|
|
omp.section {
|
|
// CHECK: omp.cancel cancellation_construct_type(sections)
|
|
omp.cancel cancellation_construct_type(sections)
|
|
omp.terminator
|
|
}
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
return
|
|
}
|
|
|
|
func.func @omp_cancellationpoint_parallel() -> () {
|
|
omp.parallel {
|
|
// CHECK: omp.cancellation_point cancellation_construct_type(parallel)
|
|
omp.cancellation_point cancellation_construct_type(parallel)
|
|
// CHECK: omp.cancel cancellation_construct_type(parallel)
|
|
omp.cancel cancellation_construct_type(parallel)
|
|
omp.terminator
|
|
}
|
|
return
|
|
}
|
|
|
|
func.func @omp_cancellationpoint_wsloop(%lb : index, %ub : index, %step : index) {
|
|
omp.wsloop {
|
|
omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
|
|
// CHECK: omp.cancellation_point cancellation_construct_type(loop)
|
|
omp.cancellation_point cancellation_construct_type(loop)
|
|
// CHECK: omp.cancel cancellation_construct_type(loop)
|
|
omp.cancel cancellation_construct_type(loop)
|
|
// CHECK: omp.yield
|
|
omp.yield
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func.func @omp_cancellationpoint_sections() -> () {
|
|
omp.sections {
|
|
omp.section {
|
|
// CHECK: omp.cancellation_point cancellation_construct_type(sections)
|
|
omp.cancellation_point cancellation_construct_type(sections)
|
|
// CHECK: omp.cancel cancellation_construct_type(sections)
|
|
omp.cancel cancellation_construct_type(sections)
|
|
omp.terminator
|
|
}
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: @omp_taskgroup_no_tasks
|
|
func.func @omp_taskgroup_no_tasks() -> () {
|
|
|
|
// CHECK: omp.taskgroup
|
|
omp.taskgroup {
|
|
// CHECK: "test.foo"() : () -> ()
|
|
"test.foo"() : () -> ()
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: @omp_taskgroup_multiple_tasks
|
|
func.func @omp_taskgroup_multiple_tasks() -> () {
|
|
// CHECK: omp.taskgroup
|
|
omp.taskgroup {
|
|
// CHECK: omp.task
|
|
omp.task {
|
|
"test.foo"() : () -> ()
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
// CHECK: omp.task
|
|
omp.task {
|
|
"test.foo"() : () -> ()
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: @omp_taskgroup_clauses
|
|
func.func @omp_taskgroup_clauses() -> () {
|
|
%testmemref = "test.memref"() : () -> (memref<i32>)
|
|
%testf32 = "test.f32"() : () -> (!llvm.ptr)
|
|
// CHECK: omp.taskgroup allocate(%{{.+}}: memref<i32> -> %{{.+}} : memref<i32>) task_reduction(@add_f32 %{{.+}} -> %{{.+}} : !llvm.ptr)
|
|
omp.taskgroup allocate(%testmemref : memref<i32> -> %testmemref : memref<i32>) task_reduction(@add_f32 %testf32 -> %arg0 : !llvm.ptr) {
|
|
// CHECK: omp.task
|
|
omp.task {
|
|
"test.foo"() : () -> ()
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
// CHECK: omp.task
|
|
omp.task {
|
|
"test.foo"() : () -> ()
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: @omp_taskloop
|
|
func.func @omp_taskloop(%lb: i32, %ub: i32, %step: i32) -> () {
|
|
|
|
// CHECK: omp.taskloop {
|
|
omp.taskloop {
|
|
omp.loop_nest (%i) : i32 = (%lb) to (%ub) step (%step) {
|
|
// CHECK: omp.yield
|
|
omp.yield
|
|
}
|
|
}
|
|
|
|
%testbool = "test.bool"() : () -> (i1)
|
|
|
|
// CHECK: omp.taskloop if(%{{[^)]+}}) {
|
|
omp.taskloop if(%testbool) {
|
|
omp.loop_nest (%i, %j) : i32 = (%lb, %ub) to (%ub, %lb) step (%step, %step) {
|
|
// CHECK: omp.yield
|
|
omp.yield
|
|
}
|
|
}
|
|
|
|
// CHECK: omp.taskloop final(%{{[^)]+}}) {
|
|
omp.taskloop final(%testbool) {
|
|
omp.loop_nest (%i, %j) : i32 = (%lb, %ub) to (%ub, %lb) step (%step, %step) {
|
|
// CHECK: omp.yield
|
|
omp.yield
|
|
}
|
|
}
|
|
|
|
// CHECK: omp.taskloop untied {
|
|
omp.taskloop untied {
|
|
omp.loop_nest (%i, %j) : i32 = (%lb, %ub) to (%ub, %lb) step (%step, %step) {
|
|
// CHECK: omp.yield
|
|
omp.yield
|
|
}
|
|
}
|
|
|
|
// CHECK: omp.taskloop mergeable {
|
|
omp.taskloop mergeable {
|
|
omp.loop_nest (%i, %j) : i32 = (%lb, %ub) to (%ub, %lb) step (%step, %step) {
|
|
// CHECK: omp.yield
|
|
omp.yield
|
|
}
|
|
}
|
|
|
|
%testf32 = "test.f32"() : () -> (!llvm.ptr)
|
|
%testf32_2 = "test.f32"() : () -> (!llvm.ptr)
|
|
// CHECK: omp.taskloop in_reduction(@add_f32 %{{.+}} -> %{{.+}}, @add_f32 %{{.+}} -> %{{.+}} : !llvm.ptr, !llvm.ptr) {
|
|
omp.taskloop in_reduction(@add_f32 %testf32 -> %arg0, @add_f32 %testf32_2 -> %arg1 : !llvm.ptr, !llvm.ptr) {
|
|
omp.loop_nest (%i, %j) : i32 = (%lb, %ub) to (%ub, %lb) step (%step, %step) {
|
|
// CHECK: omp.yield
|
|
omp.yield
|
|
}
|
|
}
|
|
|
|
// Checking byref attribute for in_reduction
|
|
// CHECK: omp.taskloop in_reduction(byref @add_f32 %{{.+}} -> %{{.+}}, @add_f32 %{{.+}} -> %{{.+}} : !llvm.ptr, !llvm.ptr) {
|
|
omp.taskloop in_reduction(byref @add_f32 %testf32 -> %arg0, @add_f32 %testf32_2 -> %arg1 : !llvm.ptr, !llvm.ptr) {
|
|
omp.loop_nest (%i, %j) : i32 = (%lb, %ub) to (%ub, %lb) step (%step, %step) {
|
|
// CHECK: omp.yield
|
|
omp.yield
|
|
}
|
|
}
|
|
|
|
// CHECK: omp.taskloop reduction(byref @add_f32 %{{.+}} -> %{{.+}}, @add_f32 %{{.+}} -> %{{.+}} : !llvm.ptr, !llvm.ptr) {
|
|
omp.taskloop reduction(byref @add_f32 %testf32 -> %arg0, @add_f32 %testf32_2 -> %arg1 : !llvm.ptr, !llvm.ptr) {
|
|
omp.loop_nest (%i, %j) : i32 = (%lb, %ub) to (%ub, %lb) step (%step, %step) {
|
|
// CHECK: omp.yield
|
|
omp.yield
|
|
}
|
|
}
|
|
|
|
// check byref attrbute for reduction
|
|
// CHECK: omp.taskloop reduction(byref @add_f32 %{{.+}} -> %{{.+}}, byref @add_f32 %{{.+}} -> %{{.+}} : !llvm.ptr, !llvm.ptr) {
|
|
omp.taskloop reduction(byref @add_f32 %testf32 -> %arg0, byref @add_f32 %testf32_2 -> %arg1 : !llvm.ptr, !llvm.ptr) {
|
|
omp.loop_nest (%i, %j) : i32 = (%lb, %ub) to (%ub, %lb) step (%step, %step) {
|
|
// CHECK: omp.yield
|
|
omp.yield
|
|
}
|
|
}
|
|
|
|
// CHECK: omp.taskloop in_reduction(@add_f32 %{{.+}} -> %{{.+}} : !llvm.ptr) reduction(@add_f32 %{{.+}} -> %{{.+}} : !llvm.ptr) {
|
|
omp.taskloop in_reduction(@add_f32 %testf32 -> %arg0 : !llvm.ptr) reduction(@add_f32 %testf32_2 -> %arg1 : !llvm.ptr) {
|
|
omp.loop_nest (%i, %j) : i32 = (%lb, %ub) to (%ub, %lb) step (%step, %step) {
|
|
// CHECK: omp.yield
|
|
omp.yield
|
|
}
|
|
}
|
|
|
|
%testi32 = "test.i32"() : () -> (i32)
|
|
// CHECK: omp.taskloop priority(%{{[^:]+}}: i32) {
|
|
omp.taskloop priority(%testi32 : i32) {
|
|
omp.loop_nest (%i, %j) : i32 = (%lb, %ub) to (%ub, %lb) step (%step, %step) {
|
|
// CHECK: omp.yield
|
|
omp.yield
|
|
}
|
|
}
|
|
|
|
%testmemref = "test.memref"() : () -> (memref<i32>)
|
|
// CHECK: omp.taskloop allocate(%{{.+}} : memref<i32> -> %{{.+}} : memref<i32>) {
|
|
omp.taskloop allocate(%testmemref : memref<i32> -> %testmemref : memref<i32>) {
|
|
omp.loop_nest (%i, %j) : i32 = (%lb, %ub) to (%ub, %lb) step (%step, %step) {
|
|
// CHECK: omp.yield
|
|
omp.yield
|
|
}
|
|
}
|
|
|
|
%testi64 = "test.i64"() : () -> (i64)
|
|
// CHECK: omp.taskloop grainsize(%{{[^:]+}}: i64) {
|
|
omp.taskloop grainsize(%testi64: i64) {
|
|
omp.loop_nest (%i, %j) : i32 = (%lb, %ub) to (%ub, %lb) step (%step, %step) {
|
|
// CHECK: omp.yield
|
|
omp.yield
|
|
}
|
|
}
|
|
|
|
// CHECK: omp.taskloop num_tasks(%{{[^:]+}}: i64) {
|
|
omp.taskloop num_tasks(%testi64: i64) {
|
|
omp.loop_nest (%i, %j) : i32 = (%lb, %ub) to (%ub, %lb) step (%step, %step) {
|
|
// CHECK: omp.yield
|
|
omp.yield
|
|
}
|
|
}
|
|
|
|
// CHECK: omp.taskloop grainsize(strict, %{{[^:]+}}: i64) {
|
|
omp.taskloop grainsize(strict, %testi64: i64) {
|
|
omp.loop_nest (%i, %j) : i32 = (%lb, %ub) to (%ub, %lb) step (%step, %step) {
|
|
// CHECK: omp.yield
|
|
omp.yield
|
|
}
|
|
}
|
|
|
|
// CHECK: omp.taskloop num_tasks(strict, %{{[^:]+}}: i64) {
|
|
omp.taskloop num_tasks(strict, %testi64: i64) {
|
|
omp.loop_nest (%i, %j) : i32 = (%lb, %ub) to (%ub, %lb) step (%step, %step) {
|
|
// CHECK: omp.yield
|
|
omp.yield
|
|
}
|
|
}
|
|
|
|
// CHECK: omp.taskloop nogroup {
|
|
omp.taskloop nogroup {
|
|
omp.loop_nest (%i, %j) : i32 = (%lb, %ub) to (%ub, %lb) step (%step, %step) {
|
|
// CHECK: omp.yield
|
|
omp.yield
|
|
}
|
|
}
|
|
|
|
// CHECK: omp.taskloop {
|
|
omp.taskloop {
|
|
omp.simd {
|
|
omp.loop_nest (%i, %j) : i32 = (%lb, %ub) to (%ub, %lb) step (%step, %step) {
|
|
// CHECK: omp.yield
|
|
omp.yield
|
|
}
|
|
} {omp.composite}
|
|
} {omp.composite}
|
|
|
|
// CHECK: return
|
|
return
|
|
}
|
|
|
|
// CHECK: func.func @omp_requires_one
|
|
// CHECK-SAME: omp.requires = #omp<clause_requires reverse_offload>
|
|
func.func @omp_requires_one() -> ()
|
|
attributes {omp.requires = #omp<clause_requires reverse_offload>} {
|
|
return
|
|
}
|
|
|
|
// CHECK: func.func @omp_requires_multiple
|
|
// CHECK-SAME: omp.requires = #omp<clause_requires unified_address|dynamic_allocators>
|
|
func.func @omp_requires_multiple() -> ()
|
|
attributes {omp.requires = #omp<clause_requires unified_address|dynamic_allocators>} {
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: @opaque_pointers_atomic_rwu
|
|
// CHECK-SAME: (%[[v:.*]]: !llvm.ptr, %[[x:.*]]: !llvm.ptr)
|
|
func.func @opaque_pointers_atomic_rwu(%v: !llvm.ptr, %x: !llvm.ptr) {
|
|
// CHECK: omp.atomic.read %[[v]] = %[[x]] : !llvm.ptr, !llvm.ptr, i32
|
|
// CHECK: %[[VAL:.*]] = llvm.load %[[x]] : !llvm.ptr -> i32
|
|
// CHECK: omp.atomic.write %[[v]] = %[[VAL]] : !llvm.ptr, i32
|
|
// CHECK: omp.atomic.update %[[x]] : !llvm.ptr {
|
|
// CHECK-NEXT: ^{{[[:alnum:]]+}}(%[[XVAL:.*]]: i32):
|
|
// CHECK-NEXT: omp.yield(%[[XVAL]] : i32)
|
|
// CHECK-NEXT: }
|
|
omp.atomic.read %v = %x : !llvm.ptr, !llvm.ptr, i32
|
|
%val = llvm.load %x : !llvm.ptr -> i32
|
|
omp.atomic.write %v = %val : !llvm.ptr, i32
|
|
omp.atomic.update %x : !llvm.ptr {
|
|
^bb0(%xval: i32):
|
|
omp.yield(%xval : i32)
|
|
}
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: @opaque_pointers_reduction
|
|
// CHECK: atomic {
|
|
// CHECK-NEXT: ^{{[[:alnum:]]+}}(%{{.*}}: !llvm.ptr, %{{.*}}: !llvm.ptr):
|
|
// CHECK-NOT: cleanup
|
|
omp.declare_reduction @opaque_pointers_reduction : f32
|
|
init {
|
|
^bb0(%arg: f32):
|
|
%0 = arith.constant 0.0 : f32
|
|
omp.yield (%0 : f32)
|
|
}
|
|
combiner {
|
|
^bb1(%arg0: f32, %arg1: f32):
|
|
%1 = arith.addf %arg0, %arg1 : f32
|
|
omp.yield (%1 : f32)
|
|
}
|
|
atomic {
|
|
^bb2(%arg2: !llvm.ptr, %arg3: !llvm.ptr):
|
|
%2 = llvm.load %arg3 : !llvm.ptr -> f32
|
|
llvm.atomicrmw fadd %arg2, %2 monotonic : !llvm.ptr, f32
|
|
omp.yield
|
|
}
|
|
|
|
// CHECK-LABEL: @alloc_reduction
|
|
// CHECK-SAME: alloc {
|
|
// CHECK-NEXT: ^bb0(%[[ARG0:.*]]: !llvm.ptr):
|
|
// ...
|
|
// CHECK: omp.yield
|
|
// CHECK-NEXT: } init {
|
|
// CHECK: } combiner {
|
|
// CHECK: }
|
|
omp.declare_reduction @alloc_reduction : !llvm.ptr
|
|
alloc {
|
|
^bb0(%arg: !llvm.ptr):
|
|
%c1 = arith.constant 1 : i32
|
|
%0 = llvm.alloca %c1 x f32 : (i32) -> !llvm.ptr
|
|
omp.yield (%0 : !llvm.ptr)
|
|
}
|
|
init {
|
|
^bb0(%mold: !llvm.ptr, %alloc: !llvm.ptr):
|
|
%cst = arith.constant 1.0 : f32
|
|
llvm.store %cst, %alloc : f32, !llvm.ptr
|
|
omp.yield (%alloc : !llvm.ptr)
|
|
}
|
|
combiner {
|
|
^bb1(%arg0: !llvm.ptr, %arg1: !llvm.ptr):
|
|
%0 = llvm.load %arg0 : !llvm.ptr -> f32
|
|
%1 = llvm.load %arg1 : !llvm.ptr -> f32
|
|
%2 = arith.addf %0, %1 : f32
|
|
llvm.store %2, %arg0 : f32, !llvm.ptr
|
|
omp.yield (%arg0 : !llvm.ptr)
|
|
}
|
|
|
|
// CHECK-LABEL: omp_targets_with_map_bounds
|
|
// CHECK-SAME: (%[[ARG0:.*]]: !llvm.ptr, %[[ARG1:.*]]: !llvm.ptr)
|
|
func.func @omp_targets_with_map_bounds(%arg0: !llvm.ptr, %arg1: !llvm.ptr) -> () {
|
|
// CHECK: %[[C_00:.*]] = llvm.mlir.constant(4 : index) : i64
|
|
// CHECK: %[[C_01:.*]] = llvm.mlir.constant(1 : index) : i64
|
|
// CHECK: %[[C_02:.*]] = llvm.mlir.constant(1 : index) : i64
|
|
// CHECK: %[[C_03:.*]] = llvm.mlir.constant(1 : index) : i64
|
|
// CHECK: %[[BOUNDS0:.*]] = omp.map.bounds lower_bound(%[[C_01]] : i64) upper_bound(%[[C_00]] : i64) stride(%[[C_02]] : i64) start_idx(%[[C_03]] : i64)
|
|
// CHECK: %[[MAP0:.*]] = omp.map.info var_ptr(%[[ARG0]] : !llvm.ptr, !llvm.array<10 x i32>) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS0]]) -> !llvm.ptr {name = ""}
|
|
%0 = llvm.mlir.constant(4 : index) : i64
|
|
%1 = llvm.mlir.constant(1 : index) : i64
|
|
%2 = llvm.mlir.constant(1 : index) : i64
|
|
%3 = llvm.mlir.constant(1 : index) : i64
|
|
%4 = omp.map.bounds lower_bound(%1 : i64) upper_bound(%0 : i64) stride(%2 : i64) start_idx(%3 : i64)
|
|
|
|
%mapv1 = omp.map.info var_ptr(%arg0 : !llvm.ptr, !llvm.array<10 x i32>) map_clauses(tofrom) capture(ByRef) bounds(%4) -> !llvm.ptr {name = ""}
|
|
// CHECK: %[[C_10:.*]] = llvm.mlir.constant(9 : index) : i64
|
|
// CHECK: %[[C_11:.*]] = llvm.mlir.constant(1 : index) : i64
|
|
// CHECK: %[[C_12:.*]] = llvm.mlir.constant(2 : index) : i64
|
|
// CHECK: %[[C_13:.*]] = llvm.mlir.constant(2 : index) : i64
|
|
// CHECK: %[[BOUNDS1:.*]] = omp.map.bounds lower_bound(%[[C_11]] : i64) upper_bound(%[[C_10]] : i64) stride(%[[C_12]] : i64) start_idx(%[[C_13]] : i64)
|
|
// CHECK: %[[MAP1:.*]] = omp.map.info var_ptr(%[[ARG1]] : !llvm.ptr, !llvm.array<10 x i32>) mapper(@my_mapper) map_clauses(exit_release_or_enter_alloc) capture(ByCopy) bounds(%[[BOUNDS1]]) -> !llvm.ptr {name = ""}
|
|
%6 = llvm.mlir.constant(9 : index) : i64
|
|
%7 = llvm.mlir.constant(1 : index) : i64
|
|
%8 = llvm.mlir.constant(2 : index) : i64
|
|
%9 = llvm.mlir.constant(2 : index) : i64
|
|
%10 = omp.map.bounds lower_bound(%7 : i64) upper_bound(%6 : i64) stride(%8 : i64) start_idx(%9 : i64)
|
|
%mapv2 = omp.map.info var_ptr(%arg1 : !llvm.ptr, !llvm.array<10 x i32>) mapper(@my_mapper) map_clauses(exit_release_or_enter_alloc) capture(ByCopy) bounds(%10) -> !llvm.ptr {name = ""}
|
|
|
|
// CHECK: omp.target map_entries(%[[MAP0]] -> {{.*}}, %[[MAP1]] -> {{.*}} : !llvm.ptr, !llvm.ptr)
|
|
omp.target map_entries(%mapv1 -> %arg2, %mapv2 -> %arg3 : !llvm.ptr, !llvm.ptr) {
|
|
omp.terminator
|
|
}
|
|
|
|
// CHECK: omp.target_data map_entries(%[[MAP0]], %[[MAP1]] : !llvm.ptr, !llvm.ptr)
|
|
omp.target_data map_entries(%mapv1, %mapv2 : !llvm.ptr, !llvm.ptr){}
|
|
|
|
// CHECK: %[[MAP2:.*]] = omp.map.info var_ptr(%[[ARG0]] : !llvm.ptr, !llvm.array<10 x i32>) map_clauses(exit_release_or_enter_alloc) capture(VLAType) bounds(%[[BOUNDS0]]) -> !llvm.ptr {name = ""}
|
|
// CHECK: omp.target_enter_data map_entries(%[[MAP2]] : !llvm.ptr)
|
|
%mapv3 = omp.map.info var_ptr(%arg0 : !llvm.ptr, !llvm.array<10 x i32>) map_clauses(exit_release_or_enter_alloc) capture(VLAType) bounds(%4) -> !llvm.ptr {name = ""}
|
|
omp.target_enter_data map_entries(%mapv3 : !llvm.ptr){}
|
|
|
|
// CHECK: %[[MAP3:.*]] = omp.map.info var_ptr(%[[ARG1]] : !llvm.ptr, !llvm.array<10 x i32>) map_clauses(exit_release_or_enter_alloc) capture(This) bounds(%[[BOUNDS1]]) -> !llvm.ptr {name = ""}
|
|
// CHECK: omp.target_exit_data map_entries(%[[MAP3]] : !llvm.ptr)
|
|
%mapv4 = omp.map.info var_ptr(%arg1 : !llvm.ptr, !llvm.array<10 x i32>) map_clauses(exit_release_or_enter_alloc) capture(This) bounds(%10) -> !llvm.ptr {name = ""}
|
|
omp.target_exit_data map_entries(%mapv4 : !llvm.ptr){}
|
|
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: omp_target_update_data
|
|
func.func @omp_target_update_data (%if_cond : i1, %device : si32, %map1: memref<?xi32>, %map2: memref<?xi32>) -> () {
|
|
%mapv_from = omp.map.info var_ptr(%map1 : memref<?xi32>, tensor<?xi32>) map_clauses(from) capture(ByRef) -> memref<?xi32> {name = ""}
|
|
|
|
%mapv_to = omp.map.info var_ptr(%map2 : memref<?xi32>, tensor<?xi32>) map_clauses(present, to) capture(ByRef) -> memref<?xi32> {name = ""}
|
|
|
|
// CHECK: omp.target_update device(%[[VAL_1:.*]] : si32) if(%[[VAL_0:.*]]) map_entries(%{{.*}}, %{{.*}} : memref<?xi32>, memref<?xi32>) nowait
|
|
omp.target_update if(%if_cond) device(%device : si32) nowait map_entries(%mapv_from , %mapv_to : memref<?xi32>, memref<?xi32>)
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: omp_targets_is_allocatable
|
|
// CHECK-SAME: (%[[ARG0:.*]]: !llvm.ptr, %[[ARG1:.*]]: !llvm.ptr)
|
|
func.func @omp_targets_is_allocatable(%arg0: !llvm.ptr, %arg1: !llvm.ptr) -> () {
|
|
// CHECK: %[[MAP0:.*]] = omp.map.info var_ptr(%[[ARG0]] : !llvm.ptr, i32) map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {name = ""}
|
|
%mapv1 = omp.map.info var_ptr(%arg0 : !llvm.ptr, i32) map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {name = ""}
|
|
// CHECK: %[[MAP1:.*]] = omp.map.info var_ptr(%[[ARG1]] : !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>) map_clauses(tofrom) capture(ByRef) members(%[[MAP0]] : [0] : !llvm.ptr) -> !llvm.ptr {name = ""}
|
|
%mapv2 = omp.map.info var_ptr(%arg1 : !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>) map_clauses(tofrom) capture(ByRef) members(%mapv1 : [0] : !llvm.ptr) -> !llvm.ptr {name = ""}
|
|
// CHECK: omp.target map_entries(%[[MAP0]] -> {{.*}}, %[[MAP1]] -> {{.*}} : !llvm.ptr, !llvm.ptr)
|
|
omp.target map_entries(%mapv1 -> %arg2, %mapv2 -> %arg3 : !llvm.ptr, !llvm.ptr) {
|
|
omp.terminator
|
|
}
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: func @omp_target_enter_update_exit_data_depend
|
|
// CHECK-SAME:([[ARG0:%.*]]: memref<?xi32>, [[ARG1:%.*]]: memref<?xi32>, [[ARG2:%.*]]: memref<?xi32>) {
|
|
func.func @omp_target_enter_update_exit_data_depend(%a: memref<?xi32>, %b: memref<?xi32>, %c: memref<?xi32>) {
|
|
// CHECK-NEXT: [[MAP0:%.*]] = omp.map.info
|
|
// CHECK-NEXT: [[MAP1:%.*]] = omp.map.info
|
|
// CHECK-NEXT: [[MAP2:%.*]] = omp.map.info
|
|
%map_a = omp.map.info var_ptr(%a: memref<?xi32>, tensor<?xi32>) map_clauses(to) capture(ByRef) -> memref<?xi32>
|
|
%map_b = omp.map.info var_ptr(%b: memref<?xi32>, tensor<?xi32>) map_clauses(from) capture(ByRef) -> memref<?xi32>
|
|
%map_c = omp.map.info var_ptr(%c: memref<?xi32>, tensor<?xi32>) map_clauses(exit_release_or_enter_alloc) capture(ByRef) -> memref<?xi32>
|
|
|
|
// Do some work on the host that writes to 'a'
|
|
omp.task depend(taskdependout -> %a : memref<?xi32>) {
|
|
"test.foo"(%a) : (memref<?xi32>) -> ()
|
|
omp.terminator
|
|
}
|
|
|
|
// Then map that over to the target
|
|
// CHECK: omp.target_enter_data depend(taskdependin -> [[ARG0]] : memref<?xi32>) map_entries([[MAP0]], [[MAP2]] : memref<?xi32>, memref<?xi32>) nowait
|
|
omp.target_enter_data depend(taskdependin -> %a: memref<?xi32>) nowait map_entries(%map_a, %map_c: memref<?xi32>, memref<?xi32>)
|
|
|
|
// Compute 'b' on the target and copy it back
|
|
// CHECK: omp.target map_entries([[MAP1]] -> {{%.*}} : memref<?xi32>) {
|
|
omp.target map_entries(%map_b -> %arg0 : memref<?xi32>) {
|
|
"test.foo"(%arg0) : (memref<?xi32>) -> ()
|
|
omp.terminator
|
|
}
|
|
|
|
// Update 'a' on the host using 'b'
|
|
omp.task depend(taskdependout -> %a: memref<?xi32>){
|
|
"test.bar"(%a, %b) : (memref<?xi32>, memref<?xi32>) -> ()
|
|
}
|
|
|
|
// Copy the updated 'a' onto the target
|
|
// CHECK: omp.target_update depend(taskdependin -> [[ARG0]] : memref<?xi32>) map_entries([[MAP0]] : memref<?xi32>) nowait
|
|
omp.target_update depend(taskdependin -> %a : memref<?xi32>) nowait map_entries(%map_a : memref<?xi32>)
|
|
|
|
// Compute 'c' on the target and copy it back
|
|
%map_c_from = omp.map.info var_ptr(%c: memref<?xi32>, tensor<?xi32>) map_clauses(from) capture(ByRef) -> memref<?xi32>
|
|
omp.target depend(taskdependout -> %c : memref<?xi32>) map_entries(%map_a -> %arg0, %map_c_from -> %arg1 : memref<?xi32>, memref<?xi32>) {
|
|
"test.foobar"() : ()->()
|
|
omp.terminator
|
|
}
|
|
// CHECK: omp.target_exit_data depend(taskdependin -> [[ARG2]] : memref<?xi32>) map_entries([[MAP2]] : memref<?xi32>)
|
|
omp.target_exit_data depend(taskdependin -> %c : memref<?xi32>) map_entries(%map_c : memref<?xi32>)
|
|
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: omp_map_with_members
|
|
// CHECK-SAME: (%[[ARG0:.*]]: !llvm.ptr, %[[ARG1:.*]]: !llvm.ptr, %[[ARG2:.*]]: !llvm.ptr, %[[ARG3:.*]]: !llvm.ptr, %[[ARG4:.*]]: !llvm.ptr, %[[ARG5:.*]]: !llvm.ptr)
|
|
func.func @omp_map_with_members(%arg0: !llvm.ptr, %arg1: !llvm.ptr, %arg2: !llvm.ptr, %arg3: !llvm.ptr, %arg4: !llvm.ptr, %arg5: !llvm.ptr) -> () {
|
|
// CHECK: %[[MAP0:.*]] = omp.map.info var_ptr(%[[ARG0]] : !llvm.ptr, i32) map_clauses(to) capture(ByRef) -> !llvm.ptr {name = ""}
|
|
%mapv1 = omp.map.info var_ptr(%arg0 : !llvm.ptr, i32) map_clauses(to) capture(ByRef) -> !llvm.ptr {name = ""}
|
|
|
|
// CHECK: %[[MAP1:.*]] = omp.map.info var_ptr(%[[ARG1]] : !llvm.ptr, f32) map_clauses(to) capture(ByRef) -> !llvm.ptr {name = ""}
|
|
%mapv2 = omp.map.info var_ptr(%arg1 : !llvm.ptr, f32) map_clauses(to) capture(ByRef) -> !llvm.ptr {name = ""}
|
|
|
|
// CHECK: %[[MAP2:.*]] = omp.map.info var_ptr(%[[ARG2]] : !llvm.ptr, !llvm.struct<(i32, f32)>) map_clauses(to) capture(ByRef) members(%[[MAP0]], %[[MAP1]] : [0], [1] : !llvm.ptr, !llvm.ptr) -> !llvm.ptr {name = "", partial_map = true}
|
|
%mapv3 = omp.map.info var_ptr(%arg2 : !llvm.ptr, !llvm.struct<(i32, f32)>) map_clauses(to) capture(ByRef) members(%mapv1, %mapv2 : [0], [1] : !llvm.ptr, !llvm.ptr) -> !llvm.ptr {name = "", partial_map = true}
|
|
|
|
// CHECK: omp.target_enter_data map_entries(%[[MAP0]], %[[MAP1]], %[[MAP2]] : !llvm.ptr, !llvm.ptr, !llvm.ptr)
|
|
omp.target_enter_data map_entries(%mapv1, %mapv2, %mapv3 : !llvm.ptr, !llvm.ptr, !llvm.ptr){}
|
|
|
|
// CHECK: %[[MAP3:.*]] = omp.map.info var_ptr(%[[ARG3]] : !llvm.ptr, i32) map_clauses(from) capture(ByRef) -> !llvm.ptr {name = ""}
|
|
%mapv4 = omp.map.info var_ptr(%arg3 : !llvm.ptr, i32) map_clauses(from) capture(ByRef) -> !llvm.ptr {name = ""}
|
|
|
|
// CHECK: %[[MAP4:.*]] = omp.map.info var_ptr(%[[ARG4]] : !llvm.ptr, f32) map_clauses(from) capture(ByRef) -> !llvm.ptr {name = ""}
|
|
%mapv5 = omp.map.info var_ptr(%arg4 : !llvm.ptr, f32) map_clauses(from) capture(ByRef) -> !llvm.ptr {name = ""}
|
|
|
|
// CHECK: %[[MAP5:.*]] = omp.map.info var_ptr(%[[ARG5]] : !llvm.ptr, !llvm.struct<(i32, struct<(i32, f32)>)>) map_clauses(from) capture(ByRef) members(%[[MAP3]], %[[MAP4]] : [1, 0], [1, 1] : !llvm.ptr, !llvm.ptr) -> !llvm.ptr {name = "", partial_map = true}
|
|
%mapv6 = omp.map.info var_ptr(%arg5 : !llvm.ptr, !llvm.struct<(i32, struct<(i32, f32)>)>) map_clauses(from) capture(ByRef) members(%mapv4, %mapv5 : [1, 0], [1, 1] : !llvm.ptr, !llvm.ptr) -> !llvm.ptr {name = "", partial_map = true}
|
|
|
|
// CHECK: omp.target_exit_data map_entries(%[[MAP3]], %[[MAP4]], %[[MAP5]] : !llvm.ptr, !llvm.ptr, !llvm.ptr)
|
|
omp.target_exit_data map_entries(%mapv4, %mapv5, %mapv6 : !llvm.ptr, !llvm.ptr, !llvm.ptr){}
|
|
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: parallel_op_privatizers
|
|
// CHECK-SAME: (%[[ARG0:[^[:space:]]+]]: !llvm.ptr, %[[ARG1:[^[:space:]]+]]: !llvm.ptr)
|
|
func.func @parallel_op_privatizers(%arg0: !llvm.ptr, %arg1: !llvm.ptr) {
|
|
// CHECK: omp.parallel private(
|
|
// CHECK-SAME: @x.privatizer %[[ARG0]] -> %[[ARG0_PRIV:[^[:space:]]+]],
|
|
// CHECK-SAME: @y.privatizer %[[ARG1]] -> %[[ARG1_PRIV:[^[:space:]]+]] : !llvm.ptr, !llvm.ptr)
|
|
omp.parallel private(@x.privatizer %arg0 -> %arg2, @y.privatizer %arg1 -> %arg3 : !llvm.ptr, !llvm.ptr) {
|
|
// CHECK: llvm.load %[[ARG0_PRIV]]
|
|
%0 = llvm.load %arg2 : !llvm.ptr -> i32
|
|
// CHECK: llvm.load %[[ARG1_PRIV]]
|
|
%1 = llvm.load %arg3 : !llvm.ptr -> i32
|
|
omp.terminator
|
|
}
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: omp.private {type = private} @a.privatizer : !llvm.ptr init {
|
|
omp.private {type = private} @a.privatizer : !llvm.ptr init {
|
|
// CHECK: ^bb0(%{{.*}}: {{.*}}, %{{.*}}: {{.*}}):
|
|
^bb0(%arg0: !llvm.ptr, %arg1: !llvm.ptr):
|
|
omp.yield(%arg0 : !llvm.ptr)
|
|
}
|
|
|
|
// CHECK-LABEL: omp.private {type = private} @x.privatizer : !llvm.ptr init {
|
|
omp.private {type = private} @x.privatizer : !llvm.ptr init {
|
|
// CHECK: ^bb0(%{{.*}}: {{.*}}, %{{.*}}: {{.*}}):
|
|
^bb0(%arg0: !llvm.ptr, %arg1: !llvm.ptr):
|
|
omp.yield(%arg0 : !llvm.ptr)
|
|
// CHECK: } dealloc {
|
|
} dealloc {
|
|
// CHECK: ^bb0(%{{.*}}: {{.*}}):
|
|
^bb0(%arg0: !llvm.ptr):
|
|
omp.yield
|
|
}
|
|
|
|
// CHECK-LABEL: omp.private {type = firstprivate} @y.privatizer : !llvm.ptr copy {
|
|
omp.private {type = firstprivate} @y.privatizer : !llvm.ptr copy {
|
|
// CHECK: ^bb0(%{{.*}}: {{.*}}, %{{.*}}: {{.*}}):
|
|
^bb0(%arg0: !llvm.ptr, %arg1: !llvm.ptr):
|
|
omp.yield(%arg0 : !llvm.ptr)
|
|
// CHECK: } dealloc {
|
|
} dealloc {
|
|
// CHECK: ^bb0(%{{.*}}: {{.*}}):
|
|
^bb0(%arg0: !llvm.ptr):
|
|
omp.yield
|
|
}
|
|
|
|
// CHECK-LABEL: parallel_op_reduction_and_private
|
|
func.func @parallel_op_reduction_and_private(%priv_var: !llvm.ptr, %priv_var2: !llvm.ptr, %reduc_var: !llvm.ptr, %reduc_var2: !llvm.ptr) {
|
|
// CHECK: omp.parallel
|
|
// CHECK-SAME: private(
|
|
// CHECK-SAME: @x.privatizer %[[PRIV_VAR:[^[:space:]]+]] -> %[[PRIV_ARG:[^[:space:]]+]],
|
|
// CHECK-SAME: @y.privatizer %[[PRIV_VAR2:[^[:space:]]+]] -> %[[PRIV_ARG2:[^[:space:]]+]] : !llvm.ptr, !llvm.ptr)
|
|
//
|
|
// CHECK-SAME: reduction(
|
|
// CHECK-SAME: @add_f32 %[[REDUC_VAR:[^[:space:]]+]] -> %[[REDUC_ARG:[^[:space:]]+]],
|
|
// CHECK-SAME: @add_f32 %[[REDUC_VAR2:[^[:space:]]+]] -> %[[REDUC_ARG2:[^[:space:]]+]] : !llvm.ptr, !llvm.ptr)
|
|
omp.parallel private(@x.privatizer %priv_var -> %priv_arg, @y.privatizer %priv_var2 -> %priv_arg2 : !llvm.ptr, !llvm.ptr)
|
|
reduction(@add_f32 %reduc_var -> %reduc_arg, @add_f32 %reduc_var2 -> %reduc_arg2 : !llvm.ptr, !llvm.ptr) {
|
|
// CHECK: llvm.load %[[PRIV_ARG]]
|
|
%0 = llvm.load %priv_arg : !llvm.ptr -> f32
|
|
// CHECK: llvm.load %[[PRIV_ARG2]]
|
|
%1 = llvm.load %priv_arg2 : !llvm.ptr -> f32
|
|
// CHECK: llvm.load %[[REDUC_ARG]]
|
|
%2 = llvm.load %reduc_arg : !llvm.ptr -> f32
|
|
// CHECK: llvm.load %[[REDUC_ARG2]]
|
|
%3 = llvm.load %reduc_arg2 : !llvm.ptr -> f32
|
|
omp.terminator
|
|
}
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: omp_target_private
|
|
func.func @omp_target_private(%map1: memref<?xi32>, %map2: memref<?xi32>, %priv_var: !llvm.ptr) -> () {
|
|
%mapv1 = omp.map.info var_ptr(%map1 : memref<?xi32>, tensor<?xi32>) map_clauses(tofrom) capture(ByRef) -> memref<?xi32> {name = ""}
|
|
%mapv2 = omp.map.info var_ptr(%map2 : memref<?xi32>, tensor<?xi32>) map_clauses(exit_release_or_enter_alloc) capture(ByRef) -> memref<?xi32> {name = ""}
|
|
|
|
// CHECK: omp.target
|
|
// CHECK-SAME: private(
|
|
// CHECK-SAME: @x.privatizer %{{[^[:space:]]+}} -> %[[PRIV_ARG:[^[:space:]]+]]
|
|
// CHECK-SAME: : !llvm.ptr
|
|
// CHECK-SAME: )
|
|
omp.target private(@x.privatizer %priv_var -> %priv_arg : !llvm.ptr) {
|
|
omp.terminator
|
|
}
|
|
|
|
// CHECK: omp.target
|
|
|
|
// CHECK-SAME: map_entries(
|
|
// CHECK-SAME: %{{[^[:space:]]+}} -> %[[MAP1_ARG:[^[:space:]]+]],
|
|
// CHECK-SAME: %{{[^[:space:]]+}} -> %[[MAP2_ARG:[^[:space:]]+]]
|
|
// CHECK-SAME: : memref<?xi32>, memref<?xi32>
|
|
// CHECK-SAME: )
|
|
|
|
// CHECK-SAME: private(
|
|
// CHECK-SAME: @x.privatizer %{{[^[:space:]]+}} -> %[[PRIV_ARG:[^[:space:]]+]]
|
|
// CHECK-SAME: : !llvm.ptr
|
|
// CHECK-SAME: )
|
|
omp.target map_entries(%mapv1 -> %arg0, %mapv2 -> %arg1 : memref<?xi32>, memref<?xi32>) private(@x.privatizer %priv_var -> %priv_arg : !llvm.ptr) {
|
|
omp.terminator
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: omp_target_private_with_map_idx
|
|
func.func @omp_target_private_with_map_idx(%map1: memref<?xi32>, %map2: memref<?xi32>, %priv_var: !llvm.ptr) -> () {
|
|
%mapv1 = omp.map.info var_ptr(%map1 : memref<?xi32>, tensor<?xi32>) map_clauses(tofrom) capture(ByRef) -> memref<?xi32> {name = ""}
|
|
%mapv2 = omp.map.info var_ptr(%map2 : memref<?xi32>, tensor<?xi32>) map_clauses(exit_release_or_enter_alloc) capture(ByRef) -> memref<?xi32> {name = ""}
|
|
|
|
// CHECK: omp.target
|
|
|
|
// CHECK-SAME: map_entries(
|
|
// CHECK-SAME: %{{[^[:space:]]+}} -> %[[MAP1_ARG:[^[:space:]]+]],
|
|
// CHECK-SAME: %{{[^[:space:]]+}} -> %[[MAP2_ARG:[^[:space:]]+]]
|
|
// CHECK-SAME: : memref<?xi32>, memref<?xi32>
|
|
// CHECK-SAME: )
|
|
|
|
// CHECK-SAME: private(
|
|
// CHECK-SAME: @x.privatizer %{{[^[:space:]]+}} -> %[[PRIV_ARG:[^[:space:]]+]] [map_idx=1]
|
|
// CHECK-SAME: : !llvm.ptr
|
|
// CHECK-SAME: )
|
|
omp.target map_entries(%mapv1 -> %arg0, %mapv2 -> %arg1 : memref<?xi32>, memref<?xi32>) private(@x.privatizer %priv_var -> %priv_arg [map_idx=1] : !llvm.ptr) {
|
|
omp.terminator
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func.func @omp_target_host_eval(%x : i32) {
|
|
// CHECK: omp.target host_eval(%{{.*}} -> %[[HOST_ARG:.*]] : i32) {
|
|
// CHECK: omp.teams num_teams( to %[[HOST_ARG]] : i32)
|
|
// CHECK-SAME: thread_limit(%[[HOST_ARG]] : i32)
|
|
omp.target host_eval(%x -> %arg0 : i32) {
|
|
omp.teams num_teams(to %arg0 : i32) thread_limit(%arg0 : i32) {
|
|
omp.terminator
|
|
}
|
|
omp.terminator
|
|
}
|
|
|
|
// CHECK: omp.target host_eval(%{{.*}} -> %[[HOST_ARG:.*]] : i32) {
|
|
// CHECK: omp.teams {
|
|
// CHECK: omp.parallel num_threads(%[[HOST_ARG]] : i32) {
|
|
// CHECK: omp.distribute {
|
|
// CHECK: omp.wsloop {
|
|
// CHECK: omp.loop_nest (%{{.*}}) : i32 = (%[[HOST_ARG]]) to (%[[HOST_ARG]]) step (%[[HOST_ARG]]) {
|
|
omp.target host_eval(%x -> %arg0 : i32) {
|
|
omp.teams {
|
|
omp.parallel num_threads(%arg0 : i32) {
|
|
omp.distribute {
|
|
omp.wsloop {
|
|
omp.loop_nest (%iv) : i32 = (%arg0) to (%arg0) step (%arg0) {
|
|
omp.yield
|
|
}
|
|
} {omp.composite}
|
|
} {omp.composite}
|
|
omp.terminator
|
|
} {omp.composite}
|
|
omp.terminator
|
|
}
|
|
omp.terminator
|
|
}
|
|
|
|
// CHECK: omp.target host_eval(%{{.*}} -> %[[HOST_ARG:.*]] : i32) {
|
|
// CHECK: omp.teams {
|
|
// CHECK: omp.distribute {
|
|
// CHECK: omp.loop_nest (%{{.*}}) : i32 = (%[[HOST_ARG]]) to (%[[HOST_ARG]]) step (%[[HOST_ARG]]) {
|
|
omp.target host_eval(%x -> %arg0 : i32) {
|
|
omp.teams {
|
|
omp.distribute {
|
|
omp.loop_nest (%iv) : i32 = (%arg0) to (%arg0) step (%arg0) {
|
|
omp.yield
|
|
}
|
|
}
|
|
omp.terminator
|
|
}
|
|
omp.terminator
|
|
}
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: omp_loop
|
|
func.func @omp_loop(%lb : index, %ub : index, %step : index) {
|
|
// CHECK: omp.loop {
|
|
omp.loop {
|
|
// CHECK: omp.loop_nest {{.*}} {
|
|
omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
|
|
// CHECK: omp.yield
|
|
omp.yield
|
|
}
|
|
// CHECK: }
|
|
}
|
|
// CHECK: }
|
|
|
|
// CHECK: omp.loop bind(teams) {
|
|
omp.loop bind(teams) {
|
|
omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
|
|
omp.yield
|
|
}
|
|
}
|
|
// CHECK: }
|
|
|
|
// CHECK: omp.loop bind(parallel) {
|
|
omp.loop bind(parallel) {
|
|
omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
|
|
omp.yield
|
|
}
|
|
}
|
|
// CHECK: }
|
|
|
|
// CHECK: omp.loop bind(thread) {
|
|
omp.loop bind(thread) {
|
|
omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
|
|
omp.yield
|
|
}
|
|
}
|
|
// CHECK: }
|
|
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: func @omp_workshare
|
|
func.func @omp_workshare() {
|
|
// CHECK: omp.workshare {
|
|
omp.workshare {
|
|
"test.payload"() : () -> ()
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: func @omp_workshare_nowait
|
|
func.func @omp_workshare_nowait() {
|
|
// CHECK: omp.workshare nowait {
|
|
omp.workshare nowait {
|
|
"test.payload"() : () -> ()
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: func @omp_workshare_multiple_blocks
|
|
func.func @omp_workshare_multiple_blocks() {
|
|
// CHECK: omp.workshare {
|
|
omp.workshare {
|
|
cf.br ^bb2
|
|
^bb2:
|
|
// CHECK: omp.terminator
|
|
omp.terminator
|
|
}
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: func @omp_workshare_loop_wrapper
|
|
func.func @omp_workshare_loop_wrapper(%idx : index) {
|
|
// CHECK-NEXT: omp.workshare {
|
|
omp.workshare {
|
|
// CHECK-NEXT: omp.workshare.loop_wrapper
|
|
omp.workshare.loop_wrapper {
|
|
// CHECK-NEXT: omp.loop_nest
|
|
omp.loop_nest (%iv) : index = (%idx) to (%idx) step (%idx) {
|
|
omp.yield
|
|
}
|
|
}
|
|
omp.terminator
|
|
}
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: func @omp_workshare_loop_wrapper_attrs
|
|
func.func @omp_workshare_loop_wrapper_attrs(%idx : index) {
|
|
// CHECK-NEXT: omp.workshare {
|
|
omp.workshare {
|
|
// CHECK-NEXT: omp.workshare.loop_wrapper {
|
|
omp.workshare.loop_wrapper {
|
|
// CHECK-NEXT: omp.loop_nest
|
|
omp.loop_nest (%iv) : index = (%idx) to (%idx) step (%idx) {
|
|
omp.yield
|
|
}
|
|
// CHECK: } {attr_in_dict}
|
|
} {attr_in_dict}
|
|
omp.terminator
|
|
}
|
|
return
|
|
}
|