[flang-commits] [flang] [flang][docs] Refresh stale status in do concurrent mapping doc (PR #224838)
via flang-commits
flang-commits at lists.llvm.org
Tue Sep 29 23:57:29 PDT 2026
================
@@ -209,131 +254,72 @@ variables: `i` and `j`. These are locally allocated inside the parallel/target
OpenMP region similar to what the single-range example in previous section
shows.
-### Data environment
+## Data environment
By default, variables that are used inside a `do concurrent` loop nest are
either treated as `shared` in case of mapping to `host`, or mapped into the
`target` region using a `map` clause in case of mapping to `device`. The only
exceptions to this are:
- 1. the loop's iteration variable(s) (IV) of **perfect** loop nests. In that
- case, for each IV, we allocate a local copy as shown by the mapping
- examples above.
+ 1. the loop's iteration variable(s) (IV). For each IV, we allocate a local
+ copy as shown by the mapping examples above.
1. any values that are from allocations outside the loop nest and used
exclusively inside of it. In such cases, a local privatized
copy is created in the OpenMP region to prevent multiple teams of threads
from accessing and destroying the same memory block, which causes runtime
issues. For an example of such cases, see
`flang/test/Transforms/DoConcurrent/locally_destroyed_temp.f90`.
+ 1. variables with locality specifiers, described below.
-Implicit mapping detection (for mapping to the target device) is still quite
-limited and work to make it smarter is underway for both OpenMP in general
-and `do concurrent` mapping.
-
-#### Non-perfectly-nested loops' IVs
-
-For non-perfectly-nested loops, the IVs are still treated as `shared` or
-`map` entries as pointed out above. This **might not** be consistent with what
-the Fortran specification tells us. In particular, taking the following
-snippets from the spec (version 2023) into account:
-
-> § 3.35
-> ------
-> construct entity
-> entity whose identifier has the scope of a construct
-
-> § 19.4
-> ------
-> A variable that appears as an index-name in a FORALL or DO CONCURRENT
-> construct [...] is a construct entity. A variable that has LOCAL or
-> LOCAL_INIT locality in a DO CONCURRENT construct is a construct entity.
-> [...]
-> The name of a variable that appears as an index-name in a DO CONCURRENT
-> construct, FORALL statement, or FORALL construct has a scope of the statement
-> or construct. A variable that has LOCAL or LOCAL_INIT locality in a DO
-> CONCURRENT construct has the scope of that construct.
-
-From the above quotes, it seems there is an equivalence between the IV of a `do
-concurrent` loop and a variable with a `LOCAL` locality specifier (equivalent
-to OpenMP's `private` clause). Which means that we should probably
-localize/privatize a `do concurrent` loop's IV even if it is not perfectly
-nested in the nest we are parallelizing. For now, however, we **do not** do
-that as pointed out previously. In the near future, we propose a middle-ground
-solution (see the Next steps section for more details).
-
-<!--
-More details about current status will be added along with relevant parts of the
-implementation in later upstreaming patches.
--->
+### Locality specifiers
+
+`LOCAL` specifiers are supported for both host and device mapping. On the FIR
+level, a `LOCAL` variable is modeled by a `fir.local` "localizer" op (which,
+similar to OpenMP's `omp.private` op, can carry `init` and `dealloc` regions)
+referenced from the `local(...)` operand group of the `fir.do_concurrent.loop`
+op. The conversion pass translates each localizer into an equivalent
+`omp.private` op and attaches the corresponding `private(...)` clause to the
+generated worksharing loop. For examples, see
+`flang/test/Transforms/DoConcurrent/locality_specifiers_simple.mlir` and
+`flang/test/Transforms/DoConcurrent/local_device.mlir`.
+
+`LOCAL_INIT` specifiers are not supported yet; the pass emits a
+"not yet implemented" error when it encounters one.
+
+### Reductions
+
+Fortran 2023 `REDUCE` specifiers are mapped to OpenMP reductions for both host
+and device. On the FIR level, a reduction is modeled by a
+`fir.declare_reduction` op referenced from the `reduce(...)` operand group of
+the `fir.do_concurrent.loop` op. The pass translates it into an equivalent
+`omp.declare_reduction` op and attaches `reduction(...)` clauses to the
+generated OpenMP ops: on the host, to the `omp.wsloop` op; on the device, to
+both the `omp.teams` and the `omp.wsloop` ops.
+
+When mapping to the device, reduction variables are mapped `tofrom` and
+captured by reference so that the reduced values are copied back to the host
+after the target region finishes.
+
+For examples, see the `reduce_*` tests in
+`flang/test/Transforms/DoConcurrent/`.
## Next steps
-This section describes some of the open questions/issues that are not tackled yet
-even in the downstream implementation.
-
-### Separate MLIR op for `do concurrent`
-
-At the moment, both increment and concurrent loops are represented by one MLIR
-op: `fir.do_loop`; where we differentiate concurrent loops with the `unordered`
-attribute. This is not ideal since the `fir.do_loop` op support only single
-iteration ranges. Consequently, to model multi-range `do concurrent` loops, flang
-emits a nest of `fir.do_loop` ops which we have to detect in the OpenMP conversion
-pass to handle multi-range loops. Instead, it would better to model multi-range
-concurrent loops using a separate op which the IR more representative of the input
-Fortran code and also easier to detect and transform.
-
-### Delayed privatization
----------------
MattPD wrote:
Could the PR description qualify the delayed-privatization claim? `LOCAL` uses the `omp.private` path, but induction variables still use inline allocations inside `omp.parallel`.
https://github.com/llvm/llvm-project/pull/224838
More information about the flang-commits
mailing list