[gcc r14-4440] i386: Implement doubleword shift left by 1 bit using add+adc.

Roger Sayle sayle@gcc.gnu.org
Fri Oct 6 19:49:24 GMT 2023


https://gcc.gnu.org/g:ce658accc7beed19341b6847e6f257f08306a96e

commit r14-4440-gce658accc7beed19341b6847e6f257f08306a96e
Author: Roger Sayle <roger@nextmovesoftware.com>
Date:   Fri Oct 6 20:11:44 2023 +0100

    i386: Implement doubleword shift left by 1 bit using add+adc.
    
    This patch tweaks the i386 back-end's ix86_split_ashl to implement
    doubleword left shifts by 1 bit, using an add followed by an add-with-carry
    (i.e. a doubleword x+x) instead of using the x86's shld instruction.
    The replacement sequence both requires fewer bytes and is faster on
    both Intel and AMD architectures (from Agner Fog's latency tables and
    confirmed by my own micro-benchmarking).
    
    For the test case:
    __int128 foo(__int128 x) { return x << 1; }
    
    with -O2 we previously generated:
    
    foo:    movq    %rdi, %rax
            movq    %rsi, %rdx
            shldq   $1, %rdi, %rdx
            addq    %rdi, %rax
            ret
    
    with this patch we now generate:
    
    foo:    movq    %rdi, %rax
            movq    %rsi, %rdx
            addq    %rdi, %rax
            adcq    %rsi, %rdx
            ret
    
    This patch has been tested on x86_64-pc-linux-gnu with make bootstrap
    and make -k check, both with and without --target_board=unix{-m32}
    with no new failures.  Ok for mainline?
    
    2023-10-06  Roger Sayle  <roger@nextmovesoftware.com>
    
    gcc/ChangeLog
            * config/i386/i386-expand.cc (ix86_split_ashl): Split shifts by
            one into add3_cc_overflow_1 followed by add3_carry.
            * config/i386/i386.md (@add<mode>3_cc_overflow_1): Renamed from
            "*add<mode>3_cc_overflow_1" to provide generator function.
    
    gcc/testsuite/ChangeLog
            * gcc.target/i386/ashldi3-2.c: New 32-bit test case.
            * gcc.target/i386/ashlti3-3.c: New 64-bit test case.

Diff:
---
 gcc/config/i386/i386-expand.cc            | 12 ++++++++++++
 gcc/config/i386/i386.md                   |  2 +-
 gcc/testsuite/gcc.target/i386/ashldi3-2.c | 10 ++++++++++
 gcc/testsuite/gcc.target/i386/ashlti3-3.c | 10 ++++++++++
 4 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/gcc/config/i386/i386-expand.cc b/gcc/config/i386/i386-expand.cc
index 9a988347200..425f3531862 100644
--- a/gcc/config/i386/i386-expand.cc
+++ b/gcc/config/i386/i386-expand.cc
@@ -6342,6 +6342,18 @@ ix86_split_ashl (rtx *operands, rtx scratch, machine_mode mode)
 	  if (count > half_width)
 	    ix86_expand_ashl_const (high[0], count - half_width, mode);
 	}
+      else if (count == 1)
+	{
+	  if (!rtx_equal_p (operands[0], operands[1]))
+	    emit_move_insn (operands[0], operands[1]);
+	  rtx x3 = gen_rtx_REG (CCCmode, FLAGS_REG);
+	  rtx x4 = gen_rtx_LTU (mode, x3, const0_rtx);
+	  half_mode = mode == DImode ? SImode : DImode;
+	  emit_insn (gen_add3_cc_overflow_1 (half_mode, low[0],
+					     low[0], low[0]));
+	  emit_insn (gen_add3_carry (half_mode, high[0], high[0], high[0],
+				     x3, x4));
+	}
       else
 	{
 	  gen_shld = mode == DImode ? gen_x86_shld : gen_x86_64_shld;
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index eef8a0e01eb..6a5bc16b21c 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -8864,7 +8864,7 @@
   [(set_attr "type" "alu")
    (set_attr "mode" "<MODE>")])
 
-(define_insn "*add<mode>3_cc_overflow_1"
+(define_insn "@add<mode>3_cc_overflow_1"
   [(set (reg:CCC FLAGS_REG)
 	(compare:CCC
 	    (plus:SWI
diff --git a/gcc/testsuite/gcc.target/i386/ashldi3-2.c b/gcc/testsuite/gcc.target/i386/ashldi3-2.c
new file mode 100644
index 00000000000..053389d1c78
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/ashldi3-2.c
@@ -0,0 +1,10 @@
+/* { dg-do compile { target ia32 } } */
+/* { dg-options "-O2 -mno-stv" } */
+
+long long foo(long long x)
+{
+  return x << 1;
+}
+
+/* { dg-final { scan-assembler "adcl" } } */
+/* { dg-final { scan-assembler-not "shldl" } } */
diff --git a/gcc/testsuite/gcc.target/i386/ashlti3-3.c b/gcc/testsuite/gcc.target/i386/ashlti3-3.c
new file mode 100644
index 00000000000..4f14ca0172b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/ashlti3-3.c
@@ -0,0 +1,10 @@
+/* { dg-do compile { target int128 } } */
+/* { dg-options "-O2" } */
+
+__int128 foo(__int128 x)
+{
+  return x << 1;
+}
+
+/* { dg-final { scan-assembler "adcq" } } */
+/* { dg-final { scan-assembler-not "shldq" } } */


More information about the Gcc-cvs mailing list