OpenMP (GNU Compiler Collection (GCC) Internals)

#### 11.7.7 OpenMP ¶

All the statements starting with `OMP_` represent directives and clauses used by the OpenMP API https://www.openmp.org.

`OMP_PARALLEL`

  Represents `#pragma omp parallel [clause1 … clauseN]`. It has four operands:

  Operand `OMP_PARALLEL_BODY` is valid while in GENERIC and High GIMPLE forms. It contains the body of code to be executed by all the threads. During GIMPLE lowering, this operand becomes `NULL` and the body is emitted linearly after `OMP_PARALLEL`.

  Operand `OMP_PARALLEL_CLAUSES` is the list of clauses associated with the directive.

  Operand `OMP_PARALLEL_FN` is created by `pass_lower_omp`, it contains the `FUNCTION_DECL` for the function that will contain the body of the parallel region.

  Operand `OMP_PARALLEL_DATA_ARG` is also created by `pass_lower_omp`. If there are shared variables to be communicated to the children threads, this operand will contain the `VAR_DECL` that contains all the shared values and variables.

`OMP_FOR`
`OMP_SIMD`
`OMP_DISTRIBUTE`
`OMP_TASKLOOP`
`OMP_LOOP`

  Represents `#pragma omp for [clause1 … clauseN]` and related loop constructs (respectively).

  A single `OMP_FOR` node represents an entire nest of collapsed loops; as noted below, some of its arguments are vectors of length equal to the collapse depth, and the corresponding elements holding data specific to a particular loop in the nest. These vectors are numbered from the outside in so that the outermost loop is element 0.

  These constructs have seven operands:

  Operand `OMP_FOR_BODY` contains the loop body.

  Operand `OMP_FOR_CLAUSES` is the list of clauses associated with the directive.

  Operand `OMP_FOR_INIT` is a vector containing iteration variable initializations of the form `VAR = N1`.

  Operand `OMP_FOR_COND` is vector containing loop conditional expressions of the form `VAR {<,>,<=,>=,!=} N2`.

  Operand `OMP_FOR_INCR` is a vector containing loop index increment expressions of the form `VAR {+=,-=} INCR`.

  Operand `OMP_FOR_PRE_BODY` contains side effect code from operands `OMP_FOR_INIT`, `OMP_FOR_COND` and `OMP_FOR_INCR`. These side effects are part of the `OMP_FOR` block but must be evaluated before the start of loop body. `OMP_FOR_PRE_BODY` specifically includes `DECL_EXPR`s for iteration variables that are declared in the nested `for` loops. Note this field is not a vector; it may be null, but otherwise is usually a statement list collecting the side effect code from all the collapsed loops.

  Operand `OMP_FOR_ORIG_DECLS` holds `VAR_DECLS` for the original user-specified iterator variables in the source code. In some cases, like C++ class iterators or range `for` with decomposition, the `for` loop is rewritten by the front end to use a temporary iteration variable. The purpose of this field is to make the original variables available to the gimplifier so it can adjust their data-sharing attributes and diagnose errors. `OMP_FOR_ORIG_DECLS` is a vector field, with each element holding a list of `VAR_DECLS` for the corresponding collapse level.

  The loop index variable `VAR` must be an integer variable, which is implicitly private to each thread. For rectangular loops, the bounds `N1` and `N2` and the increment expression `INCR` are required to be loop-invariant integer expressions that are evaluated without any synchronization. The evaluation order, frequency of evaluation and side effects are otherwise unspecified by the standard.

  For non-rectangular loops, in which the bounds of an inner loop depend on the index of an outer loop, the bit `OMP_FOR_NON_RECTANGULAR` must be set. In this case `N1` and `N2` are not ordinary expressions, but instead a `TREE_VEC` with three elements: the `DECL` for the outer loop variable, a multiplication factor, and an offset.

`OMP_SECTIONS`

  Represents `#pragma omp sections [clause1 … clauseN]`.

  Operand `OMP_SECTIONS_BODY` contains the sections body, which in turn contains a set of `OMP_SECTION` nodes for each of the concurrent sections delimited by `#pragma omp section`.

  Operand `OMP_SECTIONS_CLAUSES` is the list of clauses associated with the directive.

`OMP_SECTION`

  Section delimiter for `OMP_SECTIONS`.

`OMP_SINGLE`

  Represents `#pragma omp single`.

  Operand `OMP_SINGLE_BODY` contains the body of code to be executed by a single thread.

  Operand `OMP_SINGLE_CLAUSES` is the list of clauses associated with the directive.

`OMP_MASTER`

  Represents `#pragma omp master`.

  Operand `OMP_MASTER_BODY` contains the body of code to be executed by the master thread.

`OMP_ORDERED`

  Represents `#pragma omp ordered`.

  Operand `OMP_ORDERED_BODY` contains the body of code to be executed in the sequential order dictated by the loop index variable.

`OMP_CRITICAL`

  Represents `#pragma omp critical [name]`.

  Operand `OMP_CRITICAL_BODY` is the critical section.

  Operand `OMP_CRITICAL_NAME` is an optional identifier to label the critical section.

`OMP_RETURN`

  This does not represent any OpenMP directive, it is an artificial marker to indicate the end of the body of an OpenMP. It is used by the flow graph (`tree-cfg.cc`) and OpenMP region building code (`omp-low.cc`).

