diff --git a/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td b/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td --- a/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td +++ b/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td @@ -33,6 +33,23 @@ let assemblyFormat = "attr-dict"; } +//===----------------------------------------------------------------------===// +// 2.13.7 flush Construct +//===----------------------------------------------------------------------===// +def FlushOp : OpenMP_Op<"flush"> { + let summary = "flush construct"; + let description = [{ + The flush construct executes the OpenMP flush operation. This operation + makes a thread’s temporary view of memory consistent with memory and + enforces an order on the memory operations of the variables explicitly + specified or implied. + }]; + + let arguments = (ins Variadic:$varList); + + let assemblyFormat = "attr-dict ($varList^ `:` type($varList))?"; +} + def TaskwaitOp : OpenMP_Op<"taskwait"> { let summary = "taskwait construct"; let description = [{ diff --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp --- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp @@ -330,6 +330,18 @@ ompBuilder->CreateTaskyield(builder.saveIP()); return success(); }) + .Case([&](omp::FlushOp) { + // No support in Openmp runtime funciton (__kmpc_flush) to accept + // the argument list. + // OpenMP standard states the following: + // "An implementation may implement a flush with a list by ignoring + // the list, and treating it the same as a flush without a list." + // + // The argument list is discarded so that, flush with a list is treated + // same as a flush without a list. + ompBuilder->CreateFlush(builder.saveIP()); + return success(); + }) .Default([&](Operation *inst) { return inst->emitError("unsupported OpenMP operation: ") << inst->getName(); diff --git a/mlir/test/Dialect/OpenMP/ops.mlir b/mlir/test/Dialect/OpenMP/ops.mlir --- a/mlir/test/Dialect/OpenMP/ops.mlir +++ b/mlir/test/Dialect/OpenMP/ops.mlir @@ -17,3 +17,21 @@ omp.taskyield return } + +// CHECK-LABEL: func @omp_flush +// CHECK-SAME: %[[ARG0:.*]]: !llvm.i32 +func @omp_flush(%arg0 : !llvm.i32) -> () { + // Test without data var + // CHECK: omp.flush + omp.flush + + // Test with one data var + // CHECK: omp.flush %[[ARG0]] : !llvm.i32 + "omp.flush"(%arg0) : (!llvm.i32) -> () + + // Test with two data var + // CHECK: omp.flush %[[ARG0]], %[[ARG0]] : !llvm.i32, !llvm.i32 + "omp.flush"(%arg0, %arg0): (!llvm.i32, !llvm.i32) -> () + + return +} diff --git a/mlir/test/Target/openmp-llvm.mlir b/mlir/test/Target/openmp-llvm.mlir --- a/mlir/test/Target/openmp-llvm.mlir +++ b/mlir/test/Target/openmp-llvm.mlir @@ -1,7 +1,7 @@ // RUN: mlir-translate -mlir-to-llvmir %s | FileCheck %s -// CHECK-LABEL: define void @empty() -llvm.func @empty() { +// CHECK-LABEL: define void @test_stand_alone_directives() +llvm.func @test_stand_alone_directives() { // CHECK: [[OMP_THREAD:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* @{{[0-9]+}}) // CHECK-NEXT: call void @__kmpc_barrier(%struct.ident_t* @{{[0-9]+}}, i32 [[OMP_THREAD]]) omp.barrier @@ -14,6 +14,21 @@ // CHECK-NEXT: [[RET_VAL:%.*]] = call i32 @__kmpc_omp_taskyield(%struct.ident_t* @{{[0-9]+}}, i32 [[OMP_THREAD2]], i32 0) omp.taskyield -// CHECK-NEXT: ret void + // CHECK-NEXT: ret void + llvm.return +} + +// CHECK-LABEL: define void @test_flush_construct(i32 %0) +llvm.func @test_flush_construct(%arg0: !llvm.i32) { + // CHECK: call void @__kmpc_flush(%struct.ident_t* @{{[0-9]+}} + omp.flush + + // CHECK: call void @__kmpc_flush(%struct.ident_t* @{{[0-9]+}} + omp.flush %arg0 : !llvm.i32 + + // CHECK: call void @__kmpc_flush(%struct.ident_t* @{{[0-9]+}} + omp.flush %arg0, %arg0 : !llvm.i32, !llvm.i32 + + // CHECK-NEXT: ret void llvm.return }