[gcc r15-1702] i386: Handle sign_extend like zero_extend in *concatditi3_[346]

Roger Sayle sayle@gcc.gnu.org
Fri Jun 28 06:17:00 GMT 2024


https://gcc.gnu.org/g:07e915913b6b3d4e6e210f6dbc8e7e0e8ea594c4

commit r15-1702-g07e915913b6b3d4e6e210f6dbc8e7e0e8ea594c4
Author: Roger Sayle <roger@nextmovesoftware.com>
Date:   Fri Jun 28 07:16:07 2024 +0100

    i386: Handle sign_extend like zero_extend in *concatditi3_[346]
    
    This patch generalizes some of the patterns in i386.md that recognize
    double word concatenation, so they handle sign_extend the same way that
    they handle zero_extend in appropriate contexts.
    
    As a motivating example consider the following function:
    
    __int128 foo(long long x, unsigned long long y)
    {
      return ((__int128)x<<64) | y;
    }
    
    when compiled with -O2, x86_64 currently generates:
    
    foo:    movq    %rdi, %rdx
            xorl    %eax, %eax
            xorl    %edi, %edi
            orq     %rsi, %rax
            orq     %rdi, %rdx
            ret
    
    with this patch we now generate (the same as if x is unsigned):
    
    foo:    movq    %rsi, %rax
            movq    %rdi, %rdx
            ret
    
    Treating both extensions the same way using any_extend is valid as
    the top (extended) bits are "unused" after the shift by 64 (or more).
    In theory, the RTL optimizers might consider canonicalizing the form
    of extension used in these cases, but zero_extend is faster on some
    machine, whereas sign extension is supported via addressing modes on
    others, so handling both in the machine description is probably best.
    
    2024-06-28  Roger Sayle  <roger@nextmovesoftware.com>
    
    gcc/ChangeLog
            * config/i386/i386.md (*concat<mode><dwi>3_3): Change zero_extend
            to any_extend in first operand to left shift by mode precision.
            (*concat<mode><dwi>3_4): Likewise.
            (*concat<mode><dwi>3_6): Likewise.
    
    gcc/testsuite/ChangeLog
            * gcc.target/i386/concatditi-1.c: New test case.

Diff:
---
 gcc/config/i386/i386.md                      |  6 +++---
 gcc/testsuite/gcc.target/i386/concatditi-1.c | 10 ++++++++++
 2 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index fd48e764469..b6ccb1e798d 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -13446,7 +13446,7 @@
   [(set (match_operand:<DWI> 0 "nonimmediate_operand" "=ro,r,r,&r,x")
 	(any_or_plus:<DWI>
 	  (ashift:<DWI>
-	    (zero_extend:<DWI>
+	    (any_extend:<DWI>
 	      (match_operand:DWIH 1 "nonimmediate_operand" "r,m,r,m,x"))
 	    (match_operand:QI 2 "const_int_operand"))
 	  (zero_extend:<DWI>
@@ -13473,7 +13473,7 @@
 	  (zero_extend:<DWI>
 	    (match_operand:DWIH 1 "nonimmediate_operand" "r,m,r,m"))
 	  (ashift:<DWI>
-	    (zero_extend:<DWI>
+	    (any_extend:<DWI>
 	      (match_operand:DWIH 2 "nonimmediate_operand" "r,r,m,m"))
 	    (match_operand:QI 3 "const_int_operand"))))]
   "INTVAL (operands[3]) == <MODE_SIZE> * BITS_PER_UNIT"
@@ -13520,7 +13520,7 @@
   [(set (match_operand:<DWI> 0 "nonimmediate_operand" "=r,o,o,r")
 	(any_or_plus:<DWI>
 	  (ashift:<DWI>
-	    (zero_extend:<DWI>
+	    (any_extend:<DWI>
 	      (match_operand:DWIH 1 "nonimmediate_operand" "r,r,r,m"))
 	    (match_operand:QI 2 "const_int_operand"))
 	  (match_operand:<DWI> 3 "const_scalar_int_operand" "n,n,Wd,n")))]
diff --git a/gcc/testsuite/gcc.target/i386/concatditi-1.c b/gcc/testsuite/gcc.target/i386/concatditi-1.c
new file mode 100644
index 00000000000..25c2a95586b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/concatditi-1.c
@@ -0,0 +1,10 @@
+/* { dg-do compile { target int128 } } */
+/* { dg-options "-O2" } */
+
+__int128 foo(long long x, unsigned long long y)
+{
+  return ((__int128)x<<64) | y;
+}
+
+/* { dg-final { scan-assembler-not "xorl" } } */
+/* { dg-final { scan-assembler-not "orq" } } */


More information about the Gcc-cvs mailing list