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_EXPRs 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.