Skip to content
Snippets Groups Projects
user avatar
Roger Sayle authored
This patch improves the code generated for DImode right shifts (both
arithmetic and logical) by a single bit, and also for DImode rotates
(both left and right) by a single bit.  In approach, this is similar
to the recently added DImode left shift by a single bit patch, but
also builds upon the x86's UNSPEC carry flag representation:
https://gcc.gnu.org/pipermail/gcc-patches/2023-October/632169.html

The benefits can be seen from the four new test cases:

long long ashr(long long x) { return x >> 1; }

Before:
ashr:   asl     r2,r1,31
        lsr_s   r0,r0
        or_s    r0,r0,r2
        j_s.d   [blink]
        asr_s   r1,r1,1

After:
ashr:   asr.f   r1,r1
        j_s.d   [blink]
        rrc     r0,r0

unsigned long long lshr(unsigned long long x) { return x >> 1; }

Before:
lshr:   asl     r2,r1,31
        lsr_s   r0,r0
        or_s    r0,r0,r2
        j_s.d   [blink]
        lsr_s   r1,r1

After:
lshr:	lsr.f   r1,r1
        j_s.d   [blink]
        rrc     r0,r0

unsigned long long rotl(unsigned long long x) { return (x<<1) | (x>>63); }

Before:
rotl:   lsr     r12,r1,31
        lsr     r2,r0,31
        asl_s   r3,r0,1
        asl_s   r1,r1,1
        or      r0,r12,r3
        j_s.d   [blink]
        or_s    r1,r1,r2

After:
rotl:   add.f   r0,r0,r0
        adc.f   r1,r1,r1
        j_s.d   [blink]
        add.cs  r0,r0,1

unsigned long long rotr(unsigned long long x) { return (x>>1) | (x<<63); }

Before:
rotr:   asl     r12,r1,31
        asl     r2,r0,31
        lsr_s   r3,r0
        lsr_s   r1,r1
        or      r0,r12,r3
        j_s.d   [blink]
        or_s    r1,r1,r2

After:
rotr:   asr.f   0,r0
        rrc.f   r1,r1
        j_s.d   [blink]
        rrc     r0,r0

On CPUs without a barrel shifter the improvements are even better.

2023-11-13  Roger Sayle  <roger@nextmovesoftware.com>

gcc/ChangeLog
	* config/arc/arc.md (UNSPEC_ARC_CC_NEZ): New UNSPEC that
	represents the carry flag being set if the operand is non-zero.
	(adc_f): New define_insn representing adc with updated flags.
	(ashrdi3): New define_expand that only handles shifts by 1.
	(ashrdi3_cnt1): New pre-reload define_insn_and_split.
	(lshrdi3): New define_expand that only handles shifts by 1.
	(lshrdi3_cnt1): New pre-reload define_insn_and_split.
	(rrcsi2): New define_insn for rrc (SImode rotate right through carry).
	(rrcsi2_carry): Likewise for rrc.f, as above but updating flags.
	(rotldi3): New define_expand that only handles rotates by 1.
	(rotldi3_cnt1): New pre-reload define_insn_and_split.
	(rotrdi3): New define_expand that only handles rotates by 1.
	(rotrdi3_cnt1): New pre-reload define_insn_and_split.
	(lshrsi3_cnt1_carry): New define_insn for lsr.f.
	(ashrsi3_cnt1_carry): New define_insn for asr.f.
	(btst_0_carry): New define_insn for asr.f without result.

gcc/testsuite/ChangeLog
	* gcc.target/arc/ashrdi3-1.c: New test case.
	* gcc.target/arc/lshrdi3-1.c: Likewise.
	* gcc.target/arc/rotldi3-1.c: Likewise.
	* gcc.target/arc/rotrdi3-1.c: Likewise.
b51bfee1
History
Name Last commit Last update