Hi! In the PR57251 fixes, I've messed up the modes, convert_modes first argument is the to mode and second argument is the from mode, i.e. mode the third argument has or is assumed to have.
The following patch fixes that. Additionally I've swapped two conditions to avoid first convert_modes a CONST_INT to one mode and then convert_modes it again from the old mode rather than new one. With the two conditions swapped it uses just one convert_modes for that case. Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2018-12-21 Jakub Jelinek <ja...@redhat.com> PR rtl-optimization/88563 * expr.c (expand_expr_real_2) <case WIDEN_MULT_EXPR>: Swap innermode and mode arguments to convert_modes. Likewise swap mode and word_mode arguments. Handle both arguments with VOIDmode before convert_modes of one of them. Formatting fixes. * gcc.dg/pr88563.c: New test. --- gcc/expr.c.jj 2018-12-18 12:20:53.511482381 +0100 +++ gcc/expr.c 2018-12-21 11:57:25.523576071 +0100 @@ -8775,8 +8775,8 @@ expand_expr_real_2 (sepops ops, rtx targ != INTEGER_CST check. Handle it. */ if (GET_MODE (op0) == VOIDmode && GET_MODE (op1) == VOIDmode) { - op0 = convert_modes (innermode, mode, op0, true); - op1 = convert_modes (innermode, mode, op1, false); + op0 = convert_modes (mode, innermode, op0, true); + op1 = convert_modes (mode, innermode, op1, false); return REDUCE_BIT_FIELD (expand_mult (mode, op0, op1, target, unsignedp)); } @@ -8798,7 +8798,7 @@ expand_expr_real_2 (sepops ops, rtx targ if (TREE_CODE (treeop0) != INTEGER_CST) { if (find_widening_optab_handler (this_optab, mode, innermode) - != CODE_FOR_nothing) + != CODE_FOR_nothing) { expand_operands (treeop0, treeop1, NULL_RTX, &op0, &op1, EXPAND_NORMAL); @@ -8807,9 +8807,9 @@ expand_expr_real_2 (sepops ops, rtx targ if (GET_MODE (op0) == VOIDmode && GET_MODE (op1) == VOIDmode) { widen_mult_const: - op0 = convert_modes (innermode, mode, op0, zextend_p); + op0 = convert_modes (mode, innermode, op0, zextend_p); op1 - = convert_modes (innermode, mode, op1, + = convert_modes (mode, innermode, op1, TYPE_UNSIGNED (TREE_TYPE (treeop1))); return REDUCE_BIT_FIELD (expand_mult (mode, op0, op1, target, @@ -8820,21 +8820,19 @@ expand_expr_real_2 (sepops ops, rtx targ return REDUCE_BIT_FIELD (temp); } if (find_widening_optab_handler (other_optab, mode, innermode) - != CODE_FOR_nothing + != CODE_FOR_nothing && innermode == word_mode) { rtx htem, hipart; op0 = expand_normal (treeop0); - if (TREE_CODE (treeop1) == INTEGER_CST) - op1 = convert_modes (word_mode, mode, - expand_normal (treeop1), - TYPE_UNSIGNED (TREE_TYPE (treeop1))); - else - op1 = expand_normal (treeop1); - /* op0 and op1 might still be constant, despite the above + op1 = expand_normal (treeop1); + /* op0 and op1 might be constants, despite the above != INTEGER_CST check. Handle it. */ if (GET_MODE (op0) == VOIDmode && GET_MODE (op1) == VOIDmode) goto widen_mult_const; + if (TREE_CODE (treeop1) == INTEGER_CST) + op1 = convert_modes (mode, word_mode, op1, + TYPE_UNSIGNED (TREE_TYPE (treeop1))); temp = expand_binop (mode, other_optab, op0, op1, target, unsignedp, OPTAB_LIB_WIDEN); hipart = gen_highpart (word_mode, temp); --- gcc/testsuite/gcc.dg/pr88563.c.jj 2018-12-21 12:19:02.850681604 +0100 +++ gcc/testsuite/gcc.dg/pr88563.c 2018-12-21 12:18:52.891841942 +0100 @@ -0,0 +1,15 @@ +/* PR rtl-optimization/88563 */ +/* { dg-do run { target int128 } } */ +/* { dg-options "-O2 -fno-code-hoisting -fno-tree-ccp -fno-tree-dominator-opts -fno-tree-forwprop -fno-tree-fre -fno-tree-pre -fno-tree-vrp" } */ + +int +main () +{ +#if __SIZEOF_LONG_LONG__ == 8 && __SIZEOF_INT128__ == 16 && __CHAR_BIT__ == 8 + unsigned __int128 a = 5; + __builtin_mul_overflow (0xffffffffffffffffULL, (unsigned long long) a, &a); + if (a != ((unsigned __int128)4 << 64 | 0xfffffffffffffffb)) + __builtin_abort (); +#endif + return 0; +} Jakub