+2011-09-06 Richard Guenther <rguenther@suse.de>
+
+ PR tree-optimization/48317
+ * tree-ssa-sccvn.h (struct vn_nary_op_s): Make op a true
+ trailing array.
+ (sizeof_vn_nary_op): New inline function.
+ (vn_nary_op_lookup_pieces): Adjust.
+ (vn_nary_op_insert_pieces): Likewise.
+ * tree-ssa-sccvn.c (vn_nary_op_eq): Also compare the length.
+ (init_vn_nary_op_from_pieces): Adjust signature. Deal with
+ any number of operands.
+ (vn_nary_length_from_stmt): New function.
+ (init_vn_nary_op_from_stmt): Adjust for CONSTRUCTOR handling.
+ (vn_nary_op_lookup_pieces): Adjust signature and allocate properly
+ sized temporary.
+ (vn_nary_op_lookup): Likewise.
+ (vn_nary_op_lookup_stmt): Likewise.
+ (vn_nary_op_insert_into): Likewise.
+ (vn_nary_op_insert_stmt): Likewise.
+ (visit_use): Handle CONSTRUCTOR as nary.
+ * tree-ssa-pre.c (phi_translate_1): Adjust.
+ (create_expression_by_pieces): Likewise.
+ (compute_avail): Likewise.
+
2011-09-06 Ira Rosen <ira.rosen@linaro.org>
* config/arm/arm.c (arm_preferred_simd_mode): Check
+2011-09-06 Richard Guenther <rguenther@suse.de>
+
+ PR tree-optimization/48317
+ * gcc.dg/tree-ssa/ssa-fre-31.c: New testcase.
+
2011-09-06 Ira Rosen <ira.rosen@linaro.org>
* lib/target-supports.exp (check_effective_target_vect_multiple_sizes):
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-O -fdump-tree-fre1-details" } */
+
+typedef double d128 __attribute__((vector_size(16)));
+typedef float f128 __attribute__((vector_size(16)));
+typedef short s128 __attribute__((vector_size(16)));
+typedef char c256 __attribute__((vector_size(32)));
+
+d128 d;
+f128 f;
+s128 s;
+c256 c;
+
+void test1 (double x)
+{
+ d = (d128){x + x, x + x};
+ d = (d128){x + x, x + x};
+}
+
+void test2 (float x)
+{
+ f = (f128){x + x, x + x, x + x, x + x};
+ f = (f128){x + x, x + x, x + x, x + x};
+}
+
+void test3 (short x)
+{
+ s = (s128){x + x, x + x, x + x, x + x, x + x, x + x, x + x, x + x};
+ s = (s128){x + x, x + x, x + x, x + x, x + x, x + x, x + x, x + x};
+}
+
+void test4 (unsigned char x)
+{
+ c = (c256){x + x, x + x, x + x, x + x, x + x, x + x, x + x, x + x,
+ x + x, x + x, x + x, x + x, x + x, x + x, x + x, x + x,
+ x + x, x + x, x + x, x + x, x + x, x + x, x + x, x + x,
+ x + x, x + x, x + x, x + x, x + x, x + x, x + x, x + x};
+ c = (c256){x + x, x + x, x + x, x + x, x + x, x + x, x + x, x + x,
+ x + x, x + x, x + x, x + x, x + x, x + x, x + x, x + x,
+ x + x, x + x, x + x, x + x, x + x, x + x, x + x, x + x,
+ x + x, x + x, x + x, x + x, x + x, x + x, x + x, x + x};
+}
+
+/* { dg-final { scan-tree-dump-times "Replaced \{" 4 "fre1" } } */
+/* { dg-final { scan-tree-dump-times "Deleted redundant store" 4 "fre1" } } */
+/* { dg-final { cleanup-tree-dump "fre1" } } */
unsigned int i;
bool changed = false;
vn_nary_op_t nary = PRE_EXPR_NARY (expr);
- struct vn_nary_op_s newnary;
- /* The NARY structure is only guaranteed to have been
- allocated to the nary->length operands. */
- memcpy (&newnary, nary, (sizeof (struct vn_nary_op_s)
- - sizeof (tree) * (4 - nary->length)));
+ vn_nary_op_t newnary = XALLOCAVAR (struct vn_nary_op_s,
+ sizeof_vn_nary_op (nary->length));
+ memcpy (newnary, nary, sizeof_vn_nary_op (nary->length));
- for (i = 0; i < newnary.length; i++)
+ for (i = 0; i < newnary->length; i++)
{
- if (TREE_CODE (newnary.op[i]) != SSA_NAME)
+ if (TREE_CODE (newnary->op[i]) != SSA_NAME)
continue;
else
{
pre_expr leader, result;
- unsigned int op_val_id = VN_INFO (newnary.op[i])->value_id;
+ unsigned int op_val_id = VN_INFO (newnary->op[i])->value_id;
leader = find_leader_in_sets (op_val_id, set1, set2);
result = phi_translate (leader, set1, set2, pred, phiblock);
if (result && result != leader)
tree name = get_representative_for (result);
if (!name)
return NULL;
- newnary.op[i] = name;
+ newnary->op[i] = name;
}
else if (!result)
return NULL;
- changed |= newnary.op[i] != nary->op[i];
+ changed |= newnary->op[i] != nary->op[i];
}
}
if (changed)
pre_expr constant;
unsigned int new_val_id;
- tree result = vn_nary_op_lookup_pieces (newnary.length,
- newnary.opcode,
- newnary.type,
- newnary.op[0],
- newnary.op[1],
- newnary.op[2],
- newnary.op[3],
+ tree result = vn_nary_op_lookup_pieces (newnary->length,
+ newnary->opcode,
+ newnary->type,
+ &newnary->op[0],
&nary);
if (result && is_gimple_min_invariant (result))
return get_or_alloc_expr_for_constant (result);
VEC_safe_grow_cleared (bitmap_set_t, heap,
value_expressions,
get_max_value_id() + 1);
- nary = vn_nary_op_insert_pieces (newnary.length,
- newnary.opcode,
- newnary.type,
- newnary.op[0],
- newnary.op[1],
- newnary.op[2],
- newnary.op[3],
+ nary = vn_nary_op_insert_pieces (newnary->length,
+ newnary->opcode,
+ newnary->type,
+ &newnary->op[0],
result, new_val_id);
PRE_EXPR_NARY (expr) = nary;
constant = fully_constant_expression (expr);
nresult = vn_nary_op_lookup_pieces (1, TREE_CODE (result),
TREE_TYPE (result),
- TREE_OPERAND (result, 0),
- NULL_TREE, NULL_TREE,
- NULL_TREE,
+ &TREE_OPERAND (result, 0),
&nary);
if (nresult && is_gimple_min_invariant (nresult))
return get_or_alloc_expr_for_constant (nresult);
get_max_value_id() + 1);
nary = vn_nary_op_insert_pieces (1, TREE_CODE (result),
TREE_TYPE (result),
- TREE_OPERAND (result, 0),
- NULL_TREE, NULL_TREE,
- NULL_TREE, NULL_TREE,
+ &TREE_OPERAND (result, 0),
+ NULL_TREE,
new_val_id);
PRE_EXPR_NARY (expr) = nary;
constant = fully_constant_expression (expr);
case NARY:
{
vn_nary_op_t nary = PRE_EXPR_NARY (expr);
- switch (nary->length)
+ tree genop[4];
+ unsigned i;
+ for (i = 0; i < nary->length; ++i)
{
- case 2:
- {
- pre_expr op1 = get_or_alloc_expr_for (nary->op[0]);
- pre_expr op2 = get_or_alloc_expr_for (nary->op[1]);
- tree genop1 = find_or_generate_expression (block, op1,
- stmts, domstmt);
- tree genop2 = find_or_generate_expression (block, op2,
- stmts, domstmt);
- if (!genop1 || !genop2)
- return NULL_TREE;
- /* Ensure op2 is a ptrofftype for POINTER_PLUS_EXPR. It
- may be a constant with the wrong type. */
- if (nary->opcode == POINTER_PLUS_EXPR)
- {
- genop1 = fold_convert (nary->type, genop1);
- genop2 = convert_to_ptrofftype (genop2);
- }
- else
- {
- genop1 = fold_convert (TREE_TYPE (nary->op[0]), genop1);
- genop2 = fold_convert (TREE_TYPE (nary->op[1]), genop2);
- }
-
- folded = fold_build2 (nary->opcode, nary->type,
- genop1, genop2);
- }
- break;
- case 1:
- {
- pre_expr op1 = get_or_alloc_expr_for (nary->op[0]);
- tree genop1 = find_or_generate_expression (block, op1,
- stmts, domstmt);
- if (!genop1)
- return NULL_TREE;
- genop1 = fold_convert (TREE_TYPE (nary->op[0]), genop1);
-
- folded = fold_build1 (nary->opcode, nary->type,
- genop1);
- }
- break;
- default:
- return NULL_TREE;
+ pre_expr op = get_or_alloc_expr_for (nary->op[i]);
+ genop[i] = find_or_generate_expression (block, op,
+ stmts, domstmt);
+ if (!genop[i])
+ return NULL_TREE;
+ /* Ensure genop[1] is a ptrofftype for POINTER_PLUS_EXPR. It
+ may be a constant with the wrong type. */
+ if (i == 1
+ && nary->opcode == POINTER_PLUS_EXPR)
+ genop[i] = convert_to_ptrofftype (genop[i]);
+ else
+ genop[i] = fold_convert (TREE_TYPE (nary->op[i]), genop[i]);
+ }
+ if (nary->opcode == CONSTRUCTOR)
+ {
+ VEC(constructor_elt,gc) *elts = NULL;
+ for (i = 0; i < nary->length; ++i)
+ CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE, genop[i]);
+ folded = build_constructor (nary->type, elts);
+ }
+ else
+ {
+ switch (nary->length)
+ {
+ case 1:
+ folded = fold_build1 (nary->opcode, nary->type,
+ genop[0]);
+ break;
+ case 2:
+ folded = fold_build2 (nary->opcode, nary->type,
+ genop[0], genop[1]);
+ break;
+ case 3:
+ folded = fold_build3 (nary->opcode, nary->type,
+ genop[0], genop[1], genop[3]);
+ break;
+ default:
+ gcc_unreachable ();
+ }
}
}
break;
vn_nary_op_lookup_pieces (gimple_num_ops (stmt) - 1,
gimple_assign_rhs_code (stmt),
gimple_expr_type (stmt),
- gimple_assign_rhs1 (stmt),
- gimple_assign_rhs2 (stmt),
- NULL_TREE, NULL_TREE, &nary);
+ gimple_assign_rhs1_ptr (stmt),
+ &nary);
if (!nary)
continue;
if (vno1->hashcode != vno2->hashcode)
return false;
+ if (vno1->length != vno2->length)
+ return false;
+
if (vno1->opcode != vno2->opcode
|| !types_compatible_p (vno1->type, vno2->type))
return false;
static void
init_vn_nary_op_from_pieces (vn_nary_op_t vno, unsigned int length,
- enum tree_code code, tree type, tree op0,
- tree op1, tree op2, tree op3)
+ enum tree_code code, tree type, tree *ops)
{
vno->opcode = code;
vno->length = length;
vno->type = type;
- switch (length)
- {
- /* The fallthrus here are deliberate. */
- case 4: vno->op[3] = op3;
- case 3: vno->op[2] = op2;
- case 2: vno->op[1] = op1;
- case 1: vno->op[0] = op0;
- default:
- break;
- }
+ memcpy (&vno->op[0], ops, sizeof (tree) * length);
}
/* Initialize VNO from OP. */
vno->op[i] = TREE_OPERAND (op, i);
}
+/* Return the number of operands for a vn_nary ops structure from STMT. */
+
+static unsigned int
+vn_nary_length_from_stmt (gimple stmt)
+{
+ switch (gimple_assign_rhs_code (stmt))
+ {
+ case REALPART_EXPR:
+ case IMAGPART_EXPR:
+ case VIEW_CONVERT_EXPR:
+ return 1;
+
+ case CONSTRUCTOR:
+ return CONSTRUCTOR_NELTS (gimple_assign_rhs1 (stmt));
+
+ default:
+ return gimple_num_ops (stmt) - 1;
+ }
+}
+
/* Initialize VNO from STMT. */
static void
unsigned i;
vno->opcode = gimple_assign_rhs_code (stmt);
- vno->length = gimple_num_ops (stmt) - 1;
vno->type = gimple_expr_type (stmt);
- for (i = 0; i < vno->length; ++i)
- vno->op[i] = gimple_op (stmt, i + 1);
- if (vno->opcode == REALPART_EXPR
- || vno->opcode == IMAGPART_EXPR
- || vno->opcode == VIEW_CONVERT_EXPR)
- vno->op[0] = TREE_OPERAND (vno->op[0], 0);
+ switch (vno->opcode)
+ {
+ case REALPART_EXPR:
+ case IMAGPART_EXPR:
+ case VIEW_CONVERT_EXPR:
+ vno->length = 1;
+ vno->op[0] = TREE_OPERAND (gimple_assign_rhs1 (stmt), 0);
+ break;
+
+ case CONSTRUCTOR:
+ vno->length = CONSTRUCTOR_NELTS (gimple_assign_rhs1 (stmt));
+ for (i = 0; i < vno->length; ++i)
+ vno->op[i] = CONSTRUCTOR_ELT (gimple_assign_rhs1 (stmt), i)->value;
+ break;
+
+ default:
+ vno->length = gimple_num_ops (stmt) - 1;
+ for (i = 0; i < vno->length; ++i)
+ vno->op[i] = gimple_op (stmt, i + 1);
+ }
}
/* Compute the hashcode for VNO and look for it in the hash table;
tree
vn_nary_op_lookup_pieces (unsigned int length, enum tree_code code,
- tree type, tree op0, tree op1, tree op2,
- tree op3, vn_nary_op_t *vnresult)
+ tree type, tree *ops, vn_nary_op_t *vnresult)
{
- struct vn_nary_op_s vno1;
- init_vn_nary_op_from_pieces (&vno1, length, code, type, op0, op1, op2, op3);
- return vn_nary_op_lookup_1 (&vno1, vnresult);
+ vn_nary_op_t vno1 = XALLOCAVAR (struct vn_nary_op_s,
+ sizeof_vn_nary_op (length));
+ init_vn_nary_op_from_pieces (vno1, length, code, type, ops);
+ return vn_nary_op_lookup_1 (vno1, vnresult);
}
/* Lookup OP in the current hash table, and return the resulting value
tree
vn_nary_op_lookup (tree op, vn_nary_op_t *vnresult)
{
- struct vn_nary_op_s vno1;
- init_vn_nary_op_from_op (&vno1, op);
- return vn_nary_op_lookup_1 (&vno1, vnresult);
+ vn_nary_op_t vno1
+ = XALLOCAVAR (struct vn_nary_op_s,
+ sizeof_vn_nary_op (TREE_CODE_LENGTH (TREE_CODE (op))));
+ init_vn_nary_op_from_op (vno1, op);
+ return vn_nary_op_lookup_1 (vno1, vnresult);
}
/* Lookup the rhs of STMT in the current hash table, and return the resulting
tree
vn_nary_op_lookup_stmt (gimple stmt, vn_nary_op_t *vnresult)
{
- struct vn_nary_op_s vno1;
- init_vn_nary_op_from_stmt (&vno1, stmt);
- return vn_nary_op_lookup_1 (&vno1, vnresult);
-}
-
-/* Return the size of a vn_nary_op_t with LENGTH operands. */
-
-static size_t
-sizeof_vn_nary_op (unsigned int length)
-{
- return sizeof (struct vn_nary_op_s) - sizeof (tree) * (4 - length);
+ vn_nary_op_t vno1
+ = XALLOCAVAR (struct vn_nary_op_s,
+ sizeof_vn_nary_op (vn_nary_length_from_stmt (stmt)));
+ init_vn_nary_op_from_stmt (vno1, stmt);
+ return vn_nary_op_lookup_1 (vno1, vnresult);
}
/* Allocate a vn_nary_op_t with LENGTH operands on STACK. */
vn_nary_op_t
vn_nary_op_insert_pieces (unsigned int length, enum tree_code code,
- tree type, tree op0,
- tree op1, tree op2, tree op3,
- tree result,
- unsigned int value_id)
+ tree type, tree *ops,
+ tree result, unsigned int value_id)
{
- vn_nary_op_t vno1;
-
- vno1 = alloc_vn_nary_op (length, result, value_id);
- init_vn_nary_op_from_pieces (vno1, length, code, type, op0, op1, op2, op3);
+ vn_nary_op_t vno1 = alloc_vn_nary_op (length, result, value_id);
+ init_vn_nary_op_from_pieces (vno1, length, code, type, ops);
return vn_nary_op_insert_into (vno1, current_info->nary, true);
}
vn_nary_op_t
vn_nary_op_insert_stmt (gimple stmt, tree result)
{
- unsigned length = gimple_num_ops (stmt) - 1;
- vn_nary_op_t vno1;
-
- vno1 = alloc_vn_nary_op (length, result, VN_INFO (result)->value_id);
+ vn_nary_op_t vno1
+ = alloc_vn_nary_op (vn_nary_length_from_stmt (stmt),
+ result, VN_INFO (result)->value_id);
init_vn_nary_op_from_stmt (vno1, stmt);
return vn_nary_op_insert_into (vno1, current_info->nary, true);
}
case tcc_declaration:
changed = visit_reference_op_load (lhs, rhs1, stmt);
break;
- case tcc_expression:
+ default:
if (code == ADDR_EXPR)
{
changed = visit_nary_op (lhs, stmt);
break;
}
- /* Fallthrough. */
- default:
+ else if (code == CONSTRUCTOR)
+ {
+ changed = visit_nary_op (lhs, stmt);
+ break;
+ }
changed = defs_to_varying (stmt);
}
break;
hashval_t hashcode;
tree result;
tree type;
- tree op[4];
+ tree op[1];
} *vn_nary_op_t;
typedef const struct vn_nary_op_s *const_vn_nary_op_t;
+/* Return the size of a vn_nary_op_t with LENGTH operands. */
+
+static inline size_t
+sizeof_vn_nary_op (unsigned int length)
+{
+ return sizeof (struct vn_nary_op_s) + sizeof (tree) * (length - 1);
+}
+
/* Phi nodes in the hashtable consist of their non-VN_TOP phi
arguments, and the basic block the phi is in. Result is the value
number of the operation, and hashcode is stored to avoid having to
tree vn_nary_op_lookup (tree, vn_nary_op_t *);
tree vn_nary_op_lookup_stmt (gimple, vn_nary_op_t *);
tree vn_nary_op_lookup_pieces (unsigned int, enum tree_code,
- tree, tree, tree, tree, tree,
- vn_nary_op_t *);
+ tree, tree *, vn_nary_op_t *);
vn_nary_op_t vn_nary_op_insert (tree, tree);
vn_nary_op_t vn_nary_op_insert_stmt (gimple, tree);
vn_nary_op_t vn_nary_op_insert_pieces (unsigned int, enum tree_code,
- tree, tree, tree, tree,
- tree, tree, unsigned int);
+ tree, tree *, tree, unsigned int);
void vn_reference_fold_indirect (VEC (vn_reference_op_s, heap) **,
unsigned int *);
void copy_reference_ops_from_ref (tree, VEC(vn_reference_op_s, heap) **);