|
|
ce426f |
From 0d3555b9b4d5cefe116c32bfa38ac70f1d6c25cb Mon Sep 17 00:00:00 2001
|
|
|
ce426f |
From: Carlos Eduardo Seo <cseo@linux.vnet.ibm.com>
|
|
|
ce426f |
Date: Wed, 11 Nov 2015 17:31:28 -0200
|
|
|
ce426f |
Subject: [PATCH] powerpc: Optimization for strlen for POWER8.
|
|
|
ce426f |
|
|
|
ce426f |
This implementation takes advantage of vectorization to improve performance of
|
|
|
ce426f |
the loop over the current strlen implementation for POWER7.
|
|
|
ce426f |
|
|
|
ce426f |
(cherry picked from commit 1b045ee53e0b8bed75745b931b33f27d21c9ed22)
|
|
|
ce426f |
---
|
|
|
ce426f |
ChangeLog | 13 +
|
|
|
ce426f |
sysdeps/powerpc/powerpc64/multiarch/Makefile | 2 +-
|
|
|
ce426f |
.../powerpc/powerpc64/multiarch/ifunc-impl-list.c | 2 +
|
|
|
ce426f |
.../powerpc/powerpc64/multiarch/strlen-power8.S | 39 +++
|
|
|
ce426f |
sysdeps/powerpc/powerpc64/multiarch/strlen.c | 9 +-
|
|
|
ce426f |
sysdeps/powerpc/powerpc64/power8/strlen.S | 297 +++++++++++++++++++++
|
|
|
ce426f |
6 files changed, 358 insertions(+), 4 deletions(-)
|
|
|
ce426f |
create mode 100644 sysdeps/powerpc/powerpc64/multiarch/strlen-power8.S
|
|
|
ce426f |
create mode 100644 sysdeps/powerpc/powerpc64/power8/strlen.S
|
|
|
ce426f |
|
|
|
ce426f |
diff --git a/ChangeLog b/ChangeLog
|
|
|
ce426f |
index f030b68..e7ea58a 100644
|
|
|
ce426f |
diff --git a/sysdeps/powerpc/powerpc64/multiarch/Makefile b/sysdeps/powerpc/powerpc64/multiarch/Makefile
|
|
|
ce426f |
index 7ed56bf..57abe8f 100644
|
|
|
ce426f |
--- a/sysdeps/powerpc/powerpc64/multiarch/Makefile
|
|
|
ce426f |
+++ b/sysdeps/powerpc/powerpc64/multiarch/Makefile
|
|
|
ce426f |
@@ -20,7 +20,7 @@ sysdep_routines += memcpy-power7 memcpy-a2 memcpy-power6 memcpy-cell \
|
|
|
ce426f |
strncpy-power8 strncpy-power7 strncpy-ppc64 \
|
|
|
ce426f |
strncat-power7 \
|
|
|
ce426f |
strstr-power7 strstr-ppc64 \
|
|
|
ce426f |
- strspn-power8 strspn-ppc64 \
|
|
|
ce426f |
+ strspn-power8 strspn-ppc64 strlen-power8 \
|
|
|
ce426f |
rawmemchr-ppc64 strlen-power7 strlen-ppc64 strnlen-power7 \
|
|
|
ce426f |
strnlen-ppc64 strcasecmp-power7 strcasecmp_l-power7 \
|
|
|
ce426f |
strncase-power7 strncase_l-power7 \
|
|
|
ce426f |
diff --git a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c
|
|
|
ce426f |
index f6c70ba..583885c 100644
|
|
|
ce426f |
--- a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c
|
|
|
ce426f |
+++ b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c
|
|
|
ce426f |
@@ -101,6 +101,8 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
|
|
|
ce426f |
|
|
|
ce426f |
/* Support sysdeps/powerpc/powerpc64/multiarch/strlen.c. */
|
|
|
ce426f |
IFUNC_IMPL (i, name, strlen,
|
|
|
ce426f |
+ IFUNC_IMPL_ADD (array, i, strlen, hwcap2 & PPC_FEATURE2_ARCH_2_07,
|
|
|
ce426f |
+ __strlen_power8)
|
|
|
ce426f |
IFUNC_IMPL_ADD (array, i, strlen, hwcap & PPC_FEATURE_HAS_VSX,
|
|
|
ce426f |
__strlen_power7)
|
|
|
ce426f |
IFUNC_IMPL_ADD (array, i, strlen, 1,
|
|
|
ce426f |
diff --git a/sysdeps/powerpc/powerpc64/multiarch/strlen-power8.S b/sysdeps/powerpc/powerpc64/multiarch/strlen-power8.S
|
|
|
ce426f |
new file mode 100644
|
|
|
ce426f |
index 0000000..686dc3d
|
|
|
ce426f |
--- /dev/null
|
|
|
ce426f |
+++ b/sysdeps/powerpc/powerpc64/multiarch/strlen-power8.S
|
|
|
ce426f |
@@ -0,0 +1,39 @@
|
|
|
ce426f |
+/* Optimized strlen implementation for POWER8.
|
|
|
ce426f |
+ Copyright (C) 2016 Free Software Foundation, Inc.
|
|
|
ce426f |
+ This file is part of the GNU C Library.
|
|
|
ce426f |
+
|
|
|
ce426f |
+ The GNU C Library is free software; you can redistribute it and/or
|
|
|
ce426f |
+ modify it under the terms of the GNU Lesser General Public
|
|
|
ce426f |
+ License as published by the Free Software Foundation; either
|
|
|
ce426f |
+ version 2.1 of the License, or (at your option) any later version.
|
|
|
ce426f |
+
|
|
|
ce426f |
+ The GNU C Library is distributed in the hope that it will be useful,
|
|
|
ce426f |
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
ce426f |
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
ce426f |
+ Lesser General Public License for more details.
|
|
|
ce426f |
+
|
|
|
ce426f |
+ You should have received a copy of the GNU Lesser General Public
|
|
|
ce426f |
+ License along with the GNU C Library; if not, see
|
|
|
ce426f |
+ <http://www.gnu.org/licenses/>. */
|
|
|
ce426f |
+
|
|
|
ce426f |
+#include <sysdep.h>
|
|
|
ce426f |
+
|
|
|
ce426f |
+#undef EALIGN
|
|
|
ce426f |
+#define EALIGN(name, alignt, words) \
|
|
|
ce426f |
+ .section ".text"; \
|
|
|
ce426f |
+ ENTRY_2(__strlen_power8) \
|
|
|
ce426f |
+ .align ALIGNARG(alignt); \
|
|
|
ce426f |
+ EALIGN_W_##words; \
|
|
|
ce426f |
+ BODY_LABEL(__strlen_power8): \
|
|
|
ce426f |
+ cfi_startproc; \
|
|
|
ce426f |
+ LOCALENTRY(__strlen_power8)
|
|
|
ce426f |
+#undef END
|
|
|
ce426f |
+#define END(name) \
|
|
|
ce426f |
+ cfi_endproc; \
|
|
|
ce426f |
+ TRACEBACK(__strlen_power8) \
|
|
|
ce426f |
+ END_2(__strlen_power8)
|
|
|
ce426f |
+
|
|
|
ce426f |
+#undef libc_hidden_builtin_def
|
|
|
ce426f |
+#define libc_hidden_builtin_def(name)
|
|
|
ce426f |
+
|
|
|
ce426f |
+#include <sysdeps/powerpc/powerpc64/power8/strlen.S>
|
|
|
ce426f |
diff --git a/sysdeps/powerpc/powerpc64/multiarch/strlen.c b/sysdeps/powerpc/powerpc64/multiarch/strlen.c
|
|
|
ce426f |
index 79a53d9..4b400a5 100644
|
|
|
ce426f |
--- a/sysdeps/powerpc/powerpc64/multiarch/strlen.c
|
|
|
ce426f |
+++ b/sysdeps/powerpc/powerpc64/multiarch/strlen.c
|
|
|
ce426f |
@@ -29,11 +29,14 @@ extern __typeof (__redirect_strlen) __libc_strlen;
|
|
|
ce426f |
|
|
|
ce426f |
extern __typeof (__redirect_strlen) __strlen_ppc attribute_hidden;
|
|
|
ce426f |
extern __typeof (__redirect_strlen) __strlen_power7 attribute_hidden;
|
|
|
ce426f |
+extern __typeof (__redirect_strlen) __strlen_power8 attribute_hidden;
|
|
|
ce426f |
|
|
|
ce426f |
libc_ifunc (__libc_strlen,
|
|
|
ce426f |
- (hwcap & PPC_FEATURE_HAS_VSX)
|
|
|
ce426f |
- ? __strlen_power7
|
|
|
ce426f |
- : __strlen_ppc);
|
|
|
ce426f |
+ (hwcap2 & PPC_FEATURE2_ARCH_2_07)
|
|
|
ce426f |
+ ? __strlen_power8 :
|
|
|
ce426f |
+ (hwcap & PPC_FEATURE_HAS_VSX)
|
|
|
ce426f |
+ ? __strlen_power7
|
|
|
ce426f |
+ : __strlen_ppc);
|
|
|
ce426f |
|
|
|
ce426f |
#undef strlen
|
|
|
ce426f |
strong_alias (__libc_strlen, strlen)
|
|
|
ce426f |
diff --git a/sysdeps/powerpc/powerpc64/power8/strlen.S b/sysdeps/powerpc/powerpc64/power8/strlen.S
|
|
|
ce426f |
new file mode 100644
|
|
|
ce426f |
index 0000000..0142747
|
|
|
ce426f |
--- /dev/null
|
|
|
ce426f |
+++ b/sysdeps/powerpc/powerpc64/power8/strlen.S
|
|
|
ce426f |
@@ -0,0 +1,297 @@
|
|
|
ce426f |
+/* Optimized strlen implementation for PowerPC64/POWER8 using a vectorized
|
|
|
ce426f |
+ loop.
|
|
|
ce426f |
+ Copyright (C) 2016 Free Software Foundation, Inc.
|
|
|
ce426f |
+ This file is part of the GNU C Library.
|
|
|
ce426f |
+
|
|
|
ce426f |
+ The GNU C Library is free software; you can redistribute it and/or
|
|
|
ce426f |
+ modify it under the terms of the GNU Lesser General Public
|
|
|
ce426f |
+ License as published by the Free Software Foundation; either
|
|
|
ce426f |
+ version 2.1 of the License, or (at your option) any later version.
|
|
|
ce426f |
+
|
|
|
ce426f |
+ The GNU C Library is distributed in the hope that it will be useful,
|
|
|
ce426f |
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
ce426f |
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
ce426f |
+ Lesser General Public License for more details.
|
|
|
ce426f |
+
|
|
|
ce426f |
+ You should have received a copy of the GNU Lesser General Public
|
|
|
ce426f |
+ License along with the GNU C Library; if not, see
|
|
|
ce426f |
+ <http://www.gnu.org/licenses/>. */
|
|
|
ce426f |
+
|
|
|
ce426f |
+#include <sysdep.h>
|
|
|
ce426f |
+
|
|
|
ce426f |
+/* TODO: change these to the actual instructions when the minimum required
|
|
|
ce426f |
+ binutils allows it. */
|
|
|
ce426f |
+#define MFVRD(r,v) .long (0x7c000067 | ((v)<<(32-11)) | ((r)<<(32-16)))
|
|
|
ce426f |
+#define VBPERMQ(t,a,b) .long (0x1000054c \
|
|
|
ce426f |
+ | ((t)<<(32-11)) \
|
|
|
ce426f |
+ | ((a)<<(32-16)) \
|
|
|
ce426f |
+ | ((b)<<(32-21)) )
|
|
|
ce426f |
+
|
|
|
ce426f |
+/* int [r3] strlen (char *s [r3]) */
|
|
|
ce426f |
+
|
|
|
ce426f |
+/* TODO: change this to .machine power8 when the minimum required binutils
|
|
|
ce426f |
+ allows it. */
|
|
|
ce426f |
+ .machine power7
|
|
|
ce426f |
+EALIGN (strlen, 4, 0)
|
|
|
ce426f |
+ CALL_MCOUNT 1
|
|
|
ce426f |
+ dcbt 0,r3
|
|
|
ce426f |
+ clrrdi r4,r3,3 /* Align the address to doubleword boundary. */
|
|
|
ce426f |
+ rlwinm r6,r3,3,26,28 /* Calculate padding. */
|
|
|
ce426f |
+ li r0,0 /* Doubleword with null chars to use
|
|
|
ce426f |
+ with cmpb. */
|
|
|
ce426f |
+ li r5,-1 /* MASK = 0xffffffffffffffff. */
|
|
|
ce426f |
+ ld r12,0(r4) /* Load doubleword from memory. */
|
|
|
ce426f |
+#ifdef __LITTLE_ENDIAN__
|
|
|
ce426f |
+ sld r5,r5,r6
|
|
|
ce426f |
+#else
|
|
|
ce426f |
+ srd r5,r5,r6 /* MASK = MASK >> padding. */
|
|
|
ce426f |
+#endif
|
|
|
ce426f |
+ orc r9,r12,r5 /* Mask bits that are not part of the string. */
|
|
|
ce426f |
+ cmpb r10,r9,r0 /* Check for null bytes in DWORD1. */
|
|
|
ce426f |
+ cmpdi cr7,r10,0 /* If r10 == 0, no null's have been found. */
|
|
|
ce426f |
+ bne cr7,L(done)
|
|
|
ce426f |
+
|
|
|
ce426f |
+ /* For shorter strings (< 64 bytes), we will not use vector registers,
|
|
|
ce426f |
+ as the overhead isn't worth it. So, let's use GPRs instead. This
|
|
|
ce426f |
+ will be done the same way as we do in the POWER7 implementation.
|
|
|
ce426f |
+ Let's see if we are aligned to a quadword boundary. If so, we can
|
|
|
ce426f |
+ jump to the first (non-vectorized) loop. Otherwise, we have to
|
|
|
ce426f |
+ handle the next DWORD first. */
|
|
|
ce426f |
+ mtcrf 0x01,r4
|
|
|
ce426f |
+ mr r9,r4
|
|
|
ce426f |
+ addi r9,r9,8
|
|
|
ce426f |
+ bt 28,L(align64)
|
|
|
ce426f |
+
|
|
|
ce426f |
+ /* Handle the next 8 bytes so we are aligned to a quadword
|
|
|
ce426f |
+ boundary. */
|
|
|
ce426f |
+ ldu r5,8(r4)
|
|
|
ce426f |
+ cmpb r10,r5,r0
|
|
|
ce426f |
+ cmpdi cr7,r10,0
|
|
|
ce426f |
+ addi r9,r9,8
|
|
|
ce426f |
+ bne cr7,L(done)
|
|
|
ce426f |
+
|
|
|
ce426f |
+L(align64):
|
|
|
ce426f |
+ /* Proceed to the old (POWER7) implementation, checking two doublewords
|
|
|
ce426f |
+ per iteraction. For the first 56 bytes, we will just check for null
|
|
|
ce426f |
+ characters. After that, we will also check if we are 64-byte aligned
|
|
|
ce426f |
+ so we can jump to the vectorized implementation. We will unroll
|
|
|
ce426f |
+ these loops to avoid excessive branching. */
|
|
|
ce426f |
+ ld r6,8(r4)
|
|
|
ce426f |
+ ldu r5,16(r4)
|
|
|
ce426f |
+ cmpb r10,r6,r0
|
|
|
ce426f |
+ cmpb r11,r5,r0
|
|
|
ce426f |
+ or r5,r10,r11
|
|
|
ce426f |
+ cmpdi cr7,r5,0
|
|
|
ce426f |
+ addi r9,r9,16
|
|
|
ce426f |
+ bne cr7,L(dword_zero)
|
|
|
ce426f |
+
|
|
|
ce426f |
+ ld r6,8(r4)
|
|
|
ce426f |
+ ldu r5,16(r4)
|
|
|
ce426f |
+ cmpb r10,r6,r0
|
|
|
ce426f |
+ cmpb r11,r5,r0
|
|
|
ce426f |
+ or r5,r10,r11
|
|
|
ce426f |
+ cmpdi cr7,r5,0
|
|
|
ce426f |
+ addi r9,r9,16
|
|
|
ce426f |
+ bne cr7,L(dword_zero)
|
|
|
ce426f |
+
|
|
|
ce426f |
+ ld r6,8(r4)
|
|
|
ce426f |
+ ldu r5,16(r4)
|
|
|
ce426f |
+ cmpb r10,r6,r0
|
|
|
ce426f |
+ cmpb r11,r5,r0
|
|
|
ce426f |
+ or r5,r10,r11
|
|
|
ce426f |
+ cmpdi cr7,r5,0
|
|
|
ce426f |
+ addi r9,r9,16
|
|
|
ce426f |
+ bne cr7,L(dword_zero)
|
|
|
ce426f |
+
|
|
|
ce426f |
+ /* Are we 64-byte aligned? If so, jump to the vectorized loop.
|
|
|
ce426f |
+ Note: aligning to 64-byte will necessarily slow down performance for
|
|
|
ce426f |
+ strings around 64 bytes in length due to the extra comparisons
|
|
|
ce426f |
+ required to check alignment for the vectorized loop. This is a
|
|
|
ce426f |
+ necessary tradeoff we are willing to take in order to speed up the
|
|
|
ce426f |
+ calculation for larger strings. */
|
|
|
ce426f |
+ andi. r10,r9,63
|
|
|
ce426f |
+ beq cr0,L(preloop)
|
|
|
ce426f |
+ ld r6,8(r4)
|
|
|
ce426f |
+ ldu r5,16(r4)
|
|
|
ce426f |
+ cmpb r10,r6,r0
|
|
|
ce426f |
+ cmpb r11,r5,r0
|
|
|
ce426f |
+ or r5,r10,r11
|
|
|
ce426f |
+ cmpdi cr7,r5,0
|
|
|
ce426f |
+ addi r9,r9,16
|
|
|
ce426f |
+ bne cr7,L(dword_zero)
|
|
|
ce426f |
+
|
|
|
ce426f |
+ andi. r10,r9,63
|
|
|
ce426f |
+ beq cr0,L(preloop)
|
|
|
ce426f |
+ ld r6,8(r4)
|
|
|
ce426f |
+ ldu r5,16(r4)
|
|
|
ce426f |
+ cmpb r10,r6,r0
|
|
|
ce426f |
+ cmpb r11,r5,r0
|
|
|
ce426f |
+ or r5,r10,r11
|
|
|
ce426f |
+ cmpdi cr7,r5,0
|
|
|
ce426f |
+ addi r9,r9,16
|
|
|
ce426f |
+ bne cr7,L(dword_zero)
|
|
|
ce426f |
+
|
|
|
ce426f |
+ andi. r10,r9,63
|
|
|
ce426f |
+ beq cr0,L(preloop)
|
|
|
ce426f |
+ ld r6,8(r4)
|
|
|
ce426f |
+ ldu r5,16(r4)
|
|
|
ce426f |
+ cmpb r10,r6,r0
|
|
|
ce426f |
+ cmpb r11,r5,r0
|
|
|
ce426f |
+ or r5,r10,r11
|
|
|
ce426f |
+ cmpdi cr7,r5,0
|
|
|
ce426f |
+ addi r9,r9,16
|
|
|
ce426f |
+ bne cr7,L(dword_zero)
|
|
|
ce426f |
+
|
|
|
ce426f |
+ andi. r10,r9,63
|
|
|
ce426f |
+ beq cr0,L(preloop)
|
|
|
ce426f |
+ ld r6,8(r4)
|
|
|
ce426f |
+ ldu r5,16(r4)
|
|
|
ce426f |
+ cmpb r10,r6,r0
|
|
|
ce426f |
+ cmpb r11,r5,r0
|
|
|
ce426f |
+ or r5,r10,r11
|
|
|
ce426f |
+ cmpdi cr7,r5,0
|
|
|
ce426f |
+ addi r9,r9,16
|
|
|
ce426f |
+
|
|
|
ce426f |
+ /* At this point, we are necessarily 64-byte aligned. If no zeroes were
|
|
|
ce426f |
+ found, jump to the vectorized loop. */
|
|
|
ce426f |
+ beq cr7,L(preloop)
|
|
|
ce426f |
+
|
|
|
ce426f |
+L(dword_zero):
|
|
|
ce426f |
+ /* OK, one (or both) of the doublewords contains a null byte. Check
|
|
|
ce426f |
+ the first doubleword and decrement the address in case the first
|
|
|
ce426f |
+ doubleword really contains a null byte. */
|
|
|
ce426f |
+
|
|
|
ce426f |
+ cmpdi cr6,r10,0
|
|
|
ce426f |
+ addi r4,r4,-8
|
|
|
ce426f |
+ bne cr6,L(done)
|
|
|
ce426f |
+
|
|
|
ce426f |
+ /* The null byte must be in the second doubleword. Adjust the address
|
|
|
ce426f |
+ again and move the result of cmpb to r10 so we can calculate the
|
|
|
ce426f |
+ length. */
|
|
|
ce426f |
+
|
|
|
ce426f |
+ mr r10,r11
|
|
|
ce426f |
+ addi r4,r4,8
|
|
|
ce426f |
+
|
|
|
ce426f |
+ /* If the null byte was found in the non-vectorized code, compute the
|
|
|
ce426f |
+ final length. r10 has the output of the cmpb instruction, that is,
|
|
|
ce426f |
+ it contains 0xff in the same position as the null byte in the
|
|
|
ce426f |
+ original doubleword from the string. Use that to calculate the
|
|
|
ce426f |
+ length. */
|
|
|
ce426f |
+L(done):
|
|
|
ce426f |
+#ifdef __LITTLE_ENDIAN__
|
|
|
ce426f |
+ addi r9, r10,-1 /* Form a mask from trailing zeros. */
|
|
|
ce426f |
+ andc r9, r9,r10
|
|
|
ce426f |
+ popcntd r0, r9 /* Count the bits in the mask. */
|
|
|
ce426f |
+#else
|
|
|
ce426f |
+ cntlzd r0,r10 /* Count leading zeros before the match. */
|
|
|
ce426f |
+#endif
|
|
|
ce426f |
+ subf r5,r3,r4
|
|
|
ce426f |
+ srdi r0,r0,3 /* Convert leading/trailing zeros to bytes. */
|
|
|
ce426f |
+ add r3,r5,r0 /* Compute final length. */
|
|
|
ce426f |
+ blr
|
|
|
ce426f |
+
|
|
|
ce426f |
+ /* Vectorized implementation starts here. */
|
|
|
ce426f |
+ .p2align 4
|
|
|
ce426f |
+L(preloop):
|
|
|
ce426f |
+ /* Set up for the loop. */
|
|
|
ce426f |
+ mr r4,r9
|
|
|
ce426f |
+ li r7, 16 /* Load required offsets. */
|
|
|
ce426f |
+ li r8, 32
|
|
|
ce426f |
+ li r9, 48
|
|
|
ce426f |
+ li r12, 8
|
|
|
ce426f |
+ vxor v0,v0,v0 /* VR with null chars to use with
|
|
|
ce426f |
+ vcmpequb. */
|
|
|
ce426f |
+
|
|
|
ce426f |
+ /* Main loop to look for the end of the string. We will read in
|
|
|
ce426f |
+ 64-byte chunks. Align it to 32 bytes and unroll it 3 times to
|
|
|
ce426f |
+ leverage the icache performance. */
|
|
|
ce426f |
+ .p2align 5
|
|
|
ce426f |
+L(loop):
|
|
|
ce426f |
+ lvx v1,r4,r0 /* Load 4 quadwords. */
|
|
|
ce426f |
+ lvx v2,r4,r7
|
|
|
ce426f |
+ lvx v3,r4,r8
|
|
|
ce426f |
+ lvx v4,r4,r9
|
|
|
ce426f |
+ vminub v5,v1,v2 /* Compare and merge into one VR for speed. */
|
|
|
ce426f |
+ vminub v6,v3,v4
|
|
|
ce426f |
+ vminub v7,v5,v6
|
|
|
ce426f |
+ vcmpequb. v7,v7,v0 /* Check for NULLs. */
|
|
|
ce426f |
+ addi r4,r4,64 /* Adjust address for the next iteration. */
|
|
|
ce426f |
+ bne cr6,L(vmx_zero)
|
|
|
ce426f |
+
|
|
|
ce426f |
+ lvx v1,r4,r0 /* Load 4 quadwords. */
|
|
|
ce426f |
+ lvx v2,r4,r7
|
|
|
ce426f |
+ lvx v3,r4,r8
|
|
|
ce426f |
+ lvx v4,r4,r9
|
|
|
ce426f |
+ vminub v5,v1,v2 /* Compare and merge into one VR for speed. */
|
|
|
ce426f |
+ vminub v6,v3,v4
|
|
|
ce426f |
+ vminub v7,v5,v6
|
|
|
ce426f |
+ vcmpequb. v7,v7,v0 /* Check for NULLs. */
|
|
|
ce426f |
+ addi r4,r4,64 /* Adjust address for the next iteration. */
|
|
|
ce426f |
+ bne cr6,L(vmx_zero)
|
|
|
ce426f |
+
|
|
|
ce426f |
+ lvx v1,r4,r0 /* Load 4 quadwords. */
|
|
|
ce426f |
+ lvx v2,r4,r7
|
|
|
ce426f |
+ lvx v3,r4,r8
|
|
|
ce426f |
+ lvx v4,r4,r9
|
|
|
ce426f |
+ vminub v5,v1,v2 /* Compare and merge into one VR for speed. */
|
|
|
ce426f |
+ vminub v6,v3,v4
|
|
|
ce426f |
+ vminub v7,v5,v6
|
|
|
ce426f |
+ vcmpequb. v7,v7,v0 /* Check for NULLs. */
|
|
|
ce426f |
+ addi r4,r4,64 /* Adjust address for the next iteration. */
|
|
|
ce426f |
+ beq cr6,L(loop)
|
|
|
ce426f |
+
|
|
|
ce426f |
+L(vmx_zero):
|
|
|
ce426f |
+ /* OK, we found a null byte. Let's look for it in the current 64-byte
|
|
|
ce426f |
+ block and mark it in its corresponding VR. */
|
|
|
ce426f |
+ vcmpequb v1,v1,v0
|
|
|
ce426f |
+ vcmpequb v2,v2,v0
|
|
|
ce426f |
+ vcmpequb v3,v3,v0
|
|
|
ce426f |
+ vcmpequb v4,v4,v0
|
|
|
ce426f |
+
|
|
|
ce426f |
+ /* We will now 'compress' the result into a single doubleword, so it
|
|
|
ce426f |
+ can be moved to a GPR for the final calculation. First, we
|
|
|
ce426f |
+ generate an appropriate mask for vbpermq, so we can permute bits into
|
|
|
ce426f |
+ the first halfword. */
|
|
|
ce426f |
+ vspltisb v10,3
|
|
|
ce426f |
+ lvsl v11,r0,r0
|
|
|
ce426f |
+ vslb v10,v11,v10
|
|
|
ce426f |
+
|
|
|
ce426f |
+ /* Permute the first bit of each byte into bits 48-63. */
|
|
|
ce426f |
+ VBPERMQ(v1,v1,v10)
|
|
|
ce426f |
+ VBPERMQ(v2,v2,v10)
|
|
|
ce426f |
+ VBPERMQ(v3,v3,v10)
|
|
|
ce426f |
+ VBPERMQ(v4,v4,v10)
|
|
|
ce426f |
+
|
|
|
ce426f |
+ /* Shift each component into its correct position for merging. */
|
|
|
ce426f |
+#ifdef __LITTLE_ENDIAN__
|
|
|
ce426f |
+ vsldoi v2,v2,v2,2
|
|
|
ce426f |
+ vsldoi v3,v3,v3,4
|
|
|
ce426f |
+ vsldoi v4,v4,v4,6
|
|
|
ce426f |
+#else
|
|
|
ce426f |
+ vsldoi v1,v1,v1,6
|
|
|
ce426f |
+ vsldoi v2,v2,v2,4
|
|
|
ce426f |
+ vsldoi v3,v3,v3,2
|
|
|
ce426f |
+#endif
|
|
|
ce426f |
+
|
|
|
ce426f |
+ /* Merge the results and move to a GPR. */
|
|
|
ce426f |
+ vor v1,v2,v1
|
|
|
ce426f |
+ vor v2,v3,v4
|
|
|
ce426f |
+ vor v4,v1,v2
|
|
|
ce426f |
+ MFVRD(r10,v4)
|
|
|
ce426f |
+
|
|
|
ce426f |
+ /* Adjust address to the begninning of the current 64-byte block. */
|
|
|
ce426f |
+ addi r4,r4,-64
|
|
|
ce426f |
+
|
|
|
ce426f |
+#ifdef __LITTLE_ENDIAN__
|
|
|
ce426f |
+ addi r9, r10,-1 /* Form a mask from trailing zeros. */
|
|
|
ce426f |
+ andc r9, r9,r10
|
|
|
ce426f |
+ popcntd r0, r9 /* Count the bits in the mask. */
|
|
|
ce426f |
+#else
|
|
|
ce426f |
+ cntlzd r0,r10 /* Count leading zeros before the match. */
|
|
|
ce426f |
+#endif
|
|
|
ce426f |
+ subf r5,r3,r4
|
|
|
ce426f |
+ add r3,r5,r0 /* Compute final length. */
|
|
|
ce426f |
+ blr
|
|
|
ce426f |
+
|
|
|
ce426f |
+END (strlen)
|
|
|
ce426f |
+libc_hidden_builtin_def (strlen)
|
|
|
ce426f |
--
|
|
|
ce426f |
2.1.0
|
|
|
ce426f |
|