Skip to content

Commit d74127e

Browse files
authored
[flang][OpenMP][MLIR] Add MLIR op for loop directive (#113911)
Adds MLIR op that corresponds to the `loop` directive.
1 parent 4f3bf1c commit d74127e

File tree

6 files changed

+183
-0
lines changed

6 files changed

+183
-0
lines changed

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

+11
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

+25
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

+44
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+
AttrSizedOperandSegments, DeclareOpInterfaceMethods<LoopWrapperInterface>,
387+
NoTerminator, SingleBlock
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 can have 3 different types of binding:
397+
1. teams: in which case the binding region is the innermost enclosing `teams`
398+
region.
399+
2. parallel: in which case the binding region is the innermost enclosing `parallel`
400+
region.
401+
3. thread: in which case the binding region is not defined.
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

+17
Original file line numberDiff line numberDiff line change
@@ -1948,6 +1948,23 @@ 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+
if (llvm::isa_and_nonnull<LoopWrapperInterface>((*this)->getParentOp()) ||
1962+
getNestedWrapper())
1963+
return emitError() << "`omp.loop` expected to be a standalone loop wrapper";
1964+
1965+
return success();
1966+
}
1967+
19511968
//===----------------------------------------------------------------------===//
19521969
// WsloopOp
19531970
//===----------------------------------------------------------------------===//

mlir/test/Dialect/OpenMP/invalid.mlir

+46
Original file line numberDiff line numberDiff line change
@@ -2577,3 +2577,49 @@ 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 be a standalone loop wrapper}}
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_nesting2(%lb : index, %ub : index, %step : index) {
2600+
2601+
omp.simd {
2602+
// expected-error @below {{`omp.loop` expected to be a standalone loop wrapper}}
2603+
omp.loop {
2604+
omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
2605+
omp.yield
2606+
}
2607+
} {omp.composite}
2608+
}
2609+
2610+
return
2611+
}
2612+
2613+
// -----
2614+
2615+
func.func @omp_loop_invalid_binding(%lb : index, %ub : index, %step : index) {
2616+
2617+
// expected-error @below {{custom op 'omp.loop' invalid clause value: 'dummy_value'}}
2618+
omp.loop bind(dummy_value) {
2619+
omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
2620+
omp.yield
2621+
}
2622+
}
2623+
2624+
return
2625+
}

mlir/test/Dialect/OpenMP/ops.mlir

+40
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+
}
2762+
// CHECK: }
2763+
}
2764+
// CHECK: }
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+
}
2772+
// CHECK: }
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+
}
2780+
// CHECK: }
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+
}
2788+
// CHECK: }
2789+
2790+
return
2791+
}

0 commit comments

Comments
 (0)