| From 71ae86478edc7b21872464f43fb29ff650c1681a Mon Sep 17 00:00:00 2001 |
| From: Adhemerval Zanella <azanella@linux.vnet.ibm.com> |
| Date: Tue, 15 Jul 2014 12:19:09 -0400 |
| Subject: [PATCH] PowerPC: memset optimization for POWER8/PPC64 |
| |
| This patch adds an optimized memset implementation for POWER8. For |
| sizes from 0 to 255 bytes, a word/doubleword algorithm similar to |
| POWER7 optimized one is used. |
| |
| For size higher than 255 two strategies are used: |
| |
| 1. If the constant is different than 0, the memory is written with |
| altivec vector instruction; |
| |
| 2. If constant is 0, dbcz instructions are used. The loop is unrolled |
| to clear 512 byte at time. |
| |
| Using vector instructions increases throughput considerable, with a |
| double performance for sizes larger than 1024. The dcbz loops unrolls |
| also shows performance improvement, by doubling throughput for sizes |
| larger than 8192 bytes. |
| |
| ChangeLog | 15 + |
| benchtests/bench-memset.c | 5 + |
| sysdeps/powerpc/powerpc64/multiarch/Makefile | 2 +- |
| sysdeps/powerpc/powerpc64/multiarch/bzero.c | 11 +- |
| .../powerpc/powerpc64/multiarch/ifunc-impl-list.c | 6 + |
| .../powerpc/powerpc64/multiarch/memset-power8.S | 43 ++ |
| sysdeps/powerpc/powerpc64/multiarch/memset.c | 11 +- |
| sysdeps/powerpc/powerpc64/power8/memset.S | 449 +++++++++++++++++++++ |
| 8 files changed, 533 insertions(+), 9 deletions(-) |
| create mode 100644 sysdeps/powerpc/powerpc64/multiarch/memset-power8.S |
| create mode 100644 sysdeps/powerpc/powerpc64/power8/memset.S |
| |
| diff --git a/ChangeLog b/ChangeLog |
| index ddaf70f..dc61c87 100644 |
| diff --git a/sysdeps/powerpc/powerpc64/multiarch/Makefile b/sysdeps/powerpc/powerpc64/multiarch/Makefile |
| index 0de3804..abc9d2e 100644 |
| |
| |
| @@ -1,7 +1,8 @@ ifeq ($(subdir),string) |
| ifeq ($(subdir),string) |
| sysdep_routines += memcpy-power7 memcpy-a2 memcpy-power6 memcpy-cell \ |
| memcpy-power4 memcpy-ppc64 memcmp-power7 memcmp-power4 \ |
| - memcmp-ppc64 memset-power7 memset-power6 memset-power4 \ |
| + memcmp-ppc64 memset-power8 memset-power7 memset-power6 \ |
| + memset-power4 \ |
| memset-ppc64 bzero-power4 bzero-power6 bzero-power7 \ |
| mempcpy-power7 mempcpy-ppc64 memchr-power7 memchr-ppc64 \ |
| memrchr-power7 memrchr-ppc64 rawmemchr-power7 \ |
| diff --git a/sysdeps/powerpc/powerpc64/multiarch/bzero.c b/sysdeps/powerpc/powerpc64/multiarch/bzero.c |
| index ed83541..298cf00 100644 |
| |
| |
| @@ -26,14 +26,17 @@ extern __typeof (bzero) __bzero_ppc attribute_hidden; |
| extern __typeof (bzero) __bzero_power4 attribute_hidden; |
| extern __typeof (bzero) __bzero_power6 attribute_hidden; |
| extern __typeof (bzero) __bzero_power7 attribute_hidden; |
| +extern __typeof (bzero) __bzero_power8 attribute_hidden; |
| |
| libc_ifunc (__bzero, |
| - (hwcap & PPC_FEATURE_HAS_VSX) |
| - ? __bzero_power7 : |
| - (hwcap & PPC_FEATURE_ARCH_2_05) |
| + (hwcap2 & PPC_FEATURE2_ARCH_2_07) |
| + ? __bzero_power8 : |
| + (hwcap & PPC_FEATURE_HAS_VSX) |
| + ? __bzero_power7 : |
| + (hwcap & PPC_FEATURE_ARCH_2_05) |
| ? __bzero_power6 : |
| (hwcap & PPC_FEATURE_POWER4) |
| - ? __bzero_power4 |
| + ? __bzero_power4 |
| : __bzero_ppc); |
| |
| weak_alias (__bzero, bzero) |
| diff --git a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c |
| index a574487..06d5be9 100644 |
| |
| |
| @@ -69,6 +71,8 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, |
| |
| /* Support sysdeps/powerpc/powerpc64/multiarch/memset.c. */ |
| IFUNC_IMPL (i, name, memset, |
| + IFUNC_IMPL_ADD (array, i, memset, hwcap2 & PPC_FEATURE2_ARCH_2_07, |
| + __memset_power8) |
| IFUNC_IMPL_ADD (array, i, memset, hwcap & PPC_FEATURE_HAS_VSX, |
| __memset_power7) |
| IFUNC_IMPL_ADD (array, i, memset, hwcap & PPC_FEATURE_ARCH_2_05, |
| @@ -134,6 +138,8 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, |
| |
| /* Support sysdeps/powerpc/powerpc64/multiarch/bzero.c. */ |
| IFUNC_IMPL (i, name, bzero, |
| + IFUNC_IMPL_ADD (array, i, bzero, hwcap2 & PPC_FEATURE2_ARCH_2_07, |
| + __bzero_power8) |
| IFUNC_IMPL_ADD (array, i, bzero, hwcap & PPC_FEATURE_HAS_VSX, |
| __bzero_power7) |
| IFUNC_IMPL_ADD (array, i, bzero, hwcap & PPC_FEATURE_ARCH_2_05, |
| diff --git a/sysdeps/powerpc/powerpc64/multiarch/memset-power8.S b/sysdeps/powerpc/powerpc64/multiarch/memset-power8.S |
| new file mode 100644 |
| index 0000000..e8a604b |
| |
| |
| @@ -0,0 +1,43 @@ |
| +/* Optimized memset implementation for PowerPC64/POWER8. |
| + Copyright (C) 2014 Free Software Foundation, Inc. |
| + 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 |
| + <http://www.gnu.org/licenses/>. */ |
| + |
| +#include <sysdep.h> |
| + |
| +#undef EALIGN |
| +#define EALIGN(name, alignt, words) \ |
| + .section ".text"; \ |
| + ENTRY_2(__memset_power8) \ |
| + .align ALIGNARG(alignt); \ |
| + EALIGN_W_##words; \ |
| + BODY_LABEL(__memset_power8): \ |
| + cfi_startproc; \ |
| + LOCALENTRY(__memset_power8) |
| + |
| +#undef END_GEN_TB |
| +#define END_GEN_TB(name, mask) \ |
| + cfi_endproc; \ |
| + TRACEBACK_MASK(__memset_power8,mask) \ |
| + END_2(__memset_power8) |
| + |
| +#undef libc_hidden_builtin_def |
| +#define libc_hidden_builtin_def(name) |
| + |
| +#undef __bzero |
| +#define __bzero __bzero_power8 |
| + |
| +#include <sysdeps/powerpc/powerpc64/power8/memset.S> |
| diff --git a/sysdeps/powerpc/powerpc64/multiarch/memset.c b/sysdeps/powerpc/powerpc64/multiarch/memset.c |
| index aa2ae70..9c7ed10 100644 |
| |
| |
| @@ -32,16 +32,19 @@ extern __typeof (__redirect_memset) __memset_ppc attribute_hidden; |
| extern __typeof (__redirect_memset) __memset_power4 attribute_hidden; |
| extern __typeof (__redirect_memset) __memset_power6 attribute_hidden; |
| extern __typeof (__redirect_memset) __memset_power7 attribute_hidden; |
| +extern __typeof (__redirect_memset) __memset_power8 attribute_hidden; |
| |
| /* Avoid DWARF definition DIE on ifunc symbol so that GDB can handle |
| ifunc symbol properly. */ |
| libc_ifunc (__libc_memset, |
| - (hwcap & PPC_FEATURE_HAS_VSX) |
| - ? __memset_power7 : |
| - (hwcap & PPC_FEATURE_ARCH_2_05) |
| + (hwcap2 & PPC_FEATURE2_ARCH_2_07) |
| + ? __memset_power8 : |
| + (hwcap & PPC_FEATURE_HAS_VSX) |
| + ? __memset_power7 : |
| + (hwcap & PPC_FEATURE_ARCH_2_05) |
| ? __memset_power6 : |
| (hwcap & PPC_FEATURE_POWER4) |
| - ? __memset_power4 |
| + ? __memset_power4 |
| : __memset_ppc); |
| |
| #undef memset |
| diff --git a/sysdeps/powerpc/powerpc64/power8/memset.S b/sysdeps/powerpc/powerpc64/power8/memset.S |
| new file mode 100644 |
| index 0000000..191a4df |
| |
| |
| @@ -0,0 +1,449 @@ |
| +/* Optimized memset implementation for PowerPC64/POWER8. |
| + Copyright (C) 2014 Free Software Foundation, Inc. |
| + 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 |
| + <http://www.gnu.org/licenses/>. */ |
| + |
| +#include <sysdep.h> |
| + |
| +/* __ptr_t [r3] memset (__ptr_t s [r3], int c [r4], size_t n [r5])); |
| + Returns 's'. */ |
| + |
| + .machine power8 |
| +EALIGN (memset, 5, 0) |
| + CALL_MCOUNT 3 |
| + |
| +L(_memset): |
| + cmpldi cr7,r5,31 |
| + neg r0,r3 |
| + mr r10,r3 |
| + |
| + insrdi r4,r4,8,48 |
| + insrdi r4,r4,16,32 /* Replicate byte to word. */ |
| + ble cr7,L(write_LT_32) |
| + |
| + andi. r11,r10,15 /* Check alignment of DST. */ |
| + insrdi r4,r4,32,0 /* Replicate word to double word. */ |
| + |
| + beq L(big_aligned) |
| + |
| + mtocrf 0x01,r0 |
| + clrldi r0,r0,60 |
| + |
| + /* Get DST aligned to 16 bytes. */ |
| +1: bf 31,2f |
| + stb r4,0(r10) |
| + addi r10,r10,1 |
| + |
| +2: bf 30,4f |
| + sth r4,0(r10) |
| + addi r10,r10,2 |
| + |
| +4: bf 29,8f |
| + stw r4,0(r10) |
| + addi r10,r10,4 |
| + |
| +8: bf 28,16f |
| + std r4,0(r10) |
| + addi r10,r10,8 |
| + |
| +16: subf r5,r0,r5 |
| + |
| + .align 4 |
| +L(big_aligned): |
| + /* For sizes larger than 255 two possible paths: |
| + - if constant is '0', zero full cache lines with dcbz |
| + - otherwise uses vector instructions. */ |
| + cmpldi cr5,r5,255 |
| + dcbtst 0,r10 |
| + cmpldi cr6,r4,0 |
| + crand 27,26,21 |
| + bt 27,L(huge_dcbz) |
| + bge cr5,L(huge_vector) |
| + |
| + |
| + /* Size between 32 and 255 bytes with constant different than 0, use |
| + doubleword store instruction to achieve best throughput. */ |
| + srdi r8,r5,5 |
| + clrldi r11,r5,59 |
| + cmpldi cr6,r11,0 |
| + cmpdi r8,0 |
| + beq L(tail_bytes) |
| + mtctr r8 |
| + |
| + /* Main aligned write loop, writes 32-bytes at a time. */ |
| + .align 4 |
| +L(big_loop): |
| + std r4,0(r10) |
| + std r4,8(r10) |
| + std r4,16(r10) |
| + std r4,24(r10) |
| + addi r10,r10,32 |
| + bdz L(tail_bytes) |
| + |
| + std r4,0(r10) |
| + std r4,8(r10) |
| + std r4,16(r10) |
| + std r4,24(r10) |
| + addi r10,10,32 |
| + bdnz L(big_loop) |
| + |
| + b L(tail_bytes) |
| + |
| + /* Write remaining 1~31 bytes. */ |
| + .align 4 |
| +L(tail_bytes): |
| + beqlr cr6 |
| + |
| + srdi r7,r11,4 |
| + clrldi r8,r11,60 |
| + mtocrf 0x01,r7 |
| + |
| + .align 4 |
| + bf 31,8f |
| + std r4,0(r10) |
| + std r4,8(r10) |
| + addi r10,r10,16 |
| + |
| + .align 4 |
| +8: mtocrf 0x1,r8 |
| + bf 28,4f |
| + std r4,0(r10) |
| + addi r10,r10,8 |
| + |
| + .align 4 |
| +4: bf 29,2f |
| + stw 4,0(10) |
| + addi 10,10,4 |
| + |
| + .align 4 |
| +2: bf 30,1f |
| + sth 4,0(10) |
| + addi 10,10,2 |
| + |
| + .align 4 |
| +1: bflr 31 |
| + stb 4,0(10) |
| + blr |
| + |
| + /* Size larger than 255 bytes with constant different than 0, use |
| + vector instruction to achieve best throughput. */ |
| +L(huge_vector): |
| + /* Replicate set byte to quadword in VMX register. */ |
| + mtvsrd v1,r4 |
| + xxpermdi 32,v0,v1,0 |
| + vspltb v2,v0,15 |
| + |
| + /* Main aligned write loop: 128 bytes at a time. */ |
| + li r6,16 |
| + li r7,32 |
| + li r8,48 |
| + mtocrf 0x02,r5 |
| + srdi r12,r5,7 |
| + cmpdi r12,0 |
| + beq L(aligned_tail) |
| + mtctr r12 |
| + b L(aligned_128loop) |
| + |
| + .align 4 |
| +L(aligned_128loop): |
| + stvx v2,0,r10 |
| + stvx v2,r10,r6 |
| + stvx v2,r10,r7 |
| + stvx v2,r10,r8 |
| + addi r10,r10,64 |
| + stvx v2,0,r10 |
| + stvx v2,r10,r6 |
| + stvx v2,r10,r7 |
| + stvx v2,r10,r8 |
| + addi r10,r10,64 |
| + bdnz L(aligned_128loop) |
| + |
| + /* Write remaining 1~127 bytes. */ |
| +L(aligned_tail): |
| + mtocrf 0x01,r5 |
| + bf 25,32f |
| + stvx v2,0,r10 |
| + stvx v2,r10,r6 |
| + stvx v2,r10,r7 |
| + stvx v2,r10,r8 |
| + addi r10,r10,64 |
| + |
| +32: bf 26,16f |
| + stvx v2,0,r10 |
| + stvx v2,r10,r6 |
| + addi r10,r10,32 |
| + |
| +16: bf 27,8f |
| + stvx v2,0,r10 |
| + addi r10,r10,16 |
| + |
| +8: bf 28,4f |
| + std r4,0(r10) |
| + addi r10,r10,8 |
| + |
| + /* Copies 4~7 bytes. */ |
| +4: bf 29,L(tail2) |
| + stw r4,0(r10) |
| + bf 30,L(tail5) |
| + sth r4,4(r10) |
| + bflr 31 |
| + stb r4,6(r10) |
| + /* Return original DST pointer. */ |
| + blr |
| + |
| + /* Special case when value is 0 and we have a long length to deal |
| + with. Use dcbz to zero out a full cacheline of 128 bytes at a time. |
| + Before using dcbz though, we need to get the destination 128-byte |
| + aligned. */ |
| + .align 4 |
| +L(huge_dcbz): |
| + andi. r11,r10,127 |
| + neg r0,r10 |
| + beq L(huge_dcbz_aligned) |
| + |
| + clrldi r0,r0,57 |
| + subf r5,r0,r5 |
| + srdi r0,r0,3 |
| + mtocrf 0x01,r0 |
| + |
| + /* Write 1~128 bytes until DST is aligned to 128 bytes. */ |
| +8: bf 28,4f |
| + |
| + std r4,0(r10) |
| + std r4,8(r10) |
| + std r4,16(r10) |
| + std r4,24(r10) |
| + std r4,32(r10) |
| + std r4,40(r10) |
| + std r4,48(r10) |
| + std r4,56(r10) |
| + addi r10,r10,64 |
| + |
| + .align 4 |
| +4: bf 29,2f |
| + std r4,0(r10) |
| + std r4,8(r10) |
| + std r4,16(r10) |
| + std r4,24(r10) |
| + addi r10,r10,32 |
| + |
| + .align 4 |
| +2: bf 30,1f |
| + std r4,0(r10) |
| + std r4,8(r10) |
| + addi r10,r10,16 |
| + |
| + .align 4 |
| +1: bf 31,L(huge_dcbz_aligned) |
| + std r4,0(r10) |
| + addi r10,r10,8 |
| + |
| +L(huge_dcbz_aligned): |
| + /* Setup dcbz unroll offsets and count numbers. */ |
| + srdi r8,r5,9 |
| + clrldi r11,r5,55 |
| + cmpldi cr6,r11,0 |
| + li r9,128 |
| + cmpdi r8,0 |
| + beq L(huge_tail) |
| + li r7,256 |
| + li r6,384 |
| + mtctr r8 |
| + |
| + .align 4 |
| +L(huge_loop): |
| + /* Sets 512 bytes to zero in each iteration, the loop unrolling shows |
| + a throughput boost for large sizes (2048 bytes or higher). */ |
| + dcbz 0,r10 |
| + dcbz r9,r10 |
| + dcbz r7,r10 |
| + dcbz r6,r10 |
| + addi r10,r10,512 |
| + bdnz L(huge_loop) |
| + |
| + beqlr cr6 |
| + |
| +L(huge_tail): |
| + srdi r6,r11,8 |
| + srdi r7,r11,4 |
| + clrldi r8,r11,4 |
| + cmpldi cr6,r8,0 |
| + mtocrf 0x01,r6 |
| + |
| + beq cr6,L(tail) |
| + |
| + /* We have 1~511 bytes remaining. */ |
| + .align 4 |
| +32: bf 31,16f |
| + dcbz 0,r10 |
| + dcbz r9,r10 |
| + addi r10,r10,256 |
| + |
| + .align 4 |
| +16: mtocrf 0x01,r7 |
| + bf 28,8f |
| + dcbz 0,r10 |
| + addi r10,r10,128 |
| + |
| + .align 4 |
| +8: bf 29,4f |
| + std r4,0(r10) |
| + std r4,8(r10) |
| + std r4,16(r10) |
| + std r4,24(r10) |
| + std r4,32(r10) |
| + std r4,40(r10) |
| + std r4,48(r10) |
| + std r4,56(r10) |
| + addi r10,r10,64 |
| + |
| + .align 4 |
| +4: bf 30,2f |
| + std r4,0(r10) |
| + std r4,8(r10) |
| + std r4,16(r10) |
| + std r4,24(r10) |
| + addi r10,r10,32 |
| + |
| + .align 4 |
| +2: bf 31,L(tail) |
| + std r4,0(r10) |
| + std r4,8(r10) |
| + addi r10,r10,16 |
| + .align 4 |
| + |
| + /* Remaining 1~15 bytes. */ |
| +L(tail): |
| + mtocrf 0x01,r8 |
| + |
| + .align |
| +8: bf 28,4f |
| + std r4,0(r10) |
| + addi r10,r10,8 |
| + |
| + .align 4 |
| +4: bf 29,2f |
| + stw r4,0(r10) |
| + addi r10,r10,4 |
| + |
| + .align 4 |
| +2: bf 30,1f |
| + sth r4,0(r10) |
| + addi r10,r10,2 |
| + |
| + .align 4 |
| +1: bflr 31 |
| + stb r4,0(r10) |
| + blr |
| + |
| + /* Handle short copies of 0~31 bytes. Best throughput is achieved |
| + by just unrolling all operations. */ |
| + .align 4 |
| +L(write_LT_32): |
| + cmpldi cr6,5,8 |
| + mtocrf 0x01,r5 |
| + ble cr6,L(write_LE_8) |
| + |
| + /* At least 9 bytes to go. */ |
| + neg r8,r4 |
| + andi. r0,r8,3 |
| + cmpldi cr1,r5,16 |
| + beq L(write_LT_32_aligned) |
| + |
| + /* Force 4-byte alignment for SRC. */ |
| + mtocrf 0x01,r0 |
| + subf r5,r0,r5 |
| + |
| +2: bf 30,1f |
| + sth r4,0(r10) |
| + addi r10,r10,2 |
| + |
| +1: bf 31,L(end_4bytes_alignment) |
| + stb r4,0(r10) |
| + addi r10,r10,1 |
| + |
| + .align 4 |
| +L(end_4bytes_alignment): |
| + cmpldi cr1,r5,16 |
| + mtocrf 0x01,r5 |
| + |
| +L(write_LT_32_aligned): |
| + blt cr1,8f |
| + |
| + stw r4,0(r10) |
| + stw r4,4(r10) |
| + stw r4,8(r10) |
| + stw r4,12(r10) |
| + addi r10,r10,16 |
| + |
| +8: bf 28,L(tail4) |
| + stw r4,0(r10) |
| + stw r4,4(r10) |
| + addi r10,r10,8 |
| + |
| + .align 4 |
| + /* Copies 4~7 bytes. */ |
| +L(tail4): |
| + bf 29,L(tail2) |
| + stw r4,0(r10) |
| + bf 30,L(tail5) |
| + sth r4,4(r10) |
| + bflr 31 |
| + stb r4,6(r10) |
| + blr |
| + |
| + .align 4 |
| + /* Copies 2~3 bytes. */ |
| +L(tail2): |
| + bf 30,1f |
| + sth r4,0(r10) |
| + bflr 31 |
| + stb r4,2(r10) |
| + blr |
| + |
| + .align 4 |
| +L(tail5): |
| + bflr 31 |
| + stb r4,4(r10) |
| + blr |
| + |
| + .align 4 |
| +1: bflr 31 |
| + stb r4,0(r10) |
| + blr |
| + |
| + /* Handles copies of 0~8 bytes. */ |
| + .align 4 |
| +L(write_LE_8): |
| + bne cr6,L(tail4) |
| + |
| + stw r4,0(r10) |
| + stw r4,4(r10) |
| + blr |
| +END_GEN_TB (memset,TB_TOCLESS) |
| +libc_hidden_builtin_def (memset) |
| + |
| +/* Copied from bzero.S to prevent the linker from inserting a stub |
| + between bzero and memset. */ |
| +ENTRY (__bzero) |
| + CALL_MCOUNT 3 |
| + mr r5,r4 |
| + li r4,0 |
| + b L(_memset) |
| +END (__bzero) |
| +#ifndef __bzero |
| +weak_alias (__bzero, bzero) |
| +#endif |
| -- |
| 2.1.0 |
| |