For the following testcase (compiling with -O1; -O2 works fine), we have a stmt with stm_code SSA_NAME (_7 = _ 6) and for which _6 is defined by a GIMPLE_CALL. In this case, we are using wrong SUNREG promoted mode resulting in wrong code. Simple SSA_NAME copes are generally optimized but when they are not, we can end up using the wrong promoted mode. Attached patch fixes when we have one copy. I think it might be better to do this in a while loop but I don't think it can happen in practice. Please let me know what you think.
_6 = bar5 (-10); ... _7 = _6; _3 = (long unsigned int) _6; ... if (_3 != l5.0_4) for extern void abort (void); __attribute__ ((noinline)) static unsigned short int foo5 (int x) { return x; } __attribute__ ((noinline)) short int bar5 (int x) { return foo5 (x + 6); } unsigned long l5 = (short int) -4; int main (void) { if (bar5 (-10) != l5) abort (); return 0; } gcc/ChangeLog: 2015-09-07 Kugan Vivekanandarajah <kug...@linaro.org> * expr.c (expand_expr_real_1): Set proper SUNREG_PROMOTED_MODE for SSA_NAME that was set by GIMPLE_CALL and assigned to another SSA_NAME of same type.
>From 64ac68bfda1d3e8487827512e6d163b384e8a1cf Mon Sep 17 00:00:00 2001 From: Kugan Vivekanandarajah <kugan.vivekanandara...@linaro.org> Date: Wed, 2 Sep 2015 12:18:41 +1000 Subject: [PATCH 4/8] use correct promoted sign for result of GIMPLE_CALL --- gcc/expr.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/gcc/expr.c b/gcc/expr.c index bcd87c0..6dac3cf 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -9633,7 +9633,22 @@ 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; + 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); -- 1.9.1