Skip to content

Commit 70fe6ad

Browse files
authored
[MLIR][OpenMP] Make omp.distribute into a loop wrapper (#87239)
This patch updates the definition of `omp.distribute` to enforce the restrictions of a wrapper operation.
1 parent 58b49ce commit 70fe6ad

File tree

4 files changed

+93
-12
lines changed

4 files changed

+93
-12
lines changed

mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -840,7 +840,8 @@ def YieldOp : OpenMP_Op<"yield",
840840
//===----------------------------------------------------------------------===//
841841
def DistributeOp : OpenMP_Op<"distribute", [AttrSizedOperandSegments,
842842
DeclareOpInterfaceMethods<LoopWrapperInterface>,
843-
RecursiveMemoryEffects]> {
843+
RecursiveMemoryEffects,
844+
SingleBlockImplicitTerminator<"TerminatorOp">]> {
844845
let summary = "distribute construct";
845846
let description = [{
846847
The distribute construct specifies that the iterations of one or more loops
@@ -855,15 +856,28 @@ def DistributeOp : OpenMP_Op<"distribute", [AttrSizedOperandSegments,
855856
The distribute loop construct specifies that the iterations of the loop(s)
856857
will be executed in parallel by threads in the current context. These
857858
iterations are spread across threads that already exist in the enclosing
858-
region. The lower and upper bounds specify a half-open range: the
859-
range includes the lower bound but does not include the upper bound. If the
860-
`inclusive` attribute is specified then the upper bound is also included.
859+
region.
860+
861+
The body region can contain a single block which must contain a single
862+
operation and a terminator. The operation must be another compatible loop
863+
wrapper or an `omp.loop_nest`.
861864

862865
The `dist_schedule_static` attribute specifies the schedule for this
863866
loop, determining how the loop is distributed across the parallel threads.
864867
The optional `schedule_chunk` associated with this determines further
865868
controls this distribution.
866869

870+
```mlir
871+
omp.distribute <clauses> {
872+
omp.loop_nest (%i1, %i2) : index = (%c0, %c0) to (%c10, %c10) step (%c1, %c1) {
873+
%a = load %arrA[%i1, %i2] : memref<?x?xf32>
874+
%b = load %arrB[%i1, %i2] : memref<?x?xf32>
875+
%sum = arith.addf %a, %b : f32
876+
store %sum, %arrC[%i1, %i2] : memref<?x?xf32>
877+
omp.yield
878+
}
879+
}
880+
```
867881
// TODO: private_var, firstprivate_var, lastprivate_var, collapse
868882
}];
869883
let arguments = (ins

mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1656,6 +1656,17 @@ LogicalResult DistributeOp::verify() {
16561656
return emitError(
16571657
"expected equal sizes for allocate and allocator variables");
16581658

1659+
if (!isWrapper())
1660+
return emitOpError() << "must be a loop wrapper";
1661+
1662+
if (LoopWrapperInterface nested = getNestedWrapper()) {
1663+
// Check for the allowed leaf constructs that may appear in a composite
1664+
// construct directly after DISTRIBUTE.
1665+
if (!isa<ParallelOp, SimdLoopOp>(nested))
1666+
return emitError() << "only supported nested wrappers are 'omp.parallel' "
1667+
"and 'omp.simdloop'";
1668+
}
1669+
16591670
return success();
16601671
}
16611672

mlir/test/Dialect/OpenMP/invalid.mlir

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1866,7 +1866,16 @@ func.func @omp_target_depend(%data_var: memref<i32>) {
18661866

18671867
// -----
18681868

1869-
func.func @omp_distribute(%data_var : memref<i32>) -> () {
1869+
func.func @omp_distribute_schedule(%chunk_size : i32) -> () {
1870+
// expected-error @below {{op chunk size set without dist_schedule_static being present}}
1871+
"omp.distribute"(%chunk_size) <{operandSegmentSizes = array<i32: 1, 0, 0>}> ({
1872+
"omp.terminator"() : () -> ()
1873+
}) : (i32) -> ()
1874+
}
1875+
1876+
// -----
1877+
1878+
func.func @omp_distribute_allocate(%data_var : memref<i32>) -> () {
18701879
// expected-error @below {{expected equal sizes for allocate and allocator variables}}
18711880
"omp.distribute"(%data_var) <{operandSegmentSizes = array<i32: 0, 1, 0>}> ({
18721881
"omp.terminator"() : () -> ()
@@ -1875,6 +1884,29 @@ func.func @omp_distribute(%data_var : memref<i32>) -> () {
18751884

18761885
// -----
18771886

1887+
func.func @omp_distribute_wrapper() -> () {
1888+
// expected-error @below {{op must be a loop wrapper}}
1889+
"omp.distribute"() ({
1890+
%0 = arith.constant 0 : i32
1891+
"omp.terminator"() : () -> ()
1892+
}) : () -> ()
1893+
}
1894+
1895+
// -----
1896+
1897+
func.func @omp_distribute_nested_wrapper(%data_var : memref<i32>) -> () {
1898+
// expected-error @below {{only supported nested wrappers are 'omp.parallel' and 'omp.simdloop'}}
1899+
"omp.distribute"() ({
1900+
"omp.wsloop"() ({
1901+
%0 = arith.constant 0 : i32
1902+
"omp.terminator"() : () -> ()
1903+
}) : () -> ()
1904+
"omp.terminator"() : () -> ()
1905+
}) : () -> ()
1906+
}
1907+
1908+
// -----
1909+
18781910
omp.private {type = private} @x.privatizer : i32 alloc {
18791911
^bb0(%arg0: i32):
18801912
%0 = arith.constant 0.0 : f32

mlir/test/Dialect/OpenMP/ops.mlir

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -559,30 +559,54 @@ func.func @omp_simdloop_pretty_multiple(%lb1 : index, %ub1 : index, %step1 : ind
559559
}
560560

561561
// CHECK-LABEL: omp_distribute
562-
func.func @omp_distribute(%chunk_size : i32, %data_var : memref<i32>) -> () {
562+
func.func @omp_distribute(%chunk_size : i32, %data_var : memref<i32>, %arg0 : i32) -> () {
563563
// CHECK: omp.distribute
564564
"omp.distribute" () ({
565-
omp.terminator
565+
"omp.loop_nest" (%arg0, %arg0, %arg0) ({
566+
^bb0(%iv: i32):
567+
"omp.yield"() : () -> ()
568+
}) : (i32, i32, i32) -> ()
569+
"omp.terminator"() : () -> ()
566570
}) {} : () -> ()
567571
// CHECK: omp.distribute
568572
omp.distribute {
569-
omp.terminator
573+
omp.loop_nest (%iv) : i32 = (%arg0) to (%arg0) step (%arg0) {
574+
omp.yield
575+
}
570576
}
571577
// CHECK: omp.distribute dist_schedule_static
572578
omp.distribute dist_schedule_static {
573-
omp.terminator
579+
omp.loop_nest (%iv) : i32 = (%arg0) to (%arg0) step (%arg0) {
580+
omp.yield
581+
}
574582
}
575583
// CHECK: omp.distribute dist_schedule_static chunk_size(%{{.+}} : i32)
576584
omp.distribute dist_schedule_static chunk_size(%chunk_size : i32) {
577-
omp.terminator
585+
omp.loop_nest (%iv) : i32 = (%arg0) to (%arg0) step (%arg0) {
586+
omp.yield
587+
}
578588
}
579589
// CHECK: omp.distribute order(concurrent)
580590
omp.distribute order(concurrent) {
581-
omp.terminator
591+
omp.loop_nest (%iv) : i32 = (%arg0) to (%arg0) step (%arg0) {
592+
omp.yield
593+
}
582594
}
583595
// CHECK: omp.distribute allocate(%{{.+}} : memref<i32> -> %{{.+}} : memref<i32>)
584596
omp.distribute allocate(%data_var : memref<i32> -> %data_var : memref<i32>) {
585-
omp.terminator
597+
omp.loop_nest (%iv) : i32 = (%arg0) to (%arg0) step (%arg0) {
598+
omp.yield
599+
}
600+
}
601+
// CHECK: omp.distribute
602+
omp.distribute {
603+
// TODO Remove induction variables from omp.simdloop.
604+
omp.simdloop for (%iv) : i32 = (%arg0) to (%arg0) step (%arg0) {
605+
omp.loop_nest (%iv2) : i32 = (%arg0) to (%arg0) step (%arg0) {
606+
omp.yield
607+
}
608+
omp.yield
609+
}
586610
}
587611
return
588612
}

0 commit comments

Comments
 (0)