Skip to content

Commit 79ec1e7

Browse files
authored
[MLIR][OpenMP][Docs] Document compound constructs representation (NFC) (#107236)
This patch documents the MLIR representation of OpenMP compound constructs discussed in [this](https://discourse.llvm.org/t/rfc-representing-combined-composite-constructs-in-the-openmp-dialect/76986) and [this](https://discourse.llvm.org/t/rfc-disambiguation-between-loop-and-block-associated-omp-parallelop/79972) RFC.
1 parent 06e8c6a commit 79ec1e7

File tree

1 file changed

+114
-0
lines changed

1 file changed

+114
-0
lines changed

mlir/docs/Dialects/OpenMPDialect/_index.md

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,3 +293,117 @@ been implemented, but it is closely linked to the `omp.canonical_loop` work.
293293
Nevertheless, loop transformation that the `collapse` clause for loop-associated
294294
worksharing constructs defines can be represented by introducing multiple
295295
bounds, step and induction variables to the `omp.loop_nest` operation.
296+
297+
## Compound Construct Representation
298+
299+
The OpenMP specification defines certain shortcuts that allow specifying
300+
multiple constructs in a single directive, which are referred to as compound
301+
constructs (e.g. `parallel do` contains the `parallel` and `do` constructs).
302+
These can be further classified into [combined](#combined-constructs) and
303+
[composite](#composite-constructs) constructs. This section describes how they
304+
are represented in the dialect.
305+
306+
When clauses are specified for compound constructs, the OpenMP specification
307+
defines a set of rules to decide to which leaf constructs they apply, as well as
308+
potentially introducing some other implicit clauses. These rules must be taken
309+
into account by those creating the MLIR representation, since it is a per-leaf
310+
representation that expects these rules to have already been followed.
311+
312+
### Combined Constructs
313+
314+
Combined constructs are semantically equivalent to specifying one construct
315+
immediately nested inside another. This property is used to simplify the dialect
316+
by representing them through the operations associated to each leaf construct.
317+
For example, `target teams` would be represented as follows:
318+
319+
```mlir
320+
omp.target ... {
321+
...
322+
omp.teams ... {
323+
...
324+
omp.terminator
325+
}
326+
...
327+
omp.terminator
328+
}
329+
```
330+
331+
### Composite Constructs
332+
333+
Composite constructs are similar to combined constructs in that they specify the
334+
effect of one construct being applied immediately after another. However, they
335+
group together constructs that cannot be directly nested into each other.
336+
Specifically, they group together multiple loop-associated constructs that apply
337+
to the same collapsed loop nest.
338+
339+
As of version 5.2 of the OpenMP specification, the list of composite constructs
340+
is the following:
341+
- `{do,for} simd`;
342+
- `distribute simd`;
343+
- `distribute parallel {do,for}`;
344+
- `distribute parallel {do,for} simd`; and
345+
- `taskloop simd`.
346+
347+
Even though the list of composite constructs is relatively short and it would
348+
also be possible to create dialect operations for each, it was decided to
349+
allow attaching multiple loop wrappers to a single loop instead. This minimizes
350+
redundancy in the dialect and maximizes its modularity, since there is a single
351+
operation for each leaf construct regardless of whether it can be part of a
352+
composite construct. On the other hand, this means the `omp.loop_nest` operation
353+
will have to be interpreted differently depending on how many and which loop
354+
wrappers are attached to it.
355+
356+
To simplify the detection of operations taking part in the representation of a
357+
composite construct, the `ComposableOpInterface` was introduced. Its purpose is
358+
to handle the `omp.composite` discardable dialect attribute that can optionally
359+
be attached to these operations. Operation verifiers will ensure its presence is
360+
consistent with the context the operation appears in, so that it is valid when
361+
the attribute is present if and only if it represents a leaf of a composite
362+
construct.
363+
364+
For example, the `distribute simd` composite construct is represented as
365+
follows:
366+
367+
```mlir
368+
omp.distribute ... {
369+
omp.simd ... {
370+
omp.loop_nest (%i) : index = (%lb) to (%ub) step (%step) {
371+
...
372+
omp.yield
373+
}
374+
omp.terminator
375+
} {omp.composite}
376+
omp.terminator
377+
} {omp.composite}
378+
```
379+
380+
One exception to this is the representation of the
381+
`distribute parallel {do,for}` composite construct. The presence of a
382+
block-associated `parallel` leaf construct would introduce many problems if it
383+
was allowed to work as a loop wrapper. In this case, the "hoisted `omp.parallel`
384+
representation" is used instead. This consists in making `omp.parallel` the
385+
parent operation, with a nested `omp.loop_nest` wrapped by `omp.distribute` and
386+
`omp.wsloop` (and `omp.simd`, in the `distribute parallel {do,for} simd` case).
387+
388+
This approach works because `parallel` is a parallelism-generating construct,
389+
whereas `distribute` is a worksharing construct impacting the higher level
390+
`teams` construct, making the ordering between these constructs not cause
391+
semantic mismatches. This property is also exploited by LLVM's SPMD-mode.
392+
393+
```mlir
394+
omp.parallel ... {
395+
...
396+
omp.distribute ... {
397+
omp.wsloop ... {
398+
omp.loop_nest (%i) : index = (%lb) to (%ub) step (%step) {
399+
...
400+
omp.yield
401+
}
402+
omp.terminator
403+
} {omp.composite}
404+
omp.terminator
405+
} {omp.composite}
406+
...
407+
omp.terminator
408+
} {omp.composite}
409+
```

0 commit comments

Comments
 (0)