]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
Aarch64: Add new memset for Qualcomm's oryon-1 core
authorAndrew Pinski <quic_apinski@quicinc.com>
Wed, 12 Jun 2024 22:53:36 +0000 (15:53 -0700)
committerAndreas K. Hüttel <dilfridge@gentoo.org>
Sun, 30 Jun 2024 11:47:17 +0000 (13:47 +0200)
Qualcom's new core, oryon-1, has a different characteristics for
memset than the current versions of memset. For non-zero, larger
sizes, using GPRs rather than the SIMD stores is ~30% faster.
For even larger sizes, using the nontemporal stores is needed
not to polute the L1/L2 caches.

For zero values, using `dc zva` should be used. Since we
know the size will always be 64 bytes, we don't need to figure
out the size there.

I started with the emag memset and added back the `dc zva` code.

Changes since v1:
* v3: Fix comment formating

Signed-off-by: Andrew Pinski <quic_apinski@quicinc.com>
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
sysdeps/aarch64/multiarch/Makefile
sysdeps/aarch64/multiarch/ifunc-impl-list.c
sysdeps/aarch64/multiarch/memset.c
sysdeps/aarch64/multiarch/memset_oryon1.S [new file with mode: 0644]

index ef5ea9ab8c7bb5b0fa9e249bdecb94dd5c03d397..3e251cc234036abfd520d73ff0fc3349ec96823f 100644 (file)
@@ -15,6 +15,7 @@ sysdep_routines += \
   memset_generic \
   memset_kunpeng \
   memset_mops \
+  memset_oryon1 \
   memset_zva64 \
   strlen_asimd \
   strlen_generic \
