From 3bc104bdb4b5aa99ff6dceb246beaa65b012c5ac Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Mon, 6 May 2019 12:43:30 +0000 Subject: [PATCH] re PR tree-optimization/88828 (Inefficient update of the first element of vector registers) 2019-05-06 Richard Biener 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. From-SVN: r270908 --- gcc/ChangeLog | 7 + gcc/testsuite/ChangeLog | 5 + gcc/testsuite/gcc.target/i386/pr88828-0.c | 27 ++++ gcc/tree-ssa-forwprop.c | 159 ++++++++++++++-------- 4 files changed, 143 insertions(+), 55 deletions(-) create mode 100644 gcc/testsuite/gcc.target/i386/pr88828-0.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b4424ddd40e..3e9b69be2f0 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2019-05-06 Richard Biener + + 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. + 2019-05-06 Richard Biener PR tree-optimization/90328 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 2ad2c4ac4ce..37887397d74 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-05-06 Richard Biener + + PR tree-optimization/88828 + * gcc.target/i386/pr88828-0.c: New testcase. + 2019-05-06 Richard Biener PR tree-optimization/90328 diff --git a/gcc/testsuite/gcc.target/i386/pr88828-0.c b/gcc/testsuite/gcc.target/i386/pr88828-0.c new file mode 100644 index 00000000000..3ddb2d13526 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr88828-0.c @@ -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" } } */ diff --git a/gcc/tree-ssa-forwprop.c b/gcc/tree-ssa-forwprop.c index 1553c9e70ac..7dd1e64335a 100644 --- a/gcc/tree-ssa-forwprop.c +++ b/gcc/tree-ssa-forwprop.c @@ -1997,17 +1997,54 @@ simplify_permutation (gimple_stmt_iterator *gsi) 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; @@ -2027,6 +2064,9 @@ simplify_vector_constructor (gimple_stmt_iterator *gsi) orig[1] = NULL; conv_code = ERROR_MARK; maybe_ident = true; + tree one_constant = NULL_TREE; + auto_vec constants; + constants.safe_grow_cleared (nelts); FOR_EACH_VEC_SAFE_ELT (CONSTRUCTOR_ELTS (op), i, elt) { tree ref, op1; @@ -2034,68 +2074,57 @@ simplify_vector_constructor (gimple_stmt_iterator *gsi) 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; @@ -2138,9 +2167,29 @@ simplify_vector_constructor (gimple_stmt_iterator *gsi) 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 -- 2.30.2