aboutsummaryrefslogtreecommitdiff
path: root/gcc/c/c-array-notation.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/c/c-array-notation.c')
-rw-r--r--gcc/c/c-array-notation.c277
1 files changed, 210 insertions, 67 deletions
diff --git a/gcc/c/c-array-notation.c b/gcc/c/c-array-notation.c
index d4bcdb67e0a..941cc682ef7 100644
--- a/gcc/c/c-array-notation.c
+++ b/gcc/c/c-array-notation.c
@@ -51,6 +51,47 @@ struct inv_list
vec<tree, va_gc> *replacement;
};
+/* Returns false if there is a length mismatch among expressions
+ on the same dimension AND the same side of the equal sign. The exprs are
+ passed in through 2-D array **LIST where X and Y indicate first and
+ second dimension sizes of LIST, respectively. */
+static bool
+length_mismatch_in_expr_p (location_t loc, tree **list, size_t x, size_t y)
+{
+ size_t ii, jj;
+ tree start = NULL_TREE;
+ HOST_WIDE_INT l_start, l_node;
+ for (jj = 0; jj < y; jj++)
+ {
+ start = NULL_TREE;
+ for (ii = 0; ii < x; ii++)
+ {
+ if (!start)
+ start = list[ii][jj];
+ else if (TREE_CODE (start) == INTEGER_CST)
+ {
+ /* If start is a INTEGER, and list[ii][jj] is an integer then
+ check if they are equal. If they are not equal then return
+ true. */
+ if (TREE_CODE (list[ii][jj]) == INTEGER_CST)
+ {
+ l_node = int_cst_value (list[ii][jj]);
+ l_start = int_cst_value (start);
+ if (abs (l_start) != abs (l_node))
+ {
+ error_at (loc, "length mismatch in expression");
+ return true;
+ }
+ }
+ }
+ else
+ /* We set the start node as the current node just in case it turns
+ out to be an integer. */
+ start = list[ii][jj];
+ }
+ }
+ return false;
+}
/* Returns the rank of ARRAY through the *RANK. The user can specify whether
(s)he wants to step into array_notation-specific builtin functions
@@ -69,10 +110,20 @@ find_rank (tree array, bool ignore_builtin_fn, size_t *rank)
return;
else if (TREE_CODE (array) == ARRAY_NOTATION_REF)
{
- for (ii_tree = array;
- ii_tree && TREE_CODE (ii_tree) == ARRAY_NOTATION_REF;
- ii_tree = ARRAY_NOTATION_ARRAY (ii_tree))
- current_rank++;
+ ii_tree = array;
+ while (ii_tree)
+ {
+ if (TREE_CODE (ii_tree) == ARRAY_NOTATION_REF)
+ {
+ current_rank++;
+ ii_tree = ARRAY_NOTATION_ARRAY (ii_tree);
+ }
+ else if (TREE_CODE (ii_tree) == ARRAY_REF)
+ ii_tree = TREE_OPERAND (ii_tree, 0);
+ else if (TREE_CODE (ii_tree) == PARM_DECL
+ || TREE_CODE (ii_tree) == VAR_DECL)
+ break;
+ }
if (*rank == 0)
*rank = current_rank;
}
@@ -415,7 +466,10 @@ build_array_notation_expr (location_t location, tree lhs, tree lhs_origtype,
{
builtin_loop = fix_builtin_array_notation_fn (rhs_node, &new_var);
if (builtin_loop == error_mark_node)
- return error_mark_node;
+ {
+ pop_stmt_list (loop);
+ return error_mark_node;
+ }
else if (builtin_loop)
{
add_stmt (builtin_loop);
@@ -490,7 +544,7 @@ build_array_notation_expr (location_t location, tree lhs, tree lhs_origtype,
rhs_base);
return error_mark_node;
}
-
+
/* Here we assign the array notation components to variable so that we can
satisfy the exec once rule. */
for (ii = 0; ii < lhs_list_size; ii++)
@@ -499,62 +553,79 @@ build_array_notation_expr (location_t location, tree lhs, tree lhs_origtype,
tree array_begin = ARRAY_NOTATION_START (array_node);
tree array_lngth = ARRAY_NOTATION_LENGTH (array_node);
tree array_strde = ARRAY_NOTATION_STRIDE (array_node);
-
- begin_var = build_decl (location, VAR_DECL, NULL_TREE,
- integer_type_node);
- lngth_var = build_decl (location, VAR_DECL, NULL_TREE,
- integer_type_node);
- strde_var = build_decl (location, VAR_DECL, NULL_TREE,
- integer_type_node);
-
- add_stmt (build_modify_expr (location, begin_var, TREE_TYPE (begin_var),
- NOP_EXPR, location, array_begin,
- TREE_TYPE (array_begin)));
- add_stmt (build_modify_expr (location, lngth_var, TREE_TYPE (lngth_var),
- NOP_EXPR, location, array_lngth,
- TREE_TYPE (array_lngth)));
- add_stmt (build_modify_expr (location, strde_var, TREE_TYPE (strde_var),
- NOP_EXPR, location, array_strde,
- TREE_TYPE (array_strde)));
-
- ARRAY_NOTATION_START (array_node) = begin_var;
- ARRAY_NOTATION_LENGTH (array_node) = lngth_var;
- ARRAY_NOTATION_STRIDE (array_node) = strde_var;
- }
- for (ii = 0; ii < rhs_list_size; ii++)
- {
- tree array_node = (*rhs_list)[ii];
- if (array_node && TREE_CODE (array_node) == ARRAY_NOTATION_REF)
+
+ if (TREE_CODE (array_begin) != INTEGER_CST)
{
- tree array_begin = ARRAY_NOTATION_START (array_node);
- tree array_lngth = ARRAY_NOTATION_LENGTH (array_node);
- tree array_strde = ARRAY_NOTATION_STRIDE (array_node);
-
begin_var = build_decl (location, VAR_DECL, NULL_TREE,
integer_type_node);
- lngth_var = build_decl (location, VAR_DECL, NULL_TREE,
- integer_type_node);
- strde_var = build_decl (location, VAR_DECL, NULL_TREE,
- integer_type_node);
-
add_stmt (build_modify_expr (location, begin_var,
TREE_TYPE (begin_var),
NOP_EXPR, location, array_begin,
TREE_TYPE (array_begin)));
+ ARRAY_NOTATION_START (array_node) = begin_var;
+ }
+ if (TREE_CODE (array_lngth) != INTEGER_CST)
+ {
+ lngth_var = build_decl (location, VAR_DECL, NULL_TREE,
+ integer_type_node);
add_stmt (build_modify_expr (location, lngth_var,
TREE_TYPE (lngth_var),
NOP_EXPR, location, array_lngth,
TREE_TYPE (array_lngth)));
+ ARRAY_NOTATION_LENGTH (array_node) = lngth_var;
+ }
+ if (TREE_CODE (array_strde) != INTEGER_CST)
+ {
+ strde_var = build_decl (location, VAR_DECL, NULL_TREE,
+ integer_type_node);
+
add_stmt (build_modify_expr (location, strde_var,
TREE_TYPE (strde_var),
NOP_EXPR, location, array_strde,
- TREE_TYPE (array_strde)));
-
- ARRAY_NOTATION_START (array_node) = begin_var;
- ARRAY_NOTATION_LENGTH (array_node) = lngth_var;
+ TREE_TYPE (array_strde)));
ARRAY_NOTATION_STRIDE (array_node) = strde_var;
}
}
+ for (ii = 0; ii < rhs_list_size; ii++)
+ {
+ tree array_node = (*rhs_list)[ii];
+ if (array_node && TREE_CODE (array_node) == ARRAY_NOTATION_REF)
+ {
+ tree array_begin = ARRAY_NOTATION_START (array_node);
+ tree array_lngth = ARRAY_NOTATION_LENGTH (array_node);
+ tree array_strde = ARRAY_NOTATION_STRIDE (array_node);
+ if (TREE_CODE (array_begin) != INTEGER_CST)
+ {
+ begin_var = build_decl (location, VAR_DECL, NULL_TREE,
+ integer_type_node);
+ add_stmt (build_modify_expr (location, begin_var,
+ TREE_TYPE (begin_var),
+ NOP_EXPR, location, array_begin,
+ TREE_TYPE (array_begin)));
+ ARRAY_NOTATION_START (array_node) = begin_var;
+ }
+ if (TREE_CODE (array_lngth) != INTEGER_CST)
+ {
+ lngth_var = build_decl (location, VAR_DECL, NULL_TREE,
+ integer_type_node);
+ add_stmt (build_modify_expr (location, lngth_var,
+ TREE_TYPE (lngth_var),
+ NOP_EXPR, location, array_lngth,
+ TREE_TYPE (array_lngth)));
+ ARRAY_NOTATION_LENGTH (array_node) = lngth_var;
+ }
+ if (TREE_CODE (array_strde) != INTEGER_CST)
+ {
+ strde_var = build_decl (location, VAR_DECL, NULL_TREE,
+ integer_type_node);
+ add_stmt (build_modify_expr (location, strde_var,
+ TREE_TYPE (strde_var),
+ NOP_EXPR, location, array_strde,
+ TREE_TYPE (array_strde)));
+ ARRAY_NOTATION_STRIDE (array_node) = strde_var;
+ }
+ }
+ }
lhs_vector = XNEWVEC (bool *, lhs_list_size);
for (ii = 0; ii < lhs_list_size; ii++)
@@ -642,14 +713,26 @@ build_array_notation_expr (location_t location, tree lhs, tree lhs_origtype,
if (lhs_rank)
{
for (ii = 0; ii < lhs_list_size; ii++)
+ for (jj = 0; jj < lhs_rank; jj++)
+ lhs_array[ii][jj] = NULL_TREE;
+
+ for (ii = 0; ii < lhs_list_size; ii++)
{
jj = 0;
- for (ii_tree = (*lhs_list)[ii];
- ii_tree && TREE_CODE (ii_tree) == ARRAY_NOTATION_REF;
- ii_tree = ARRAY_NOTATION_ARRAY (ii_tree))
+ ii_tree = (*lhs_list)[ii];
+ while (ii_tree)
{
- lhs_array[ii][jj] = ii_tree;
- jj++;
+ if (TREE_CODE (ii_tree) == ARRAY_NOTATION_REF)
+ {
+ lhs_array[ii][jj] = ii_tree;
+ jj++;
+ ii_tree = ARRAY_NOTATION_ARRAY (ii_tree);
+ }
+ else if (TREE_CODE (ii_tree) == ARRAY_REF)
+ ii_tree = TREE_OPERAND (ii_tree, 0);
+ else if (TREE_CODE (ii_tree) == VAR_DECL
+ || TREE_CODE (ii_tree) == PARM_DECL)
+ break;
}
}
}
@@ -659,18 +742,31 @@ build_array_notation_expr (location_t location, tree lhs, tree lhs_origtype,
if (rhs_rank)
{
for (ii = 0; ii < rhs_list_size; ii++)
+ for (jj = 0; jj < rhs_rank; jj++)
+ rhs_array[ii][jj] = NULL_TREE;
+ for (ii = 0; ii < rhs_list_size; ii++)
{
- jj = 0;
- for (ii_tree = (*rhs_list)[ii];
- ii_tree && TREE_CODE (ii_tree) == ARRAY_NOTATION_REF;
- ii_tree = ARRAY_NOTATION_ARRAY (ii_tree))
+ jj = 0;
+ ii_tree = (*rhs_list)[ii];
+ while (ii_tree)
{
- rhs_array[ii][jj] = ii_tree;
- jj++;
+ if (TREE_CODE (ii_tree) == ARRAY_NOTATION_REF)
+ {
+ rhs_array[ii][jj] = ii_tree;
+ jj++;
+ ii_tree = ARRAY_NOTATION_ARRAY (ii_tree);
+ }
+ else if (TREE_CODE (ii_tree) == ARRAY_REF)
+ ii_tree = TREE_OPERAND (ii_tree, 0);
+ else if (TREE_CODE (ii_tree) == VAR_DECL
+ || TREE_CODE (ii_tree) == PARM_DECL)
+ break;
+ else if (TREE_CODE (ii_tree) == CALL_EXPR)
+ break;
}
}
}
-
+
for (ii = 0; ii < lhs_list_size; ii++)
{
tree lhs_node = (*lhs_list)[ii];
@@ -743,8 +839,31 @@ build_array_notation_expr (location_t location, tree lhs, tree lhs_origtype,
rhs_vector[ii][jj] = false;
}
-
-
+ if (length_mismatch_in_expr_p (EXPR_LOCATION (lhs), lhs_length,
+ lhs_list_size, lhs_rank)
+ || length_mismatch_in_expr_p (EXPR_LOCATION (rhs), rhs_length,
+ rhs_list_size, rhs_rank))
+ {
+ pop_stmt_list (loop);
+ return error_mark_node;
+ }
+
+ if (lhs_list_size > 0 && rhs_list_size > 0)
+ if (TREE_CODE (lhs_length[0][0]) == INTEGER_CST
+ && TREE_CODE (rhs_length[0][0]) == INTEGER_CST)
+ {
+ HOST_WIDE_INT l_length = int_cst_value (lhs_length[0][0]);
+ HOST_WIDE_INT r_length = int_cst_value (rhs_length[0][0]);
+ /* The length can be negative or positive. As long as the
+ magnitude is OK, then the array notation is valid. */
+ if (abs (l_length) != abs (r_length))
+ {
+ error_at (location, "length mismatch between LHS and RHS");
+ pop_stmt_list (loop);
+ return error_mark_node;
+ }
+ }
+
for (ii = 0; ii < lhs_rank; ii++)
{
if (lhs_vector[0][ii])
@@ -1768,12 +1887,26 @@ fix_builtin_array_notation_fn (tree an_builtin_fn, tree *new_var)
|| TREE_CODE (func_parm) == NOP_EXPR)
func_parm = TREE_OPERAND (func_parm, 0);
- find_rank (an_builtin_fn, true, &rank);
+ find_rank (func_parm, false, &rank);
location = EXPR_LOCATION (an_builtin_fn);
if (rank == 0)
- return an_builtin_fn;
+ {
+ if (an_type == REDUCE_ADD || an_type == REDUCE_MUL
+ || an_type == REDUCE_MAX || an_type == REDUCE_MIN
+ || an_type == REDUCE_ALL_ZEROS || an_type == REDUCE_ANY_ZEROS
+ || an_type == REDUCE_ANY_NONZEROS || an_type == REDUCE_ALL_NONZEROS
+ || an_type == REDUCE_MAX_INDEX || an_type == REDUCE_MIN_INDEX
+ || an_type == REDUCE_CUSTOM || an_type == REDUCE_MUTATING)
+ {
+ error_at (location, "array notation builtin functions cannot have"
+ " array notation parameter with zero rank");
+ return error_mark_node;
+ }
+ else
+ return an_builtin_fn;
+ }
else if (rank > 1
&& (an_type == REDUCE_MAX_INDEX || an_type == REDUCE_MIN_INDEX))
{
@@ -2109,9 +2242,14 @@ fix_builtin_array_notation_fn (tree an_builtin_fn, tree *new_var)
TREE_TYPE (new_yes_expr), new_no_expr, TREE_TYPE (new_no_expr));
break;
case REDUCE_MAX:
- new_var_init = build_modify_expr
- (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
- location, func_parm, new_var_type);
+ if (TYPE_MIN_VALUE (new_var_type))
+ new_var_init = build_modify_expr
+ (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
+ location, TYPE_MIN_VALUE (new_var_type), new_var_type);
+ else
+ new_var_init = build_modify_expr
+ (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
+ location, func_parm, new_var_type);
new_no_expr = build_modify_expr
(location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
location, *new_var, TREE_TYPE (*new_var));
@@ -2124,9 +2262,14 @@ fix_builtin_array_notation_fn (tree an_builtin_fn, tree *new_var)
new_yes_expr, TREE_TYPE (*new_var), new_no_expr, TREE_TYPE (*new_var));
break;
case REDUCE_MIN:
- new_var_init = build_modify_expr
- (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
- location, func_parm, new_var_type);
+ if (TYPE_MAX_VALUE (new_var_type))
+ new_var_init = build_modify_expr
+ (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
+ location, TYPE_MAX_VALUE (new_var_type), new_var_type);
+ else
+ new_var_init = build_modify_expr
+ (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
+ location, func_parm, new_var_type);
new_no_expr = build_modify_expr
(location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
location, *new_var, TREE_TYPE (*new_var));