return 0;
}
+/* Get the BIT_FIELD_REF definition of VAL, if any, looking through
+ conversions with code CONV_CODE or update it if still ERROR_MARK.
+ Return NULL_TREE if no such matching def was found. */
+
+static tree
+get_bit_field_ref_def (tree val, enum tree_code &conv_code)
+{
+ if (TREE_CODE (val) != SSA_NAME)
+ return NULL_TREE ;
+ gimple *def_stmt = get_prop_source_stmt (val, false, NULL);
+ if (!def_stmt)
+ return NULL_TREE;
+ enum tree_code code = gimple_assign_rhs_code (def_stmt);
+ if (code == FLOAT_EXPR
+ || code == FIX_TRUNC_EXPR)
+ {
+ tree op1 = gimple_assign_rhs1 (def_stmt);
+ if (conv_code == ERROR_MARK)
+ {
+ if (maybe_ne (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (val))),
+ GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op1)))))
+ return NULL_TREE;
+ conv_code = code;
+ }
+ else if (conv_code != code)
+ return NULL_TREE;
+ if (TREE_CODE (op1) != SSA_NAME)
+ return NULL_TREE;
+ def_stmt = SSA_NAME_DEF_STMT (op1);
+ if (! is_gimple_assign (def_stmt))
+ return NULL_TREE;
+ code = gimple_assign_rhs_code (def_stmt);
+ }
+ if (code != BIT_FIELD_REF)
+ return NULL_TREE;
+ return gimple_assign_rhs1 (def_stmt);
+}
+
/* Recognize a VEC_PERM_EXPR. Returns true if there were any changes. */
static bool
simplify_vector_constructor (gimple_stmt_iterator *gsi)
{
gimple *stmt = gsi_stmt (*gsi);
- gimple *def_stmt;
tree op, op2, orig[2], type, elem_type;
unsigned elem_size, i;
unsigned HOST_WIDE_INT nelts;
- enum tree_code code, conv_code;
+ enum tree_code conv_code;
constructor_elt *elt;
bool maybe_ident;
orig[1] = NULL;
conv_code = ERROR_MARK;
maybe_ident = true;
+ tree one_constant = NULL_TREE;
+ auto_vec<tree> constants;
+ constants.safe_grow_cleared (nelts);
FOR_EACH_VEC_SAFE_ELT (CONSTRUCTOR_ELTS (op), i, elt)
{
tree ref, op1;
if (i >= nelts)
return false;
- if (TREE_CODE (elt->value) != SSA_NAME)
- return false;
- def_stmt = get_prop_source_stmt (elt->value, false, NULL);
- if (!def_stmt)
- return false;
- code = gimple_assign_rhs_code (def_stmt);
- if (code == FLOAT_EXPR
- || code == FIX_TRUNC_EXPR)
+ op1 = get_bit_field_ref_def (elt->value, conv_code);
+ if (op1)
{
- op1 = gimple_assign_rhs1 (def_stmt);
- if (conv_code == ERROR_MARK)
+ ref = TREE_OPERAND (op1, 0);
+ unsigned int j;
+ for (j = 0; j < 2; ++j)
{
- if (maybe_ne (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (elt->value))),
- GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op1)))))
- return false;
- conv_code = code;
+ if (!orig[j])
+ {
+ if (TREE_CODE (ref) != SSA_NAME)
+ return false;
+ if (! VECTOR_TYPE_P (TREE_TYPE (ref))
+ || ! useless_type_conversion_p (TREE_TYPE (op1),
+ TREE_TYPE (TREE_TYPE (ref))))
+ return false;
+ if (j && !useless_type_conversion_p (TREE_TYPE (orig[0]),
+ TREE_TYPE (ref)))
+ return false;
+ orig[j] = ref;
+ break;
+ }
+ else if (ref == orig[j])
+ break;
}
- else if (conv_code != code)
- return false;
- if (TREE_CODE (op1) != SSA_NAME)
+ if (j == 2)
return false;
- def_stmt = SSA_NAME_DEF_STMT (op1);
- if (! is_gimple_assign (def_stmt))
+
+ unsigned int elt;
+ if (maybe_ne (bit_field_size (op1), elem_size)
+ || !constant_multiple_p (bit_field_offset (op1), elem_size, &elt))
return false;
- code = gimple_assign_rhs_code (def_stmt);
+ if (j)
+ elt += nelts;
+ if (elt != i)
+ maybe_ident = false;
+ sel.quick_push (elt);
}
- if (code != BIT_FIELD_REF)
- return false;
- op1 = gimple_assign_rhs1 (def_stmt);
- ref = TREE_OPERAND (op1, 0);
- unsigned int j;
- for (j = 0; j < 2; ++j)
+ else if (CONSTANT_CLASS_P (elt->value))
{
- if (!orig[j])
- {
- if (TREE_CODE (ref) != SSA_NAME)
- return false;
- if (! VECTOR_TYPE_P (TREE_TYPE (ref))
- || ! useless_type_conversion_p (TREE_TYPE (op1),
- TREE_TYPE (TREE_TYPE (ref))))
- return false;
- if (j && !useless_type_conversion_p (TREE_TYPE (orig[0]),
- TREE_TYPE (ref)))
- return false;
- orig[j] = ref;
- break;
- }
- else if (ref == orig[j])
- break;
+ if (orig[1]
+ && orig[1] != error_mark_node)
+ return false;
+ orig[1] = error_mark_node;
+ if (!one_constant)
+ one_constant = elt->value;
+ constants[i] = elt->value;
+ sel.quick_push (i + nelts);
+ maybe_ident = false;
}
- if (j == 2)
- return false;
-
- unsigned int elt;
- if (maybe_ne (bit_field_size (op1), elem_size)
- || !constant_multiple_p (bit_field_offset (op1), elem_size, &elt))
+ else
return false;
- if (j)
- elt += nelts;
- if (elt != i)
- maybe_ident = false;
- sel.quick_push (elt);
}
if (i < nelts)
return false;
op2 = vec_perm_indices_to_tree (mask_type, indices);
if (!orig[1])
orig[1] = orig[0];
+ if (orig[1] == error_mark_node)
+ {
+ tree_vector_builder vec (type, nelts, 1);
+ for (unsigned i = 0; i < nelts; ++i)
+ if (constants[i])
+ vec.quick_push (constants[i]);
+ else
+ /* ??? Push a don't-care value. */
+ vec.quick_push (one_constant);
+ orig[1] = vec.build ();
+ }
if (conv_code == ERROR_MARK)
gimple_assign_set_rhs_with_ops (gsi, VEC_PERM_EXPR, orig[0],
orig[1], op2);
+ else if (TREE_CODE (orig[1]) == VECTOR_CST)
+ {
+ gimple *conv
+ = gimple_build_assign (make_ssa_name (type), conv_code, orig[0]);
+ orig[0] = gimple_assign_lhs (conv);
+ gsi_insert_before (gsi, conv, GSI_SAME_STMT);
+ gimple_assign_set_rhs_with_ops (gsi, VEC_PERM_EXPR,
+ orig[0], orig[1], op2);
+ }
else
{
gimple *perm