I've added a new define_expand for msp430 to handle "mulhisi", but when testing
the changes, some builtin tests (e.g. builtin-arith-overflow-{1,5,p-1}.c) fail.
I've narrowed a test case down to:
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
This is clearly a very simple instruction that should be handled by "movhi":
(define_insn "movhi"
[(set (match_operand:HI 0 "msp_nonimmediate_operand" "=r,rYs,rm")
(match_operand:HI 1 "msp_general_operand" "N,riYs,rmi"))]
"msp_general_operand" is an ior of general_operand and a volatile memory
operand.
When debugging this I noticed that "general_operand" is returning 0 for
(const_int 65535 [0xffff]), i.e. it has not validated this operand:
> Breakpoint 3, general_operand (op=op@entry=0x7ffff7309740,
> mode=mode@entry=E_HImode) at ../../gcc/recog.c:959 959 {
> (gdb) call debug_rtx(op)
> (const_int 65535 [0xffff])
> Run till exit from #0 0x0000000000b56da4 in general_operand
> (op=op@entry=0x7ffff7309740, mode=<optimised out>, mode@entry=E_HImode) at
> ../../gcc/recog.c:974
> 0x0000000001194400 in msp430_general_operand (op=0x7ffff7309740,
> mode=mode@entry=E_HImode) at ../../gcc/config/msp430/predicates.md:37
> 37 ; general_operand refuses to match volatile memory refs.
> Value returned is $3 = 0
trunc_int_for_mode changes 65535 to -1, which I think is the cause of the
problem:
> Run till exit from #0 trunc_int_for_mode (c=65535, mode=mode@entry=E_HImode)
> at ../../gcc/explow.c:55
> 0x0000000000b56da4 in general_operand (op=op@entry=0x7ffff7309740,
> mode=<optimised out>, mode@entry=E_HImode) at ../../gcc/recog.c:974
> 974 && trunc_int_for_mode (INTVAL (op), mode) != INTVAL (op))
> Value returned is $2 = -1
So this results in the following clause evaluating to true and general_operand
returning 0:
if (CONST_INT_P (op)
&& mode != VOIDmode
&& trunc_int_for_mode (INTVAL (op), mode) != INTVAL (op))
return 0;
I haven't narrowed down where the (const_int 65535) is being generated. I
suspect if MODE was VOIDmode we wouldn't have this problem.
I've noticed that normally a constant like would normally show as (const_int
-1).
I guess the bug is wherever the (const_int 65535) is generated, it should be -1
sign extend to a HWI. That is based on this statement from the docs:
Constants generated for modes with fewer bits than in HOST_WIDE_INT must be
sign extended to full width (e.g., with gen_int_mode). For constants for modes
with more bits than in HOST_WIDE_INT the implied high order bits of that con-
stant are copies of the top bit. Note however that values are neither inherently
signed nor inherently unsigned; where necessary, signedness is determined by
the rtl operation instead.
Can anyone offer any further insight? Do I just need to track down what is
generating this const_int and fix that?
Could it be some edge-case interaction because it is an argument to a builtin?
Thanks,
Jozef