re PR tree-optimization/70497 (Missed CSE of subregs on GIMPLE)
authorRichard Biener <rguenther@suse.de>
Tue, 10 May 2016 08:20:43 +0000 (08:20 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Tue, 10 May 2016 08:20:43 +0000 (08:20 +0000)
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

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/torture/20160404-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-54.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-55.c [new file with mode: 0644]
gcc/tree-complex.c
gcc/tree-ssa-pre.c
gcc/tree-ssa-sccvn.c

index fb9b6a7f4166b0de6e9b96f3de5157526c7c646f..2365d851407ef0eecc0723377aad1876fb88c34c 100644 (file)
@@ -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
index f144648aae8e68a9cef871e396b82dfacbed4acb..08392c708007083b88aaac8387d83cfa9f4c388e 100644 (file)
@@ -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 (file)
index 0000000..b3a85b5
--- /dev/null
@@ -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 (file)
index 0000000..be7537e
--- /dev/null
@@ -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 (file)
index 0000000..7bfa284
--- /dev/null
@@ -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" } } */
index d781a8aa014c4340adad348f37f4e80e410fdf69..d7baf227c7dd7878d8a9017506ae7ce41a6d28c1 100644 (file)
@@ -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:
index 7b9eb2e5b9cd65e2f8c09a545c541c3a844e2c3b..4a771d3b0be8ec297617e140087baa1805bb84f9 100644 (file)
@@ -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;
 
index 2dbe4084420f153eafefde6048c61f612e17dfde..63441178deaa28b84fb51771fd9ad79232bd899e 100644 (file)
@@ -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)