aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorRichard Biener <rguenther@suse.de>2016-05-10 08:20:43 +0000
committerRichard Biener <rguenth@gcc.gnu.org>2016-05-10 08:20:43 +0000
commit64ea4e151b40fde37eb2b3190731f03c4a65dcf3 (patch)
treeb05b58da2c9cc46b7fbde8e9ef7b5966d8ea1a1d /gcc
parent5a96dae3efa97317540aee2a55f717aab1efe064 (diff)
downloadgcc-64ea4e151b40fde37eb2b3190731f03c4a65dcf3.zip
gcc-64ea4e151b40fde37eb2b3190731f03c4a65dcf3.tar.gz
gcc-64ea4e151b40fde37eb2b3190731f03c4a65dcf3.tar.bz2
re PR tree-optimization/70497 (Missed CSE of subregs on GIMPLE)
2016-05-10 Richard Biener <rguenther@suse.de> 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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog13
-rw-r--r--gcc/testsuite/ChangeLog8
-rw-r--r--gcc/testsuite/gcc.dg/torture/20160404-1.c21
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-54.c56
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-55.c17
-rw-r--r--gcc/tree-complex.c15
-rw-r--r--gcc/tree-ssa-pre.c17
-rw-r--r--gcc/tree-ssa-sccvn.c266
8 files changed, 282 insertions, 131 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index fb9b6a7..2365d85 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,16 @@
+2016-05-10 Richard Biener <rguenther@suse.de>
+
+ 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 <derodat@adacore.com>
* dwarf2out.c (add_abstract_origin_attribute): Adjust
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index f144648..08392c7 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,11 @@
+2016-05-10 Richard Biener <rguenther@suse.de>
+
+ 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 <derodat@adacore.com>
* 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 0000000..b3a85b5
--- /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 0000000..be7537e
--- /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 0000000..7bfa284
--- /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 d781a8a..d7baf22 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 7b9eb2e..4a771d3 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 2dbe408..6344117 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 <TREE_TYPE (result)> (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)