Add an operation omp.critical.declare to declare names/symbols of critical sections. Named omp.critical operations should use symbols declared by omp.critical.declare. Having a declare operation ensures that the names of critical sections are global and unique. In the lowering flow to LLVM IR, the OpenMP IRBuilder creates unique names for critical sections. Reviewed By: ftynse, jeanPerier Differential Revision: https://reviews.llvm.org/D108713
316 lines
7.0 KiB
MLIR
316 lines
7.0 KiB
MLIR
// RUN: mlir-opt -split-input-file -verify-diagnostics %s
|
|
|
|
func @unknown_clause() {
|
|
// expected-error@+1 {{invalid is not a valid clause for the omp.parallel operation}}
|
|
omp.parallel invalid {
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// -----
|
|
|
|
func @if_once(%n : i1) {
|
|
// expected-error@+1 {{at most one if clause can appear on the omp.parallel operation}}
|
|
omp.parallel if(%n : i1) if(%n : i1) {
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// -----
|
|
|
|
func @num_threads_once(%n : si32) {
|
|
// expected-error@+1 {{at most one num_threads clause can appear on the omp.parallel operation}}
|
|
omp.parallel num_threads(%n : si32) num_threads(%n : si32) {
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// -----
|
|
|
|
func @private_once(%n : memref<i32>) {
|
|
// expected-error@+1 {{at most one private clause can appear on the omp.parallel operation}}
|
|
omp.parallel private(%n : memref<i32>) private(%n : memref<i32>) {
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// -----
|
|
|
|
func @firstprivate_once(%n : memref<i32>) {
|
|
// expected-error@+1 {{at most one firstprivate clause can appear on the omp.parallel operation}}
|
|
omp.parallel firstprivate(%n : memref<i32>) firstprivate(%n : memref<i32>) {
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// -----
|
|
|
|
func @shared_once(%n : memref<i32>) {
|
|
// expected-error@+1 {{at most one shared clause can appear on the omp.parallel operation}}
|
|
omp.parallel shared(%n : memref<i32>) shared(%n : memref<i32>) {
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// -----
|
|
|
|
func @copyin_once(%n : memref<i32>) {
|
|
// expected-error@+1 {{at most one copyin clause can appear on the omp.parallel operation}}
|
|
omp.parallel copyin(%n : memref<i32>) copyin(%n : memref<i32>) {
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// -----
|
|
|
|
func @default_once() {
|
|
// expected-error@+1 {{at most one default clause can appear on the omp.parallel operation}}
|
|
omp.parallel default(private) default(firstprivate) {
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// -----
|
|
|
|
func @proc_bind_once() {
|
|
// expected-error@+1 {{at most one proc_bind clause can appear on the omp.parallel operation}}
|
|
omp.parallel proc_bind(close) proc_bind(spread) {
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// -----
|
|
|
|
// expected-error @below {{op expects initializer region with one argument of the reduction type}}
|
|
omp.reduction.declare @add_f32 : f64
|
|
init {
|
|
^bb0(%arg: f32):
|
|
%0 = constant 0.0 : f32
|
|
omp.yield (%0 : f32)
|
|
}
|
|
combiner {
|
|
^bb1(%arg0: f32, %arg1: f32):
|
|
%1 = addf %arg0, %arg1 : f32
|
|
omp.yield (%1 : f32)
|
|
}
|
|
|
|
// -----
|
|
|
|
// expected-error @below {{expects initializer region to yield a value of the reduction type}}
|
|
omp.reduction.declare @add_f32 : f32
|
|
init {
|
|
^bb0(%arg: f32):
|
|
%0 = constant 0.0 : f64
|
|
omp.yield (%0 : f64)
|
|
}
|
|
combiner {
|
|
^bb1(%arg0: f32, %arg1: f32):
|
|
%1 = addf %arg0, %arg1 : f32
|
|
omp.yield (%1 : f32)
|
|
}
|
|
|
|
// -----
|
|
|
|
// expected-error @below {{expects reduction region with two arguments of the reduction type}}
|
|
omp.reduction.declare @add_f32 : f32
|
|
init {
|
|
^bb0(%arg: f32):
|
|
%0 = constant 0.0 : f32
|
|
omp.yield (%0 : f32)
|
|
}
|
|
combiner {
|
|
^bb1(%arg0: f64, %arg1: f64):
|
|
%1 = addf %arg0, %arg1 : f64
|
|
omp.yield (%1 : f64)
|
|
}
|
|
|
|
// -----
|
|
|
|
// expected-error @below {{expects reduction region to yield a value of the reduction type}}
|
|
omp.reduction.declare @add_f32 : f32
|
|
init {
|
|
^bb0(%arg: f32):
|
|
%0 = constant 0.0 : f32
|
|
omp.yield (%0 : f32)
|
|
}
|
|
combiner {
|
|
^bb1(%arg0: f32, %arg1: f32):
|
|
%1 = addf %arg0, %arg1 : f32
|
|
%2 = fpext %1 : f32 to f64
|
|
omp.yield (%2 : f64)
|
|
}
|
|
|
|
// -----
|
|
|
|
// expected-error @below {{expects atomic reduction region with two arguments of the same type}}
|
|
omp.reduction.declare @add_f32 : f32
|
|
init {
|
|
^bb0(%arg: f32):
|
|
%0 = constant 0.0 : f32
|
|
omp.yield (%0 : f32)
|
|
}
|
|
combiner {
|
|
^bb1(%arg0: f32, %arg1: f32):
|
|
%1 = addf %arg0, %arg1 : f32
|
|
omp.yield (%1 : f32)
|
|
}
|
|
atomic {
|
|
^bb2(%arg0: memref<f32>, %arg1: memref<f64>):
|
|
omp.yield
|
|
}
|
|
|
|
// -----
|
|
|
|
// expected-error @below {{expects atomic reduction region arguments to be accumulators containing the reduction type}}
|
|
omp.reduction.declare @add_f32 : f32
|
|
init {
|
|
^bb0(%arg: f32):
|
|
%0 = constant 0.0 : f32
|
|
omp.yield (%0 : f32)
|
|
}
|
|
combiner {
|
|
^bb1(%arg0: f32, %arg1: f32):
|
|
%1 = addf %arg0, %arg1 : f32
|
|
omp.yield (%1 : f32)
|
|
}
|
|
atomic {
|
|
^bb2(%arg0: memref<f64>, %arg1: memref<f64>):
|
|
omp.yield
|
|
}
|
|
|
|
// -----
|
|
|
|
omp.reduction.declare @add_f32 : f32
|
|
init {
|
|
^bb0(%arg: f32):
|
|
%0 = constant 0.0 : f32
|
|
omp.yield (%0 : f32)
|
|
}
|
|
combiner {
|
|
^bb1(%arg0: f32, %arg1: f32):
|
|
%1 = addf %arg0, %arg1 : f32
|
|
omp.yield (%1 : f32)
|
|
}
|
|
|
|
func @foo(%lb : index, %ub : index, %step : index) {
|
|
%c1 = constant 1 : i32
|
|
%0 = llvm.alloca %c1 x i32 : (i32) -> !llvm.ptr<f32>
|
|
%1 = llvm.alloca %c1 x i32 : (i32) -> !llvm.ptr<f32>
|
|
|
|
omp.wsloop (%iv) : index = (%lb) to (%ub) step (%step)
|
|
reduction(@add_f32 -> %0 : !llvm.ptr<f32>) {
|
|
%2 = constant 2.0 : f32
|
|
// expected-error @below {{accumulator is not used by the parent}}
|
|
omp.reduction %2, %1 : !llvm.ptr<f32>
|
|
omp.yield
|
|
}
|
|
return
|
|
}
|
|
|
|
// -----
|
|
|
|
func @foo(%lb : index, %ub : index, %step : index) {
|
|
%c1 = constant 1 : i32
|
|
%0 = llvm.alloca %c1 x i32 : (i32) -> !llvm.ptr<f32>
|
|
%1 = llvm.alloca %c1 x i32 : (i32) -> !llvm.ptr<f32>
|
|
|
|
// expected-error @below {{expected symbol reference @foo to point to a reduction declaration}}
|
|
omp.wsloop (%iv) : index = (%lb) to (%ub) step (%step)
|
|
reduction(@foo -> %0 : !llvm.ptr<f32>) {
|
|
%2 = constant 2.0 : f32
|
|
omp.reduction %2, %1 : !llvm.ptr<f32>
|
|
omp.yield
|
|
}
|
|
return
|
|
}
|
|
|
|
// -----
|
|
|
|
omp.reduction.declare @add_f32 : f32
|
|
init {
|
|
^bb0(%arg: f32):
|
|
%0 = constant 0.0 : f32
|
|
omp.yield (%0 : f32)
|
|
}
|
|
combiner {
|
|
^bb1(%arg0: f32, %arg1: f32):
|
|
%1 = addf %arg0, %arg1 : f32
|
|
omp.yield (%1 : f32)
|
|
}
|
|
|
|
func @foo(%lb : index, %ub : index, %step : index) {
|
|
%c1 = constant 1 : i32
|
|
%0 = llvm.alloca %c1 x i32 : (i32) -> !llvm.ptr<f32>
|
|
|
|
// expected-error @below {{accumulator variable used more than once}}
|
|
omp.wsloop (%iv) : index = (%lb) to (%ub) step (%step)
|
|
reduction(@add_f32 -> %0 : !llvm.ptr<f32>, @add_f32 -> %0 : !llvm.ptr<f32>) {
|
|
%2 = constant 2.0 : f32
|
|
omp.reduction %2, %0 : !llvm.ptr<f32>
|
|
omp.yield
|
|
}
|
|
return
|
|
}
|
|
|
|
// -----
|
|
|
|
omp.reduction.declare @add_f32 : f32
|
|
init {
|
|
^bb0(%arg: f32):
|
|
%0 = constant 0.0 : f32
|
|
omp.yield (%0 : f32)
|
|
}
|
|
combiner {
|
|
^bb1(%arg0: f32, %arg1: f32):
|
|
%1 = addf %arg0, %arg1 : f32
|
|
omp.yield (%1 : f32)
|
|
}
|
|
atomic {
|
|
^bb2(%arg2: !llvm.ptr<f32>, %arg3: !llvm.ptr<f32>):
|
|
%2 = llvm.load %arg3 : !llvm.ptr<f32>
|
|
llvm.atomicrmw fadd %arg2, %2 monotonic : f32
|
|
omp.yield
|
|
}
|
|
|
|
func @foo(%lb : index, %ub : index, %step : index, %mem : memref<1xf32>) {
|
|
%c1 = constant 1 : i32
|
|
|
|
// expected-error @below {{expected accumulator ('memref<1xf32>') to be the same type as reduction declaration ('!llvm.ptr<f32>')}}
|
|
omp.wsloop (%iv) : index = (%lb) to (%ub) step (%step)
|
|
reduction(@add_f32 -> %mem : memref<1xf32>) {
|
|
%2 = constant 2.0 : f32
|
|
omp.reduction %2, %mem : memref<1xf32>
|
|
omp.yield
|
|
}
|
|
return
|
|
}
|
|
|
|
// -----
|
|
|
|
func @omp_critical1() -> () {
|
|
// expected-error @below {{must specify a name unless the effect is as if hint(none) is specified}}
|
|
omp.critical hint(nonspeculative) {
|
|
omp.terminator
|
|
}
|
|
return
|
|
}
|
|
|
|
// -----
|
|
|
|
func @omp_critical2() -> () {
|
|
// expected-error @below {{expected symbol reference @excl to point to a critical declaration}}
|
|
omp.critical(@excl) hint(speculative) {
|
|
omp.terminator
|
|
}
|
|
return
|
|
}
|