diff options
Diffstat (limited to 'gcc/c-family')
-rw-r--r-- | gcc/c-family/c-common.h | 2 | ||||
-rw-r--r-- | gcc/c-family/c-omp.c | 340 |
2 files changed, 298 insertions, 44 deletions
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index c74b23d..6162726 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -1196,7 +1196,7 @@ extern void c_finish_omp_taskyield (location_t); extern tree c_finish_omp_for (location_t, enum tree_code, tree, tree, tree, tree, tree, tree, tree, bool); extern bool c_omp_check_loop_iv (tree, tree, walk_tree_lh); -extern bool c_omp_check_loop_iv_exprs (location_t, tree, tree, tree, tree, +extern bool c_omp_check_loop_iv_exprs (location_t, tree, int, tree, tree, tree, walk_tree_lh); extern tree c_finish_oacc_wait (location_t, tree, tree); extern tree c_oacc_split_loop_clauses (tree, tree *, bool); diff --git a/gcc/c-family/c-omp.c b/gcc/c-family/c-omp.c index 6f8fba3..1ca2802 100644 --- a/gcc/c-family/c-omp.c +++ b/gcc/c-family/c-omp.c @@ -34,6 +34,7 @@ along with GCC; see the file COPYING3. If not see #include "memmodel.h" #include "attribs.h" #include "gimplify.h" +#include "langhooks.h" /* Complete a #pragma oacc wait construct. LOC is the location of @@ -1041,13 +1042,37 @@ struct c_omp_check_loop_iv_data { tree declv; bool fail; + bool maybe_nonrect; location_t stmt_loc; location_t expr_loc; int kind; + int idx; walk_tree_lh lh; hash_set<tree> *ppset; }; +/* Return -1 if DECL is not a loop iterator in loop nest D, otherwise + return the index of the loop in which it is an iterator. + Return TREE_VEC_LENGTH (d->declv) if it is a C++ range for iterator. */ + +static int +c_omp_is_loop_iterator (tree decl, struct c_omp_check_loop_iv_data *d) +{ + for (int i = 0; i < TREE_VEC_LENGTH (d->declv); i++) + if (decl == TREE_VEC_ELT (d->declv, i) + || (TREE_CODE (TREE_VEC_ELT (d->declv, i)) == TREE_LIST + && decl == TREE_PURPOSE (TREE_VEC_ELT (d->declv, i)))) + return i; + else if (TREE_CODE (TREE_VEC_ELT (d->declv, i)) == TREE_LIST + && TREE_CHAIN (TREE_VEC_ELT (d->declv, i)) + && (TREE_CODE (TREE_CHAIN (TREE_VEC_ELT (d->declv, i))) + == TREE_VEC) + && decl == TREE_VEC_ELT (TREE_CHAIN (TREE_VEC_ELT (d->declv, + i)), 2)) + return TREE_VEC_LENGTH (d->declv); + return -1; +} + /* Helper function called via walk_tree, to diagnose uses of associated loop IVs inside of lb, b and incr expressions of OpenMP loops. */ @@ -1059,51 +1084,234 @@ c_omp_check_loop_iv_r (tree *tp, int *walk_subtrees, void *data) = (struct c_omp_check_loop_iv_data *) data; if (DECL_P (*tp)) { - int i; - for (i = 0; i < TREE_VEC_LENGTH (d->declv); i++) - if (*tp == TREE_VEC_ELT (d->declv, i) - || (TREE_CODE (TREE_VEC_ELT (d->declv, i)) == TREE_LIST - && *tp == TREE_PURPOSE (TREE_VEC_ELT (d->declv, i))) - || (TREE_CODE (TREE_VEC_ELT (d->declv, i)) == TREE_LIST - && TREE_CHAIN (TREE_VEC_ELT (d->declv, i)) - && (TREE_CODE (TREE_CHAIN (TREE_VEC_ELT (d->declv, i))) - == TREE_VEC) - && *tp == TREE_VEC_ELT (TREE_CHAIN (TREE_VEC_ELT (d->declv, - i)), 2))) - { - location_t loc = d->expr_loc; - if (loc == UNKNOWN_LOCATION) - loc = d->stmt_loc; - switch (d->kind) - { - case 0: - error_at (loc, "initializer expression refers to " - "iteration variable %qD", *tp); - break; - case 1: - error_at (loc, "condition expression refers to " - "iteration variable %qD", *tp); - break; - case 2: - error_at (loc, "increment expression refers to " - "iteration variable %qD", *tp); - break; - } - d->fail = true; - } + int idx = c_omp_is_loop_iterator (*tp, d); + if (idx == -1) + return NULL_TREE; + + if ((d->kind & 4) && idx < d->idx) + { + d->maybe_nonrect = true; + return NULL_TREE; + } + + if (d->ppset->add (*tp)) + return NULL_TREE; + + location_t loc = d->expr_loc; + if (loc == UNKNOWN_LOCATION) + loc = d->stmt_loc; + + switch (d->kind & 3) + { + case 0: + error_at (loc, "initializer expression refers to " + "iteration variable %qD", *tp); + break; + case 1: + error_at (loc, "condition expression refers to " + "iteration variable %qD", *tp); + break; + case 2: + error_at (loc, "increment expression refers to " + "iteration variable %qD", *tp); + break; + } + d->fail = true; } + else if (d->ppset->add (*tp)) + *walk_subtrees = 0; /* Don't walk dtors added by C++ wrap_cleanups_r. */ else if (TREE_CODE (*tp) == TRY_CATCH_EXPR && TRY_CATCH_IS_CLEANUP (*tp)) { *walk_subtrees = 0; return walk_tree_1 (&TREE_OPERAND (*tp, 0), c_omp_check_loop_iv_r, data, - d->ppset, d->lh); + NULL, d->lh); } return NULL_TREE; } +/* Check the allowed expressions for non-rectangular loop nest lb and b + expressions. Return the outer var decl referenced in the expression. */ + +static tree +c_omp_check_nonrect_loop_iv (tree *tp, struct c_omp_check_loop_iv_data *d, + walk_tree_lh lh) +{ + d->maybe_nonrect = false; + if (d->fail) + return NULL_TREE; + + hash_set<tree> pset; + hash_set<tree> *ppset = d->ppset; + d->ppset = &pset; + + tree t = *tp; + if (TREE_CODE (t) == TREE_VEC + && TREE_VEC_LENGTH (t) == 3 + && DECL_P (TREE_VEC_ELT (t, 0)) + && c_omp_is_loop_iterator (TREE_VEC_ELT (t, 0), d) >= 0) + { + d->kind &= 3; + walk_tree_1 (&TREE_VEC_ELT (t, 1), c_omp_check_loop_iv_r, d, NULL, lh); + walk_tree_1 (&TREE_VEC_ELT (t, 1), c_omp_check_loop_iv_r, d, NULL, lh); + d->ppset = ppset; + return d->fail ? NULL_TREE : TREE_VEC_ELT (t, 0); + } + + while (CONVERT_EXPR_P (t)) + t = TREE_OPERAND (t, 0); + + tree a1 = t, a2 = integer_zero_node; + bool neg_a1 = false, neg_a2 = false; + switch (TREE_CODE (t)) + { + case PLUS_EXPR: + case MINUS_EXPR: + a1 = TREE_OPERAND (t, 0); + a2 = TREE_OPERAND (t, 1); + while (CONVERT_EXPR_P (a1)) + a1 = TREE_OPERAND (a1, 0); + while (CONVERT_EXPR_P (a2)) + a2 = TREE_OPERAND (a2, 0); + if (DECL_P (a1) && c_omp_is_loop_iterator (a1, d) >= 0) + { + a2 = TREE_OPERAND (t, 1); + if (TREE_CODE (t) == MINUS_EXPR) + neg_a2 = true; + t = a1; + break; + } + if (DECL_P (a2) && c_omp_is_loop_iterator (a2, d) >= 0) + { + a1 = TREE_OPERAND (t, 0); + if (TREE_CODE (t) == MINUS_EXPR) + neg_a1 = true; + t = a2; + a2 = a1; + break; + } + if (TREE_CODE (a1) == MULT_EXPR && TREE_CODE (a2) == MULT_EXPR) + { + tree o1 = TREE_OPERAND (a1, 0); + tree o2 = TREE_OPERAND (a1, 1); + while (CONVERT_EXPR_P (o1)) + o1 = TREE_OPERAND (o1, 0); + while (CONVERT_EXPR_P (o2)) + o2 = TREE_OPERAND (o2, 0); + if ((DECL_P (o1) && c_omp_is_loop_iterator (o1, d) >= 0) + || (DECL_P (o2) && c_omp_is_loop_iterator (o2, d) >= 0)) + { + a2 = TREE_OPERAND (t, 1); + if (TREE_CODE (t) == MINUS_EXPR) + neg_a2 = true; + t = a1; + break; + } + } + if (TREE_CODE (a2) == MULT_EXPR) + { + a1 = TREE_OPERAND (t, 0); + if (TREE_CODE (t) == MINUS_EXPR) + neg_a1 = true; + t = a2; + a2 = a1; + break; + } + if (TREE_CODE (a1) == MULT_EXPR) + { + a2 = TREE_OPERAND (t, 1); + if (TREE_CODE (t) == MINUS_EXPR) + neg_a2 = true; + t = a1; + break; + } + a2 = integer_zero_node; + break; + default: + break; + } + + a1 = integer_one_node; + if (TREE_CODE (t) == MULT_EXPR) + { + tree o1 = TREE_OPERAND (t, 0); + tree o2 = TREE_OPERAND (t, 1); + while (CONVERT_EXPR_P (o1)) + o1 = TREE_OPERAND (o1, 0); + while (CONVERT_EXPR_P (o2)) + o2 = TREE_OPERAND (o2, 0); + if (DECL_P (o1) && c_omp_is_loop_iterator (o1, d) >= 0) + { + a1 = TREE_OPERAND (t, 1); + t = o1; + } + else if (DECL_P (o2) && c_omp_is_loop_iterator (o2, d) >= 0) + { + a1 = TREE_OPERAND (t, 0); + t = o2; + } + } + + d->kind &= 3; + tree ret = NULL_TREE; + if (DECL_P (t) && c_omp_is_loop_iterator (t, d) >= 0) + { + location_t loc = d->expr_loc; + if (loc == UNKNOWN_LOCATION) + loc = d->stmt_loc; + if (!lang_hooks.types_compatible_p (TREE_TYPE (*tp), TREE_TYPE (t))) + { + if (d->kind == 0) + error_at (loc, "outer iteration variable %qD used in initializer" + " expression has type other than %qT", + t, TREE_TYPE (*tp)); + else + error_at (loc, "outer iteration variable %qD used in condition" + " expression has type other than %qT", + t, TREE_TYPE (*tp)); + d->fail = true; + } + else if (!INTEGRAL_TYPE_P (TREE_TYPE (a1))) + { + error_at (loc, "outer iteration variable %qD multiplier expression" + " %qE is not integral", t, a1); + d->fail = true; + } + else if (!INTEGRAL_TYPE_P (TREE_TYPE (a2))) + { + error_at (loc, "outer iteration variable %qD addend expression" + " %qE is not integral", t, a2); + d->fail = true; + } + else + { + walk_tree_1 (&a1, c_omp_check_loop_iv_r, d, NULL, lh); + walk_tree_1 (&a2, c_omp_check_loop_iv_r, d, NULL, lh); + } + if (!d->fail) + { + a1 = fold_convert (TREE_TYPE (*tp), a1); + a2 = fold_convert (TREE_TYPE (*tp), a2); + if (neg_a1) + a1 = fold_build1 (NEGATE_EXPR, TREE_TYPE (a1), a1); + if (neg_a2) + a2 = fold_build1 (NEGATE_EXPR, TREE_TYPE (a2), a2); + ret = t; + *tp = make_tree_vec (3); + TREE_VEC_ELT (*tp, 0) = t; + TREE_VEC_ELT (*tp, 1) = a1; + TREE_VEC_ELT (*tp, 2) = a2; + } + } + else + walk_tree_1 (&t, c_omp_check_loop_iv_r, d, NULL, lh); + + d->ppset = ppset; + return ret; +} + /* Diagnose invalid references to loop iterators in lb, b and incr expressions. */ @@ -1116,6 +1324,7 @@ c_omp_check_loop_iv (tree stmt, tree declv, walk_tree_lh lh) data.declv = declv; data.fail = false; + data.maybe_nonrect = false; data.stmt_loc = EXPR_LOCATION (stmt); data.lh = lh; data.ppset = &pset; @@ -1129,9 +1338,31 @@ c_omp_check_loop_iv (tree stmt, tree declv, walk_tree_lh lh) gcc_assert (TREE_OPERAND (cond, 0) == decl); tree incr = TREE_VEC_ELT (OMP_FOR_INCR (stmt), i); data.expr_loc = EXPR_LOCATION (TREE_OPERAND (init, 1)); - data.kind = 0; + tree vec_outer1 = NULL_TREE, vec_outer2 = NULL_TREE; + int kind = 0; + if (i > 0 + && (unsigned) c_omp_is_loop_iterator (decl, &data) < (unsigned) i) + { + location_t loc = data.expr_loc; + if (loc == UNKNOWN_LOCATION) + loc = data.stmt_loc; + error_at (loc, "the same loop iteration variables %qD used in " + "multiple associated loops", decl); + data.fail = true; + } + /* Handle non-rectangular loop nests. */ + if (TREE_CODE (stmt) != OACC_LOOP + && (TREE_CODE (TREE_OPERAND (init, 1)) == TREE_VEC + || INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (init, 1)))) + && i > 0) + kind = 4; + data.kind = kind; + data.idx = i; walk_tree_1 (&TREE_OPERAND (init, 1), - c_omp_check_loop_iv_r, &data, &pset, lh); + c_omp_check_loop_iv_r, &data, NULL, lh); + if (data.maybe_nonrect) + vec_outer1 = c_omp_check_nonrect_loop_iv (&TREE_OPERAND (init, 1), + &data, lh); /* Don't warn for C++ random access iterators here, the expression then involves the subtraction and always refers to the original value. The C++ FE needs to warn on those @@ -1141,10 +1372,24 @@ c_omp_check_loop_iv (tree stmt, tree declv, walk_tree_lh lh) && decl == TREE_PURPOSE (TREE_VEC_ELT (declv, i)))) { data.expr_loc = EXPR_LOCATION (cond); - data.kind = 1; + data.kind = kind | 1; walk_tree_1 (&TREE_OPERAND (cond, 1), - c_omp_check_loop_iv_r, &data, &pset, lh); + c_omp_check_loop_iv_r, &data, NULL, lh); + if (data.maybe_nonrect) + vec_outer2 = c_omp_check_nonrect_loop_iv (&TREE_OPERAND (cond, 1), + &data, lh); + } + if (vec_outer1 && vec_outer2 && vec_outer1 != vec_outer2) + { + location_t loc = data.expr_loc; + if (loc == UNKNOWN_LOCATION) + loc = data.stmt_loc; + error_at (loc, "two different outer iteration variables %qD and %qD" + " used in a single loop", vec_outer1, vec_outer2); + data.fail = true; } + if (vec_outer1 || vec_outer2) + OMP_FOR_NON_RECTANGULAR (stmt) = 1; if (TREE_CODE (incr) == MODIFY_EXPR) { gcc_assert (TREE_OPERAND (incr, 0) == decl); @@ -1155,13 +1400,13 @@ c_omp_check_loop_iv (tree stmt, tree declv, walk_tree_lh lh) { data.expr_loc = EXPR_LOCATION (TREE_OPERAND (incr, 0)); walk_tree_1 (&TREE_OPERAND (incr, 0), - c_omp_check_loop_iv_r, &data, &pset, lh); + c_omp_check_loop_iv_r, &data, NULL, lh); } else { data.expr_loc = EXPR_LOCATION (TREE_OPERAND (incr, 1)); walk_tree_1 (&TREE_OPERAND (incr, 1), - c_omp_check_loop_iv_r, &data, &pset, lh); + c_omp_check_loop_iv_r, &data, NULL, lh); } } } @@ -1171,7 +1416,7 @@ c_omp_check_loop_iv (tree stmt, tree declv, walk_tree_lh lh) /* Similar, but allows to check the init or cond expressions individually. */ bool -c_omp_check_loop_iv_exprs (location_t stmt_loc, tree declv, tree decl, +c_omp_check_loop_iv_exprs (location_t stmt_loc, tree declv, int i, tree decl, tree init, tree cond, walk_tree_lh lh) { hash_set<tree> pset; @@ -1179,15 +1424,24 @@ c_omp_check_loop_iv_exprs (location_t stmt_loc, tree declv, tree decl, data.declv = declv; data.fail = false; + data.maybe_nonrect = false; data.stmt_loc = stmt_loc; data.lh = lh; data.ppset = &pset; + data.idx = i; + if (i > 0 + && (unsigned) c_omp_is_loop_iterator (decl, &data) < (unsigned) i) + { + error_at (stmt_loc, "the same loop iteration variables %qD used in " + "multiple associated loops", decl); + data.fail = true; + } if (init) { data.expr_loc = EXPR_LOCATION (init); data.kind = 0; walk_tree_1 (&init, - c_omp_check_loop_iv_r, &data, &pset, lh); + c_omp_check_loop_iv_r, &data, NULL, lh); } if (cond) { @@ -1196,10 +1450,10 @@ c_omp_check_loop_iv_exprs (location_t stmt_loc, tree declv, tree decl, data.kind = 1; if (TREE_OPERAND (cond, 0) == decl) walk_tree_1 (&TREE_OPERAND (cond, 1), - c_omp_check_loop_iv_r, &data, &pset, lh); + c_omp_check_loop_iv_r, &data, NULL, lh); else walk_tree_1 (&TREE_OPERAND (cond, 0), - c_omp_check_loop_iv_r, &data, &pset, lh); + c_omp_check_loop_iv_r, &data, NULL, lh); } return !data.fail; } |