Skip to content

Commit 0d8cbe4

Browse files
committed
[flang][OpenMP][MLIR] Add MLIR op for loop directive
Adds MLIR op that corresponds to the `loop` directive.
1 parent 8d59554 commit 0d8cbe4

File tree

6 files changed

+173
-0
lines changed

6 files changed

+173
-0
lines changed

llvm/include/llvm/Frontend/OpenMP/OMP.td

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,21 @@ def OMPC_AtomicDefaultMemOrder : Clause<"atomic_default_mem_order"> {
7171
let clangClass = "OMPAtomicDefaultMemOrderClause";
7272
let flangClass = "OmpAtomicDefaultMemOrderClause";
7373
}
74+
75+
def OMP_BIND_parallel : ClauseVal<"parallel",1,1> {}
76+
def OMP_BIND_teams : ClauseVal<"teams",2,1> {}
77+
def OMP_BIND_thread : ClauseVal<"thread",3,1> { let isDefault = true; }
7478
def OMPC_Bind : Clause<"bind"> {
7579
let clangClass = "OMPBindClause";
7680
let flangClass = "OmpBindClause";
81+
let enumClauseValue = "BindKind";
82+
let allowedClauseValues = [
83+
OMP_BIND_parallel,
84+
OMP_BIND_teams,
85+
OMP_BIND_thread
86+
];
7787
}
88+
7889
def OMP_CANCELLATION_CONSTRUCT_Parallel : ClauseVal<"parallel", 1, 1> {}
7990
def OMP_CANCELLATION_CONSTRUCT_Loop : ClauseVal<"loop", 2, 1> {}
8091
def OMP_CANCELLATION_CONSTRUCT_Sections : ClauseVal<"sections", 3, 1> {}

mlir/include/mlir/Dialect/OpenMP/OpenMPClauses.td

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,31 @@ class OpenMP_CancelDirectiveNameClauseSkip<
107107

108108
def OpenMP_CancelDirectiveNameClause : OpenMP_CancelDirectiveNameClauseSkip<>;
109109

