Skip to content

[MLIR][omp] Add omp.workshare op #101443

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,49 @@ def SingleOp : OpenMP_Op<"single", traits = [
let hasVerifier = 1;
}

//===----------------------------------------------------------------------===//
// 2.8.3 Workshare Construct
//===----------------------------------------------------------------------===//

def WorkshareOp : OpenMP_Op<"workshare", traits = [
RecursiveMemoryEffects,
], clauses = [
OpenMP_NowaitClause,
], singleRegion = true> {
let summary = "workshare directive";
let description = [{
The workshare construct divides the execution of the enclosed structured
block into separate units of work, and causes the threads of the team to
share the work such that each unit is executed only once by one thread, in
the context of its implicit task

This operation is used for the intermediate representation of the workshare
block before the work gets divided between the threads. See the flang
LowerWorkshare pass for details.
}] # clausesDescription;

let builders = [
OpBuilder<(ins CArg<"const WorkshareOperands &">:$clauses)>
];
}

def WorkshareLoopWrapperOp : OpenMP_Op<"workshare.loop_wrapper", traits = [
DeclareOpInterfaceMethods<LoopWrapperInterface>, NoTerminator,
RecursiveMemoryEffects, SingleBlock
], singleRegion = true> {
let summary = "contains loop nests to be parallelized by workshare";
let description = [{
This operation wraps a loop nest that is marked for dividing into units of
work by an encompassing omp.workshare operation.
}];

let builders = [
OpBuilder<(ins), [{ build($_builder, $_state, {}); }]>
];
let assemblyFormat = "$region attr-dict";
let hasVerifier = 1;
}

//===----------------------------------------------------------------------===//
// Loop Nest
//===----------------------------------------------------------------------===//
Expand Down
21 changes: 21 additions & 0 deletions mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1897,6 +1897,27 @@ LogicalResult SingleOp::verify() {
getCopyprivateSyms());
}

//===----------------------------------------------------------------------===//
// WorkshareOp
//===----------------------------------------------------------------------===//

void WorkshareOp::build(OpBuilder &builder, OperationState &state,
const WorkshareOperands &clauses) {
WorkshareOp::build(builder, state, clauses.nowait);
}

//===----------------------------------------------------------------------===//
// WorkshareLoopWrapperOp
//===----------------------------------------------------------------------===//

LogicalResult WorkshareLoopWrapperOp::verify() {
if (!(*this)->getParentOfType<WorkshareOp>())
return emitError() << "must be nested in an omp.workshare";
if (getNestedWrapper())
return emitError() << "cannot be composite";
return success();
}

//===----------------------------------------------------------------------===//
// LoopWrapperInterface
//===----------------------------------------------------------------------===//
Expand Down
38 changes: 38 additions & 0 deletions mlir/test/Dialect/OpenMP/invalid.mlir
Original file line number Diff line number Diff line change
Expand Up @@ -2620,6 +2620,44 @@ func.func @omp_loop_invalid_binding(%lb : index, %ub : index, %step : index) {
omp.yield
}
}
return
}

// -----
func.func @nested_wrapper(%idx : index) {
omp.workshare {
// expected-error @below {{cannot be composite}}
omp.workshare.loop_wrapper {
omp.simd {
omp.loop_nest (%iv) : index = (%idx) to (%idx) step (%idx) {
omp.yield
}
} {omp.composite}
}
omp.terminator
}
return
}

// -----
func.func @not_wrapper() {
omp.workshare {
// expected-error @below {{op nested in loop wrapper is not another loop wrapper or `omp.loop_nest`}}
omp.workshare.loop_wrapper {
%0 = arith.constant 0 : index
}
omp.terminator
}
return
}

// -----
func.func @missing_workshare(%idx : index) {
// expected-error @below {{must be nested in an omp.workshare}}
omp.workshare.loop_wrapper {
omp.loop_nest (%iv) : index = (%idx) to (%idx) step (%idx) {
omp.yield
}
}
return
}
67 changes: 67 additions & 0 deletions mlir/test/Dialect/OpenMP/ops.mlir
Original file line number Diff line number Diff line change
Expand Up @@ -2789,3 +2789,70 @@ func.func @omp_loop(%lb : index, %ub : index, %step : index) {

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
}
Loading