index 65c56b9b418b4655afbedca1bf86c5ccad2e0286..b2fda541f9b83242543b11544d3ce7cad57a1ded 100644 (file)
@@ -56,6 +56,7 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
              IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_generic))
   IFUNC_IMPL (i, name, memset,
              IFUNC_IMPL_ADD (array, i, memset, (zva_size == 64), __memset_zva64)
+             IFUNC_IMPL_ADD (array, i, memset, (zva_size == 64), __memset_oryon1)
              IFUNC_IMPL_ADD (array, i, memset, 1, __memset_emag)
              IFUNC_IMPL_ADD (array, i, memset, 1, __memset_kunpeng)
 #if HAVE_AARCH64_SVE_ASM
index 34bce045dd64ba9bd33bdaf06b346dc9da36bbee..bd063c16c9492c32f010ebb94b8c7373173e8f0a 100644 (file)
@@ -1,5 +1,6 @@
 /* Multiple versions of memset. AARCH64 version.
    Copyright (C) 2017-2024 Free Software Foundation, Inc.
+   Copyright The GNU Toolchain Authors.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -34,6 +35,7 @@ extern __typeof (__redirect_memset) __memset_kunpeng attribute_hidden;
 extern __typeof (__redirect_memset) __memset_a64fx attribute_hidden;
 extern __typeof (__redirect_memset) __memset_generic attribute_hidden;
 extern __typeof (__redirect_memset) __memset_mops attribute_hidden;
+extern __typeof (__redirect_memset) __memset_oryon1 attribute_hidden;
 
 static inline __typeof (__redirect_memset) *
 select_memset_ifunc (void)
@@ -49,6 +51,9 @@ select_memset_ifunc (void)
        return __memset_a64fx;
     }
 
+  if (IS_ORYON1 (midr) && zva_size == 64)
+    return __memset_oryon1;
+
   if (IS_KUNPENG920 (midr))
     return __memset_kunpeng;
 
diff --git a/sysdeps/aarch64/multiarch/memset_oryon1.S b/sysdeps/aarch64/multiarch/memset_oryon1.S
new file mode 100644 (file)
index 0000000..b43a43b
--- /dev/null
@@ -0,0 +1,169 @@
+/* Optimized memset for Qualcomm's oyron-1 core.
+   Copyright (C) 2018-2024 Free Software Foundation, Inc.
+   Copyright The GNU Toolchain Authors.
+
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <sysdep.h>
+#include "memset-reg.h"
+
+/* Assumptions:
+   ARMv8-a, AArch64, unaligned accesses
+ */
+
+ENTRY (__memset_oryon1)
+
+       PTR_ARG (0)
+       SIZE_ARG (2)
+
+       bfi     valw, valw, 8, 8
+       bfi     valw, valw, 16, 16
+       bfi     val, val, 32, 32
+
+       add     dstend, dstin, count
+
+       cmp     count, 96
+       b.hi    L(set_long)
+       cmp     count, 16
+       b.hs    L(set_medium)
+
+       /* Set 0..15 bytes.  */
+       tbz     count, 3, 1f
+       str     val, [dstin]
+       str     val, [dstend, -8]
+       ret
+
+       .p2align 3
+1:     tbz     count, 2, 2f
+       str     valw, [dstin]
+       str     valw, [dstend, -4]
+       ret
+2:     cbz     count, 3f
+       strb    valw, [dstin]
+       tbz     count, 1, 3f
+       strh    valw, [dstend, -2]
+3:     ret
+
+       .p2align 3
+       /* Set 16..96 bytes.  */
+L(set_medium):
+       stp     val, val, [dstin]
+       tbnz    count, 6, L(set96)
+       stp     val, val, [dstend, -16]
+       tbz     count, 5, 1f
+       stp     val, val, [dstin, 16]
+       stp     val, val, [dstend, -32]
+1:     ret
+
+       .p2align 6
+       /* Set 64..96 bytes.  Write 64 bytes from the start and
+          32 bytes from the end.  */
+L(set96):
+       stp     val, val, [dstin, 16]
+       stp     val, val, [dstin, 32]
+       stp     val, val, [dstin, 48]
+       stp     val, val, [dstend, -32]
+       stp     val, val, [dstend, -16]
+       ret
+
+       .p2align 6
+L(set_long):
+       stp     val, val, [dstin]
+       bic     dst, dstin, 15
+       cmp     count, 256
+       ccmp    valw, 0, 0, cs
+       b.eq    L(try_zva)
+       cmp     count, #32768
+       b.hi    L(set_long_with_nontemp)
+       /* Small-size or non-zero memset does not use DC ZVA. */
+       sub     count, dstend, dst
+
+       /* Adjust count and bias for loop. By subtracting extra 1 from count,
+         it is easy to use tbz instruction to check whether loop tailing
+         count is less than 33 bytes, so as to bypass 2 unnecessary stps. */
+       sub     count, count, 64+16+1
+
+1:     stp     val, val, [dst, 16]
+       stp     val, val, [dst, 32]
+       stp     val, val, [dst, 48]
+       stp     val, val, [dst, 64]!
+       subs    count, count, 64
+       b.hs    1b
+
+       tbz     count, 5, 1f    /* Remaining count is less than 33 bytes? */
+       stp     val, val, [dst, 16]
+       stp     val, val, [dst, 32]
+1:     stp     val, val, [dstend, -32]
+       stp     val, val, [dstend, -16]
+       ret
+
+L(set_long_with_nontemp):
+       /* Small-size or non-zero memset does not use DC ZVA. */
+       sub     count, dstend, dst
+
+       /* Adjust count and bias for loop. By subtracting extra 1 from count,
+          it is easy to use tbz instruction to check whether loop tailing
+          count is less than 33 bytes, so as to bypass 2 unnecessary stps. */
+       sub     count, count, 64+16+1
+
+1:     stnp    val, val, [dst, 16]
+       stnp    val, val, [dst, 32]
+       stnp    val, val, [dst, 48]
+       stnp    val, val, [dst, 64]
+       add     dst, dst, #64
+       subs    count, count, 64
+       b.hs    1b
+
+       tbz     count, 5, 1f    /* Remaining count is less than 33 bytes? */
+       stnp    val, val, [dst, 16]
+       stnp    val, val, [dst, 32]
+1:     stnp    val, val, [dstend, -32]
+       stnp    val, val, [dstend, -16]
+       ret
+
+L(try_zva):
+       /* Write the first and last 64 byte aligned block using stp rather
+          than using DC ZVA as it is faster. */
+       .p2align 6
+L(zva_64):
+       stp     val, val, [dst, 16]
+       stp     val, val, [dst, 32]
+       stp     val, val, [dst, 48]
+       bic     dst, dst, 63
+       stp     val, val, [dst, 64]
+       stp     val, val, [dst, 64+16]
+       stp     val, val, [dst, 96]
+       stp     val, val, [dst, 96+16]
+       sub     count, dstend, dst      /* Count is now 128 too large.  */
+       sub     count, count, 128+64+64 /* Adjust count and bias for loop.  */
+       add     dst, dst, 128
+1:     dc      zva, dst
+       add     dst, dst, 64
+       subs    count, count, 64
+       b.hi    1b
+       stp     val, val, [dst, 0]
+       stp     val, val, [dst, 16]
+       stp     val, val, [dst, 32]
+       stp     val, val, [dst, 48]
+
+       stp     val, val, [dstend, -64]
+       stp     val, val, [dstend, -64+16]
+       stp     val, val, [dstend, -32]
+       stp     val, val, [dstend, -16]
+       ret
+
+END (__memset_oryon1)