110+
//===----------------------------------------------------------------------===//
111+
// V5.2: [11.7.1] `bind` clause
112+
//===----------------------------------------------------------------------===//
113+
114+
class OpenMP_BindClauseSkip<
115+
bit traits = false, bit arguments = false, bit assemblyFormat = false,
116+
bit description = false, bit extraClassDeclaration = false
117+
> : OpenMP_Clause<traits, arguments, assemblyFormat, description,
118+
extraClassDeclaration> {
119+
let arguments = (ins
120+
OptionalAttr<BindKindAttr>:$bind_kind
121+
);
122+
123+
let optAssemblyFormat = [{
124+
`bind` `(` custom<ClauseAttr>($bind_kind) `)`
125+
}];
126+
127+
let description = [{
128+
The `bind` clause specifies the binding region of the construct on which it
129+
appears.
130+
}];
131+
}
132+
133+
def OpenMP_BindClause : OpenMP_BindClauseSkip<>;
134+
110135
//===----------------------------------------------------------------------===//
111136
// V5.2: [5.7.2] `copyprivate` clause
112137
//===----------------------------------------------------------------------===//

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

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,50 @@ def LoopNestOp : OpenMP_Op<"loop_nest", traits = [
382382
// 2.9.2 Workshare Loop Construct
383383
//===----------------------------------------------------------------------===//
384384

385+
def LoopOp : OpenMP_Op<"loop", traits = [
386+
DeclareOpInterfaceMethods<LoopWrapperInterface>, NoTerminator, SingleBlock,
387+
AttrSizedOperandSegments
388+
], clauses = [
389+
OpenMP_BindClause, OpenMP_PrivateClause, OpenMP_OrderClause,
390+
OpenMP_ReductionClause
391+
], singleRegion = true> {
392+
let summary = "loop construct";
393+
let description = [{
394+
A loop construct specifies that the logical iterations of the associated loops
395+
may execute concurrently and permits the encountering threads to execute the
396+
loop accordingly. A loop construct is a worksharing construct if its binding
397+
region is the innermost enclosing parallel region. Otherwise it is not a work-
398+
sharing region. The directive asserts that the iterations of the associated
399+
loops may execute in any order, including concurrently. Each logical iteration
400+
is executed once per instance of the loop region that is encountered by exactly
401+
one thread that is a member of the binding thread set.
402+
403+
The body region can only contain a single block which must contain a single
404+
operation, this operation must be an `omp.loop_nest`.
405+
406+
```
407+
omp.loop <clauses> {
408+
omp.loop_nest (%i1, %i2) : index = (%c0, %c0) to (%c10, %c10) step (%c1, %c1) {
409+
%a = load %arrA[%i1, %i2] : memref<?x?xf32>
410+
%b = load %arrB[%i1, %i2] : memref<?x?xf32>
411+
%sum = arith.addf %a, %b : f32
412+
store %sum, %arrC[%i1, %i2] : memref<?x?xf32>
413+
omp.yield
414+
}
415+
}
416+
```
417+
}] # clausesDescription;
418+
419+
let assemblyFormat = clausesAssemblyFormat # [{
420+
custom<PrivateReductionRegion>($region, $private_vars, type($private_vars),
421+
$private_syms, $reduction_vars, type($reduction_vars), $reduction_byref,
422+
$reduction_syms) attr-dict
423+
}];
424+
425+
let hasVerifier = 1;
426+
let hasRegionVerifier = 1;
427+
}
428+
385429
def WsloopOp : OpenMP_Op<"wsloop", traits = [
386430
AttrSizedOperandSegments, DeclareOpInterfaceMethods<ComposableOpInterface>,
387431
DeclareOpInterfaceMethods<LoopWrapperInterface>, NoTerminator,

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1948,6 +1948,29 @@ LogicalResult LoopWrapperInterface::verifyImpl() {
19481948
return success();
19491949
}
19501950

1951+
//===----------------------------------------------------------------------===//
1952+
// LoopOp
1953+
//===----------------------------------------------------------------------===//
1954+
1955+
LogicalResult LoopOp::verify() {
1956+
return verifyReductionVarList(*this, getReductionSyms(), getReductionVars(),
1957+
getReductionByref());
1958+
}
1959+
1960+
LogicalResult LoopOp::verifyRegions() {
1961+
Region &region = getRegion();
1962+
1963+
// Minimal amount of checks to verify the only nested op is an
1964+
// `omp.loop_nest`. A more extensive vierfication is done by the
1965+
// `LoopWrapperInterface` trait but the difference is that `omp.loop` cannot
1966+
// have another nested `LoopWrapperInterface`.
1967+
if (range_size(region.getOps()) != 1 || !isa<LoopNestOp>(*region.op_begin()))
1968+
return emitError() << "`omp.loop` expected to have a single nested "
1969+
"operation which is a `omp.loop_nest`";
1970+
1971+
return success();
1972+
}
1973+
19511974
//===----------------------------------------------------------------------===//
19521975
// WsloopOp
19531976
//===----------------------------------------------------------------------===//

mlir/test/Dialect/OpenMP/invalid.mlir

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2577,3 +2577,33 @@ func.func @omp_taskloop_invalid_composite(%lb: index, %ub: index, %step: index)
25772577
} {omp.composite}
25782578
return
25792579
}
2580+
2581+
// -----
2582+
2583+
func.func @omp_loop_invalid_nesting(%lb : index, %ub : index, %step : index) {
2584+
2585+
// expected-error @below {{`omp.loop` expected to have a single nested operation which is a `omp.loop_nest`}}
2586+
omp.loop {
2587+
omp.simd {
2588+
omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
2589+
omp.yield
2590+
}
2591+
} {omp.composite}
2592+
}
2593+
2594+
return
2595+
}
2596+
2597+
// -----
2598+
2599+
func.func @omp_loop_invalid_nesting(%lb : index, %ub : index, %step : index) {
2600+
2601+
// expected-error @below {{custom op 'omp.loop' invalid clause value: 'dummy_value'}}
2602+
omp.loop bind(dummy_value) {
2603+
omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
2604+
omp.yield
2605+
}
2606+
}
2607+
2608+
return
2609+
}

mlir/test/Dialect/OpenMP/ops.mlir

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2749,3 +2749,43 @@ func.func @omp_target_private(%map1: memref<?xi32>, %map2: memref<?xi32>, %priv_
27492749

27502750
return
27512751
}
2752+
2753+
// CHECK-LABEL: omp_loop
2754+
func.func @omp_loop(%lb : index, %ub : index, %step : index) {
2755+
// CHECK: omp.loop {
2756+
omp.loop {
2757+
// CHECK: omp.loop_nest {{.*}} {
2758+
omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
2759+
// CHECK: omp.yield
2760+
omp.yield
2761+
// CHECK: }
2762+
}
2763+
// CHECK: }
2764+
}
2765+
2766+
// CHECK: omp.loop bind(teams) {
2767+
omp.loop bind(teams) {
2768+
omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
2769+
omp.yield
2770+
}
2771+
// CHECK: }
2772+
}
2773+
2774+
// CHECK: omp.loop bind(parallel) {
2775+
omp.loop bind(parallel) {
2776+
omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
2777+
omp.yield
2778+
}
2779+
// CHECK: }
2780+
}
2781+
2782+
// CHECK: omp.loop bind(thread) {
2783+
omp.loop bind(thread) {
2784+
omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
2785+
omp.yield
2786+
}
2787+
// CHECK: }
2788+
}
2789+
2790+
return
2791+
}

0 commit comments

Comments
 (0)