The following refactors simplify_vector_constructor and adds handling of constants to it in a straight-forward way.
A followup will handle the testcases posted in HJs patch. Bootstrap / regtest running on x86_64-unknown-linux-gnu. Richard. 2019-05-03 Richard Biener <rguent...@suse.de> PR tree-optimization/88828 * tree-ssa-forwprop.c (get_bit_field_ref_def): Split out from... (simplify_vector_constructor): ...here. Handle constants in the constructor. * gcc.target/i386/pr88828-0.c: New testcase. Index: gcc/tree-ssa-forwprop.c =================================================================== --- gcc/tree-ssa-forwprop.c (revision 270847) +++ gcc/tree-ssa-forwprop.c (working copy) @@ -1997,6 +1997,44 @@ simplify_permutation (gimple_stmt_iterat 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 @@ -2027,6 +2065,9 @@ simplify_vector_constructor (gimple_stmt 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; @@ -2034,68 +2075,55 @@ simplify_vector_constructor (gimple_stmt 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) + if (j == 2) return false; - if (TREE_CODE (op1) != SSA_NAME) - 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)) - return false; - if (j) - elt += nelts; - if (elt != i) - maybe_ident = false; - sel.quick_push (elt); } if (i < nelts) return false; @@ -2138,9 +2166,29 @@ simplify_vector_constructor (gimple_stmt 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 Index: gcc/testsuite/gcc.target/i386/pr88828-0.c =================================================================== --- gcc/testsuite/gcc.target/i386/pr88828-0.c (nonexistent) +++ gcc/testsuite/gcc.target/i386/pr88828-0.c (working copy) @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -msse4.2" } */ + +typedef int v4si __attribute__((vector_size(16))); +typedef float v4sf __attribute__((vector_size(16))); + +v4si foo (v4si x) +{ + return (v4si){ x[0], 1, x[2], 3 }; +} + +/* { dg-final { scan-assembler "pblendw" } } */ + +v4si bar (v4sf x) +{ + return (v4si){ 1, x[1], x[2], 3 }; +} + +/* { dg-final { scan-assembler "cvttps2dq" } } */ +/* { dg-final { scan-assembler "pblendw" } } */ + +v4si baz (v4si x) +{ + return (v4si) { x[1], x[2], x[3], 0 }; +} + +/* { dg-final { scan-assembler "psrldq" } } */