mirror of
https://github.com/intel/llvm.git
synced 2026-01-16 05:32:28 +08:00
[MLIR] [OpenMP] Add basic OpenMP parallel operation
Summary: This includes a basic implementation for the OpenMP parallel operation without a custom pretty-printer and parser. The if, num_threads, private, shared, first_private, last_private, proc_bind and default clauses are included in this implementation. Currently the reduction clause is omitted as it is more complex and requires analysis to see if we can share implementation with the loop dialect. The allocate clause is also omitted. A discussion about the design of this operation can be found here: https://llvm.discourse.group/t/openmp-parallel-operation-design-issues/686 The current OpenMP Specification can be found here: https://www.openmp.org/wp-content/uploads/OpenMP-API-Specification-5.0.pdf Co-authored-by: Kiran Chandramohan <kiran.chandramohan@arm.com> Reviewers: jdoerfert Subscribers: mgorny, yaxunl, kristof.beyls, guansong, mehdi_amini, rriddle, jpienaar, shauheen, antiagainst, nicolasvasilache, arpith-jacob, mgester, lucyrfox, aartbik, liufengdb, Joonsoo, grosul1, frgossen, Kayjukh, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D79410
This commit is contained in:
@@ -1,2 +1,8 @@
|
||||
add_mlir_dialect(OpenMPOps omp)
|
||||
set(LLVM_TARGET_DEFINITIONS OpenMPOps.td)
|
||||
mlir_tablegen(OpenMPOpsDialect.h.inc -gen-dialect-decls -dialect=omp)
|
||||
mlir_tablegen(OpenMPOps.h.inc -gen-op-decls)
|
||||
mlir_tablegen(OpenMPOps.cpp.inc -gen-op-defs)
|
||||
mlir_tablegen(OpenMPOpsEnums.h.inc -gen-enum-decls)
|
||||
mlir_tablegen(OpenMPOpsEnums.cpp.inc -gen-enum-defs)
|
||||
add_mlir_doc(OpenMPOps -gen-dialect-doc OpenMPDialect Dialects/)
|
||||
add_public_tablegen_target(MLIROpenMPOpsIncGen)
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
#include "mlir/IR/Dialect.h"
|
||||
#include "mlir/IR/OpDefinition.h"
|
||||
|
||||
#include "mlir/Dialect/OpenMP/OpenMPOpsEnums.h.inc"
|
||||
|
||||
namespace mlir {
|
||||
namespace omp {
|
||||
|
||||
|
||||
@@ -18,16 +18,103 @@ include "mlir/IR/OpBase.td"
|
||||
|
||||
def OpenMP_Dialect : Dialect {
|
||||
let name = "omp";
|
||||
let cppNamespace = "omp";
|
||||
}
|
||||
|
||||
class OpenMP_Op<string mnemonic, list<OpTrait> traits = []> :
|
||||
Op<OpenMP_Dialect, mnemonic, traits>;
|
||||
|
||||
def BarrierOp : OpenMP_Op<"barrier"> {
|
||||
let summary = "barrier construct";
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// 2.6 parallel Construct
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Possible values for the default clause
|
||||
def ClauseDefaultPrivate : StrEnumAttrCase<"defprivate">;
|
||||
def ClauseDefaultFirstPrivate : StrEnumAttrCase<"deffirstprivate">;
|
||||
def ClauseDefaultShared : StrEnumAttrCase<"defshared">;
|
||||
def ClauseDefaultNone : StrEnumAttrCase<"defnone">;
|
||||
|
||||
def ClauseDefault : StrEnumAttr<
|
||||
"ClauseDefault",
|
||||
"default clause",
|
||||
[ClauseDefaultPrivate, ClauseDefaultFirstPrivate, ClauseDefaultShared,
|
||||
ClauseDefaultNone]> {
|
||||
let cppNamespace = "::mlir::omp";
|
||||
}
|
||||
|
||||
// Possible values for the proc_bind clause
|
||||
def ClauseProcMaster : StrEnumAttrCase<"master">;
|
||||
def ClauseProcClose : StrEnumAttrCase<"close">;
|
||||
def ClauseProcSpread : StrEnumAttrCase<"spread">;
|
||||
|
||||
def ClauseProcBind : StrEnumAttr<
|
||||
"ClauseProcBind",
|
||||
"procbind clause",
|
||||
[ClauseProcMaster, ClauseProcClose, ClauseProcSpread]> {
|
||||
let cppNamespace = "::mlir::omp";
|
||||
}
|
||||
|
||||
def ParallelOp : OpenMP_Op<"parallel", [AttrSizedOperandSegments]> {
|
||||
let summary = "parallel construct";
|
||||
let description = [{
|
||||
The barrier construct specifies an explicit barrier at the point at which
|
||||
the construct appears.
|
||||
The parallel construct includes a region of code which is to be executed
|
||||
by a team of threads.
|
||||
|
||||
The optional $if_expr_var parameter specifies a boolean result of a
|
||||
conditional check. If this value is 1 or is not provided then the parallel
|
||||
region runs as normal, if it is 0 then the parallel region is executed with
|
||||
one thread.
|
||||
|
||||
The optional $num_threads_var parameter specifies the number of threads which
|
||||
should be used to execute the parallel region.
|
||||
|
||||
The optional $default_val attribute specifies the default data sharing attribute
|
||||
of variables used in the parallel region that are not passed explicitly as parameters
|
||||
to the operation.
|
||||
|
||||
The $private_vars, $firstprivate_vars, $shared_vars and $copyin_vars parameters
|
||||
are a variadic list of variables that specify the data sharing attribute of
|
||||
those variables.
|
||||
|
||||
The optional $proc_bind_val attribute controls the thread affinity for the execution
|
||||
of the parallel region.
|
||||
}];
|
||||
|
||||
let arguments = (ins Optional<I1>:$if_expr_var,
|
||||
Optional<AnyInteger>:$num_threads_var,
|
||||
OptionalAttr<ClauseDefault>:$default_val,
|
||||
Variadic<AnyType>:$private_vars,
|
||||
Variadic<AnyType>:$firstprivate_vars,
|
||||
Variadic<AnyType>:$shared_vars,
|
||||
Variadic<AnyType>:$copyin_vars,
|
||||
OptionalAttr<ClauseProcBind>:$proc_bind_val);
|
||||
|
||||
let regions = (region AnyRegion:$region);
|
||||
}
|
||||
|
||||
def TerminatorOp : OpenMP_Op<"terminator", [Terminator]> {
|
||||
let summary = "terminator for OpenMP regions.";
|
||||
let description = [{
|
||||
A terminator operation for regions that appear in the body of OpenMP
|
||||
operation. These regions are not expected to return any value so the
|
||||
terminator takes no operands. The terminator op returns control to the
|
||||
enclosing op.
|
||||
}];
|
||||
|
||||
let parser = [{ return success(); }];
|
||||
let printer = [{ p << getOperationName(); }];
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// 2.10.4 taskyield Construct
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
def TaskyieldOp : OpenMP_Op<"taskyield"> {
|
||||
let summary = "taskyield construct";
|
||||
let description = [{
|
||||
The taskyield construct specifies that the current task can be suspended
|
||||
in favor of execution of a different task.
|
||||
}];
|
||||
|
||||
let assemblyFormat = "attr-dict";
|
||||
@@ -50,6 +137,24 @@ def FlushOp : OpenMP_Op<"flush"> {
|
||||
let assemblyFormat = "attr-dict ($varList^ `:` type($varList))?";
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// 2.17.2 barrier Construct
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
def BarrierOp : OpenMP_Op<"barrier"> {
|
||||
let summary = "barrier construct";
|
||||
let description = [{
|
||||
The barrier construct specifies an explicit barrier at the point at which
|
||||
the construct appears.
|
||||
}];
|
||||
|
||||
let assemblyFormat = "attr-dict";
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// 2.17.5 taskwait Construct
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
def TaskwaitOp : OpenMP_Op<"taskwait"> {
|
||||
let summary = "taskwait construct";
|
||||
let description = [{
|
||||
@@ -60,14 +165,4 @@ def TaskwaitOp : OpenMP_Op<"taskwait"> {
|
||||
let assemblyFormat = "attr-dict";
|
||||
}
|
||||
|
||||
def TaskyieldOp : OpenMP_Op<"taskyield"> {
|
||||
let summary = "taskyield construct";
|
||||
let description = [{
|
||||
The taskyield construct specifies that the current task can be suspended
|
||||
in favor of execution of a different task.
|
||||
}];
|
||||
|
||||
let assemblyFormat = "attr-dict";
|
||||
}
|
||||
|
||||
#endif // OPENMP_OPS
|
||||
|
||||
@@ -11,8 +11,13 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
|
||||
#include "mlir/Dialect/StandardOps/IR/Ops.h"
|
||||
#include "mlir/IR/OpImplementation.h"
|
||||
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
|
||||
#include "mlir/Dialect/OpenMP/OpenMPOpsEnums.cpp.inc"
|
||||
|
||||
using namespace mlir;
|
||||
using namespace mlir::omp;
|
||||
|
||||
|
||||
@@ -35,3 +35,39 @@ func @omp_flush(%arg0 : !llvm.i32) -> () {
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func @omp_terminator() -> () {
|
||||
// CHECK: omp.terminator
|
||||
omp.terminator
|
||||
}
|
||||
|
||||
func @omp_parallel(%data_var : memref<i32>, %if_cond : i1, %num_threads : si32) -> () {
|
||||
// CHECK: omp_parallel
|
||||
"omp.parallel" (%if_cond, %num_threads, %data_var, %data_var, %data_var, %data_var) ({
|
||||
|
||||
// test without if condition
|
||||
// CHECK: omp.parallel
|
||||
"omp.parallel"(%num_threads, %data_var, %data_var, %data_var, %data_var) ({
|
||||
omp.terminator
|
||||
}) {operand_segment_sizes = dense<[0,1,1,1,1,1]>: vector<6xi32>, default_val = "defshared"} : (si32, memref<i32>, memref<i32>, memref<i32>, memref<i32>) -> ()
|
||||
|
||||
// CHECK: omp.barrier
|
||||
omp.barrier
|
||||
|
||||
// test without num_threads
|
||||
// CHECK: omp.parallel
|
||||
"omp.parallel"(%if_cond, %data_var, %data_var, %data_var, %data_var) ({
|
||||
omp.terminator
|
||||
}) {operand_segment_sizes = dense<[1,0,1,1,1,1]> : vector<6xi32>} : (i1, memref<i32>, memref<i32>, memref<i32>, memref<i32>) -> ()
|
||||
|
||||
omp.terminator
|
||||
}) {operand_segment_sizes = dense<[1,1,1,1,1,1]> : vector<6xi32>, proc_bind_val = "spread"} : (i1, si32, memref<i32>, memref<i32>, memref<i32>, memref<i32>) -> ()
|
||||
|
||||
// test with multiple parameters for single variadic argument
|
||||
// CHECK: omp.parallel
|
||||
"omp.parallel" (%data_var, %data_var, %data_var, %data_var, %data_var) ({
|
||||
omp.terminator
|
||||
}) {operand_segment_sizes = dense<[0,0,1,2,1,1]> : vector<6xi32>} : (memref<i32>, memref<i32>, memref<i32>, memref<i32>, memref<i32>) -> ()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user