diff options
author | Jakub Jelinek <jakub@redhat.com> | 2019-11-02 00:30:55 +0100 |
---|---|---|
committer | Jakub Jelinek <jakub@gcc.gnu.org> | 2019-11-02 00:30:55 +0100 |
commit | 917dd789e55c88123d804a8a411e4a61ee7b6e43 (patch) | |
tree | f9f2f596da38caa176b5dafe2a18ac61f1957f4f /gcc/omp-general.c | |
parent | f968ef9b8df2bc2287e5e7e87299e5a2a44e8c94 (diff) | |
download | gcc-917dd789e55c88123d804a8a411e4a61ee7b6e43.zip gcc-917dd789e55c88123d804a8a411e4a61ee7b6e43.tar.gz gcc-917dd789e55c88123d804a8a411e4a61ee7b6e43.tar.bz2 |
omp-general.h (omp_context_selector_set_compare): Declare.
* omp-general.h (omp_context_selector_set_compare): Declare.
* omp-general.c (omp_construct_simd_compare,
omp_context_selector_props_compare, omp_context_selector_set_compare,
omp_context_selector_compare): New functions.
(omp_resolve_declare_variant): Prune variants that are strict subset
of another variant.
c-family/
* c-omp.c (c_omp_mark_declare_variant): Use
omp_context_selector_set_compare.
testsuite/
* c-c++-common/gomp/declare-variant-6.c: Expect construct rather than
constructor in diagnostic messages.
* c-c++-common/gomp/declare-variant-7.c: Likewise.
* c-c++-common/gomp/declare-variant-11.c: New test.
From-SVN: r277734
Diffstat (limited to 'gcc/omp-general.c')
-rw-r--r-- | gcc/omp-general.c | 366 |
1 files changed, 358 insertions, 8 deletions
diff --git a/gcc/omp-general.c b/gcc/omp-general.c index 82f4746..6700e7f 100644 --- a/gcc/omp-general.c +++ b/gcc/omp-general.c @@ -947,6 +947,320 @@ omp_context_selector_matches (tree ctx) return ret; } +/* Compare construct={simd} CLAUSES1 with CLAUSES2, return 0/-1/1/2 as + in omp_context_selector_set_compare. */ + +static int +omp_construct_simd_compare (tree clauses1, tree clauses2) +{ + if (clauses1 == NULL_TREE) + return clauses2 == NULL_TREE ? 0 : -1; + if (clauses2 == NULL_TREE) + return 1; + + int r = 0; + 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 = i ? clauses2 : clauses1; 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; + } + /* Here, r is used as a bitmask, 2 is set if CLAUSES1 has something + CLAUSES2 doesn't, 1 is set if CLAUSES2 has something CLAUSES1 + doesn't. Thus, r == 3 implies return value 2, r == 1 implies + -1, r == 2 implies 1 and r == 0 implies 0. */ + if (data[0].inbranch != data[1].inbranch) + r |= data[0].inbranch ? 2 : 1; + if (data[0].notinbranch != data[1].notinbranch) + r |= data[0].notinbranch ? 2 : 1; + if (!simple_cst_equal (data[0].simdlen, data[1].simdlen)) + { + if (data[0].simdlen && data[1].simdlen) + return 2; + r |= data[0].simdlen ? 2 : 1; + } + if (data[0].data_sharing.length () < data[1].data_sharing.length () + || data[0].aligned.length () < data[1].aligned.length ()) + r |= 1; + tree c1, c2; + FOR_EACH_VEC_ELT (data[0].data_sharing, i, c1) + { + c2 = (i < data[1].data_sharing.length () + ? data[1].data_sharing[i] : NULL_TREE); + if ((c1 == NULL_TREE) != (c2 == NULL_TREE)) + { + r |= c1 != NULL_TREE ? 2 : 1; + continue; + } + if (c1 == NULL_TREE) + continue; + if (OMP_CLAUSE_CODE (c1) != OMP_CLAUSE_CODE (c2)) + return 2; + if (OMP_CLAUSE_CODE (c1) != OMP_CLAUSE_LINEAR) + continue; + if (OMP_CLAUSE_LINEAR_VARIABLE_STRIDE (c1) + != OMP_CLAUSE_LINEAR_VARIABLE_STRIDE (c2)) + return 2; + if (OMP_CLAUSE_LINEAR_KIND (c1) != OMP_CLAUSE_LINEAR_KIND (c2)) + return 2; + if (!simple_cst_equal (OMP_CLAUSE_LINEAR_STEP (c1), + OMP_CLAUSE_LINEAR_STEP (c2))) + return 2; + } + FOR_EACH_VEC_ELT (data[0].aligned, i, c1) + { + c2 = i < data[1].aligned.length () ? data[1].aligned[i] : NULL_TREE; + if ((c1 == NULL_TREE) != (c2 == NULL_TREE)) + { + r |= c1 != NULL_TREE ? 2 : 1; + continue; + } + if (c1 == NULL_TREE) + continue; + if (!simple_cst_equal (OMP_CLAUSE_ALIGNED_ALIGNMENT (c1), + OMP_CLAUSE_ALIGNED_ALIGNMENT (c2))) + return 2; + } + switch (r) + { + case 0: return 0; + case 1: return -1; + case 2: return 1; + case 3: return 2; + default: gcc_unreachable (); + } +} + +/* Compare properties of selectors SEL from SET other than construct. + Return 0/-1/1/2 as in omp_context_selector_set_compare. + Unlike set names or selector names, properties can have duplicates. */ + +static int +omp_context_selector_props_compare (const char *set, const char *sel, + tree ctx1, tree ctx2) +{ + int ret = 0; + for (int pass = 0; pass < 2; pass++) + for (tree t1 = pass ? ctx2 : ctx1; t1; t1 = TREE_CHAIN (t1)) + { + tree t2; + for (t2 = pass ? ctx1 : ctx2; t2; t2 = TREE_CHAIN (t2)) + if (TREE_PURPOSE (t1) == TREE_PURPOSE (t2)) + { + if (TREE_PURPOSE (t1) == NULL_TREE) + { + if (set[0] == 'u' && strcmp (sel, "condition") == 0) + { + if (integer_zerop (TREE_VALUE (t1)) + != integer_zerop (TREE_VALUE (t2))) + return 2; + break; + } + if (simple_cst_equal (TREE_VALUE (t1), TREE_VALUE (t2))) + break; + } + else if (strcmp (IDENTIFIER_POINTER (TREE_PURPOSE (t1)), + " score") == 0) + { + if (!simple_cst_equal (TREE_VALUE (t1), TREE_VALUE (t2))) + return 2; + break; + } + else + break; + } + if (t2 == NULL_TREE) + { + int r = pass ? -1 : 1; + if (ret && ret != r) + return 2; + else if (pass) + return r; + else + { + ret = r; + break; + } + } + } + return ret; +} + +/* Compare single context selector sets CTX1 and CTX2 with SET name. + Return 0 if CTX1 is equal to CTX2, + -1 if CTX1 is a strict subset of CTX2, + 1 if CTX2 is a strict subset of CTX1, or + 2 if neither context is a subset of another one. */ + +int +omp_context_selector_set_compare (const char *set, tree ctx1, tree ctx2) +{ + bool swapped = false; + int ret = 0; + int len1 = list_length (ctx1); + int len2 = list_length (ctx2); + int cnt = 0; + if (len1 < len2) + { + swapped = true; + std::swap (ctx1, ctx2); + std::swap (len1, len2); + } + if (set[0] == 'c') + { + tree t1; + tree t2 = ctx2; + tree simd = get_identifier ("simd"); + /* Handle construct set specially. In this case the order + of the selector matters too. */ + for (t1 = ctx1; t1; t1 = TREE_CHAIN (t1)) + if (TREE_PURPOSE (t1) == TREE_PURPOSE (t2)) + { + int r = 0; + if (TREE_PURPOSE (t1) == simd) + r = omp_construct_simd_compare (TREE_VALUE (t1), + TREE_VALUE (t2)); + if (r == 2 || (ret && r && (ret < 0) != (r < 0))) + return 2; + if (ret == 0) + ret = r; + t2 = TREE_CHAIN (t2); + if (t2 == NULL_TREE) + { + t1 = TREE_CHAIN (t1); + break; + } + } + else if (ret < 0) + return 2; + else + ret = 1; + if (t2 != NULL_TREE) + return 2; + if (t1 != NULL_TREE) + { + if (ret < 0) + return 2; + ret = 1; + } + if (ret == 0) + return 0; + return swapped ? -ret : ret; + } + for (tree t1 = ctx1; t1; t1 = TREE_CHAIN (t1)) + { + tree t2; + for (t2 = ctx2; t2; t2 = TREE_CHAIN (t2)) + if (TREE_PURPOSE (t1) == TREE_PURPOSE (t2)) + { + const char *sel = IDENTIFIER_POINTER (TREE_PURPOSE (t1)); + int r = omp_context_selector_props_compare (set, sel, + TREE_VALUE (t1), + TREE_VALUE (t2)); + if (r == 2 || (ret && r && (ret < 0) != (r < 0))) + return 2; + if (ret == 0) + ret = r; + cnt++; + break; + } + if (t2 == NULL_TREE) + { + if (ret == -1) + return 2; + ret = 1; + } + } + if (cnt < len2) + return 2; + if (ret == 0) + return 0; + return swapped ? -ret : ret; +} + +/* Compare whole context selector specification CTX1 and CTX2. + Return 0 if CTX1 is equal to CTX2, + -1 if CTX1 is a strict subset of CTX2, + 1 if CTX2 is a strict subset of CTX1, or + 2 if neither context is a subset of another one. */ + +static int +omp_context_selector_compare (tree ctx1, tree ctx2) +{ + bool swapped = false; + int ret = 0; + int len1 = list_length (ctx1); + int len2 = list_length (ctx2); + int cnt = 0; + if (len1 < len2) + { + swapped = true; + std::swap (ctx1, ctx2); + std::swap (len1, len2); + } + for (tree t1 = ctx1; t1; t1 = TREE_CHAIN (t1)) + { + tree t2; + for (t2 = ctx2; t2; t2 = TREE_CHAIN (t2)) + if (TREE_PURPOSE (t1) == TREE_PURPOSE (t2)) + { + const char *set = IDENTIFIER_POINTER (TREE_PURPOSE (t1)); + int r = omp_context_selector_set_compare (set, TREE_VALUE (t1), + TREE_VALUE (t2)); + if (r == 2 || (ret && r && (ret < 0) != (r < 0))) + return 2; + if (ret == 0) + ret = r; + cnt++; + break; + } + if (t2 == NULL_TREE) + { + if (ret == -1) + return 2; + ret = 1; + } + } + if (cnt < len2) + return 2; + if (ret == 0) + return 0; + return swapped ? -ret : ret; +} + /* Try to resolve declare variant, return the variant decl if it should be used instead of base, or base otherwise. */ @@ -954,11 +1268,14 @@ tree omp_resolve_declare_variant (tree base) { tree variant = NULL_TREE; + auto_vec <tree, 16> variants; for (tree attr = DECL_ATTRIBUTES (base); attr; attr = TREE_CHAIN (attr)) { attr = lookup_attribute ("omp declare variant base", attr); if (attr == NULL_TREE) break; + if (TREE_CODE (TREE_PURPOSE (TREE_VALUE (attr))) != FUNCTION_DECL) + continue; switch (omp_context_selector_matches (TREE_VALUE (TREE_VALUE (attr)))) { case 0: @@ -968,16 +1285,49 @@ omp_resolve_declare_variant (tree base) /* Needs to be deferred. */ return base; default: - /* FIXME: Scoring not implemented yet, so just resolve it - if there is a single variant only. */ - if (variant) - return base; - if (TREE_CODE (TREE_PURPOSE (TREE_VALUE (attr))) == FUNCTION_DECL) - variant = TREE_PURPOSE (TREE_VALUE (attr)); - else - return base; + variants.safe_push (attr); } } + if (variants.length () == 0) + return base; + 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. */ + tree attr1, attr2; + unsigned int i, j; + FOR_EACH_VEC_ELT (variants, i, attr1) + if (attr1) + { + tree ctx1 = TREE_VALUE (TREE_VALUE (attr1)); + FOR_EACH_VEC_ELT_FROM (variants, j, attr2, i + 1) + if (attr2) + { + tree ctx2 = TREE_VALUE (TREE_VALUE (attr2)); + int r = omp_context_selector_compare (ctx1, ctx2); + if (r == -1) + { + /* ctx1 is a strict subset of ctx2, remove + attr1 from the vector. */ + variants[i] = NULL_TREE; + break; + } + else if (r == 1) + /* ctx2 is a strict subset of ctx1, remove attr2 + from the vector. */ + variants[j] = NULL_TREE; + } + } + /* FIXME: Scoring not implemented yet, so just resolve it + if there is a single variant left. */ + FOR_EACH_VEC_ELT (variants, i, attr1) + if (attr1) + { + if (variant) + return base; + variant = TREE_PURPOSE (TREE_VALUE (attr1)); + } return variant ? variant : base; } |