Hi! The comment on convert_modes says: Both modes may be floating, or both integer. but as the testcase shows, with a MEM_REF with a different mode class than a VAR_DECL as its operand we can end up with e.g. floating point vs. integral mode etc. and convert_modes doesn't handle those cases.
This patch uses simplify_gen_subreg in those case first. Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk/7.3? 2017-12-30 Jakub Jelinek <ja...@redhat.com> PR middle-end/83608 * expr.c (store_expr_with_bounds): Use simplify_gen_subreg instead of convert_modes if target mode has the right side, but different mode class. * g++.dg/opt/pr83608.C: New test. --- gcc/expr.c.jj 2017-12-30 14:35:52.095877981 +0100 +++ gcc/expr.c 2017-12-30 14:36:06.268882813 +0100 @@ -5638,8 +5638,21 @@ store_expr_with_bounds (tree exp, rtx ta if (CONSTANT_P (temp) && GET_MODE (temp) == VOIDmode && TREE_CODE (exp) != ERROR_MARK && GET_MODE (target) != TYPE_MODE (TREE_TYPE (exp))) - temp = convert_modes (GET_MODE (target), TYPE_MODE (TREE_TYPE (exp)), - temp, TYPE_UNSIGNED (TREE_TYPE (exp))); + { + if (GET_MODE_CLASS (GET_MODE (target)) + != GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (exp))) + && GET_MODE_BITSIZE (GET_MODE (target)) + == GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (exp)))) + { + rtx t = simplify_gen_subreg (GET_MODE (target), temp, + TYPE_MODE (TREE_TYPE (exp)), 0); + if (t) + temp = t; + } + if (GET_MODE (temp) == VOIDmode) + temp = convert_modes (GET_MODE (target), TYPE_MODE (TREE_TYPE (exp)), + temp, TYPE_UNSIGNED (TREE_TYPE (exp))); + } /* If value was not generated in the target, store it there. Convert the value to TARGET's type first if necessary and emit the --- gcc/testsuite/g++.dg/opt/pr83608.C.jj 2017-12-30 14:36:52.323898522 +0100 +++ gcc/testsuite/g++.dg/opt/pr83608.C 2017-12-30 14:00:12.811195532 +0100 @@ -0,0 +1,28 @@ +// PR middle-end/83608 +// { dg-do compile } +// { dg-options "-O2" } + +template <typename> class B; +template <> struct B<float> +{ + float foo () { return __real__ b; } + _Complex double b; +}; + +void bar (int); + +template <class T> +void +baz () +{ + B<T> h; + T *a = (T *) &h; + a[0] = a[1] = 6; + h.foo () ? void () : bar (7); +} + +int +main () +{ + baz<float> (); +} Jakub