Hi!

I've committed following fix, approved by Richard on IRC and Jeff in the PR.
process_assignment was assuming that no code needs to be emitted
for gimple_assign_cast_p if the mode is the same, which is usually true,
except for the case when REDUCE_BIT_FIELD in expand_expr_real_2 needs to
mask or shift up/down to adjust for reduced precision.

Bootstrapped/regtested on x86_64-linux and i686-linux, committed to trunk
and 4.9.

2014-04-29  Jakub Jelinek  <ja...@redhat.com>

        PR tree-optimization/60971
        * tree-tailcall.c (process_assignment): Reject conversions which
        reduce precision.

        * c-c++-common/turtore/pr60971.c: New test.

--- gcc/tree-tailcall.c.jj      2014-04-17 14:48:59.000000000 +0200
+++ gcc/tree-tailcall.c 2014-04-29 12:13:12.649414120 +0200
@@ -285,9 +285,19 @@ process_assignment (gimple stmt, gimple_
     {
       /* Reject a tailcall if the type conversion might need
         additional code.  */
-      if (gimple_assign_cast_p (stmt)
-         && TYPE_MODE (TREE_TYPE (dest)) != TYPE_MODE (TREE_TYPE (src_var)))
-       return false;
+      if (gimple_assign_cast_p (stmt))
+       {
+         if (TYPE_MODE (TREE_TYPE (dest)) != TYPE_MODE (TREE_TYPE (src_var)))
+           return false;
+
+         /* Even if the type modes are the same, if the precision of the
+            type is smaller than mode's precision,
+            reduce_to_bit_field_precision would generate additional code.  */
+         if (INTEGRAL_TYPE_P (TREE_TYPE (dest))
+             && (GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (dest)))
+                 > TYPE_PRECISION (TREE_TYPE (dest))))
+           return false;
+       }
 
       if (src_var != *ass_var)
        return false;
--- gcc/testsuite/c-c++-common/torture/pr60971.c.jj     2014-04-29 
11:15:06.448764325 +0200
+++ gcc/testsuite/c-c++-common/torture/pr60971.c        2014-04-29 
11:14:49.000000000 +0200
@@ -0,0 +1,34 @@
+/* PR tree-optimization/60971 */
+/* { dg-do run } */
+
+#ifndef __cplusplus
+#define bool _Bool
+#endif
+
+volatile unsigned char c;
+
+__attribute__((noinline)) unsigned char
+foo (void)
+{
+  return c;
+}
+
+__attribute__((noinline)) bool
+bar (void)
+{
+  return foo () & 1;
+}
+
+int
+main ()
+{
+  c = 0x41;
+  c = bar ();
+  if (c != 1)
+    __builtin_abort ();
+  c = 0x20;
+  c = bar ();
+  if (c != 0)
+    __builtin_abort ();
+  return 0;
+}

        Jakub

Reply via email to