https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127028
Bug ID: 127028
Summary: Code bloat due to inline expansion of widening mul
Product: gcc
Version: 17.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: tree-optimization
Assignee: unassigned at gcc dot gnu.org
Reporter: gjl at gcc dot gnu.org
Target Milestone: ---
Inline expansion of widening multiplication is leading to code bloat, for
example on AVR. Many AVR devices have very limited memory constraints,
sometimes only a few KiB of program memory.
As it seems, it is due to recent changes like r17-3443. Here is an example:
typedef __UINT16_TYPE__ uint16_t;
typedef __UINT32_TYPE__ uint32_t;
uint16_t wmul16 (uint16_t x)
{
return ((uint32_t) x * 0xaaab) >> 16;
}
$ avr-gcc x.c -S -Os -dp
wmul16:
push r28 ; 129 [c=4 l=1] pushqi1/0
push r29 ; 130 [c=4 l=1] pushqi1/0
/* stack size = 2 */
mov r26,r24 ; 139 [c=4 l=1] movqi_insn/0
mov r27,r25 ; 140 [c=4 l=1] movqi_insn/0
mov r24,r25 ; 103 [c=4 l=1] movqi_insn/0
ldi r25,0 ; 104 [c=4 l=1] movqi_insn/0
ldi r22,lo8(-85) ; 144 [c=4 l=1] movqi_insn/1
ldi r23,0 ; 145 [c=4 l=1] movqi_insn/0
rcall __mulhi3 ; 106 [c=4 l=1] *mulhi3_call
mov r28,r24 ; 146 [c=4 l=1] movqi_insn/0
mov r29,r25 ; 147 [c=4 l=1] movqi_insn/0
mov r24,r26 ; 148 [c=4 l=1] movqi_insn/0
ldi r25,0 ; 149 [c=4 l=1] movqi_insn/0
ldi r22,lo8(-86) ; 150 [c=4 l=1] movqi_insn/1
ldi r23,0 ; 151 [c=4 l=1] movqi_insn/0
rcall __mulhi3 ; 110 [c=4 l=1] *mulhi3_call
add r24,r28 ; 111 [c=8 l=2] *addhi3/0
adc r25,r29
mov r30,r24 ; 152 [c=4 l=1] movqi_insn/0
mov r31,r25 ; 153 [c=4 l=1] movqi_insn/0
mov r24,r26 ; 154 [c=4 l=1] movqi_insn/0
ldi r25,0 ; 155 [c=4 l=1] movqi_insn/0
ldi r22,lo8(-85) ; 156 [c=4 l=1] movqi_insn/1
ldi r23,0 ; 157 [c=4 l=1] movqi_insn/0
rcall __mulhi3 ; 115 [c=4 l=1] *mulhi3_call
mov r18,r25 ; 116 [c=4 l=1] movqi_insn/0
add r18,r30 ; 117 [c=12 l=3] *usum_widenqihi3
clr r19
rol r19
mov r18,r19 ; 158 [c=4 l=1] movqi_insn/0
ldi r19,0 ; 159 [c=4 l=1] movqi_insn/0
mov r24,r27 ; 119 [c=4 l=1] movqi_insn/0
ldi r25,0 ; 120 [c=4 l=1] movqi_insn/0
ldi r22,lo8(-86) ; 160 [c=4 l=1] movqi_insn/1
ldi r23,0 ; 161 [c=4 l=1] movqi_insn/0
rcall __mulhi3 ; 122 [c=4 l=1] *mulhi3_call
mov r20,r31 ; 162 [c=4 l=1] movqi_insn/0
ldi r21,0 ; 163 [c=4 l=1] movqi_insn/0
add r24,r20 ; 124 [c=8 l=2] *addhi3/0
adc r25,r21
add r18,r24 ; 125 [c=8 l=2] *addhi3/0
adc r19,r25
ldi r20,lo8(1) ; 126 [c=4 l=1] movqi_insn/1
cp r30,r28 ; 127 [c=8 l=2] cmphi3/2
cpc r31,r29
brlo .L2 ; 128 [c=4 l=1] branch
ldi r20,0 ; 99 [c=4 l=1] movqi_insn/0
.L2:
mov r25,r20 ; 97 [c=4 l=1] movqi_insn/0
mov r24,r18 ; 166 [c=4 l=1] movqi_insn/0
add r25,r19 ; 167 [c=4 l=1] *addqi3/0
/* epilogue start */
pop r29 ; 133 [c=4 l=1] popqi
pop r28 ; 134 [c=4 l=1] popqi
ret ; 135 [c=0 l=1] return_from_epilogue
With v16, all is fine:
$ avr-gcc-16 x.c -S -Os -dp
wmul16:
/* stack size = 0 */
mov r18,r24 ; 34 [c=4 l=1] movqi_insn/0
mov r19,r25 ; 35 [c=4 l=1] movqi_insn/0
ldi r20,0 ; 36 [c=4 l=1] movqi_insn/0
ldi r21,0 ; 37 [c=4 l=1] movqi_insn/0
ldi r22,lo8(-85) ; 38 [c=4 l=1] movqi_insn/1
ldi r23,lo8(-86) ; 39 [c=4 l=1] movqi_insn/1
ldi r24,0 ; 40 [c=4 l=1] movqi_insn/0
ldi r25,0 ; 41 [c=4 l=1] movqi_insn/0
rcall __mulsi3 ; 29 [c=16 l=1] *mulsi3_call_pr118012
/* epilogue start */
ret ; 32 [c=0 l=1] return
So the v17 cost extimate is complete moonshine, and the code tries to mimic
stuff like __mulsi3 that libgcc provides as hand-optimized asm.
Using presence / absence of specific insns as a proxy for costs is a blunder.
Just the fact that an insn exists doesn't mean it's cheap. It just means that
providing the insns yiels better code than not providing it.
Target: avr
Configured with: ../../source/gcc-master/configure --target=avr --disable-nls
--with-dwarf2 --with-gnu-as --with-gnu-ld --with-long-double=64
--disable-libcc1 --enable-languages=c,c++
Thread model: single
Supported LTO compression algorithms: zlib
gcc version 17.0.0 20260819 (experimental) (GCC)