if (symtab->state == PARSING)
/* Maybe. */
return true;
+ if (cfun && cfun->after_inlining)
+ return false;
if (current_function_decl
&& lookup_attribute ("omp declare target",
DECL_ATTRIBUTES (current_function_decl)))
(so in most of the cases), and we'd need to maintain set of
surrounding OpenMP constructs, which is better handled during
gimplification. */
- if (symtab->state == PARSING
- || (cfun->curr_properties & PROP_gimple_any) != 0)
+ if (symtab->state == PARSING)
{
ret = -1;
continue;
enum tree_code constructs[5];
int nconstructs
= omp_constructor_traits_to_codes (TREE_VALUE (t1), constructs);
+
+ if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
+ {
+ if (!cfun->after_inlining)
+ {
+ ret = -1;
+ continue;
+ }
+ int i;
+ for (i = 0; i < nconstructs; ++i)
+ if (constructs[i] == OMP_SIMD)
+ break;
+ if (i < nconstructs)
+ {
+ ret = -1;
+ continue;
+ }
+ /* If there is no simd, assume it is ok after IPA,
+ constructs should have been checked before. */
+ continue;
+ }
+
int r = omp_construct_selector_matches (constructs, nconstructs,
NULL);
if (r == 0)
case 'a':
if (set == 'i' && !strcmp (sel, "atomic_default_mem_order"))
{
+ if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
+ break;
+
enum omp_memory_order omo
= ((enum omp_memory_order)
(omp_requires_mask
case 'u':
if (set == 'i' && !strcmp (sel, "unified_address"))
{
+ if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
+ break;
+
if ((omp_requires_mask & OMP_REQUIRES_UNIFIED_ADDRESS) == 0)
{
if (symtab->state == PARSING)
}
if (set == 'i' && !strcmp (sel, "unified_shared_memory"))
{
+ if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
+ break;
+
if ((omp_requires_mask
& OMP_REQUIRES_UNIFIED_SHARED_MEMORY) == 0)
{
case 'd':
if (set == 'i' && !strcmp (sel, "dynamic_allocators"))
{
+ if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
+ break;
+
if ((omp_requires_mask
& OMP_REQUIRES_DYNAMIC_ALLOCATORS) == 0)
{
case 'r':
if (set == 'i' && !strcmp (sel, "reverse_offload"))
{
+ if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
+ break;
+
if ((omp_requires_mask & OMP_REQUIRES_REVERSE_OFFLOAD) == 0)
{
if (symtab->state == PARSING)
#pragma omp declare simd on it, some simd clones
might have the isa added later on. */
if (r == -1
- && targetm.simd_clone.compute_vecsize_and_simdlen)
+ && targetm.simd_clone.compute_vecsize_and_simdlen
+ && (cfun == NULL || !cfun->after_inlining))
{
tree attrs
= DECL_ATTRIBUTES (current_function_decl);
return ret;
}
+/* Class describing a single variant. */
+struct GTY(()) omp_declare_variant_entry {
+ /* NODE of the variant. */
+ cgraph_node *variant;
+ /* Score if not in declare simd clone. */
+ widest_int score;
+ /* Score if in declare simd clone. */
+ widest_int score_in_declare_simd_clone;
+ /* Context selector for the variant. */
+ tree ctx;
+ /* True if the context selector is known to match already. */
+ bool matches;
+};
+
+/* Class describing a function with variants. */
+struct GTY((for_user)) omp_declare_variant_base_entry {
+ /* NODE of the base function. */
+ cgraph_node *base;
+ /* NODE of the artificial function created for the deferred variant
+ resolution. */
+ cgraph_node *node;
+ /* Vector of the variants. */
+ vec<omp_declare_variant_entry, va_gc> *variants;
+};
+
+struct omp_declare_variant_hasher
+ : ggc_ptr_hash<omp_declare_variant_base_entry> {
+ static hashval_t hash (omp_declare_variant_base_entry *);
+ static bool equal (omp_declare_variant_base_entry *,
+ omp_declare_variant_base_entry *);
+};
+
+hashval_t
+omp_declare_variant_hasher::hash (omp_declare_variant_base_entry *x)
+{
+ inchash::hash hstate;
+ hstate.add_int (DECL_UID (x->base->decl));
+ hstate.add_int (x->variants->length ());
+ omp_declare_variant_entry *variant;
+ unsigned int i;
+ FOR_EACH_VEC_SAFE_ELT (x->variants, i, variant)
+ {
+ hstate.add_int (DECL_UID (variant->variant->decl));
+ hstate.add_wide_int (variant->score);
+ hstate.add_wide_int (variant->score_in_declare_simd_clone);
+ hstate.add_ptr (variant->ctx);
+ hstate.add_int (variant->matches);
+ }
+ return hstate.end ();
+}
+
+bool
+omp_declare_variant_hasher::equal (omp_declare_variant_base_entry *x,
+ omp_declare_variant_base_entry *y)
+{
+ if (x->base != y->base
+ || x->variants->length () != y->variants->length ())
+ return false;
+ omp_declare_variant_entry *variant;
+ unsigned int i;
+ FOR_EACH_VEC_SAFE_ELT (x->variants, i, variant)
+ if (variant->variant != (*y->variants)[i].variant
+ || variant->score != (*y->variants)[i].score
+ || (variant->score_in_declare_simd_clone
+ != (*y->variants)[i].score_in_declare_simd_clone)
+ || variant->ctx != (*y->variants)[i].ctx
+ || variant->matches != (*y->variants)[i].matches)
+ return false;
+ return true;
+}
+
+static GTY(()) hash_table<omp_declare_variant_hasher> *omp_declare_variants;
+
+struct omp_declare_variant_alt_hasher
+ : ggc_ptr_hash<omp_declare_variant_base_entry> {
+ static hashval_t hash (omp_declare_variant_base_entry *);
+ static bool equal (omp_declare_variant_base_entry *,
+ omp_declare_variant_base_entry *);
+};
+
+hashval_t
+omp_declare_variant_alt_hasher::hash (omp_declare_variant_base_entry *x)
+{
+ return DECL_UID (x->node->decl);
+}
+
+bool
+omp_declare_variant_alt_hasher::equal (omp_declare_variant_base_entry *x,
+ omp_declare_variant_base_entry *y)
+{
+ return x->node == y->node;
+}
+
+static GTY(()) hash_table<omp_declare_variant_alt_hasher>
+ *omp_declare_variant_alt;
+
+/* Try to resolve declare variant after gimplification. */
+
+static tree
+omp_resolve_late_declare_variant (tree alt)
+{
+ cgraph_node *node = cgraph_node::get (alt);
+ cgraph_node *cur_node = cgraph_node::get (cfun->decl);
+ if (node == NULL
+ || !node->declare_variant_alt
+ || !cfun->after_inlining)
+ return alt;
+
+ omp_declare_variant_base_entry entry;
+ entry.base = NULL;
+ entry.node = node;
+ entry.variants = NULL;
+ omp_declare_variant_base_entry *entryp
+ = omp_declare_variant_alt->find_with_hash (&entry, DECL_UID (alt));
+
+ unsigned int i, j;
+ omp_declare_variant_entry *varentry1, *varentry2;
+ auto_vec <bool, 16> matches;
+ unsigned int nmatches = 0;
+ FOR_EACH_VEC_SAFE_ELT (entryp->variants, i, varentry1)
+ {
+ if (varentry1->matches)
+ {
+ /* This has been checked to be ok already. */
+ matches.safe_push (true);
+ nmatches++;
+ continue;
+ }
+ switch (omp_context_selector_matches (varentry1->ctx))
+ {
+ case 0:
+ matches.safe_push (false);
+ break;
+ case -1:
+ return alt;
+ default:
+ matches.safe_push (true);
+ nmatches++;
+ break;
+ }
+ }
+
+ if (nmatches == 0)
+ return entryp->base->decl;
+
+ /* A context selector that is a strict subset of another context selector
+ has a score of zero. */
+ FOR_EACH_VEC_SAFE_ELT (entryp->variants, i, varentry1)
+ if (matches[i])
+ {
+ for (j = i + 1;
+ vec_safe_iterate (entryp->variants, j, &varentry2); ++j)
+ if (matches[j])
+ {
+ int r = omp_context_selector_compare (varentry1->ctx,
+ varentry2->ctx);
+ if (r == -1)
+ {
+ /* ctx1 is a strict subset of ctx2, ignore ctx1. */
+ matches[i] = false;
+ break;
+ }
+ else if (r == 1)
+ /* ctx2 is a strict subset of ctx1, remove ctx2. */
+ matches[j] = false;
+ }
+ }
+
+ widest_int max_score = -1;
+ varentry2 = NULL;
+ FOR_EACH_VEC_SAFE_ELT (entryp->variants, i, varentry1)
+ if (matches[i])
+ {
+ widest_int score
+ = (cur_node->simdclone ? varentry1->score_in_declare_simd_clone
+ : varentry1->score);
+ if (score > max_score)
+ {
+ max_score = score;
+ varentry2 = varentry1;
+ }
+ }
+ return varentry2->variant->decl;
+}
+
/* Try to resolve declare variant, return the variant decl if it should
be used instead of base, or base otherwise. */
omp_resolve_declare_variant (tree base)
{
tree variant1 = NULL_TREE, variant2 = NULL_TREE;
+ if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
+ return omp_resolve_late_declare_variant (base);
+
auto_vec <tree, 16> variants;
auto_vec <bool, 16> defer;
bool any_deferred = false;
bool first = true;
unsigned int i;
tree attr1, attr2;
+ omp_declare_variant_base_entry entry;
+ entry.base = cgraph_node::get_create (base);
+ entry.node = NULL;
+ vec_alloc (entry.variants, variants.length ());
FOR_EACH_VEC_ELT (variants, i, attr1)
{
widest_int score1;
variant2 = defer[i] ? NULL_TREE : attr1;
}
}
+ omp_declare_variant_entry varentry;
+ varentry.variant
+ = cgraph_node::get_create (TREE_PURPOSE (TREE_VALUE (attr1)));
+ varentry.score = score1;
+ varentry.score_in_declare_simd_clone = score2;
+ varentry.ctx = ctx;
+ varentry.matches = !defer[i];
+ entry.variants->quick_push (varentry);
}
/* If there is a clear winner variant with the score which is not
}
}
if (variant1)
- return TREE_PURPOSE (TREE_VALUE (variant1));
+ {
+ vec_free (entry.variants);
+ return TREE_PURPOSE (TREE_VALUE (variant1));
+ }
+ }
+
+ if (omp_declare_variants == NULL)
+ omp_declare_variants
+ = hash_table<omp_declare_variant_hasher>::create_ggc (64);
+ omp_declare_variant_base_entry **slot
+ = omp_declare_variants->find_slot (&entry, INSERT);
+ if (*slot != NULL)
+ {
+ vec_free (entry.variants);
+ return (*slot)->node->decl;
}
- return base;
+ *slot = ggc_cleared_alloc<omp_declare_variant_base_entry> ();
+ (*slot)->base = entry.base;
+ (*slot)->node = entry.base;
+ (*slot)->variants = entry.variants;
+ tree alt = build_decl (DECL_SOURCE_LOCATION (base), FUNCTION_DECL,
+ DECL_NAME (base), TREE_TYPE (base));
+ DECL_ARTIFICIAL (alt) = 1;
+ DECL_IGNORED_P (alt) = 1;
+ TREE_STATIC (alt) = 1;
+ tree attributes = DECL_ATTRIBUTES (base);
+ if (lookup_attribute ("noipa", attributes) == NULL)
+ {
+ attributes = tree_cons (get_identifier ("noipa"), NULL, attributes);
+ if (lookup_attribute ("noinline", attributes) == NULL)
+ attributes = tree_cons (get_identifier ("noinline"), NULL,
+ attributes);
+ if (lookup_attribute ("noclone", attributes) == NULL)
+ attributes = tree_cons (get_identifier ("noclone"), NULL,
+ attributes);
+ if (lookup_attribute ("no_icf", attributes) == NULL)
+ attributes = tree_cons (get_identifier ("no_icf"), NULL,
+ attributes);
+ }
+ DECL_ATTRIBUTES (alt) = attributes;
+ DECL_INITIAL (alt) = error_mark_node;
+ (*slot)->node = cgraph_node::create (alt);
+ (*slot)->node->declare_variant_alt = 1;
+ (*slot)->node->create_reference (entry.base, IPA_REF_ADDR);
+ omp_declare_variant_entry *varentry;
+ FOR_EACH_VEC_SAFE_ELT (entry.variants, i, varentry)
+ (*slot)->node->create_reference (varentry->variant, IPA_REF_ADDR);
+ if (omp_declare_variant_alt == NULL)
+ omp_declare_variant_alt
+ = hash_table<omp_declare_variant_alt_hasher>::create_ggc (64);
+ *omp_declare_variant_alt->find_slot_with_hash (*slot, DECL_UID (alt),
+ INSERT) = *slot;
+ return alt;
}
if (variants.length () == 1)
return TREE_PURPOSE (TREE_VALUE (variants[0]));
- /* A context selector that is a strict subset of another context selector has a score
- of zero. */
+ /* A context selector that is a strict subset of another context selector
+ has a score of zero. */
tree attr1, attr2;
unsigned int i, j;
FOR_EACH_VEC_ELT (variants, i, attr1)
gcc_checking_assert (axis >= 0 && axis < GOMP_DIM_MAX);
return (int) axis;
}
+
+#include "gt-omp-general.h"