diff options
author | Jakub Jelinek <jakub@redhat.com> | 2019-10-12 10:27:36 +0200 |
---|---|---|
committer | Jakub Jelinek <jakub@gcc.gnu.org> | 2019-10-12 10:27:36 +0200 |
commit | 20de9568b49e663be848a35ce0bb08f63f14b5b2 (patch) | |
tree | 302f44f3d609ab83db0ef9a7e4ec5aeb4287965e /gcc/c-family | |
parent | 47370f050940a2e140e89fc0d46e808fab206f04 (diff) | |
download | gcc-20de9568b49e663be848a35ce0bb08f63f14b5b2.zip gcc-20de9568b49e663be848a35ce0bb08f63f14b5b2.tar.gz gcc-20de9568b49e663be848a35ce0bb08f63f14b5b2.tar.bz2 |
c-common.h (c_omp_mark_declare_variant, [...]): Declare.
c-family/
* c-common.h (c_omp_mark_declare_variant,
c_omp_context_selector_matches): Declare.
* c-omp.c: Include attribs.h, gimplify.h, cgraph.h, symbol-summary.h
and hsa-common.h.
(c_omp_get_context_selector): Support second argument NULL.
(c_omp_mark_declare_variant, c_omp_context_selector_matches): New
functions.
* c-attribs.c (c_common_attribute_table): Remove "omp declare variant"
attribute, add "omp declare variant base" and
"omp declare variant variant" attributes.
c/
* c-parser.c (c_parser_omp_context_selector): Improve error recovery.
For simd properties, put them directly into TREE_VALUE.
(c_finish_omp_declare_variant): Call c_omp_mark_declare_variant.
If c_omp_context_selector_matches is 0, don't add attribute, otherwise
add "omp declare variant base" attribute rather than
"omp declare variant".
cp/
* parser.c (cp_parser_omp_context_selector): Improve error recovery.
For simd properties, put them directly into TREE_VALUE.
(cp_finish_omp_declare_variant): Add "omp declare variant base"
attribute rather than "omp declare variant".
testsuite/
* c-c++-common/gomp/declare-variant-2.c: Adjust for error recovery
improvements. Add new tests.
* c-c++-common/gomp/declare-variant-4.c: New test.
* c-c++-common/gomp/declare-variant-5.c: New test.
* c-c++-common/gomp/declare-variant-6.c: New test.
* c-c++-common/gomp/declare-variant-7.c: New test.
From-SVN: r276914
Diffstat (limited to 'gcc/c-family')
-rw-r--r-- | gcc/c-family/ChangeLog | 13 | ||||
-rw-r--r-- | gcc/c-family/c-attribs.c | 6 | ||||
-rw-r--r-- | gcc/c-family/c-common.h | 2 | ||||
-rw-r--r-- | gcc/c-family/c-omp.c | 333 |
4 files changed, 347 insertions, 7 deletions
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index fea97bb..2b63689 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,16 @@ +2019-10-12 Jakub Jelinek <jakub@redhat.com> + + * c-common.h (c_omp_mark_declare_variant, + c_omp_context_selector_matches): Declare. + * c-omp.c: Include attribs.h, gimplify.h, cgraph.h, symbol-summary.h + and hsa-common.h. + (c_omp_get_context_selector): Support second argument NULL. + (c_omp_mark_declare_variant, c_omp_context_selector_matches): New + functions. + * c-attribs.c (c_common_attribute_table): Remove "omp declare variant" + attribute, add "omp declare variant base" and + "omp declare variant variant" attributes. + 2019-10-11 Joseph Myers <joseph@codesourcery.com> * c.opt (Wc11-c2x-compat): Add CPP(cpp_warn_c11_c2x_compat) diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c index 917d483..ea273f8 100644 --- a/gcc/c-family/c-attribs.c +++ b/gcc/c-family/c-attribs.c @@ -444,7 +444,9 @@ const struct attribute_spec c_common_attribute_table[] = handle_returns_nonnull_attribute, NULL }, { "omp declare simd", 0, -1, true, false, false, false, handle_omp_declare_simd_attribute, NULL }, - { "omp declare variant", 0, -1, true, false, false, false, + { "omp declare variant base", 0, -1, true, false, false, false, + handle_omp_declare_variant_attribute, NULL }, + { "omp declare variant variant", 0, -1, true, false, false, false, handle_omp_declare_variant_attribute, NULL }, { "simd", 0, 1, true, false, false, false, handle_simd_attribute, NULL }, @@ -3068,7 +3070,7 @@ handle_omp_declare_simd_attribute (tree *, tree, tree, int, bool *) return NULL_TREE; } -/* Handle an "omp declare variant" attribute; arguments as in +/* Handle an "omp declare variant {base,variant}" attribute; arguments as in struct attribute_spec.handler. */ static tree diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index eabe689..db7f26e 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -1191,6 +1191,8 @@ extern bool c_omp_predefined_variable (tree); extern enum omp_clause_default_kind c_omp_predetermined_sharing (tree); extern tree c_omp_check_context_selector (location_t, tree); extern tree c_omp_get_context_selector (tree, const char *, const char *); +extern void c_omp_mark_declare_variant (location_t, tree, tree); +extern int c_omp_context_selector_matches (tree); /* Return next tree in the chain for chain_next walking of tree nodes. */ static inline tree diff --git a/gcc/c-family/c-omp.c b/gcc/c-family/c-omp.c index 5426256..3398188 100644 --- a/gcc/c-family/c-omp.c +++ b/gcc/c-family/c-omp.c @@ -32,6 +32,11 @@ along with GCC; see the file COPYING3. If not see #include "omp-general.h" #include "gomp-constants.h" #include "memmodel.h" +#include "attribs.h" +#include "gimplify.h" +#include "cgraph.h" +#include "symbol-summary.h" +#include "hsa-common.h" /* Complete a #pragma oacc wait construct. LOC is the location of @@ -2236,17 +2241,335 @@ c_omp_check_context_selector (location_t loc, tree ctx) } /* From context selector CTX, return trait-selector with name SEL in - trait-selector-set with name SET if any, or NULL_TREE if not found. */ + trait-selector-set with name SET if any, or NULL_TREE if not found. + If SEL is NULL, return the list of trait-selectors in SET. */ tree c_omp_get_context_selector (tree ctx, const char *set, const char *sel) { tree setid = get_identifier (set); - tree selid = get_identifier (sel); + tree selid = sel ? get_identifier (sel) : NULL_TREE; for (tree t1 = ctx; t1; t1 = TREE_CHAIN (t1)) if (TREE_PURPOSE (t1) == setid) - for (tree t2 = TREE_VALUE (t1); t2; t2 = TREE_CHAIN (t2)) - if (TREE_PURPOSE (t2) == selid) - return t2; + { + if (sel == NULL) + return TREE_VALUE (t1); + for (tree t2 = TREE_VALUE (t1); t2; t2 = TREE_CHAIN (t2)) + if (TREE_PURPOSE (t2) == selid) + return t2; + } return NULL_TREE; } + +/* Register VARIANT as variant of some base function marked with + #pragma omp declare variant. CONSTRUCT is corresponding construct + selector set. */ + +void +c_omp_mark_declare_variant (location_t loc, tree variant, tree construct) +{ + tree attr = lookup_attribute ("omp declare variant variant", + DECL_ATTRIBUTES (variant)); + if (attr == NULL_TREE) + { + attr = tree_cons (get_identifier ("omp declare variant variant"), + unshare_expr (construct), + DECL_ATTRIBUTES (variant)); + DECL_ATTRIBUTES (variant) = attr; + return; + } + tree t1 = TREE_VALUE (attr); + tree t2 = construct; + tree simd = get_identifier ("simd"); + while (t1 && t2) + { + if (TREE_PURPOSE (t1) != TREE_PURPOSE (t2)) + break; + if (TREE_PURPOSE (t1) == simd) + { + if ((TREE_VALUE (t1) == NULL_TREE) + != (TREE_VALUE (t2) == NULL_TREE)) + break; + if (TREE_VALUE (t1)) + { + struct declare_variant_simd_data { + bool inbranch, notinbranch; + tree simdlen; + auto_vec<tree,16> data_sharing; + auto_vec<tree,16> aligned; + declare_variant_simd_data () + : inbranch(false), notinbranch(false), simdlen(NULL_TREE) {} + } data[2]; + unsigned int i; + for (i = 0; i < 2; i++) + for (tree c = TREE_VALUE (i ? t2 : t1); + c; c = OMP_CLAUSE_CHAIN (c)) + { + vec<tree> *v; + switch (OMP_CLAUSE_CODE (c)) + { + case OMP_CLAUSE_INBRANCH: + data[i].inbranch = true; + continue; + case OMP_CLAUSE_NOTINBRANCH: + data[i].notinbranch = true; + continue; + case OMP_CLAUSE_SIMDLEN: + data[i].simdlen = OMP_CLAUSE_SIMDLEN_EXPR (c); + continue; + case OMP_CLAUSE_UNIFORM: + case OMP_CLAUSE_LINEAR: + v = &data[i].data_sharing; + break; + case OMP_CLAUSE_ALIGNED: + v = &data[i].aligned; + break; + default: + gcc_unreachable (); + } + unsigned HOST_WIDE_INT argno + = tree_to_uhwi (OMP_CLAUSE_DECL (c)); + if (argno >= v->length ()) + v->safe_grow_cleared (argno + 1); + (*v)[argno] = c; + } + if (data[0].inbranch != data[1].inbranch + || data[0].notinbranch != data[1].notinbranch + || !simple_cst_equal (data[0].simdlen, + data[1].simdlen) + || (data[0].data_sharing.length () + != data[1].data_sharing.length ()) + || (data[0].aligned.length () + != data[1].aligned.length ())) + break; + tree c1, c2; + FOR_EACH_VEC_ELT (data[0].data_sharing, i, c1) + { + c2 = data[1].data_sharing[i]; + if ((c1 == NULL_TREE) != (c2 == NULL_TREE)) + break; + if (c1 == NULL_TREE) + continue; + if (OMP_CLAUSE_CODE (c1) != OMP_CLAUSE_CODE (c2)) + break; + if (OMP_CLAUSE_CODE (c1) != OMP_CLAUSE_LINEAR) + continue; + if (OMP_CLAUSE_LINEAR_VARIABLE_STRIDE (c1) + != OMP_CLAUSE_LINEAR_VARIABLE_STRIDE (c2)) + break; + if (OMP_CLAUSE_LINEAR_KIND (c1) + != OMP_CLAUSE_LINEAR_KIND (c2)) + break; + if (!simple_cst_equal (OMP_CLAUSE_LINEAR_STEP (c1), + OMP_CLAUSE_LINEAR_STEP (c2))) + break; + } + if (i < data[0].data_sharing.length ()) + break; + FOR_EACH_VEC_ELT (data[0].aligned, i, c1) + { + c2 = data[1].aligned[i]; + if ((c1 == NULL_TREE) != (c2 == NULL_TREE)) + break; + if (c1 == NULL_TREE) + continue; + if (!simple_cst_equal (OMP_CLAUSE_ALIGNED_ALIGNMENT (c1), + OMP_CLAUSE_ALIGNED_ALIGNMENT (c2))) + break; + } + if (i < data[0].aligned.length ()) + break; + } + } + t1 = TREE_CHAIN (t1); + t2 = TREE_CHAIN (t2); + } + if (t1 || t2) + error_at (loc, "%qD used as a variant with incompatible %<constructor%> " + "selector sets", variant); +} + +/* 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. */ + +int +c_omp_context_selector_matches (tree ctx) +{ + int ret = 1; + for (tree t1 = ctx; t1; t1 = TREE_CHAIN (t1)) + { + char set = IDENTIFIER_POINTER (TREE_PURPOSE (t1))[0]; + if (set == 'c') + { + /* For now, ignore the construct set. While something can be + determined already during parsing, we don't know until end of TU + whether additional constructs aren't added through declare variant + unless "omp declare variant variant" attribute exists already + (so in most of the cases), and we'd need to maintain set of + surrounding OpenMP constructs, which is better handled during + gimplification. */ + ret = -1; + continue; + } + for (tree t2 = TREE_VALUE (t1); t2; t2 = TREE_CHAIN (t2)) + { + const char *sel = IDENTIFIER_POINTER (TREE_PURPOSE (t2)); + switch (*sel) + { + case 'v': + if (set == 'i' && !strcmp (sel, "vendor")) + for (tree t3 = TREE_VALUE (t2); t3; t3 = TREE_CHAIN (t3)) + { + const char *prop = IDENTIFIER_POINTER (TREE_PURPOSE (t3)); + if (!strcmp (prop, " score") || !strcmp (prop, "gnu")) + continue; + return 0; + } + break; + case 'e': + if (set == 'i' && !strcmp (sel, "extension")) + /* We don't support any extensions right now. */ + return 0; + break; + case 'a': + if (set == 'i' && !strcmp (sel, "atomic_default_mem_order")) + { + enum omp_memory_order omo + = ((enum omp_memory_order) + (omp_requires_mask + & OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER)); + if (omo == OMP_MEMORY_ORDER_UNSPECIFIED) + { + /* We don't know yet, until end of TU. */ + ret = -1; + break; + } + tree t3 = TREE_VALUE (t2); + const char *prop = IDENTIFIER_POINTER (TREE_PURPOSE (t3)); + if (!strcmp (prop, " score")) + { + t3 = TREE_CHAIN (t3); + prop = IDENTIFIER_POINTER (TREE_PURPOSE (t3)); + } + if (!strcmp (prop, "relaxed") + && omo != OMP_MEMORY_ORDER_RELAXED) + return 0; + else if (!strcmp (prop, "seq_cst") + && omo != OMP_MEMORY_ORDER_SEQ_CST) + return 0; + else if (!strcmp (prop, "acq_rel") + && omo != OMP_MEMORY_ORDER_ACQ_REL) + return 0; + } + if (set == 'd' && !strcmp (sel, "arch")) + /* For now, need a target hook. */ + ret = -1; + break; + case 'u': + if (set == 'i' && !strcmp (sel, "unified_address")) + { + if ((omp_requires_mask & OMP_REQUIRES_UNIFIED_ADDRESS) == 0) + ret = -1; + break; + } + if (set == 'i' && !strcmp (sel, "unified_shared_memory")) + { + if ((omp_requires_mask + & OMP_REQUIRES_UNIFIED_SHARED_MEMORY) == 0) + ret = -1; + break; + } + break; + case 'd': + if (set == 'i' && !strcmp (sel, "dynamic_allocators")) + { + if ((omp_requires_mask + & OMP_REQUIRES_DYNAMIC_ALLOCATORS) == 0) + ret = -1; + break; + } + break; + case 'r': + if (set == 'i' && !strcmp (sel, "reverse_offload")) + { + if ((omp_requires_mask & OMP_REQUIRES_REVERSE_OFFLOAD) == 0) + ret = -1; + break; + } + break; + case 'k': + if (set == 'd' && !strcmp (sel, "kind")) + for (tree t3 = TREE_VALUE (t2); t3; t3 = TREE_CHAIN (t3)) + { + const char *prop = IDENTIFIER_POINTER (TREE_PURPOSE (t3)); + if (!strcmp (prop, "any")) + continue; + if (!strcmp (prop, "fpga")) + return 0; /* Right now GCC doesn't support any fpgas. */ + if (!strcmp (prop, "host")) + { + if (ENABLE_OFFLOADING || hsa_gen_requested_p ()) + ret = -1; + continue; + } + if (!strcmp (prop, "nohost")) + { + if (ENABLE_OFFLOADING || hsa_gen_requested_p ()) + ret = -1; + else + return 0; + continue; + } + if (!strcmp (prop, "cpu") || !strcmp (prop, "gpu")) + { + bool maybe_gpu = false; + if (hsa_gen_requested_p ()) + maybe_gpu = true; + else if (ENABLE_OFFLOADING) + for (const char *c = getenv ("OFFLOAD_TARGET_NAMES"); + c; ) + { + if (!strncmp (c, "nvptx", strlen ("nvptx")) + || !strncmp (c, "amdgcn", strlen ("amdgcn"))) + { + maybe_gpu = true; + break; + } + else if ((c = strchr (c, ','))) + c++; + } + if (!maybe_gpu) + { + if (prop[0] == 'g') + return 0; + } + else + ret = -1; + continue; + } + /* Any other kind doesn't match. */ + return 0; + } + break; + case 'i': + if (set == 'd' && !strcmp (sel, "isa")) + /* For now, need a target hook. */ + ret = -1; + break; + case 'c': + if (set == 'u' && !strcmp (sel, "condition")) + for (tree t3 = TREE_VALUE (t2); t3; t3 = TREE_CHAIN (t3)) + if (TREE_PURPOSE (t3) == NULL_TREE + && integer_zerop (TREE_VALUE (t3))) + return 0; + break; + default: + break; + } + } + } + return ret; +} |