As of svn r16432 on mcs51, constants/literals can have the smallest type of int. When doing computations where one of the operands is an 8-bit type it always first promotes the operand to 16-bit, which is not necessary.
Most obvious example is the usage of mcs51's multiplication instruction (or lack there of):
int test_02 (unsigned char x)
{
return x * 5;
}
=>
mov r7, dpl
mov r6,#0x00
push ar7
push ar6
mov dptr,#0x0005
lcall __mulint
mov r6, dpl
mov r7, dph
dec sp
dec sp
mov dpl, r6
mov dph, r7
ret
int test_06 (unsigned char x)
{
return x * (char)5;
}
=>
mov a,dpl
mov b,#0x05
mul ab
mov r7,a
mov r6,b
mov dpl, r7
mov dph, r6
ret
So when the constant would fit into a smaller type than the standard int, it could do that automatically.
Not sure if this ought to be handled by each backend on a case-by-case basis or whether it can be a generic optimization.
Generic optimization based on generalized constant propagation, I'd say. In the front-end, we need that int, since too many things break otherwise. But later, we should narrow it (e.g. after checking that the operands are in the 0 to 255 range, and that the backend does have an unsigned 8x8->16 multiplication). Interestingly, for your example we do get okayish code for z180, but currently not mcs51 and stm8.