[Bug middle-end/122871] [13/14/15/16/17 Regression] de-optimized synthesis of long long shift and add
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=122871
--- Comment #17 from GCC Commits ---
The master branch has been updated by Roger Sayle :
https://gcc.gnu.org/g:373e2c30b1710e271664cf95fcfb66fea7dd15ed
commit r17-1373-g373e2c30b1710e271664cf95fcfb66fea7dd15ed
Author: Roger Sayle
Date: Fri Jun 5 14:53:27 2026 +0100
PR target/56102: Improve rtx_costs from -mthumb on ARM.
This patch provides improved (more accurate) RTX costs for -mthumb on ARM.
My recent patch for double word multiplication, PR 122871, revealed that
the current costs for THUMB code on ARM are... let's say a little dubious.
To demonstrate the code generation improvements provided by better
thumb1_rtx_costs consider the function below (from PR middle-end/122871).
long long foo (long long a)
{
long long c = a << 33;
c += a;
return c;
}
With the ARM backend's current costs, this produces 11 instructions with
-O2 -mthumb.
Before: movsr3, r0
movsr2, #0
addsr2, r2, r0
adcsr3, r3, r1
addsr2, r2, r2
adcsr3, r3, r3
subsr2, r2, r0
sbcsr3, r3, r1
movsr0, r2
movsr1, r3
bx lr
With sane RTX costs, GCC now generate the much more reasonable 5 insns:
After: movsr2, #0
lslsr3, r0, #1
addsr0, r0, r2
adcsr1, r1, r3
bx lr
2026-06-05 Roger Sayle
Richard Earnshaw
gcc/ChangeLog
PR target/56102
PR middle-end/122871
* config/arm/arm.cc (thumb1_rtx_costs): Provide reasonable costs
for PLUS, MINUS, COMPARE, AND, XOR, IOR, NEG, NOT, ASHIFT,
ASHIFTRT and ROTATERT for SImode, DImode, HImode and QImode.
(thumb1_size_rtx_costs): Likewise.
(comp_not_to_clear_mask_str_un): Silence host compiler warning.
[Bug middle-end/122871] [13/14/15/16/17 Regression] de-optimized synthesis of long long shift and add
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=122871 --- Comment #16 from Roger Sayle --- The slightly unusual results from synth_mult on ARM with -mthumb are due to incorrect values being returned by rtx_costs. DImode addition and subtraction should both be COSTS_N_INSNS(2), i.e. adds+adcs and subs+sbcs respectively, but currently return COSTS_N_INSNS(1).
[Bug middle-end/122871] [13/14/15/16/17 Regression] de-optimized synthesis of long long shift and add
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=122871 --- Comment #15 from GCC Commits --- The master branch has been updated by Roger Sayle : https://gcc.gnu.org/g:08d8760c3d97a329f543aec19b0d465b24fd42ea commit r17-493-g08d8760c3d97a329f543aec19b0d465b24fd42ea Author: Roger Sayle Date: Wed May 13 12:23:41 2026 +0100 testsuite: Skip new test case gcc.target/arm/muldi-1.c with -mthumb The recent test to confirm PR middle-end/122871 is resolved on ARM, wasn't expecting -mthumb. This adds a requires-effective-target. Committed as obvious. 2026-05-13 Roger Sayle Richard Earnshaw gcc/testsuite/ChangeLog PR middle-end/122871 * gcc.target/arm/muldi-1.c: Skip test if compiled with -mthumb.
[Bug middle-end/122871] [13/14/15/16/17 Regression] de-optimized synthesis of long long shift and add
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=122871 --- Comment #14 from Richard Earnshaw --- We don't normally split double-word operations because the thumb1 port cannot expose the Carry flag (most operations clobber the PSR, so it unsafe to do so until after register allocation; we have very limited support for post-regalloc as well). I think this confirms that we will need a separate test for thumb1 and a separate ticket to see if code can be further improved there.
[Bug middle-end/122871] [13/14/15/16/17 Regression] de-optimized synthesis of long long shift and add
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=122871 --- Comment #13 from Roger Sayle --- This patch does indeed help thumb1, reducing the number of -mthumb instructions for muldi-1.c from 23 before the patch, to only 10 after. As Richard Earnshaw points out this should ideally be around 3, if suitably optimized by the backend. As shown in Torbjorn's comment (#11) the current thumb code loads zero into a register r2, and then uses it in an addition!? I suspect the thumb backend isn't using splitters to decompose double word operations before or after reload.
[Bug middle-end/122871] [13/14/15/16/17 Regression] de-optimized synthesis of long long shift and add
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=122871
--- Comment #12 from Richard Earnshaw ---
(In reply to Torbjorn SVENSSON from comment #11)
> The new test case fail for Cortex-M0 and Cortex-M23. Is this a thumb2-only
> improvement?
In principle the optimization is valid for thumb1 cores, but since we lack
shift+add patterns there, we should end up with something like
lsls r2, r0, #1
adds r1, r1, r2
bx lr
That's still much better than the sequence using adc(s), but obviously not
quite as simple as a single shift+add pattern.
And obviously this won't match the expected output in the current testcase.
The current test should probably add
/* { dg-require-effective-target arm32 } */
And then create a separate test for thumb1 targets.
If the thumb1 code generator isn't generating something like the above sequence
we should create a new PR for that as it's likely a costing issue in the
backend.
[Bug middle-end/122871] [13/14/15/16/17 Regression] de-optimized synthesis of long long shift and add
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=122871
Torbjorn SVENSSON changed:
What|Removed |Added
CC||azoff at gcc dot gnu.org
--- Comment #11 from Torbjorn SVENSSON ---
(In reply to GCC Commits from comment #10)
> The master branch has been updated by Roger Sayle :
>
> https://gcc.gnu.org/g:1a06a37611e3b27889c595a17df13f6d27202a95
>
> commit r17-383-g1a06a37611e3b27889c595a17df13f6d27202a95
> Author: Roger Sayle
> Date: Thu May 7 18:46:37 2026 +0100
>
> PR middle-end/122871: Doubleword multiplication improvements
>
> This patch resolves PR middle-end/122871 by improving RTL expansion of
> doubleword multiplications. The main change is to synth_mult adding
> support for the case where the constant being multiplied has
> BITS_PER_WORD
> or more trailing zeros. The shift_cost tables in expmed are only
> parameterized for shifts less than BITS_PER_WORD, so doubleword shifts
> by more than this can't use the usual code path. This patch teaches
> synth_mult that for scalar doubleword multiplications, a doubleword shift
> by more than BITS_PER_WORD typically requires two instructions; one to
> set the result lowpart to zero, and the other a wordmode shift to
> calculate the result highpart.
>
> For the testcase given in the PR:
>
> long long ashll_fn (long long a)
> {
> long long c;
>
> c = a << 33;
> c += a;
> return c;
> }
>
> GCC for arm-linux-gnueabihf currently generates with -O2:
>
> ashll_fn:
> lsl r2, r1, #11
> lsl ip, r0, #11
> subsip, ip, r0
> orr r2, r2, r0, lsr #21
> sbc r2, r2, r1
> lsl r3, ip, #11
> lsl r2, r2, #11
> addsr3, r3, r0
> orr r2, r2, ip, lsr #21
> adc r1, r1, r2
> lsl r2, r1, #11
> lsl r0, r3, #11
> addsr0, r3, r0
> orr r2, r2, r3, lsr #21
> adc r1, r1, r2
> bx lr
>
> with this patch, we instead generate:
>
> ashll_fn:
> add r1, r1, r0, lsl #1
> bx lr
>
> Additionally, this patch includes a clean-up (identified by A. Pinski)
> to prevent RTL expansion of doubleword multiplications from
> initially emitting multiply instructions by immediate constants 0, 1
> or 2. These dubious multiplications eventually get tidied up by later
> RTL optimization passes, but being sensible during RTL expansion
> both speeds up the compiler and reduces unnecessary memory usage.
>
> 2026-05-07 Roger Sayle
>
> gcc/ChangeLog
> PR middle-end/122871
> * expmed.cc (synth_mult): Handle doubleword left shifts by
> BITS_PER_WORD bits or more, for scalar modes.
> * optabs.cc (expand_doubleword_mult): Avoid generating multiply
> instructions by immediate constants 0, 1 or 2.
>
> gcc/testsuite/ChangeLog
> PR middle-end/122871
> * gcc.target/arm/muldi-1.c: New test case.
The new test case fail for Cortex-M0 and Cortex-M23. Is this a thumb2-only
improvement?
For Cortex-M0, I get:
$ /build/r17-409-g8376a674e3564f/bin/arm-none-eabi-gcc
/build/gcc_src/gcc/testsuite/gcc.target/arm/muldi-1.c -mthumb -march=armv6s-m
-mtune=cortex-m0 -mfloat-abi=soft -mfpu=auto -fdiagnostics-plain-output -O2
-ffat-lto-objects -fno-ident -S -o - -dP
.arch armv6s-m
.fpu softvfp
.eabi_attribute 20, 1
.eabi_attribute 21, 1
.eabi_attribute 23, 3
.eabi_attribute 24, 1
.eabi_attribute 25, 1
.eabi_attribute 26, 1
.eabi_attribute 30, 2
.eabi_attribute 34, 0
.eabi_attribute 18, 4
.file "muldi-1.c"
.text
.align 1
.p2align 2,,3
.global ashll_fn
.syntax unified
.code 16
.thumb_func
.type ashll_fn, %function
ashll_fn:
@ args = 0, pretend = 0, frame = 0
@ frame_needed = 0, uses_anonymous_args = 0
@ link register save eliminated.
@(insn 23 3 38 (set (reg:SI 3 r3 [ a+4 ])
@(reg:SI 0 r0 [orig:107 a ] [107]))
"/build/gcc_src/gcc/testsuite/gcc.target/arm/muldi-1.c":9:5 743
{*thumb1_movsi_insn}
@ (nil))
@ 0x
movsr3, r0 @ 23[c=4 l=2] *thumb1_movsi_insn/0
@(insn 32 38 22 (unspec:SI [
@(reg/f:SI 13 sp)
@] UNSPEC_REGISTER_USE)
"/build/gcc_src/gcc/testsuite/gcc.target/arm/muldi-1.c":11:1 403
{force_register_use}
@ (nil))
@ 0x0002
@ sp needed @ 32[c=8 l=0] force_register_use
@(insn 22 32 11 (set (reg:SI 2 r2 [orig:99 a ] [99])
@(const_int 0 [0]))
[Bug middle-end/122871] [13/14/15/16/17 Regression] de-optimized synthesis of long long shift and add
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=122871
--- Comment #10 from GCC Commits ---
The master branch has been updated by Roger Sayle :
https://gcc.gnu.org/g:1a06a37611e3b27889c595a17df13f6d27202a95
commit r17-383-g1a06a37611e3b27889c595a17df13f6d27202a95
Author: Roger Sayle
Date: Thu May 7 18:46:37 2026 +0100
PR middle-end/122871: Doubleword multiplication improvements
This patch resolves PR middle-end/122871 by improving RTL expansion of
doubleword multiplications. The main change is to synth_mult adding
support for the case where the constant being multiplied has BITS_PER_WORD
or more trailing zeros. The shift_cost tables in expmed are only
parameterized for shifts less than BITS_PER_WORD, so doubleword shifts
by more than this can't use the usual code path. This patch teaches
synth_mult that for scalar doubleword multiplications, a doubleword shift
by more than BITS_PER_WORD typically requires two instructions; one to
set the result lowpart to zero, and the other a wordmode shift to
calculate the result highpart.
For the testcase given in the PR:
long long ashll_fn (long long a)
{
long long c;
c = a << 33;
c += a;
return c;
}
GCC for arm-linux-gnueabihf currently generates with -O2:
ashll_fn:
lsl r2, r1, #11
lsl ip, r0, #11
subsip, ip, r0
orr r2, r2, r0, lsr #21
sbc r2, r2, r1
lsl r3, ip, #11
lsl r2, r2, #11
addsr3, r3, r0
orr r2, r2, ip, lsr #21
adc r1, r1, r2
lsl r2, r1, #11
lsl r0, r3, #11
addsr0, r3, r0
orr r2, r2, r3, lsr #21
adc r1, r1, r2
bx lr
with this patch, we instead generate:
ashll_fn:
add r1, r1, r0, lsl #1
bx lr
Additionally, this patch includes a clean-up (identified by A. Pinski)
to prevent RTL expansion of doubleword multiplications from
initially emitting multiply instructions by immediate constants 0, 1
or 2. These dubious multiplications eventually get tidied up by later
RTL optimization passes, but being sensible during RTL expansion
both speeds up the compiler and reduces unnecessary memory usage.
2026-05-07 Roger Sayle
gcc/ChangeLog
PR middle-end/122871
* expmed.cc (synth_mult): Handle doubleword left shifts by
BITS_PER_WORD bits or more, for scalar modes.
* optabs.cc (expand_doubleword_mult): Avoid generating multiply
instructions by immediate constants 0, 1 or 2.
gcc/testsuite/ChangeLog
PR middle-end/122871
* gcc.target/arm/muldi-1.c: New test case.
