]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
i386: Handle sign_extend like zero_extend in *concatditi3_[346]
authorRoger Sayle <roger@nextmovesoftware.com>
Fri, 28 Jun 2024 06:16:07 +0000 (07:16 +0100)
committerRoger Sayle <roger@nextmovesoftware.com>
Fri, 28 Jun 2024 06:16:07 +0000 (07:16 +0100)
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.

gcc/config/i386/i386.md
gcc/testsuite/gcc.target/i386/concatditi-1.c [new file with mode: 0644]

index fd48e76446951614dcaaaa3b97d7b43072352870..b6ccb1e798d2858d9f8fbde210d9b7087baa617a 100644 (file)
   [(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>
          (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"
   [(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 (file)
index 0000000..25c2a95
--- /dev/null
@@ -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" } } */