I experienced the following ICE when working on a downstream patch for msp430:
void foo (unsigned int r, unsigned int y) { __builtin_umul_overflow ((unsigned int) (-1), y, &r); } > msp430-elf-gcc -S tester.c -O0 tester.c: In function 'foo': tester.c:4:1: error: unrecognizable insn: 4 | } | ^ (insn 16 15 17 2 (set (reg:HI 32) (const_int 65535 [0xffff])) "tester.c":3:3 -1 (nil)) during RTL pass: vregs dump file: tester.c.234r.vregs tester.c:4:1: internal compiler error: in extract_insn, at recog.c:2311 Following discussions on ml/gcc (https://gcc.gnu.org/ml/gcc/2019-10/msg00083.html), I narrowed this down to a call to expand_mult_highpart_adjust in expand_expr_real_2. If one of the operands is a constant, its mode had been converted to the wide mode of our multiplication to generate some RTL, but not converted back to the narrow mode before expanding what will be the high part of the result of the multiplication. If we look at the other two uses of expand_mult_highpart_adjust in the sources, (both in expmed.c (expmed_mult_highpart_optab)) we can see that the narrow version of the constant is always used: if (tem) /* We used the wrong signedness. Adjust the result. */ return expand_mult_highpart_adjust (mode, tem, op0, narrow_op1, tem, unsignedp); So the attached patch updates the use in expand_expr_real_2 to also use the narrow version of the constant operand. This fixes the aforementioned ICE. Successfully bootstrapped and regtested for x86_64-pc-linux-gnu. Successfully regtested for msp430-elf. Ok for trunk?
>From b430cddbd257353f162fe3968a447b63cbcaa964 Mon Sep 17 00:00:00 2001 From: Jozef Lawrynowicz <joze...@mittosystems.com> Date: Thu, 17 Oct 2019 18:22:01 +0100 Subject: [PATCH] Use narrow mode of constant when expanding widening multiplication gcc/ChangeLog: 2019-10-18 Jozef Lawrynowicz <joze...@mittosystems.com> * expr.c (expand_expr_real_2): Use op1 in its original narrow mode when calling expand_mult_highpart_adjust. --- gcc/expr.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/gcc/expr.c b/gcc/expr.c index b54bf1d3dc5..0a571d3f7e3 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -8947,9 +8947,12 @@ expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode, != CODE_FOR_nothing && innermode == word_mode) { - rtx htem, hipart; + rtx htem, hipart, narrow_op1; op0 = expand_normal (treeop0); op1 = expand_normal (treeop1); + /* Save op1 in the narrower mode WORD_MODE for when we expand + the high part. */ + narrow_op1 = op1; /* op0 and op1 might be constants, despite the above != INTEGER_CST check. Handle it. */ if (GET_MODE (op0) == VOIDmode && GET_MODE (op1) == VOIDmode) @@ -8961,7 +8964,7 @@ expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode, unsignedp, OPTAB_LIB_WIDEN); hipart = gen_highpart (word_mode, temp); htem = expand_mult_highpart_adjust (word_mode, hipart, - op0, op1, hipart, + op0, narrow_op1, hipart, zextend_p); if (htem != hipart) emit_move_insn (hipart, htem); -- 2.17.1