@@ -2868,6 +2868,7 @@ GTFILES = $(CPPLIB_H) $(srcdir)/input.h $(srcdir)/coretypes.h \
$(srcdir)/tree-ssa-operands.h \
$(srcdir)/tree-profile.cc $(srcdir)/tree-nested.cc \
$(srcdir)/omp-offload.h \
+ $(srcdir)/omp-general.h \
$(srcdir)/omp-general.cc \
$(srcdir)/omp-low.cc \
$(srcdir)/targhooks.cc $(out_file) $(srcdir)/passes.cc \
@@ -2894,7 +2895,6 @@ GTFILES = $(CPPLIB_H) $(srcdir)/input.h $(srcdir)/coretypes.h \
$(srcdir)/ipa-strub.cc \
$(srcdir)/internal-fn.h \
$(srcdir)/calls.cc \
- $(srcdir)/omp-general.h \
$(srcdir)/analyzer/analyzer-language.cc \
@all_gtfiles@
@@ -878,6 +878,8 @@ DEF_FUNCTION_TYPE_4 (BT_FN_VOID_UINT_PTR_INT_PTR, BT_VOID, BT_INT, BT_PTR,
BT_INT, BT_PTR)
DEF_FUNCTION_TYPE_4 (BT_FN_BOOL_UINT_UINT_UINT_BOOL,
BT_BOOL, BT_UINT, BT_UINT, BT_UINT, BT_BOOL)
+DEF_FUNCTION_TYPE_4 (BT_FN_BOOL_INT_CONST_PTR_CONST_PTR_CONST_PTR,
+ BT_BOOL, BT_INT, BT_CONST_PTR, BT_CONST_PTR, BT_CONST_PTR)
DEF_FUNCTION_TYPE_5 (BT_FN_INT_STRING_INT_SIZE_CONST_STRING_VALIST_ARG,
BT_INT, BT_STRING, BT_INT, BT_SIZE, BT_CONST_STRING,
@@ -24729,7 +24729,7 @@ c_finish_omp_declare_variant (c_parser *parser, tree fndecl, tree parms)
tree ctx = c_parser_omp_context_selector_specification (parser, parms);
if (ctx == error_mark_node)
goto fail;
- ctx = omp_check_context_selector (match_loc, ctx);
+ ctx = omp_check_context_selector (match_loc, ctx, false);
if (ctx != error_mark_node && variant != error_mark_node)
{
if (TREE_CODE (variant) != FUNCTION_DECL)
@@ -24762,7 +24762,7 @@ c_finish_omp_declare_variant (c_parser *parser, tree fndecl, tree parms)
tree construct
= omp_get_context_selector_list (ctx, OMP_TRAIT_SET_CONSTRUCT);
omp_mark_declare_variant (match_loc, variant, construct);
- if (omp_context_selector_matches (ctx))
+ if (omp_context_selector_matches (ctx, false, true))
{
tree attr
= tree_cons (get_identifier ("omp declare variant base"),
@@ -8328,7 +8328,7 @@ omp_declare_variant_finalize_one (tree decl, tree attr)
tree construct
= omp_get_context_selector_list (ctx, OMP_TRAIT_SET_CONSTRUCT);
omp_mark_declare_variant (match_loc, variant, construct);
- if (!omp_context_selector_matches (ctx))
+ if (!omp_context_selector_matches (ctx, false, true))
return true;
TREE_PURPOSE (TREE_VALUE (attr)) = variant;
}
@@ -48020,7 +48020,7 @@ cp_finish_omp_declare_variant (cp_parser *parser, cp_token *pragma_tok,
tree ctx = cp_parser_omp_context_selector_specification (parser, true);
if (ctx == error_mark_node)
goto fail;
- ctx = omp_check_context_selector (match_loc, ctx);
+ ctx = omp_check_context_selector (match_loc, ctx, false);
if (ctx != error_mark_node && variant != error_mark_node)
{
tree match_loc_node = maybe_wrap_with_location (integer_zero_node,
@@ -2335,6 +2335,7 @@ edge. Rethrowing the exception is represented using @code{RESX_EXPR}.
@tindex OMP_CONTINUE
@tindex OMP_ATOMIC
@tindex OMP_CLAUSE
+@tindex OMP_METADIRECTIVE
All the statements starting with @code{OMP_} represent directives and
clauses used by the OpenMP API @w{@uref{https://www.openmp.org}}.
@@ -2552,6 +2553,37 @@ same clause @code{C} need to be represented as multiple @code{C} clauses
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{omp-general.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.
+
@end table
@node OpenACC
@@ -8491,7 +8491,7 @@ gfc_trans_omp_declare_variant (gfc_namespace *ns)
continue;
}
set_selectors = omp_check_context_selector
- (gfc_get_location (&odv->where), set_selectors);
+ (gfc_get_location (&odv->where), set_selectors, false);
if (set_selectors != error_mark_node)
{
if (!variant_proc_sym->attr.implicit_type
@@ -8528,7 +8528,7 @@ gfc_trans_omp_declare_variant (gfc_namespace *ns)
omp_mark_declare_variant (gfc_get_location (&odv->where),
gfc_get_symbol_decl (variant_proc_sym),
construct);
- if (omp_context_selector_matches (set_selectors))
+ if (omp_context_selector_matches (set_selectors, false, true))
{
tree id = get_identifier ("omp declare variant base");
tree variant = gfc_get_symbol_decl (variant_proc_sym);
@@ -176,6 +176,8 @@ DEF_FUNCTION_TYPE_4 (BT_FN_VOID_UINT_PTR_INT_PTR, BT_VOID, BT_INT, BT_PTR,
BT_INT, BT_PTR)
DEF_FUNCTION_TYPE_4 (BT_FN_BOOL_UINT_UINT_UINT_BOOL,
BT_BOOL, BT_UINT, BT_UINT, BT_UINT, BT_BOOL)
+DEF_FUNCTION_TYPE_4 (BT_FN_BOOL_INT_CONST_PTR_CONST_PTR_CONST_PTR,
+ BT_BOOL, BT_INT, BT_CONST_PTR, BT_CONST_PTR, BT_CONST_PTR)
DEF_FUNCTION_TYPE_5 (BT_FN_VOID_OMPFN_PTR_UINT_UINT_UINT,
BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT, BT_UINT,
@@ -476,3 +476,6 @@ DEF_GOMP_BUILTIN (BUILT_IN_GOMP_WARNING, "GOMP_warning",
BT_FN_VOID_CONST_PTR_SIZE, ATTR_NOTHROW_LEAF_LIST)
DEF_GOMP_BUILTIN (BUILT_IN_GOMP_ERROR, "GOMP_error",
BT_FN_VOID_CONST_PTR_SIZE, ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_EVALUATE_TARGET_DEVICE, "GOMP_evaluate_target_device",
+ BT_FN_BOOL_INT_CONST_PTR_CONST_PTR_CONST_PTR,
+ ATTR_NOTHROW_LEAF_LIST)
@@ -1258,7 +1258,7 @@ omp_context_name_list_prop (tree prop)
it is correct or error_mark_node otherwise. */
tree
-omp_check_context_selector (location_t loc, tree ctx)
+omp_check_context_selector (location_t loc, tree ctx, bool metadirective_p)
{
bool tss_seen[OMP_TRAIT_SET_LAST], ts_seen[OMP_TRAIT_LAST];
@@ -1267,9 +1267,10 @@ omp_check_context_selector (location_t loc, tree ctx)
{
enum omp_tss_code tss_code = OMP_TSS_CODE (tss);
- /* We can parse this, but not handle it yet. */
- if (tss_code == OMP_TRAIT_SET_TARGET_DEVICE)
- sorry_at (loc, "%<target_device%> selector set is not supported yet");
+ /* FIXME: not implemented yet. */
+ if (!metadirective_p && tss_code == OMP_TRAIT_SET_TARGET_DEVICE)
+ sorry_at (loc, "%<target_device%> selector set is not supported "
+ "yet for %<declare variant%>");
/* Each trait-set-selector-name can only be specified once. */
if (tss_seen[tss_code])
@@ -1421,14 +1422,29 @@ make_trait_property (tree name, tree value, tree chain)
return tree_cons (name, value, chain);
}
+/* Constructor for metadirective variants. */
+tree
+make_omp_metadirective_variant (tree selector, tree directive, tree body)
+{
+ return build_tree_list (selector, build_tree_list (directive, body));
+}
+
+
/* Return 1 if context selector matches the current OpenMP context, 0
if it does not and -1 if it is unknown and need to be determined later.
Some properties can be checked right away during parsing (this routine),
others need to wait until the whole TU is parsed, others need to wait until
- IPA, others until vectorization. */
+ IPA, others until vectorization.
+
+ METADIRECTIVE_P is true if this is a metadirective context, and DELAY_P
+ is true if it's too early in compilation to determine whether some
+ properties match.
+
+ Dynamic properties (which are evaluated at run-time) should always
+ return 1. */
int
-omp_context_selector_matches (tree ctx)
+omp_context_selector_matches (tree ctx, bool metadirective_p, bool delay_p)
{
int ret = 1;
for (tree tss = ctx; tss; tss = TREE_CHAIN (tss))
@@ -1501,6 +1517,11 @@ omp_context_selector_matches (tree ctx)
ret = -1;
continue;
}
+ else if (set == OMP_TRAIT_SET_TARGET_DEVICE)
+ /* The target_device set is dynamic, so treat it as always
+ resolvable. */
+ continue;
+
for (tree ts = selectors; ts; ts = TREE_CHAIN (ts))
{
enum omp_ts_code sel = OMP_TS_CODE (ts);
@@ -1570,6 +1591,9 @@ omp_context_selector_matches (tree ctx)
const char *arch = omp_context_name_list_prop (p);
if (arch == NULL)
return 0;
+ if (metadirective_p && delay_p)
+ return -1;
+
int r = 0;
if (targetm.omp.device_kind_arch_isa != NULL)
r = targetm.omp.device_kind_arch_isa (omp_device_arch,
@@ -1692,6 +1716,9 @@ omp_context_selector_matches (tree ctx)
#endif
continue;
}
+ if (metadirective_p && delay_p)
+ return -1;
+
int r = 0;
if (targetm.omp.device_kind_arch_isa != NULL)
r = targetm.omp.device_kind_arch_isa (omp_device_kind,
@@ -1731,6 +1758,9 @@ omp_context_selector_matches (tree ctx)
const char *isa = omp_context_name_list_prop (p);
if (isa == NULL)
return 0;
+ if (metadirective_p && delay_p)
+ return -1;
+
int r = 0;
if (targetm.omp.device_kind_arch_isa != NULL)
r = targetm.omp.device_kind_arch_isa (omp_device_isa,
@@ -1782,6 +1812,12 @@ omp_context_selector_matches (tree ctx)
for (tree p = OMP_TS_PROPERTIES (ts); p; p = TREE_CHAIN (p))
if (OMP_TP_NAME (p) == NULL_TREE)
{
+ /* OpenMP 5.1 allows non-constant conditions for
+ metadirectives. */
+ if (metadirective_p
+ && !tree_fits_shwi_p (OMP_TP_VALUE (p)))
+ break;
+
if (integer_zerop (OMP_TP_VALUE (p)))
return 0;
if (integer_nonzerop (OMP_TP_VALUE (p)))
@@ -2180,9 +2216,87 @@ omp_lookup_ts_code (enum omp_tss_code set, const char *s)
return OMP_TRAIT_INVALID;
}
-/* Needs to be a GC-friendly widest_int variant, but precision is
- desirable to be the same on all targets. */
-typedef generic_wide_int <fixed_wide_int_storage <1024> > score_wide_int;
+/* Return a tree expression representing the dynamic part of the context
+ selector CTX. */
+static tree
+omp_dynamic_cond (tree ctx)
+{
+ tree expr = NULL_TREE;
+
+ tree user = omp_get_context_selector (ctx, OMP_TRAIT_SET_USER,
+ OMP_TRAIT_USER_CONDITION);
+ if (user)
+ {
+ tree expr_list = OMP_TS_PROPERTIES (user);
+
+ gcc_assert (OMP_TP_NAME (expr_list) == NULL_TREE);
+
+ /* The user condition is not dynamic if it is constant. */
+ if (!tree_fits_shwi_p (TREE_VALUE (expr_list)))
+ expr = TREE_VALUE (expr_list);
+ }
+
+ tree target_device
+ = omp_get_context_selector_list (ctx, OMP_TRAIT_SET_TARGET_DEVICE);
+ if (target_device)
+ {
+ tree device_num = null_pointer_node;
+ tree kind = null_pointer_node;
+ tree arch = null_pointer_node;
+ tree isa = null_pointer_node;
+
+ tree device_num_sel
+ = omp_get_context_selector (ctx, OMP_TRAIT_SET_TARGET_DEVICE,
+ OMP_TRAIT_DEVICE_NUM);
+ if (device_num_sel)
+ device_num = OMP_TP_VALUE (OMP_TS_PROPERTIES (device_num_sel));
+ else
+ device_num = build_int_cst (integer_type_node, -1);
+
+ tree kind_sel
+ = omp_get_context_selector (ctx, OMP_TRAIT_SET_TARGET_DEVICE,
+ OMP_TRAIT_DEVICE_KIND);
+ if (kind_sel)
+ {
+ const char *str
+ = omp_context_name_list_prop (OMP_TS_PROPERTIES (kind_sel));
+ kind = build_string_literal (strlen (str) + 1, str);
+ }
+
+ tree arch_sel
+ = omp_get_context_selector (ctx, OMP_TRAIT_SET_TARGET_DEVICE,
+ OMP_TRAIT_DEVICE_ARCH);
+ if (arch_sel)
+ {
+ const char *str
+ = omp_context_name_list_prop (OMP_TS_PROPERTIES (arch_sel));
+ arch = build_string_literal (strlen (str) + 1, str);
+ }
+
+ tree isa_sel
+ = omp_get_context_selector (ctx, OMP_TRAIT_SET_TARGET_DEVICE,
+ OMP_TRAIT_DEVICE_ISA);
+ if (isa_sel)
+ {
+ const char *str
+ = omp_context_name_list_prop (OMP_TS_PROPERTIES (isa_sel));
+ isa = build_string_literal (strlen (str) + 1, str);
+ }
+
+ /* Generate a call to GOMP_evaluate_target_device. */
+ tree builtin_fn
+ = builtin_decl_explicit (BUILT_IN_GOMP_EVALUATE_TARGET_DEVICE);
+ tree call = build_call_expr (builtin_fn, 4, device_num, kind, arch, isa);
+
+ if (expr == NULL_TREE)
+ expr = call;
+ else
+ expr = fold_build2 (TRUTH_ANDIF_EXPR, boolean_type_node, expr, call);
+ }
+
+ return expr;
+}
+
/* Compute *SCORE for context selector CTX. Return true if the score
would be different depending on whether it is a declare simd clone or
@@ -2194,12 +2308,21 @@ omp_context_compute_score (tree ctx, score_wide_int *score, bool declare_simd)
{
tree selectors
= omp_get_context_selector_list (ctx, OMP_TRAIT_SET_CONSTRUCT);
- bool has_kind = omp_get_context_selector (ctx, OMP_TRAIT_SET_DEVICE,
- OMP_TRAIT_DEVICE_KIND);
- bool has_arch = omp_get_context_selector (ctx, OMP_TRAIT_SET_DEVICE,
- OMP_TRAIT_DEVICE_ARCH);
- bool has_isa = omp_get_context_selector (ctx, OMP_TRAIT_SET_DEVICE,
- OMP_TRAIT_DEVICE_ISA);
+ bool has_kind
+ = (omp_get_context_selector (ctx, OMP_TRAIT_SET_DEVICE,
+ OMP_TRAIT_DEVICE_KIND)
+ || omp_get_context_selector (ctx, OMP_TRAIT_SET_TARGET_DEVICE,
+ OMP_TRAIT_DEVICE_KIND));
+ bool has_arch
+ = (omp_get_context_selector (ctx, OMP_TRAIT_SET_DEVICE,
+ OMP_TRAIT_DEVICE_ARCH)
+ || omp_get_context_selector (ctx, OMP_TRAIT_SET_TARGET_DEVICE,
+ OMP_TRAIT_DEVICE_ARCH));
+ bool has_isa
+ = (omp_get_context_selector (ctx, OMP_TRAIT_SET_DEVICE,
+ OMP_TRAIT_DEVICE_ISA)
+ || omp_get_context_selector (ctx, OMP_TRAIT_SET_TARGET_DEVICE,
+ OMP_TRAIT_DEVICE_ISA));
bool ret = false;
*score = 1;
for (tree tss = ctx; tss; tss = TREE_CHAIN (tss))
@@ -2384,7 +2507,7 @@ omp_resolve_late_declare_variant (tree alt)
nmatches++;
continue;
}
- switch (omp_context_selector_matches (varentry1->ctx))
+ switch (omp_context_selector_matches (varentry1->ctx, false, true))
{
case 0:
matches.safe_push (false);
@@ -2488,7 +2611,8 @@ omp_resolve_declare_variant (tree base)
don't process it again. */
if (node && node->declare_variant_alt)
return base;
- switch (omp_context_selector_matches (TREE_VALUE (TREE_VALUE (attr))))
+ switch (omp_context_selector_matches (TREE_VALUE (TREE_VALUE (attr)),
+ false, true))
{
case 0:
/* No match, ignore. */
@@ -2853,6 +2977,185 @@ omp_lto_input_declare_variant_alt (lto_input_block *ib, cgraph_node *node,
INSERT) = entryp;
}
+/* Comparison function for sorting routines, to sort OpenMP metadirective
+ variants by decreasing score. */
+
+static int
+sort_variant (const void * a, const void *b, void *)
+{
+ score_wide_int score1
+ = ((const struct omp_metadirective_variant *) a)->score;
+ score_wide_int score2
+ = ((const struct omp_metadirective_variant *) b)->score;
+
+ if (score1 > score2)
+ return -1;
+ else if (score1 < score2)
+ return 1;
+ else
+ return 0;
+}
+
+/* Return a vector of dynamic replacement candidates for the directive
+ candidates in ALL_VARIANTS. Return an empty vector if the metadirective
+ cannot be resolved. */
+
+static vec<struct omp_metadirective_variant>
+omp_get_dynamic_candidates (vec <struct omp_metadirective_variant> &all_variants,
+ bool delay_p)
+{
+ auto_vec <struct omp_metadirective_variant> variants;
+ struct omp_metadirective_variant default_variant;
+ bool default_found = false;
+
+ for (unsigned int i = 0; i < all_variants.length (); i++)
+ {
+ struct omp_metadirective_variant variant = all_variants[i];
+
+ if (variant.selector == NULL_TREE)
+ {
+ gcc_assert (!default_found);
+ default_found = true;
+ default_variant = variant;
+ default_variant.score = 0;
+ default_variant.resolvable_p = true;
+ default_variant.dynamic_selector = NULL_TREE;
+ if (dump_file)
+ fprintf (dump_file,
+ "Considering default selector as candidate\n");
+ continue;
+ }
+
+ variant.resolvable_p = true;
+
+ if (dump_file)
+ {
+ fprintf (dump_file, "Considering selector ");
+ print_omp_context_selector (dump_file, variant.selector, TDF_NONE);
+ fprintf (dump_file, " as candidate - ");
+ }
+
+ switch (omp_context_selector_matches (variant.selector, true, delay_p))
+ {
+ case -1:
+ variant.resolvable_p = false;
+ if (dump_file)
+ fprintf (dump_file, "unresolvable");
+ /* FALLTHRU */
+ case 1:
+ /* TODO: Handle SIMD score?. */
+ omp_context_compute_score (variant.selector, &variant.score, false);
+ variant.dynamic_selector = omp_dynamic_cond (variant.selector);
+ variants.safe_push (variant);
+ if (dump_file && variant.resolvable_p)
+ {
+ if (variant.dynamic_selector)
+ fprintf (dump_file, "matched, dynamic");
+ else
+ fprintf (dump_file, "matched, non-dynamic");
+ }
+ break;
+ case 0:
+ if (dump_file)
+ fprintf (dump_file, "no match");
+ break;
+ }
+
+ if (dump_file)
+ fprintf (dump_file, "\n");
+ }
+
+ /* There must be one default variant. */
+ gcc_assert (default_found);
+
+ /* A context selector that is a strict subset of another context selector
+ has a score of zero. */
+ for (unsigned int i = 0; i < variants.length (); i++)
+ for (unsigned int j = i + 1; j < variants.length (); j++)
+ {
+ int r = omp_context_selector_compare (variants[i].selector,
+ variants[j].selector);
+ if (r == -1)
+ {
+ /* variant1 is a strict subset of variant2. */
+ variants[i].score = 0;
+ break;
+ }
+ else if (r == 1)
+ /* variant2 is a strict subset of variant1. */
+ variants[j].score = 0;
+ }
+
+ /* Sort the variants by decreasing score, preserving the original order
+ in case of a tie. */
+ variants.stablesort (sort_variant, NULL);
+
+ /* Add the default as a final choice. */
+ variants.safe_push (default_variant);
+
+ /* Build the dynamic candidate list. */
+ for (unsigned i = 0; i < variants.length (); i++)
+ {
+ /* If one of the candidates is unresolvable, give up for now. */
+ if (!variants[i].resolvable_p)
+ {
+ variants.truncate (0);
+ break;
+ }
+
+ if (dump_file)
+ {
+ fprintf (dump_file, "Adding directive variant with ");
+
+ if (variants[i].selector)
+ {
+ fprintf (dump_file, "selector ");
+ print_omp_context_selector (dump_file, variants[i].selector,
+ TDF_NONE);
+ }
+ else
+ fprintf (dump_file, "default selector");
+
+ fprintf (dump_file, " as candidate.\n");
+ }
+
+ /* The last of the candidates is ended by a static selector. */
+ if (!variants[i].dynamic_selector)
+ {
+ variants.truncate (i + 1);
+ break;
+ }
+ }
+
+ return variants.copy ();
+}
+
+/* Return a vector of dynamic replacement candidates for the metadirective
+ statement in METADIRECTIVE. Return an empty vector if the metadirective
+ cannot be resolved. */
+
+vec<struct omp_metadirective_variant>
+omp_resolve_metadirective (tree metadirective)
+{
+ auto_vec <struct omp_metadirective_variant> candidates;
+ tree variant = OMP_METADIRECTIVE_VARIANTS (metadirective);
+
+ gcc_assert (variant);
+ while (variant)
+ {
+ struct omp_metadirective_variant candidate;
+
+ candidate.selector = OMP_METADIRECTIVE_VARIANT_SELECTOR (variant);
+ candidate.directive = OMP_METADIRECTIVE_VARIANT_DIRECTIVE (variant);
+ candidate.body = OMP_METADIRECTIVE_VARIANT_BODY (variant);
+
+ candidates.safe_push (candidate);
+ variant = TREE_CHAIN (variant);
+ }
+
+ return omp_get_dynamic_candidates (candidates, true);
+}
+
/* Encode an oacc launch argument. This matches the GOMP_LAUNCH_PACK
macro on gomp-constants.h. We do not check for overflow. */
@@ -91,6 +91,22 @@ struct omp_for_data
tree adjn1;
};
+/* Needs to be a GC-friendly widest_int variant, but precision is
+ desirable to be the same on all targets. */
+typedef generic_wide_int <fixed_wide_int_storage <1024> > score_wide_int;
+
+/* A structure describing a variant in a metadirective. */
+
+struct GTY(()) omp_metadirective_variant
+{
+ score_wide_int score;
+ tree selector;
+ tree directive;
+ tree body;
+ tree dynamic_selector;
+ bool resolvable_p : 1;
+};
+
#define OACC_FN_ATTRIB "oacc function"
/* Accessors for OMP context selectors, used by variant directives.
@@ -150,6 +166,15 @@ extern tree make_trait_set_selector (enum omp_tss_code, tree, tree);
extern tree make_trait_selector (enum omp_ts_code, tree, tree, tree);
extern tree make_trait_property (tree, tree, tree);
+/* Accessors and constructor for metadirective variants. */
+#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))
+extern tree make_omp_metadirective_variant (tree, tree, tree);
+
extern tree omp_find_clause (tree clauses, enum omp_clause_code kind);
extern bool omp_is_allocatable_or_ptr (tree decl);
extern tree omp_check_optional_argument (tree decl, bool for_present_check);
@@ -166,15 +191,17 @@ extern poly_uint64 omp_max_vf (void);
extern int omp_max_simt_vf (void);
extern const char *omp_context_name_list_prop (tree);
extern void omp_construct_traits_to_codes (tree, int, enum tree_code *);
-extern tree omp_check_context_selector (location_t loc, tree ctx);
+extern tree omp_check_context_selector (location_t loc, tree ctx,
+ bool metadirective_p);
extern void omp_mark_declare_variant (location_t loc, tree variant,
tree construct);
-extern int omp_context_selector_matches (tree);
+extern int omp_context_selector_matches (tree, bool, bool);
extern int omp_context_selector_set_compare (enum omp_tss_code, tree, tree);
extern tree omp_get_context_selector (tree, enum omp_tss_code,
enum omp_ts_code);
extern tree omp_get_context_selector_list (tree, enum omp_tss_code);
extern tree omp_resolve_declare_variant (tree);
+extern vec<struct omp_metadirective_variant> omp_resolve_metadirective (tree);
extern tree oacc_launch_pack (unsigned code, tree device, unsigned op);
extern tree oacc_replace_fn_attrib_attr (tree attribs, tree dims);
extern void oacc_replace_fn_attrib (tree fn, tree dims);
@@ -1499,7 +1499,7 @@ dump_omp_clauses (pretty_printer *pp, tree clause, int spc, dump_flags_t flags,
}
/* Dump an OpenMP context selector CTX to PP. */
-static void
+void
dump_omp_context_selector (pretty_printer *pp, tree ctx, int spc,
dump_flags_t flags)
{
@@ -4008,6 +4008,40 @@ dump_generic_node (pretty_printer *pp, tree node, int spc, dump_flags_t flags,
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, "default:");
+ 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 TRANSACTION_EXPR:
if (TRANSACTION_EXPR_OUTER (node))
pp_string (pp, "__transaction_atomic [[outer]]");
@@ -45,6 +45,8 @@ extern void dump_omp_atomic_memory_order (pretty_printer *,
enum omp_memory_order);
extern void dump_omp_loop_non_rect_expr (pretty_printer *, tree, int,
dump_flags_t);
+extern void dump_omp_context_selector (pretty_printer *, tree, int,
+ dump_flags_t);
extern void print_omp_context_selector (FILE *, tree, dump_flags_t);
extern int dump_generic_node (pretty_printer *, tree, int, dump_flags_t, bool);
extern void print_declaration (pretty_printer *, tree, int, dump_flags_t);
@@ -1340,6 +1340,12 @@ DEFTREECODE (OMP_TARGET_ENTER_DATA, "omp_target_enter_data", tcc_statement, 1)
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. Use the interface in omp-general.h to construct variants
+ and access their fields. */
+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. */
@@ -1592,6 +1592,9 @@ class auto_suppress_location_wrappers
#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_SCAN_BODY(NODE) TREE_OPERAND (OMP_SCAN_CHECK (NODE), 0)
#define OMP_SCAN_CLAUSES(NODE) TREE_OPERAND (OMP_SCAN_CHECK (NODE), 1)