When promote_function_mode and promote_ssa_mode changes the sign differently, following is the cause for the problem in PR67714.

 _8 = fn1D.5055 ();
  f_13 = _8;

function returns -15 and in _8 it is sign extended. In the second statement, we say that the value is SUBREG_PROMOTED and promoted sign in unsigned which is wrong. When the value in _8 had come other ways than function call it would be correct (as it would be zero extended). Attached patch checks that and uses the correct promoted sign in this case.

The problem with the approach is, when you the following piece of code, we can still fail. But, I dont think I will ever happen. Any thoughts?


 _8 = fn1D.5055 ();
  _9 = _8
  f_13 = _9;

This is similar to PR65932 where sign change in PROMOTE_MODE causes problem for parameter. But need a different fix there. Regression tested on arm-none-linux-gnu with no new regression. I also bootstrapped regression tested (on an earlier version of trunk) for x86_64-none-linux-gnu with no new regressions. If this OK, I will do a full testing again. Comments?

Thanks,
Kugan


gcc/ChangeLog:

2016-01-12  Kugan Vivekanandarajah  <kug...@linaro.org>

        * expr.c (expand_expr_real_1): Fix promoted sign in SUBREG_PRMOTED
        for SSA_NAME when rhs has a value returned from function call.

gcc/testsuite/ChangeLog:

2016-01-12  Kugan Vivekanandarajah  <kug...@linaro.org>

        * gcc.target/arm/pr67714.c: New test.
diff --git a/gcc/expr.c b/gcc/expr.c
index bd43dc4..6a2b3c0 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -9710,7 +9710,25 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode 
tmode,
                                           gimple_call_fntype (g),
                                           2);
          else
-           pmode = promote_ssa_mode (ssa_name, &unsignedp);
+           {
+             tree rhs;
+             gimple *stmt;
+             /* When this is a SSA copy from a value returned from a
+                function call, use the corect promoted sign for 
SUBREG_PROMOTED_P
+                (PR67714).  */
+             if (code == SSA_NAME
+                 && is_gimple_assign (g)
+                 && (rhs = gimple_assign_rhs1 (g))
+                 && TREE_CODE (rhs) == SSA_NAME
+                 && (stmt = SSA_NAME_DEF_STMT (rhs))
+                 && gimple_code (stmt) == GIMPLE_CALL
+                 && !gimple_call_internal_p (stmt))
+               pmode = promote_function_mode (type, mode, &unsignedp,
+                                              gimple_call_fntype (stmt),
+                                              2);
+             else
+               pmode = promote_ssa_mode (ssa_name, &unsignedp);
+           }
          gcc_assert (GET_MODE (decl_rtl) == pmode);
 
          temp = gen_lowpart_SUBREG (mode, decl_rtl);
diff --git a/gcc/testsuite/gcc.target/arm/pr67714.c 
b/gcc/testsuite/gcc.target/arm/pr67714.c
index e69de29..355b559 100644
--- a/gcc/testsuite/gcc.target/arm/pr67714.c
+++ b/gcc/testsuite/gcc.target/arm/pr67714.c
@@ -0,0 +1,26 @@
+
+/* PR target/67714 */
+/* { dg-do-run } */
+/* { dg-options "-O1" } */
+
+unsigned int b;
+int c;
+
+signed char fn1 ()
+{
+  signed char d;
+  for (int i = 0; i < 1; i++)
+    d = -15;
+  return d;
+}
+
+int main()
+{
+  for (c = 0; c < 1; c++)
+    b = 0;
+  char e = fn1();
+  signed char f = e ^ b;
+  __builtin_printf("checksum = %x\n", (int)f);
+  if ((int)f != 0xfffffff1)
+    __builtin_abort ();
+}

Reply via email to