+ 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)))
@@ -2202,9 +2238,114 @@ 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;
+/* Helper for omp_dynamic_cond: encode the kind/arch/isa property-lists
+ into strings for GOMP_evaluate_target_device. The property-list
+ strings are encoded similarly to those in omp_offload_kind_arch_isa,
+ above: each trait is passed as a string, with each property for the
+ string separated by '\0', and an extra '\0' at the end of the string. */
+static tree
+omp_encode_kind_arch_isa_props (tree props)
+{
+ if (!props)
+ return NULL_TREE;
+ size_t length = 1;
+ for (tree p = props; p; p = TREE_CHAIN (p))
+ length += strlen (omp_context_name_list_prop (p)) + 1;
+ char *buffer = (char *) alloca (length);
+ size_t n = 0;
+ for (tree p = props; p; p = TREE_CHAIN (p))
+ {
+ const char *str = omp_context_name_list_prop (p);
+ strcpy (buffer + n, str);
+ n += strlen (str) + 1;
+ }
+ *(buffer + n) = '\0';
+ return build_string_literal (length, buffer);
+}
+
+/* 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);
+
+ /* The user condition is not dynamic if it is constant. */
+ if (!tree_fits_shwi_p (OMP_TP_VALUE (expr_list)))
+ expr = OMP_TP_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)
+ /* Generate
+ devnum = (num == -1) ? GOMP_DEVICE_HOST_FALLBACK : num);
+ to remap -1 for GOMP_* functions. */
+ {
+ tree num = OMP_TP_VALUE (OMP_TS_PROPERTIES (device_num_sel));
+ location_t loc = EXPR_LOCATION (num);
+ tree icv = build_int_cst (integer_type_node, -1);
+ tree compare = fold_build2_loc (loc, EQ_EXPR, unsigned_type_node,
+ num, icv);
+ tree fallback = build_int_cst (integer_type_node,
+ GOMP_DEVICE_HOST_FALLBACK);
+ device_num = fold_build3_loc (loc, COND_EXPR, integer_type_node,
+ compare, fallback, save_expr (num));
+ }
+ else
+ device_num = build_int_cst (integer_type_node, GOMP_DEVICE_ICV);
+ tree kind_sel
+ = omp_get_context_selector (ctx, OMP_TRAIT_SET_TARGET_DEVICE,
+ OMP_TRAIT_DEVICE_KIND);
+ /* "any" is equivalent to omitting this trait selector. */
+ if (kind_sel
+ && strcmp (omp_context_name_list_prop (OMP_TS_PROPERTIES (kind_sel)),
+ "any"))
+ kind = omp_encode_kind_arch_isa_props (OMP_TS_PROPERTIES (kind_sel));
+
+
+ tree arch_sel
+ = omp_get_context_selector (ctx, OMP_TRAIT_SET_TARGET_DEVICE,
+ OMP_TRAIT_DEVICE_ARCH);
+ if (arch_sel)
+ arch = omp_encode_kind_arch_isa_props (OMP_TS_PROPERTIES (arch_sel));
+
+ tree isa_sel
+ = omp_get_context_selector (ctx, OMP_TRAIT_SET_TARGET_DEVICE,
+ OMP_TRAIT_DEVICE_ISA);
+ if (isa_sel)
+ isa = omp_encode_kind_arch_isa_props (OMP_TS_PROPERTIES (isa_sel));
+
+ /* 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
@@ -2216,12 +2357,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))
@@ -2406,7 +2556,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);
@@ -2510,7 +2660,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. */
@@ -2875,6 +3026,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_variant *) a)->score;
+ score_wide_int score2
+ = ((const struct omp_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_variant>
+omp_get_dynamic_candidates (vec <struct omp_variant> &all_variants,
+ bool delay_p)
+{
+ auto_vec <struct omp_variant> variants;
+ struct omp_variant default_variant;
+ bool default_found = false;
+
+ for (unsigned int i = 0; i < all_variants.length (); i++)
+ {
+ struct omp_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_variant>
+omp_early_resolve_metadirective (tree metadirective)
+{
+ auto_vec <struct omp_variant> candidates;
+ tree variant = OMP_METADIRECTIVE_VARIANTS (metadirective);
+
+ gcc_assert (variant);
+ while (variant)
+ {
+ struct omp_variant candidate;
+
+ candidate.selector = OMP_METADIRECTIVE_VARIANT_SELECTOR (variant);
+ candidate.alternative = 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. */
diff --git a/gcc/omp-general.h b/gcc/omp-general.h
index 37f0548befd..8fe25b3108f 100644
--- a/gcc/omp-general.h
+++ b/gcc/omp-general.h
@@ -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_variant
+{
+ score_wide_int score;
+ tree selector;
+ tree alternative;
+ 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_variant> omp_early_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);
diff --git a/gcc/tree-pretty-print.cc b/gcc/tree-pretty-print.cc
index 4bb946bb0e8..59db597c10d 100644
--- a/gcc/tree-pretty-print.cc
+++ b/gcc/tree-pretty-print.cc
@@ -1522,7 +1522,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)
{
@@ -4048,6 +4048,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, "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 TRANSACTION_EXPR:
if (TRANSACTION_EXPR_OUTER (node))
pp_string (pp, "__transaction_atomic [[outer]]"); diff --git a/gcc/tree-pretty-print.h b/gcc/tree-pretty-print.h
index c5089f82cf6..d9d4f82909f 100644 --- a/gcc/tree-pretty-print.h
+++ b/gcc/tree-pretty-print.h @@ -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); diff --git a/gcc/tree.def
b/gcc/tree.def index 85ab182c6f5..155a508f0d3 100644 ---
a/gcc/tree.def +++ b/gcc/tree.def @@ -1348,6 +1348,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. */
diff --git a/gcc/tree.h b/gcc/tree.h
index 28e8e71b036..dfd738353b8 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -1600,6 +1600,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)
-- 2.25.1