GCC Bugzilla – Bug 34522
inefficient code for long long multiply when only low bits are needed
Last modified: 2008-03-12 15:34:15 UTC
int test(long long a, long long b)
return a * b;
GCC generates a widening multiply, and cannot remove the DImode operations until after register allocation. This causes unnecessary splits.
This could be fixed on the tree level by folding to (int)a * (int)b, or alternatively in expand.
expand_expr is called with
type <integer_type 0x2aaaae937840 long long int DI>
arg 0 <parm_decl 0x2aaaae92d2d0 b type <integer_type 0x2aaaae937840 long
arg 1 <parm_decl 0x2aaaae92d240 a type <integer_type 0x2aaaae937840 long
and tmode SImode, still enough info to choose a better multiply. However, tmode is not passed on to expand_mult.
Prototype untested patch. Produces
movl 12(%esp), %eax
imull 4(%esp), %eax
on the testcase.
--- expr.c (revision 130928)
+++ expr.c (working copy)
@@ -8642,7 +8642,8 @@ expand_expr_real_1 (tree exp, rtx target
expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
subtarget, &op0, &op1, 0);
- return REDUCE_BIT_FIELD (expand_mult (mode, op0, op1, target, unsignedp));
+ return REDUCE_BIT_FIELD (expand_mult (tmode != VOIDmode ? tmode : mode,
+ op0, op1, target, unsignedp));
Shouldn't tmode be only used if GET_MODE_CLASS (tmode) == MODE_INT
&& GET_MODE_CLASS (mode) == MODE_INT && GET_MODE_BITSIZE (tmode) < GET_MODE_BITSIZE (mode), to make sure we optimize only narrow, never widen, and
that float etc. multiplication is not affected?
Makes a lot of sense. I made the patch only to test that it would not crash, or something like that.
(In reply to comment #1)
> Prototype untested patch. Produces
Paolo, do you plan to test your patch and submit it to gcc-patches@ ?
I want to clear 17236 first (and Jakub's tweaks are needed anyway).
Feel free to beat me to it.
The expand patch does not bootstrap, even with the tweaks Jakub suggested.
I'm also hesitant to fold it on the tree level because it's actually undefined code unless -fwrapv. For example if a = b = 65536LL,
(int) a * (int) b = undefined
(int) (a * b) = (int) (1LL << 32) = 0
Hmm maybe I can go through an unsigned type.
fixed in 4.4