From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-ej1-x636.google.com (mail-ej1-x636.google.com [IPv6:2a00:1450:4864:20::636]) by sourceware.org (Postfix) with ESMTPS id 09B9F3858401 for ; Sat, 29 Oct 2022 20:20:09 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 09B9F3858401 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gmail.com Received: by mail-ej1-x636.google.com with SMTP id ud5so20599017ejc.4 for ; Sat, 29 Oct 2022 13:20:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=xhTX0lmWKDEZzQznC9RO3Us5euviLQ98TzLVxLcyOLA=; b=kNDD+vgezZVJePbgn802h/qJjfdWtEHgu4KgSxRkcszoW/7O7zccg3ikucpjiL6TUv 2IPfC+zw8+oG9iyDvlMlpiB3z0rB9zI13N0mLUctC/7a+0p61VJbHpy2KY5tkC5x2GVv 6zc1uzDfr1/Ube3OZ58T8KtqDkdDCE2iqdSVdlxcq0f1egIugI3VfcHJ1cP4STnQxtdt DFaTilxCBY6UnwLaw8Qg+r+YsJZ1d1XfLt5KBlTPd3MJP5DhkWPebm8fJ1D9tIE6wkP7 7+y2YmFNJtVyfyTE2xMSBaD6Z9Q8cDhtr9v+rOgSO9QJDeOcOissSTRvG5/gLbfMU8ce d5XQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=xhTX0lmWKDEZzQznC9RO3Us5euviLQ98TzLVxLcyOLA=; b=5+0b2bNAguHrYoO6OZ+Mq6vcP8Wo+yF92yG1G0LJycFJZocxx/E6eKh8lqsmq7HkCf KXvSdPR+hnf+FNrOyYDzjnnbyyQ4EgxcKCygGnJFYO0zCkKAaY7spm5iXf+KwDwOTele QlfdwDW1K43FLIl2jRU2x46jJIshZazmSHrewW1cflw+JMrLa99yXd4Tek7R2f8rAjVw LBKoUX0eDclAC3SyWpdbTWQMpHPzjAi+oFosfPSG5jZV6H3EadouzuLQl1k3U385KuRh MNEbxaAfF6AiqSJ70ouPvY23LR3U8HL/4wSksKyMqurS1nBt7Aie1oK0SaT1877UWQr0 g79w== X-Gm-Message-State: ACrzQf1XVgJfU4f2TU9y6uA3BBJOEJ8OUH3ACneRghm3V31Im7l42Pqi fHEr4ZnIEDnBna0ZsLO177Ommd8rbs4YRg== X-Google-Smtp-Source: AMsMyM7FHZ0JjSoWMYGpHVVR/EvW7TbwbOfbmr2m+xiAJ4cCAF9YFux7EIE8WOVFID3c3SQHpFDuFw== X-Received: by 2002:a17:906:db0e:b0:77b:82cf:54a6 with SMTP id xj14-20020a170906db0e00b0077b82cf54a6mr5064719ejb.691.1667074807495; Sat, 29 Oct 2022 13:20:07 -0700 (PDT) Received: from noahgold-DESK.lan (2603-8080-1301-76c6-d6f1-87e2-664d-e1ca.res6.spectrum.com. [2603:8080:1301:76c6:d6f1:87e2:664d:e1ca]) by smtp.gmail.com with ESMTPSA id f2-20020a056402194200b00461bb7e7ef1sm1203074edz.30.2022.10.29.13.20.06 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 29 Oct 2022 13:20:07 -0700 (PDT) From: Noah Goldstein To: libc-alpha@sourceware.org Cc: goldstein.w.n@gmail.com, hjl.tools@gmail.com, carlos@systemhalted.org Subject: [PATCH v1 3/3] x86: Use VMM API in memcmpeq-evex.S and minor changes Date: Sat, 29 Oct 2022 15:19:59 -0500 Message-Id: <20221029201959.4082193-3-goldstein.w.n@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20221029201959.4082193-1-goldstein.w.n@gmail.com> References: <20221029201959.4082193-1-goldstein.w.n@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-12.1 required=5.0 tests=BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,FREEMAIL_FROM,GIT_PATCH_0,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_PASS,TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: Changes to generated code are: 1. In a few places use `vpcmpeqb` instead of `vpcmpneq` to save a byte of code size. 2. Add a branch for length <= (VEC_SIZE * 6) as opposed to doing the entire block of [VEC_SIZE * 4 + 1, VEC_SIZE * 8] in a single basic-block (the space to add the extra branch without changing code size is bought with the above change). Change (2) has roughly a 20-25% speedup for sizes in [VEC_SIZE * 4 + 1, VEC_SIZE * 6] and negligible to no-cost for [VEC_SIZE * 6 + 1, VEC_SIZE * 8] >From N=10 runs on Tigerlake: align1,align2 ,length ,result ,New TIme ,Cur Time,New Time / Old Time 0 ,0 ,129 ,0 ,5.404 ,6.887 ,0.785 0 ,0 ,129 ,1 ,5.308 ,6.826 ,0.778 0 ,0 ,129 ,18446744073709551615 ,5.359 ,6.823 ,0.785 0 ,0 ,161 ,0 ,5.284 ,6.827 ,0.774 0 ,0 ,161 ,1 ,5.317 ,6.745 ,0.788 0 ,0 ,161 ,18446744073709551615 ,5.406 ,6.778 ,0.798 0 ,0 ,193 ,0 ,6.969 ,6.832 ,1.000 0 ,0 ,193 ,1 ,6.943 ,6.748 ,1.029 0 ,0 ,193 ,18446744073709551615 ,6.997 ,6.728 ,1.011 0 ,0 ,225 ,0 ,7.144 ,6.746 ,0.989 0 ,0 ,225 ,1 ,7.218 ,6.683 ,1.003 0 ,0 ,225 ,18446744073709551615 ,6.864 ,6.767 ,0.992 0 ,0 ,256 ,0 ,5.423 ,5.482 ,0.989 0 ,0 ,256 ,1 ,5.348 ,5.465 ,0.978 0 ,0 ,256 ,18446744073709551615 ,5.321 ,5.518 ,0.964 Rewriting with VMM API allows for memcmpeq-evex to be used with evex512 by including "x86-evex512-vecs.h" at the top. Complete check passes on x86-64. --- sysdeps/x86_64/multiarch/memcmpeq-evex.S | 255 ++++++++++++++--------- 1 file changed, 155 insertions(+), 100 deletions(-) diff --git a/sysdeps/x86_64/multiarch/memcmpeq-evex.S b/sysdeps/x86_64/multiarch/memcmpeq-evex.S index 41124ef1d3..671d19393e 100644 --- a/sysdeps/x86_64/multiarch/memcmpeq-evex.S +++ b/sysdeps/x86_64/multiarch/memcmpeq-evex.S @@ -41,24 +41,53 @@ # define MEMCMPEQ __memcmpeq_evex # endif +# ifndef VEC_SIZE +# include "x86-evex512-vecs.h" +# endif +# include "reg-macros.h" + + +# if VEC_SIZE == 32 + +# define TEST_ZERO_VCMP(reg) inc %VGPR(reg) +# define TEST_ZERO(reg) test %VGPR(reg), %VGPR(reg) + +# define TO_32BIT_P1(reg) /* Do nothing. */ +# define TO_32BIT_P2(reg) /* Do nothing. */ +# define TO_32BIT(reg) /* Do nothing. */ + +# define VEC_CMP VPCMPEQ + +# elif VEC_SIZE == 64 + +# define TEST_ZERO_VCMP(reg) TEST_ZERO(reg) +# define TEST_ZERO(reg) neg %VGPR(reg) + + + /* VEC_SIZE == 64 needs to reduce the 64-bit mask to a 32-bit + int. We have two methods for this. If the mask with branched + on, we use `neg` for the branch then `sbb` to get the 32-bit + return. If the mask was no branched on, we just use + `popcntq`. */ +# define TO_32BIT_P1(reg) TEST_ZERO(reg) +# define TO_32BIT_P2(reg) sbb %VGPR_SZ(reg, 32), %VGPR_SZ(reg, 32) +# define TO_32BIT(reg) popcntq %reg, %reg + +# define VEC_CMP VPCMPNEQ + +# else +# error "Unsupported VEC_SIZE" +# endif + + # define VMOVU_MASK vmovdqu8 -# define VMOVU vmovdqu64 -# define VPCMP vpcmpub +# define VPCMPNEQ vpcmpneqb +# define VPCMPEQ vpcmpeqb # define VPTEST vptestmb -# define VEC_SIZE 32 # define PAGE_SIZE 4096 -# define YMM0 ymm16 -# define YMM1 ymm17 -# define YMM2 ymm18 -# define YMM3 ymm19 -# define YMM4 ymm20 -# define YMM5 ymm21 -# define YMM6 ymm22 - - - .section .text.evex, "ax", @progbits + .section SECTION(.text), "ax", @progbits ENTRY_P2ALIGN (MEMCMPEQ, 6) # ifdef __ILP32__ /* Clear the upper 32 bits. */ @@ -69,47 +98,54 @@ ENTRY_P2ALIGN (MEMCMPEQ, 6) ja L(more_1x_vec) /* Create mask of bytes that are guranteed to be valid because - of length (edx). Using masked movs allows us to skip checks for - page crosses/zero size. */ - movl $-1, %ecx - bzhil %edx, %ecx, %ecx - kmovd %ecx, %k2 + of length (edx). Using masked movs allows us to skip checks + for page crosses/zero size. */ + mov $-1, %VRAX + bzhi %VRDX, %VRAX, %VRAX + /* NB: A `jz` might be useful here. Page-faults that are + invalidated by predicate execution (the evex mask) can be + very slow. The expectation is this is not the norm so and + "most" code will not regularly call 'memcmp' with length = 0 + and memory that is not wired up. */ + KMOV %VRAX, %k2 /* Use masked loads as VEC_SIZE could page cross where length (edx) would not. */ - VMOVU_MASK (%rsi), %YMM2{%k2} - VPCMP $4,(%rdi), %YMM2, %k1{%k2} - kmovd %k1, %eax + VMOVU_MASK (%rsi), %VMM(2){%k2}{z} + VPCMPNEQ (%rdi), %VMM(2), %k1{%k2} + KMOV %k1, %VRAX + TO_32BIT (VRAX) ret - + .p2align 4,, 3 L(last_1x_vec): - VMOVU -(VEC_SIZE * 1)(%rsi, %rdx), %YMM1 - VPCMP $4, -(VEC_SIZE * 1)(%rdi, %rdx), %YMM1, %k1 - kmovd %k1, %eax + VMOVU -(VEC_SIZE * 1)(%rsi, %rdx), %VMM(1) + VPCMPNEQ -(VEC_SIZE * 1)(%rdi, %rdx), %VMM(1), %k1 + KMOV %k1, %VRAX + TO_32BIT_P1 (rax) L(return_neq0): + TO_32BIT_P2 (rax) ret - - .p2align 4 + .p2align 4,, 12 L(more_1x_vec): /* From VEC + 1 to 2 * VEC. */ - VMOVU (%rsi), %YMM1 + VMOVU (%rsi), %VMM(1) /* Use compare not equals to directly check for mismatch. */ - VPCMP $4,(%rdi), %YMM1, %k1 - kmovd %k1, %eax - testl %eax, %eax + VPCMPNEQ (%rdi), %VMM(1), %k1 + KMOV %k1, %VRAX + TEST_ZERO (rax) jnz L(return_neq0) cmpq $(VEC_SIZE * 2), %rdx jbe L(last_1x_vec) /* Check second VEC no matter what. */ - VMOVU VEC_SIZE(%rsi), %YMM2 - VPCMP $4, VEC_SIZE(%rdi), %YMM2, %k1 - kmovd %k1, %eax - testl %eax, %eax + VMOVU VEC_SIZE(%rsi), %VMM(2) + VPCMPNEQ VEC_SIZE(%rdi), %VMM(2), %k1 + KMOV %k1, %VRAX + TEST_ZERO (rax) jnz L(return_neq0) /* Less than 4 * VEC. */ @@ -117,16 +153,16 @@ L(more_1x_vec): jbe L(last_2x_vec) /* Check third and fourth VEC no matter what. */ - VMOVU (VEC_SIZE * 2)(%rsi), %YMM3 - VPCMP $4,(VEC_SIZE * 2)(%rdi), %YMM3, %k1 - kmovd %k1, %eax - testl %eax, %eax + VMOVU (VEC_SIZE * 2)(%rsi), %VMM(3) + VEC_CMP (VEC_SIZE * 2)(%rdi), %VMM(3), %k1 + KMOV %k1, %VRAX + TEST_ZERO_VCMP (rax) jnz L(return_neq0) - VMOVU (VEC_SIZE * 3)(%rsi), %YMM4 - VPCMP $4,(VEC_SIZE * 3)(%rdi), %YMM4, %k1 - kmovd %k1, %eax - testl %eax, %eax + VMOVU (VEC_SIZE * 3)(%rsi), %VMM(4) + VEC_CMP (VEC_SIZE * 3)(%rdi), %VMM(4), %k1 + KMOV %k1, %VRAX + TEST_ZERO_VCMP (rax) jnz L(return_neq0) /* Go to 4x VEC loop. */ @@ -136,8 +172,8 @@ L(more_1x_vec): /* Handle remainder of size = 4 * VEC + 1 to 8 * VEC without any branches. */ - VMOVU -(VEC_SIZE * 4)(%rsi, %rdx), %YMM1 - VMOVU -(VEC_SIZE * 3)(%rsi, %rdx), %YMM2 + VMOVU -(VEC_SIZE * 1)(%rsi, %rdx), %VMM(1) + VMOVU -(VEC_SIZE * 2)(%rsi, %rdx), %VMM(2) addq %rdx, %rdi /* Wait to load from s1 until addressed adjust due to @@ -145,26 +181,32 @@ L(more_1x_vec): /* vpxor will be all 0s if s1 and s2 are equal. Otherwise it will have some 1s. */ - vpxorq -(VEC_SIZE * 4)(%rdi), %YMM1, %YMM1 - /* Ternary logic to xor -(VEC_SIZE * 3)(%rdi) with YMM2 while - oring with YMM1. Result is stored in YMM1. */ - vpternlogd $0xde, -(VEC_SIZE * 3)(%rdi), %YMM1, %YMM2 - - VMOVU -(VEC_SIZE * 2)(%rsi, %rdx), %YMM3 - vpxorq -(VEC_SIZE * 2)(%rdi), %YMM3, %YMM3 - /* Or together YMM1, YMM2, and YMM3 into YMM3. */ - VMOVU -(VEC_SIZE)(%rsi, %rdx), %YMM4 - vpxorq -(VEC_SIZE)(%rdi), %YMM4, %YMM4 - - /* Or together YMM2, YMM3, and YMM4 into YMM4. */ - vpternlogd $0xfe, %YMM2, %YMM3, %YMM4 - - /* Compare YMM4 with 0. If any 1s s1 and s2 don't match. */ - VPTEST %YMM4, %YMM4, %k1 - kmovd %k1, %eax + vpxorq -(VEC_SIZE * 1)(%rdi), %VMM(1), %VMM(1) + /* Ternary logic to xor -(VEC_SIZE * 3)(%rdi) with VEC(2) while + oring with VEC(1). Result is stored in VEC(1). */ + vpternlogd $0xde, -(VEC_SIZE * 2)(%rdi), %VMM(1), %VMM(2) + + cmpl $(VEC_SIZE * 6), %edx + jbe L(4x_last_2x_vec) + + VMOVU -(VEC_SIZE * 3)(%rsi, %rdx), %VMM(3) + vpxorq -(VEC_SIZE * 3)(%rdi), %VMM(3), %VMM(3) + /* Or together VEC(1), VEC(2), and VEC(3) into VEC(3). */ + VMOVU -(VEC_SIZE * 4)(%rsi, %rdx), %VMM(4) + vpxorq -(VEC_SIZE * 4)(%rdi), %VMM(4), %VMM(4) + + /* Or together VEC(4), VEC(3), and VEC(2) into VEC(2). */ + vpternlogd $0xfe, %VMM(4), %VMM(3), %VMM(2) + + /* Compare VEC(4) with 0. If any 1s s1 and s2 don't match. */ +L(4x_last_2x_vec): + VPTEST %VMM(2), %VMM(2), %k1 + KMOV %k1, %VRAX + TO_32BIT (VRAX) ret - .p2align 4 + + .p2align 4,, 10 L(more_8x_vec): /* Set end of s1 in rdx. */ leaq -(VEC_SIZE * 4)(%rdi, %rdx), %rdx @@ -175,67 +217,80 @@ L(more_8x_vec): andq $-VEC_SIZE, %rdi /* Adjust because first 4x vec where check already. */ subq $-(VEC_SIZE * 4), %rdi - .p2align 4 + .p2align 5,, 12 + .p2align 4,, 8 L(loop_4x_vec): - VMOVU (%rsi, %rdi), %YMM1 - vpxorq (%rdi), %YMM1, %YMM1 + VMOVU (%rsi, %rdi), %VMM(1) + vpxorq (%rdi), %VMM(1), %VMM(1) - VMOVU VEC_SIZE(%rsi, %rdi), %YMM2 - vpternlogd $0xde,(VEC_SIZE)(%rdi), %YMM1, %YMM2 + VMOVU VEC_SIZE(%rsi, %rdi), %VMM(2) + vpternlogd $0xde, (VEC_SIZE)(%rdi), %VMM(1), %VMM(2) - VMOVU (VEC_SIZE * 2)(%rsi, %rdi), %YMM3 - vpxorq (VEC_SIZE * 2)(%rdi), %YMM3, %YMM3 + VMOVU (VEC_SIZE * 2)(%rsi, %rdi), %VMM(3) + vpxorq (VEC_SIZE * 2)(%rdi), %VMM(3), %VMM(3) - VMOVU (VEC_SIZE * 3)(%rsi, %rdi), %YMM4 - vpxorq (VEC_SIZE * 3)(%rdi), %YMM4, %YMM4 + VMOVU (VEC_SIZE * 3)(%rsi, %rdi), %VMM(4) + vpxorq (VEC_SIZE * 3)(%rdi), %VMM(4), %VMM(4) - vpternlogd $0xfe, %YMM2, %YMM3, %YMM4 - VPTEST %YMM4, %YMM4, %k1 - kmovd %k1, %eax - testl %eax, %eax + vpternlogd $0xfe, %VMM(2), %VMM(3), %VMM(4) + VPTEST %VMM(4), %VMM(4), %k1 + KMOV %k1, %VRAX + TEST_ZERO (rax) jnz L(return_neq2) subq $-(VEC_SIZE * 4), %rdi cmpq %rdx, %rdi jb L(loop_4x_vec) subq %rdx, %rdi - VMOVU (VEC_SIZE * 3)(%rsi, %rdx), %YMM4 - vpxorq (VEC_SIZE * 3)(%rdx), %YMM4, %YMM4 + + VMOVU (VEC_SIZE * 3)(%rsi, %rdx), %VMM(4) + vpxorq (VEC_SIZE * 3)(%rdx), %VMM(4), %VMM(4) /* rdi has 4 * VEC_SIZE - remaining length. */ - cmpl $(VEC_SIZE * 3), %edi - jae L(8x_last_1x_vec) + /* Load regardless of branch. */ - VMOVU (VEC_SIZE * 2)(%rsi, %rdx), %YMM3 - /* Ternary logic to xor (VEC_SIZE * 2)(%rdx) with YMM3 while - oring with YMM4. Result is stored in YMM4. */ - vpternlogd $0xf6,(VEC_SIZE * 2)(%rdx), %YMM3, %YMM4 + VMOVU (VEC_SIZE * 2)(%rsi, %rdx), %VMM(3) + /* Ternary logic to xor (VEC_SIZE * 2)(%rdx) with VEC(3) while + oring with VEC(4). Result is stored in VEC(4). */ + vpternlogd $0xf6, (VEC_SIZE * 2)(%rdx), %VMM(3), %VMM(4) + + /* Seperate logic as we can only use testb for VEC_SIZE == 64. + */ +# if VEC_SIZE == 64 + testb %dil, %dil + js L(8x_last_2x_vec) +# else cmpl $(VEC_SIZE * 2), %edi - jae L(8x_last_2x_vec) + jge L(8x_last_2x_vec) +# endif - VMOVU VEC_SIZE(%rsi, %rdx), %YMM2 - vpxorq VEC_SIZE(%rdx), %YMM2, %YMM2 + VMOVU VEC_SIZE(%rsi, %rdx), %VMM(2) + vpxorq VEC_SIZE(%rdx), %VMM(2), %VMM(2) - VMOVU (%rsi, %rdx), %YMM1 - vpxorq (%rdx), %YMM1, %YMM1 + VMOVU (%rsi, %rdx), %VMM(1) + vpxorq (%rdx), %VMM(1), %VMM(1) - vpternlogd $0xfe, %YMM1, %YMM2, %YMM4 + vpternlogd $0xfe, %VMM(1), %VMM(2), %VMM(4) L(8x_last_1x_vec): L(8x_last_2x_vec): - VPTEST %YMM4, %YMM4, %k1 - kmovd %k1, %eax + VPTEST %VMM(4), %VMM(4), %k1 + KMOV %k1, %VRAX + TO_32BIT_P1 (rax) L(return_neq2): + TO_32BIT_P2 (rax) ret - .p2align 4,, 8 + .p2align 4,, 4 L(last_2x_vec): - VMOVU -(VEC_SIZE * 2)(%rsi, %rdx), %YMM1 - vpxorq -(VEC_SIZE * 2)(%rdi, %rdx), %YMM1, %YMM1 - VMOVU -(VEC_SIZE * 1)(%rsi, %rdx), %YMM2 - vpternlogd $0xde, -(VEC_SIZE * 1)(%rdi, %rdx), %YMM1, %YMM2 - VPTEST %YMM2, %YMM2, %k1 - kmovd %k1, %eax + VMOVU -(VEC_SIZE * 2)(%rsi, %rdx), %VMM(1) + vpxorq -(VEC_SIZE * 2)(%rdi, %rdx), %VMM(1), %VMM(1) + VMOVU -(VEC_SIZE * 1)(%rsi, %rdx), %VMM(2) + vpternlogd $0xde, -(VEC_SIZE * 1)(%rdi, %rdx), %VMM(1), %VMM(2) + VPTEST %VMM(2), %VMM(2), %k1 + KMOV %k1, %VRAX + TO_32BIT (VRAX) ret - /* 1 Bytes from next cache line. */ + /* evex256: 1 Bytes from next cache line. evex512: 15 Bytes from + next cache line. */ END (MEMCMPEQ) #endif -- 2.34.1