`OMP_CONTINUE`

  Similarly, this instruction does not represent an OpenMP directive, it is used by `OMP_FOR` (and similar codes) as well as `OMP_SECTIONS` to mark the place where the code needs to loop to the next iteration, or the next section, respectively.

  In some cases, `OMP_CONTINUE` is placed right before `OMP_RETURN`. But if there are cleanups that need to occur right after the looping body, it will be emitted between `OMP_CONTINUE` and `OMP_RETURN`.

`OMP_STRUCTURED_BLOCK`

  This is another statement that doesn’t correspond to an OpenMP directive. It is used to mark sections of code in another directive that must be structured block sequences, in particular for sequences of intervening code in the body of an `OMP_FOR`. It is not necessary to use this when the entire body of a directive is required to be a structured block sequence, since that is implicit in the representation of the corresponding node.

  This tree node is used only to allow error checking transfers of control in/out of the structured block sequence after gimplification. It has a single operand (`OMP_STRUCTURED_BLOCK_BODY`) that is the code within the structured block sequence.

`OMP_ATOMIC`

  Represents `#pragma omp atomic`.

  Operand 0 is the address at which the atomic operation is to be performed.

  Operand 1 is the expression to evaluate. The gimplifier tries three alternative code generation strategies. Whenever possible, an atomic update built-in is used. If that fails, a compare-and-swap loop is attempted. If that also fails, a regular critical section around the expression is used.

`OMP_CLAUSE`

  Represents clauses associated with one of the `OMP_` directives. Clauses are represented by separate subcodes defined in `tree.h`. Clauses codes can be one of: `OMP_CLAUSE_PRIVATE`, `OMP_CLAUSE_SHARED`, `OMP_CLAUSE_FIRSTPRIVATE`, `OMP_CLAUSE_LASTPRIVATE`, `OMP_CLAUSE_COPYIN`, `OMP_CLAUSE_COPYPRIVATE`, `OMP_CLAUSE_IF`, `OMP_CLAUSE_NUM_THREADS`, `OMP_CLAUSE_SCHEDULE`, `OMP_CLAUSE_NOWAIT`, `OMP_CLAUSE_ORDERED`, `OMP_CLAUSE_DEFAULT`, `OMP_CLAUSE_REDUCTION`, `OMP_CLAUSE_COLLAPSE`, `OMP_CLAUSE_UNTIED`, `OMP_CLAUSE_FINAL`, and `OMP_CLAUSE_MERGEABLE`. Each code represents the corresponding OpenMP clause.

  Clauses associated with the same directive are chained together via `OMP_CLAUSE_CHAIN`. Those clauses that accept a list of variables are restricted to exactly one, accessed with `OMP_CLAUSE_VAR`. Therefore, multiple variables under the same clause `C` need to be represented as multiple `C` clauses chained together. This facilitates adding new clauses during compilation.

`OMP_METADIRECTIVE`

  Represents `#pragma omp metadirective`. This node has one field, accessed by the `OMP_METADIRECTIVE_VARIANTS (node)` macro.

  Metadirective variants are represented internally as `TREE_LIST` nodes but you should use the interface provided in `tree.h` to access their components.

  `OMP_METADIRECTIVE_VARIANT_SELECTOR (variant)` is the selector associated with the variant; this is null for the ‘`otherwise`’/‘`default`’ alternative.

  `OMP_METADIRECTIVE_VARIANT_DIRECTIVE (variant)` is the nested directive for the variant.

  `OMP_METADIRECTIVE_VARIANT_BODY (variant)` represents statements following a nested standalone or utility directive. In other cases, this field is null and the body is part of the nested directive instead.

  Metadirective context selectors (as well as context selectors for `#pragma omp declare variant`) are also represented internally using a `TREE_LIST` representation but with accessors and constructors declared in `omp-general.h`. A complete context selector is a list of trait-set selectors, which are in turn composed of a list of trait selectors, each of which may have a list of trait properties. Identifiers for trait-set selectors and trait selectors are enums defined in `omp-selectors.h`, while trait property identifiers are string constants.

`OMP_NEXT_VARIANT`

  Some OpenMP variant constructs cannot be resolved until the ompdevlow pass, in `omp-offload.cc`. The gimplifier turns these into a `switch` statement in a loop, using `OMP_NEXT_VARIANT` as a placeholder to set the switch control variable. The ompdevlow pass replaces these with constant integers after resolution.

  `OMP_NEXT_VARIANT` has two operands. Operand 0 is `OMP_NEXT_VARIANT_INDEX`, an `INTEGER_CST` for the current current index. Operand 1 is `OMP_NEXT_VARIANT_STATE`, a `TREE_LIST` shared among all `OMP_NEXT_VARIANT` expressions for the same variant construct that holds resolution state information for that construct.

`OMP_TARGET_DEVICE_MATCHES`

  Similarly to `OMP_NEXT_VARIANT`, this tree node is a placeholder that is resolved in the ompdevlow pass. It is used to implement the `target_device` dynamic selector. The gimplifier generates these nodes and arranges for them to be executed on the `device_num` specified in the selector. The ompdevlow pass replaces each `OMP_TARGET_DEVICE_MATCHES` node with a constant value, depending on the corresponding kind, arch, or isa properties configured for the offload compiler.

  `OMP_TARGET_DEVICES` has two operands. Operand 0 is `OMP_TARGET_DEVICE_MATCHES_SELECTOR`, an `INTEGER_CST` encoding one of the constants `OMP_TRAIT_DEVICE_KIND`, `OMP_TRAIT_DEVICE_ARCH`, or `OMP_TRAIT_DEVICE_ISA`. Operand 1 is `OMP_TARGET_DEVICE_MATCHES_PROPERTIES`, a `TREE_LIST` using the same internal representation as the properties part of the selector.