From: Richard Biener Date: Tue, 10 May 2016 08:20:43 +0000 (+0000) Subject: re PR tree-optimization/70497 (Missed CSE of subregs on GIMPLE) X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=64ea4e151b40fde37eb2b3190731f03c4a65dcf3;p=gcc.git re PR tree-optimization/70497 (Missed CSE of subregs on GIMPLE) 2016-05-10 Richard Biener PR tree-optimization/70497 PR tree-optimization/28367 * tree-ssa-sccvn.c (vn_nary_build_or_lookup): New function split out from ... (visit_reference_op_load): ... here. (vn_reference_lookup_3): Use it to handle subreg-like accesses with simplified BIT_FIELD_REFs. * tree-ssa-pre.c (eliminate_insert): Handle inserting BIT_FIELD_REFs. * tree-complex.c (extract_component): Handle BIT_FIELD_REFs correctly. * gcc.dg/torture/20160404-1.c: New testcase. * gcc.dg/tree-ssa/ssa-fre-54.c: Likewise. * gcc.dg/tree-ssa/ssa-fre-55.c: Likewise. From-SVN: r236066 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index fb9b6a7f416..2365d851407 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,16 @@ +2016-05-10 Richard Biener + + PR tree-optimization/70497 + PR tree-optimization/28367 + * tree-ssa-sccvn.c (vn_nary_build_or_lookup): New function + split out from ... + (visit_reference_op_load): ... here. + (vn_reference_lookup_3): Use it to handle subreg-like accesses + with simplified BIT_FIELD_REFs. + * tree-ssa-pre.c (eliminate_insert): Handle inserting BIT_FIELD_REFs. + * tree-complex.c (extract_component): Handle BIT_FIELD_REFs + correctly. + 2016-05-10 Pierre-Marie de Rodat * dwarf2out.c (add_abstract_origin_attribute): Adjust diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index f144648aae8..08392c70800 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2016-05-10 Richard Biener + + PR tree-optimization/70497 + PR tree-optimization/28367 + * gcc.dg/torture/20160404-1.c: New testcase. + * gcc.dg/tree-ssa/ssa-fre-54.c: Likewise. + * gcc.dg/tree-ssa/ssa-fre-55.c: Likewise. + 2016-05-10 Pierre-Marie de Rodat * gcc.dg/debug/dwarf2/nested_fun.c: New testcase. diff --git a/gcc/testsuite/gcc.dg/torture/20160404-1.c b/gcc/testsuite/gcc.dg/torture/20160404-1.c new file mode 100644 index 00000000000..b3a85b55ad7 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/20160404-1.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ + +typedef __UINT64_TYPE__ UINT64; +typedef union { + struct { + unsigned short lo4; + unsigned short lo3; + unsigned short lo2; + unsigned short lo1; + } i; + long double f; +} BID_BINARY80LDOUBLE; +UINT64 __binary80_to_bid32 (long double x) +{ + BID_BINARY80LDOUBLE x_in; + x_in.f = x; + return (x_in.i.lo4 + + ((UINT64)x_in.i.lo3 << 16) + + ((UINT64)x_in.i.lo2 << 32) + + ((UINT64)x_in.i.lo1 << 48)); +} diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-54.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-54.c new file mode 100644 index 00000000000..be7537e80c1 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-54.c @@ -0,0 +1,56 @@ +/* { dg-do run } */ +/* { dg-require-effective-target int32plus } */ +/* { dg-options "-O -fdump-tree-fre1 -fdump-tree-dse1" } */ + +extern void abort (void); + +union U { int i; char c[4]; short s[2]; }; + +char __attribute__((noinline,noclone)) foo(int i) +{ + union U u; + u.i = i; + /* This should be equivalent to (char) i. */ +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + return u.c[0]; +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + return u.c[3]; +#else + return 0x04; +#endif +} + +short __attribute__((noinline,noclone)) baz(int i) +{ + union U u; + u.i = i; + /* This should be equivalent to (char) i. */ +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + return u.s[0]; +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + return u.s[1]; +#else + return 0x0304; +#endif +} + +char __attribute__((noinline,noclone)) bar(int j) +{ + union U u; + u.i = j; + /* This gets simplified to a BIT_FIELD_REF. */ + return u.c[2]; +} + +int main() +{ + if (foo (0x01020304) != 0x04) + abort (); + if (baz (0x01020304) != 0x0304) + abort (); + return 0; +} + +/* { dg-final { scan-tree-dump "\\(char\\) i_" "fre1" } } */ +/* { dg-final { scan-tree-dump "\\(short int\\) i_" "fre1" } } */ +/* { dg-final { scan-tree-dump-not "u.i =" "dse1" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-55.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-55.c new file mode 100644 index 00000000000..7bfa2847878 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-55.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-O -fdump-tree-optimized" } */ + +typedef int v4si __attribute__((vector_size(16))); + +int f(v4si t) +{ + union { + v4si t1; + int t2[4]; + } u; + u.t1 = t; + return u.t2[1]; +} + +/* { dg-final { scan-tree-dump-not "u;" "optimized" } } */ +/* { dg-final { scan-tree-dump-times "BIT_FIELD_REF" 1 "optimized" } } */ diff --git a/gcc/tree-complex.c b/gcc/tree-complex.c index d781a8aa014..d7baf227c7d 100644 --- a/gcc/tree-complex.c +++ b/gcc/tree-complex.c @@ -604,6 +604,21 @@ extract_component (gimple_stmt_iterator *gsi, tree t, bool imagpart_p, case COMPLEX_EXPR: gcc_unreachable (); + case BIT_FIELD_REF: + { + tree inner_type = TREE_TYPE (TREE_TYPE (t)); + t = unshare_expr (t); + TREE_TYPE (t) = inner_type; + TREE_OPERAND (t, 1) = TYPE_SIZE (inner_type); + if (imagpart_p) + TREE_OPERAND (t, 2) = size_binop (PLUS_EXPR, TREE_OPERAND (t, 2), + TYPE_SIZE (inner_type)); + if (gimple_p) + t = force_gimple_operand_gsi (gsi, t, true, NULL, true, + GSI_SAME_STMT); + return t; + } + case VAR_DECL: case RESULT_DECL: case PARM_DECL: diff --git a/gcc/tree-ssa-pre.c b/gcc/tree-ssa-pre.c index 7b9eb2e5b9c..4a771d3b0be 100644 --- a/gcc/tree-ssa-pre.c +++ b/gcc/tree-ssa-pre.c @@ -3855,19 +3855,28 @@ eliminate_insert (gimple_stmt_iterator *gsi, tree val) gimple *stmt = gimple_seq_first_stmt (VN_INFO (val)->expr); if (!is_gimple_assign (stmt) || (!CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (stmt)) - && gimple_assign_rhs_code (stmt) != VIEW_CONVERT_EXPR)) + && gimple_assign_rhs_code (stmt) != VIEW_CONVERT_EXPR + && gimple_assign_rhs_code (stmt) != BIT_FIELD_REF)) return NULL_TREE; tree op = gimple_assign_rhs1 (stmt); - if (gimple_assign_rhs_code (stmt) == VIEW_CONVERT_EXPR) + if (gimple_assign_rhs_code (stmt) == VIEW_CONVERT_EXPR + || gimple_assign_rhs_code (stmt) == BIT_FIELD_REF) op = TREE_OPERAND (op, 0); tree leader = TREE_CODE (op) == SSA_NAME ? eliminate_avail (op) : op; if (!leader) return NULL_TREE; gimple_seq stmts = NULL; - tree res = gimple_build (&stmts, gimple_assign_rhs_code (stmt), - TREE_TYPE (val), leader); + tree res; + if (gimple_assign_rhs_code (stmt) == BIT_FIELD_REF) + res = gimple_build (&stmts, BIT_FIELD_REF, + TREE_TYPE (val), leader, + TREE_OPERAND (gimple_assign_rhs1 (stmt), 1), + TREE_OPERAND (gimple_assign_rhs1 (stmt), 2)); + else + res = gimple_build (&stmts, gimple_assign_rhs_code (stmt), + TREE_TYPE (val), leader); gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); VN_INFO_GET (res)->valnum = val; diff --git a/gcc/tree-ssa-sccvn.c b/gcc/tree-ssa-sccvn.c index 2dbe4084420..63441178dea 100644 --- a/gcc/tree-ssa-sccvn.c +++ b/gcc/tree-ssa-sccvn.c @@ -1610,6 +1610,105 @@ vn_reference_lookup_or_insert_for_pieces (tree vuse, operands.copy (), value, value_id); } +static vn_nary_op_t vn_nary_op_insert_stmt (gimple *stmt, tree result); + +/* Hook for maybe_push_res_to_seq, lookup the expression in the VN tables. */ + +static tree +vn_lookup_simplify_result (code_helper rcode, tree type, tree *ops) +{ + if (!rcode.is_tree_code ()) + return NULL_TREE; + vn_nary_op_t vnresult = NULL; + return vn_nary_op_lookup_pieces (TREE_CODE_LENGTH ((tree_code) rcode), + (tree_code) rcode, type, ops, &vnresult); +} + +/* Return a value-number for RCODE OPS... either by looking up an existing + value-number for the simplified result or by inserting the operation. */ + +static tree +vn_nary_build_or_lookup (code_helper rcode, tree type, tree *ops) +{ + tree result = NULL_TREE; + /* We will be creating a value number for + ROCDE (OPS...). + So first simplify and lookup this expression to see if it + is already available. */ + mprts_hook = vn_lookup_simplify_result; + bool res = false; + switch (TREE_CODE_LENGTH ((tree_code) rcode)) + { + case 1: + res = gimple_resimplify1 (NULL, &rcode, type, ops, vn_valueize); + break; + case 2: + res = gimple_resimplify2 (NULL, &rcode, type, ops, vn_valueize); + break; + case 3: + res = gimple_resimplify3 (NULL, &rcode, type, ops, vn_valueize); + break; + } + mprts_hook = NULL; + gimple *new_stmt = NULL; + if (res + && gimple_simplified_result_is_gimple_val (rcode, ops)) + /* The expression is already available. */ + result = ops[0]; + else + { + tree val = vn_lookup_simplify_result (rcode, type, ops); + if (!val) + { + gimple_seq stmts = NULL; + result = maybe_push_res_to_seq (rcode, type, ops, &stmts); + if (result) + { + gcc_assert (gimple_seq_singleton_p (stmts)); + new_stmt = gimple_seq_first_stmt (stmts); + } + } + else + /* The expression is already available. */ + result = val; + } + if (new_stmt) + { + /* The expression is not yet available, value-number lhs to + the new SSA_NAME we created. */ + /* Initialize value-number information properly. */ + VN_INFO_GET (result)->valnum = result; + VN_INFO (result)->value_id = get_next_value_id (); + gimple_seq_add_stmt_without_update (&VN_INFO (result)->expr, + new_stmt); + VN_INFO (result)->needs_insertion = true; + /* As all "inserted" statements are singleton SCCs, insert + to the valid table. This is strictly needed to + avoid re-generating new value SSA_NAMEs for the same + expression during SCC iteration over and over (the + optimistic table gets cleared after each iteration). + We do not need to insert into the optimistic table, as + lookups there will fall back to the valid table. */ + if (current_info == optimistic_info) + { + current_info = valid_info; + vn_nary_op_insert_stmt (new_stmt, result); + current_info = optimistic_info; + } + else + vn_nary_op_insert_stmt (new_stmt, result); + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Inserting name "); + print_generic_expr (dump_file, result, 0); + fprintf (dump_file, " for expression "); + print_gimple_expr (dump_file, new_stmt, 0, TDF_SLIM); + fprintf (dump_file, "\n"); + } + } + return result; +} + /* Callback for walk_non_aliased_vuses. Tries to perform a lookup from the statement defining VUSE and if not successful tries to translate *REFP and VR_ through an aggregate copy at the definition @@ -1772,15 +1871,16 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *vr_, /* 3) Assignment from a constant. We can use folds native encode/interpret routines to extract the assigned bits. */ - else if (vn_walk_kind == VN_WALKREWRITE - && CHAR_BIT == 8 && BITS_PER_UNIT == 8 - && ref->size == maxsize - && maxsize % BITS_PER_UNIT == 0 - && offset % BITS_PER_UNIT == 0 + else if (ref->size == maxsize && is_gimple_reg_type (vr->type) && !contains_storage_order_barrier_p (vr->operands) && gimple_assign_single_p (def_stmt) - && is_gimple_min_invariant (gimple_assign_rhs1 (def_stmt))) + && CHAR_BIT == 8 && BITS_PER_UNIT == 8 + && maxsize % BITS_PER_UNIT == 0 + && offset % BITS_PER_UNIT == 0 + && (is_gimple_min_invariant (gimple_assign_rhs1 (def_stmt)) + || (TREE_CODE (gimple_assign_rhs1 (def_stmt)) == SSA_NAME + && is_gimple_min_invariant (SSA_VAL (gimple_assign_rhs1 (def_stmt)))))) { tree base2; HOST_WIDE_INT offset2, size2, maxsize2; @@ -1800,6 +1900,9 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *vr_, unsigned char buffer[64]; int len; + tree rhs = gimple_assign_rhs1 (def_stmt); + if (TREE_CODE (rhs) == SSA_NAME) + rhs = SSA_VAL (rhs); len = native_encode_expr (gimple_assign_rhs1 (def_stmt), buffer, sizeof (buffer)); if (len > 0) @@ -1824,56 +1927,37 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *vr_, && gimple_assign_single_p (def_stmt) && TREE_CODE (gimple_assign_rhs1 (def_stmt)) == SSA_NAME) { - tree rhs1 = gimple_assign_rhs1 (def_stmt); - gimple *def_stmt2 = SSA_NAME_DEF_STMT (rhs1); - if (is_gimple_assign (def_stmt2) - && (gimple_assign_rhs_code (def_stmt2) == COMPLEX_EXPR - || gimple_assign_rhs_code (def_stmt2) == CONSTRUCTOR) - && types_compatible_p (vr->type, TREE_TYPE (TREE_TYPE (rhs1)))) + tree base2; + HOST_WIDE_INT offset2, size2, maxsize2; + bool reverse; + base2 = get_ref_base_and_extent (gimple_assign_lhs (def_stmt), + &offset2, &size2, &maxsize2, + &reverse); + if (!reverse + && maxsize2 != -1 + && maxsize2 == size2 + && operand_equal_p (base, base2, 0) + && offset2 <= offset + && offset2 + size2 >= offset + maxsize + /* ??? We can't handle bitfield precision extracts without + either using an alternate type for the BIT_FIELD_REF and + then doing a conversion or possibly adjusting the offset + according to endianess. */ + && (! INTEGRAL_TYPE_P (vr->type) + || ref->size == TYPE_PRECISION (vr->type)) + && ref->size % BITS_PER_UNIT == 0) { - tree base2; - HOST_WIDE_INT offset2, size2, maxsize2, off; - bool reverse; - base2 = get_ref_base_and_extent (gimple_assign_lhs (def_stmt), - &offset2, &size2, &maxsize2, - &reverse); - off = offset - offset2; - if (!reverse - && maxsize2 != -1 - && maxsize2 == size2 - && operand_equal_p (base, base2, 0) - && offset2 <= offset - && offset2 + size2 >= offset + maxsize) + code_helper rcode = BIT_FIELD_REF; + tree ops[3]; + ops[0] = SSA_VAL (gimple_assign_rhs1 (def_stmt)); + ops[1] = bitsize_int (ref->size); + ops[2] = bitsize_int (offset - offset2); + tree val = vn_nary_build_or_lookup (rcode, vr->type, ops); + if (val) { - tree val = NULL_TREE; - HOST_WIDE_INT elsz - = TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (TREE_TYPE (rhs1)))); - if (gimple_assign_rhs_code (def_stmt2) == COMPLEX_EXPR) - { - if (off == 0) - val = gimple_assign_rhs1 (def_stmt2); - else if (off == elsz) - val = gimple_assign_rhs2 (def_stmt2); - } - else if (gimple_assign_rhs_code (def_stmt2) == CONSTRUCTOR - && off % elsz == 0) - { - tree ctor = gimple_assign_rhs1 (def_stmt2); - unsigned i = off / elsz; - if (i < CONSTRUCTOR_NELTS (ctor)) - { - constructor_elt *elt = CONSTRUCTOR_ELT (ctor, i); - if (TREE_CODE (TREE_TYPE (rhs1)) == VECTOR_TYPE) - { - if (TREE_CODE (TREE_TYPE (elt->value)) - != VECTOR_TYPE) - val = elt->value; - } - } - } - if (val) - return vn_reference_lookup_or_insert_for_pieces - (vuse, vr->set, vr->type, vr->operands, val); + vn_reference_t res = vn_reference_lookup_or_insert_for_pieces + (vuse, vr->set, vr->type, vr->operands, val); + return res; } } } @@ -2611,18 +2695,6 @@ vn_nary_op_lookup_stmt (gimple *stmt, vn_nary_op_t *vnresult) return vn_nary_op_lookup_1 (vno1, vnresult); } -/* Hook for maybe_push_res_to_seq, lookup the expression in the VN tables. */ - -static tree -vn_lookup_simplify_result (code_helper rcode, tree type, tree *ops) -{ - if (!rcode.is_tree_code ()) - return NULL_TREE; - vn_nary_op_t vnresult = NULL; - return vn_nary_op_lookup_pieces (TREE_CODE_LENGTH ((tree_code) rcode), - (tree_code) rcode, type, ops, &vnresult); -} - /* Allocate a vn_nary_op_t with LENGTH operands on STACK. */ static vn_nary_op_t @@ -3371,69 +3443,9 @@ visit_reference_op_load (tree lhs, tree op, gimple *stmt) of VIEW_CONVERT_EXPR (result). So first simplify and lookup this expression to see if it is already available. */ - mprts_hook = vn_lookup_simplify_result; code_helper rcode = VIEW_CONVERT_EXPR; tree ops[3] = { result }; - bool res = gimple_resimplify1 (NULL, &rcode, TREE_TYPE (op), ops, - vn_valueize); - mprts_hook = NULL; - gimple *new_stmt = NULL; - if (res - && gimple_simplified_result_is_gimple_val (rcode, ops)) - /* The expression is already available. */ - result = ops[0]; - else - { - tree val = vn_lookup_simplify_result (rcode, TREE_TYPE (op), ops); - if (!val) - { - gimple_seq stmts = NULL; - result = maybe_push_res_to_seq (rcode, TREE_TYPE (op), ops, - &stmts); - if (result) - { - gcc_assert (gimple_seq_singleton_p (stmts)); - new_stmt = gimple_seq_first_stmt (stmts); - } - } - else - /* The expression is already available. */ - result = val; - } - if (new_stmt) - { - /* The expression is not yet available, value-number lhs to - the new SSA_NAME we created. */ - /* Initialize value-number information properly. */ - VN_INFO_GET (result)->valnum = result; - VN_INFO (result)->value_id = get_next_value_id (); - gimple_seq_add_stmt_without_update (&VN_INFO (result)->expr, - new_stmt); - VN_INFO (result)->needs_insertion = true; - /* As all "inserted" statements are singleton SCCs, insert - to the valid table. This is strictly needed to - avoid re-generating new value SSA_NAMEs for the same - expression during SCC iteration over and over (the - optimistic table gets cleared after each iteration). - We do not need to insert into the optimistic table, as - lookups there will fall back to the valid table. */ - if (current_info == optimistic_info) - { - current_info = valid_info; - vn_nary_op_insert_stmt (new_stmt, result); - current_info = optimistic_info; - } - else - vn_nary_op_insert_stmt (new_stmt, result); - if (dump_file && (dump_flags & TDF_DETAILS)) - { - fprintf (dump_file, "Inserting name "); - print_generic_expr (dump_file, result, 0); - fprintf (dump_file, " for expression "); - print_gimple_expr (dump_file, new_stmt, 0, TDF_SLIM); - fprintf (dump_file, "\n"); - } - } + result = vn_nary_build_or_lookup (rcode, TREE_TYPE (op), ops); } if (result)