aboutsummaryrefslogtreecommitdiff
path: root/gcc/c-family
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2019-10-12 10:27:36 +0200
committerJakub Jelinek <jakub@gcc.gnu.org>2019-10-12 10:27:36 +0200
commit20de9568b49e663be848a35ce0bb08f63f14b5b2 (patch)
tree302f44f3d609ab83db0ef9a7e4ec5aeb4287965e /gcc/c-family
parent47370f050940a2e140e89fc0d46e808fab206f04 (diff)
downloadgcc-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/ChangeLog13
-rw-r--r--gcc/c-family/c-attribs.c6
-rw-r--r--gcc/c-family/c-common.h2
-rw-r--r--gcc/c-family/c-omp.c333
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;
+}