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 ();
+}