@tindex OMP_CONTINUE
@tindex OMP_ATOMIC
@tindex OMP_CLAUSE
+@tindex OMP_METADIRECTIVE
+@tindex OMP_NEXT_VARIANT
+@tindex OMP_TARGET_DEVICE_MATCHES
All the statements starting with @code{OMP_} represent directives and
clauses used by the OpenMP API @w{@uref{https://www.openmp.org}}.
chained together. This facilitates adding new clauses during
compilation.
+@item OMP_METADIRECTIVE
+
+Represents @code{#pragma omp metadirective}. This node has one field,
+accessed by the @code{OMP_METADIRECTIVE_VARIANTS (@var{node})} macro.
+
+Metadirective variants are represented internally as @code{TREE_LIST} nodes
+but you should use the interface provided in @file{tree.h} to
+access their components.
+
+@code{OMP_METADIRECTIVE_VARIANT_SELECTOR (@var{variant})}
+is the selector associated with the variant; this is null for the
+@samp{otherwise}/@samp{default} alternative.
+
+@code{OMP_METADIRECTIVE_VARIANT_DIRECTIVE (@var{variant})} is the
+nested directive for the variant.
+
+@code{OMP_METADIRECTIVE_VARIANT_BODY (@var{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
+@code{#pragma omp declare variant}) are also represented internally using
+a @code{TREE_LIST} representation but with accessors and constructors
+declared in @file{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 @file{omp-selectors.h}, while trait property identifiers are
+string constants.
+
+@item OMP_NEXT_VARIANT
+Some OpenMP variant constructs cannot be resolved until the ompdevlow pass,
+in @file{omp-offload.cc}. The gimplifier turns these into a @code{switch}
+statement in a loop, using @code{OMP_NEXT_VARIANT} as a placeholder to set
+the switch control variable. The ompdevlow pass replaces these with constant
+integers after resolution.
+
+@code{OMP_NEXT_VARIANT} has two operands. Operand 0 is
+@code{OMP_NEXT_VARIANT_INDEX}, an @code{INTEGER_CST} for the current current
+index. Operand 1 is @code{OMP_NEXT_VARIANT_STATE}, a @code{TREE_LIST} shared
+among all @code{OMP_NEXT_VARIANT} expressions for the same variant construct
+that holds resolution state information for that construct.
+
+@item OMP_TARGET_DEVICE_MATCHES
+Similarly to @code{OMP_NEXT_VARIANT}, this tree node is a placeholder that is
+resolved in the ompdevlow pass. It is used to implement the
+@code{target_device} dynamic selector. The gimplifier generates these
+nodes and arranges for them to be executed on the @code{device_num} specified
+in the selector. The ompdevlow pass replaces each
+@code{OMP_TARGET_DEVICE_MATCHES} node with a constant value, depending on the
+corresponding kind, arch, or isa properties configured for the offload compiler.
+
+@code{OMP_TARGET_DEVICES} has two operands. Operand 0 is
+@code{OMP_TARGET_DEVICE_MATCHES_SELECTOR}, an @code{INTEGER_CST}
+encoding one of the constants @code{OMP_TRAIT_DEVICE_KIND},
+@code{OMP_TRAIT_DEVICE_ARCH}, or @code{OMP_TRAIT_DEVICE_ISA}. Operand
+1 is @code{OMP_TARGET_DEVICE_MATCHES_PROPERTIES}, a @code{TREE_LIST}
+using the same internal representation as the properties part of the selector.
+
@end table
@node OpenACC
return;
case BLOCK:
case OMP_CLAUSE:
+ case OMP_NEXT_VARIANT:
+ case OMP_TARGET_DEVICE_MATCHES:
/* Ignore. */
return;
case TREE_LIST:
&& !is_gimple_reg (t))
return false;
+ /* These eventually expand into constants, so treat them like that. */
+ if (TREE_CODE (t) == OMP_NEXT_VARIANT
+ || TREE_CODE (t) == OMP_TARGET_DEVICE_MATCHES)
+ return true;
+
return (is_gimple_variable (t) || is_gimple_min_invariant (t));
}
|| (SYM) == OBJ_TYPE_REF \
|| (SYM) == ADDR_EXPR \
|| (SYM) == WITH_SIZE_EXPR \
- || (SYM) == SSA_NAME) ? GIMPLE_SINGLE_RHS \
+ || (SYM) == SSA_NAME \
+ || (SYM) == OMP_NEXT_VARIANT \
+ || (SYM) == OMP_TARGET_DEVICE_MATCHES) ? GIMPLE_SINGLE_RHS \
: GIMPLE_INVALID_RHS),
#define END_OF_BASE_TREE_CODES (unsigned char) GIMPLE_INVALID_RHS,
|| TREE_CODE (t) == SSA_NAME
|| TREE_CODE (t) == IDENTIFIER_NODE
|| TREE_CODE (t) == CASE_LABEL_EXPR
+ || TREE_CODE (t) == OMP_NEXT_VARIANT
|| is_gimple_min_invariant (t))
return true;
*walk_subtrees = 0;
}
+ else if (TREE_CODE (*tp) == OMP_NEXT_VARIANT)
+ {
+ /* Neither operand is interesting, and walking the selector
+ causes problems because it's not an expression. */
+ gcc_assert (TREE_CODE (TREE_OPERAND (*tp, 0)) == INTEGER_CST);
+ *walk_subtrees = 0;
+ }
}
/* Update the TREE_BLOCK for the cloned expr. */
is_expr = false;
break;
+ case OMP_METADIRECTIVE:
+ {
+ pp_string (pp, "#pragma omp metadirective");
+ newline_and_indent (pp, spc + 2);
+ pp_left_brace (pp);
+
+ tree variant = OMP_METADIRECTIVE_VARIANTS (node);
+ while (variant != NULL_TREE)
+ {
+ tree selector = OMP_METADIRECTIVE_VARIANT_SELECTOR (variant);
+ tree directive = OMP_METADIRECTIVE_VARIANT_DIRECTIVE (variant);
+ tree body = OMP_METADIRECTIVE_VARIANT_BODY (variant);
+
+ newline_and_indent (pp, spc + 4);
+ if (selector == NULL_TREE)
+ pp_string (pp, "otherwise:");
+ else
+ {
+ pp_string (pp, "when (");
+ dump_omp_context_selector (pp, selector, spc + 4, flags);
+ pp_string (pp, "):");
+ }
+ newline_and_indent (pp, spc + 6);
+
+ dump_generic_node (pp, directive, spc + 6, flags, false);
+ newline_and_indent (pp, spc + 6);
+ dump_generic_node (pp, body, spc + 6, flags, false);
+ variant = TREE_CHAIN (variant);
+ }
+ newline_and_indent (pp, spc + 2);
+ pp_right_brace (pp);
+ }
+ break;
+
+ case OMP_NEXT_VARIANT:
+ {
+ pp_string (pp, "OMP_NEXT_VARIANT <");
+ dump_generic_node (pp, OMP_NEXT_VARIANT_INDEX (node), spc,
+ flags, false);
+ pp_string (pp, ", ");
+ tree state = OMP_NEXT_VARIANT_STATE (node);
+ gcc_assert (state && TREE_CODE (state) == TREE_LIST);
+ if (TREE_PURPOSE (state))
+ {
+ newline_and_indent (pp, spc + 2);
+ pp_string (pp, "resolution map = ");
+ dump_generic_node (pp, TREE_PURPOSE (state), spc, flags, false);
+ }
+ newline_and_indent (pp, spc + 2);
+ pp_string (pp, "construct context = ");
+ if (TREE_VALUE (state))
+ dump_generic_node (pp, TREE_VALUE (state), spc, flags, false);
+ else
+ pp_string (pp, "NULL");
+
+ tree selectors = TREE_CHAIN (state);
+ for (int i = 0; i < TREE_VEC_LENGTH (selectors); i++)
+ {
+ newline_and_indent (pp, spc + 2);
+ pp_decimal_int (pp, i + 1);
+ pp_string (pp, ": ");
+ dump_omp_context_selector (pp, TREE_VEC_ELT (selectors, i),
+ spc + 4, flags);
+ }
+ pp_string (pp, ">");
+ }
+ break;
+
+ case OMP_TARGET_DEVICE_MATCHES:
+ pp_string (pp, "OMP_TARGET_DEVICE_MATCHES <");
+ dump_generic_node (pp, OMP_TARGET_DEVICE_MATCHES_SELECTOR (node), spc,
+ flags, false);
+ for (tree p = OMP_TARGET_DEVICE_MATCHES_PROPERTIES (node);
+ p; p = TREE_CHAIN (p))
+ {
+ pp_string (pp, ", ");
+ dump_generic_node (pp, OMP_TP_VALUE (p), spc, flags, false);
+ }
+ pp_string (pp, ")>");
+ break;
+
case TRANSACTION_EXPR:
if (TRANSACTION_EXPR_OUTER (node))
pp_string (pp, "__transaction_atomic [[outer]]");
add_stmt_operand (expr_p, flags);
return;
+ case OMP_NEXT_VARIANT:
+ case OMP_TARGET_DEVICE_MATCHES:
+ return;
+
case DEBUG_EXPR_DECL:
gcc_assert (gimple_debug_bind_p (stmt));
return;
Operand 0: OMP_TARGET_EXIT_DATA_CLAUSES: List of clauses. */
DEFTREECODE (OMP_TARGET_EXIT_DATA, "omp_target_exit_data", tcc_statement, 1)
+/* OpenMP - #pragma omp metadirective [variant1 ... variantN]
+ Operand 0: OMP_METADIRECTIVE_VARIANTS: List of selectors and directive
+ variants. The variants are internally TREE_LISTs, but use
+ make_omp_metadirective_variant to build them. */
+DEFTREECODE (OMP_METADIRECTIVE, "omp_metadirective", tcc_statement, 1)
+
/* OMP_ATOMIC through OMP_ATOMIC_CAPTURE_NEW must be consecutive,
or OMP_ATOMIC_SEQ_CST needs adjusting. */
/* An OpenMP array section. */
DEFTREECODE (OMP_ARRAY_SECTION, "omp_array_section", tcc_expression, 3)
+/* OpenMP variant construct selector, used only in the middle end in the
+ expansions of variant constructs that can't be resolved until the
+ ompdevlow pass. These variants are converted into switch expressions
+ that use OMP_NEXT_VARIANT as a placeholder for the index of next variant
+ to try if a dynamic selector does not match. The ompdevlow pass
+ replaces these nodes with constant integers after resolution.
+ Operand 0: OMP_NEXT_VARIANT_INDEX: an INTEGER_CST holding the switch
+ index of the current variant.
+ Operand 1: OMP_NEXT_VARIANT_STATE: a TREE_LIST that is shared among all
+ OMP_NEXT_VARIANT expressions for the same variant directive. The
+ TREE_PURPOSE of this node holds the resolved lookup table, while
+ TREE_VALUE holds the saved construct context and TREE_CHAIN the
+ original vector of selectors that are used to fill in the table. */
+DEFTREECODE (OMP_NEXT_VARIANT, "omp_next_variant", tcc_expression, 2)
+
+/* OpenMP target_device match placeholder, similarly used only in the middle
+ end in the expansions of variant constructs that need to be resolved in
+ the ompdevlow pass.
+ Operand 0: OMP_TARGET_DEVICE_MATCHES_SELECTOR: INTEGER_CST encoding one
+ of OMP_TRAIT_DEVICE_KIND, OMP_TRAIT_DEVICE_ARCH, or OMP_TRAIT_DEVICE_ISA.
+ Operand 1: OMP_TARGET_DEVICE_MATCHES_PROPERTIES: A TREE_LIST of strings
+ and/or identifiers, corresponding to the OMP_TS_PROPERTIES for the trait
+ selector.
+ This resolves to a boolean truth value if the properties match the
+ trait selector for the offload compiler. */
+DEFTREECODE (OMP_TARGET_DEVICE_MATCHES, "omp_target_device_matches",
+ tcc_expression, 2)
+
/* TRANSACTION_EXPR tree code.
Operand 0: BODY: contains body of the transaction. */
DEFTREECODE (TRANSACTION_EXPR, "transaction_expr", tcc_expression, 1)
#define OMP_TARGET_EXIT_DATA_CLAUSES(NODE)\
TREE_OPERAND (OMP_TARGET_EXIT_DATA_CHECK (NODE), 0)
+#define OMP_METADIRECTIVE_VARIANTS(NODE) \
+ TREE_OPERAND (OMP_METADIRECTIVE_CHECK (NODE), 0)
+
+#define OMP_METADIRECTIVE_VARIANT_SELECTOR(v) \
+ TREE_PURPOSE (v)
+#define OMP_METADIRECTIVE_VARIANT_DIRECTIVE(v) \
+ TREE_PURPOSE (TREE_VALUE (v))
+#define OMP_METADIRECTIVE_VARIANT_BODY(v) \
+ TREE_VALUE (TREE_VALUE (v))
+
#define OMP_SCAN_BODY(NODE) TREE_OPERAND (OMP_SCAN_CHECK (NODE), 0)
#define OMP_SCAN_CLAUSES(NODE) TREE_OPERAND (OMP_SCAN_CHECK (NODE), 1)
#define OMP_CLAUSE__SCANTEMP__CONTROL(NODE) \
TREE_PRIVATE (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE__SCANTEMP_))
+/* OpenMP OMP_NEXT_VARIANT accessors. */
+#define OMP_NEXT_VARIANT_INDEX(NODE) \
+ TREE_OPERAND (OMP_NEXT_VARIANT_CHECK (NODE), 0)
+#define OMP_NEXT_VARIANT_STATE(NODE) \
+ TREE_OPERAND (OMP_NEXT_VARIANT_CHECK (NODE), 1)
+
+/* OpenMP OMP_TARGET_DEVICE_MATCHES accessors. */
+#define OMP_TARGET_DEVICE_MATCHES_SELECTOR(NODE) \
+ TREE_OPERAND (OMP_TARGET_DEVICE_MATCHES_CHECK (NODE), 0)
+#define OMP_TARGET_DEVICE_MATCHES_PROPERTIES(NODE) \
+ TREE_OPERAND (OMP_TARGET_DEVICE_MATCHES_CHECK (NODE), 1)
+
/* SSA_NAME accessors. */
/* Whether SSA_NAME NODE is a virtual operand. This simply caches the