linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH V2 01/30] bitops: add parity functions
@ 2016-04-05  2:06 Zeng Zhaoxiu
  2016-04-05  4:23 ` [PATCH V2 02/30] Include generic parity.h in some architectures' bitops.h Zeng Zhaoxiu
                   ` (29 more replies)
  0 siblings, 30 replies; 84+ messages in thread
From: Zeng Zhaoxiu @ 2016-04-05  2:06 UTC (permalink / raw)
  To: Arnd Bergmann, Andrew Morton, Martin Kepplinger,
	Rasmus Villemoes, Ingo Molnar, Yury Norov, Sasha Levin,
	Denys Vlasenko
  Cc: linux-kernel, linux-arch

From: Zhaoxiu Zeng <zhaoxiu.zeng@gmail.com>

These patches provide generic and architecture-specific odd parity 
calculations.

I did not use GCC's __builtin_parity* functions, based on the following 
reasons:
   1. I don't know where to identify which version of GCC from the beginning
      supported __builtin_parity for the architecture.
   2. For the architectures that doesn't have popcount instruction, GCC 
instead use
      "call __paritysi2" (__paritydi2 for 64-bits). So if use 
__builtin_parity, we must
      provide __paritysi2 and __paritydi2 functions for these architectures.
      Additionally, parity4,8,16 might be "__builtin_parity(x & mask)", 
but the "& mask"
      operation is totally unnecessary.
   3. For the architectures that have popcount instruction, we do the 
same things.
   4. For powerpc, sparc, and x86, we do runtime patching to use 
popcount instruction
      if the CPU support.

I have compiled successfully with x86_64_defconfig, i386_defconfig, 
pseries_defconfig
and sparc64_defconfig. And I used the following codes to test:

     #include <stdio.h>
     #include <stdlib.h>
     #include <stdint.h>

     #ifdef __x86_64__
     /* popcnt %edi, %eax -- redundant REX prefix for alignment */
     #define POPCNT32 ".byte 0xf3,0x40,0x0f,0xb8,0xc7"
     /* popcnt %rdi, %rax */
     #define POPCNT64 ".byte 0xf3,0x48,0x0f,0xb8,0xc7"
     #define REG_IN "D"
     #define REG_OUT "a"
     #else
     /* popcnt %eax, %eax */
     #define POPCNT32 ".byte 0xf3,0x0f,0xb8,0xc0"
     #define REG_IN "a"
     #define REG_OUT "a"
     #endif

     static inline int c_parity4(unsigned int w)
     {
         w &= 0xf;
         return (0x6996 >> w) & 1;
     }

     static inline int c_parity8(unsigned int w)
     {
         w ^= w >> 4;
         return c_parity4(w);
     }

     static inline int c_parity16(unsigned int w)
     {
         w ^= w >> 8;
         return c_parity8(w);
     }

     static inline int c_parity32(unsigned int w)
     {
         w ^= w >> 16;
         return c_parity16(w);
     }

     static inline int c_parity64(uint64_t w)
     {
         return c_parity32((unsigned int)w ^ (unsigned int)(w >> 32));
     }

     static inline int asm_parity4(unsigned int w)
     {
         unsigned int res = 0;

         asm("test    $0xf, %1        \n"
             "setpo    %b0                \n"
             : "+q" (res)
             : "r" (w)
             : "cc");

         return res;
     }

     static inline int asm_parity8(unsigned int w)
     {
         unsigned int res = 0;

         asm("test    %1, %1            \n"
             "setpo    %b0            \n"
             : "+q" (res)
             : "r" (w)
             : "cc");

         return res;
     }

     static inline int asm_parity16(unsigned int w)
     {
         unsigned int res = 0;

         asm("xor    %h1, %b1        \n"
             "setpo    %b0            \n"
             : "+q" (res), "+q" (w)
             : : "cc");

         return res;
     }

     static inline int asm_parity32_1(unsigned int w)
     {
         unsigned int res;

         w ^= w >> 16;
         asm("xor    %%ah, %%al        \n"
             "mov    $0, %%eax        \n"
             "setpo    %%al            \n"
             : "=a" (res)
             : "a" (w)
             : "cc");

         return res;
     }

     static inline int asm_parity32_2(unsigned int w)
     {
         unsigned int res;

         asm(POPCNT32 "                \n"
             "andl    $1, %0            \n"
             : "="REG_OUT (res)
             : REG_IN (w)
             : "cc");

         return res;
     }

     #ifdef __x86_64__
     static inline int asm_parity64_1(uint64_t w)
     {
         unsigned int res = (unsigned int)w ^ (unsigned int)(w >> 32);

         res ^= res >> 16;
         asm("xor    %%ah, %%al        \n"
             "mov    $0, %%eax        \n"
             "setpo    %%al            \n"
             : "=a" (res)
             : "a" (res)
             : "cc");

         return res;
     }

     static inline int asm_parity64_2(uint64_t w)
     {
         unsigned int res;

         asm(POPCNT64 "                \n"
             "andl    $1, %0            \n"
             : "="REG_OUT (res)
             : REG_IN (w)
             : "cc");

         return res;
     }
     #else
     static inline int asm_parity64_1(uint64_t w)
     {
         return asm_parity32_1((unsigned int)(w >> 32) ^ (unsigned int)w);
     }

     static inline int asm_parity64_2(uint64_t w)
     {
         return asm_parity32_2((unsigned int)(w >> 32) ^ (unsigned int)w);
     }
     #endif

     int main(int argc, char **argv)
     {
         int ok = 1;
         int count = 1000, i;

         if (argc >= 2)
             count = atoi(argv[1]);

         srand((unsigned)time(NULL));

         for (i = 0; i < count; i++) {
             uint64_t w = rand() | (uint64_t)rand() << 32;
             int p4_1 = c_parity4(w);
             int p4_2 = asm_parity4(w);
             int p8_1 = c_parity8(w);
             int p8_2 = asm_parity8(w);
             int p16_1 = c_parity16(w);
             int p16_2 = asm_parity16(w);
             int p32_1 = c_parity32(w);
             int p32_2 = asm_parity32_1(w);
             int p32_3 = asm_parity32_2(w);
             int p64_1 = c_parity64(w);
             int p64_2 = asm_parity64_1(w);
             int p64_3 = asm_parity64_2(w);
             if (p4_1 != p4_2 ||
                 p8_1 != p8_2 ||
                 p16_1 != p16_2 ||
                 p32_1 != p32_2 || p32_1 != p32_3 ||
                 p64_1 != p64_2 || p64_1 != p64_3) {
                 fprintf(stderr, "Err: %llx\n"
                             "\tc_parity4 = %d, asm_parity4 = %d,\n"
                             "\tc_parity8 = %d, asm_parity8 = %d,\n"
                             "\tc_parity16 = %d, asm_parity16 = %d,\n"
                             "\tc_parity32 = %d, asm_parity32_1 = %d, 
asm_parity32_2 = %d\n"
                             "\tc_parity64 = %d, asm_parity64_1 = %d, 
asm_parity64_2 = %d\n",
                             w, p4_1, p4_2, p8_1, p8_2, p16_1, p16_2, 
p32_1, p32_2, p32_3, p64_1, p64_2, p64_3);
                 ok = 0;
             }
         }

         fprintf(stderr, "%s\n", ok ? "OK" : "FAIL");
         return 0;
     }

---
  include/asm-generic/bitops.h              |  1 +
  include/asm-generic/bitops/arch_parity.h  | 39 
+++++++++++++++++++++++++++++++
  include/asm-generic/bitops/const_parity.h | 36 
++++++++++++++++++++++++++++
  include/asm-generic/bitops/parity.h       |  7 ++++++
  include/linux/bitops.h                    |  5 ++++
  5 files changed, 88 insertions(+)
  create mode 100644 include/asm-generic/bitops/arch_parity.h
  create mode 100644 include/asm-generic/bitops/const_parity.h
  create mode 100644 include/asm-generic/bitops/parity.h

diff --git a/include/asm-generic/bitops.h b/include/asm-generic/bitops.h
index dcdcacf..d85722f 100644
--- a/include/asm-generic/bitops.h
+++ b/include/asm-generic/bitops.h
@@ -27,6 +27,7 @@
  #include <asm-generic/bitops/sched.h>
  #include <asm-generic/bitops/ffs.h>
  #include <asm-generic/bitops/hweight.h>
+#include <asm-generic/bitops/parity.h>
  #include <asm-generic/bitops/lock.h>

  #include <asm-generic/bitops/atomic.h>
diff --git a/include/asm-generic/bitops/arch_parity.h 
b/include/asm-generic/bitops/arch_parity.h
new file mode 100644
index 0000000..cddc555
--- /dev/null
+++ b/include/asm-generic/bitops/arch_parity.h
@@ -0,0 +1,39 @@
+#ifndef _ASM_GENERIC_BITOPS_ARCH_PARITY_H_
+#define _ASM_GENERIC_BITOPS_ARCH_PARITY_H_
+
+#include <asm/types.h>
+
+/*
+ * Refrence to 
'https://graphics.stanford.edu/~seander/bithacks.html#ParityParallel'.
+ */
+
+static inline unsigned int __arch_parity4(unsigned int w)
+{
+    w &= 0xf;
+    return (0x6996 >> w) & 1;
+}
+
+static inline unsigned int __arch_parity8(unsigned int w)
+{
+    w ^= w >> 4;
+    return __arch_parity4(w);
+}
+
+static inline unsigned int __arch_parity16(unsigned int w)
+{
+    w ^= w >> 8;
+    return __arch_parity8(w);
+}
+
+static inline unsigned int __arch_parity32(unsigned int w)
+{
+    w ^= w >> 16;
+    return __arch_parity16(w);
+}
+
+static inline unsigned int __arch_parity64(__u64 w)
+{
+    return __arch_parity32((unsigned int)(w >> 32) ^ (unsigned int)w);
+}
+
+#endif /* _ASM_GENERIC_BITOPS_ARCH_PARITY_H_ */
diff --git a/include/asm-generic/bitops/const_parity.h 
b/include/asm-generic/bitops/const_parity.h
new file mode 100644
index 0000000..6af7987
--- /dev/null
+++ b/include/asm-generic/bitops/const_parity.h
@@ -0,0 +1,36 @@
+#ifndef _ASM_GENERIC_BITOPS_CONST_PARITY_H_
+#define _ASM_GENERIC_BITOPS_CONST_PARITY_H_
+
+/*
+ * Compile time versions of __arch_parityN()
+ */
+#define __const_parity4(w)   ((0x6996 >> ((w) & 0xf)) & 1)
+#define __const_parity8(w)   (__const_parity4((w) ^ ((w) >> 4)))
+#define __const_parity16(w)  (__const_parity8((w) ^ ((w) >> 8)))
+#define __const_parity32(w)  (__const_parity16((w) ^ ((w) >> 16)))
+#define __const_parity64(w)  (__const_parity32((w) ^ ((w) >> 32)))
+
+/*
+ * Generic interface.
+ */
+#define parity4(w)   (__builtin_constant_p(w) ? __const_parity4(w) : 
__arch_parity4(w))
+#define parity8(w)   (__builtin_constant_p(w) ? __const_parity8(w) : 
__arch_parity8(w))
+#define parity16(w)  (__builtin_constant_p(w) ? __const_parity16(w) : 
__arch_parity16(w))
+#define parity32(w)  (__builtin_constant_p(w) ? __const_parity32(w) : 
__arch_parity32(w))
+#define parity64(w)  (__builtin_constant_p(w) ? __const_parity64(w) : 
__arch_parity64(w))
+
+/*
+ * Interface for known constant arguments
+ */
+#define PARITY4(w)   (BUILD_BUG_ON_ZERO(!__builtin_constant_p(w)) + 
__const_parity4(w))
+#define PARITY8(w)   (BUILD_BUG_ON_ZERO(!__builtin_constant_p(w)) + 
__const_parity8(w))
+#define PARITY16(w)  (BUILD_BUG_ON_ZERO(!__builtin_constant_p(w)) + 
__const_parity16(w))
+#define PARITY32(w)  (BUILD_BUG_ON_ZERO(!__builtin_constant_p(w)) + 
__const_parity32(w))
+#define PARITY64(w)  (BUILD_BUG_ON_ZERO(!__builtin_constant_p(w)) + 
__const_parity64(w))
+
+/*
+ * Type invariant interface to the compile time constant parity functions.
+ */
+#define PARITY(w)    PARITY64((u64)(w))
+
+#endif /* _ASM_GENERIC_BITOPS_CONST_PARITY_H_ */
diff --git a/include/asm-generic/bitops/parity.h 
b/include/asm-generic/bitops/parity.h
new file mode 100644
index 0000000..a91dce7
--- /dev/null
+++ b/include/asm-generic/bitops/parity.h
@@ -0,0 +1,7 @@
+#ifndef _ASM_GENERIC_BITOPS_PARITY_H_
+#define _ASM_GENERIC_BITOPS_PARITY_H_
+
+#include <asm-generic/bitops/arch_parity.h>
+#include <asm-generic/bitops/const_parity.h>
+
+#endif /* _ASM_GENERIC_BITOPS_PARITY_H_ */
diff --git a/include/linux/bitops.h b/include/linux/bitops.h
index defeaac..8952f88 100644
--- a/include/linux/bitops.h
+++ b/include/linux/bitops.h
@@ -80,6 +80,11 @@ static __always_inline unsigned long 
hweight_long(unsigned long w)
      return sizeof(w) == 4 ? hweight32(w) : hweight64(w);
  }

+static __always_inline unsigned int parity_long(unsigned long w)
+{
+    return sizeof(w) == 4 ? parity32(w) : parity64(w);
+}
+
  /**
   * rol64 - rotate a 64-bit value left
   * @word: value to rotate
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 84+ messages in thread

end of thread, other threads:[~2016-05-18 10:39 UTC | newest]

Thread overview: 84+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-04-05  2:06 [PATCH V2 01/30] bitops: add parity functions Zeng Zhaoxiu
2016-04-05  4:23 ` [PATCH V2 02/30] Include generic parity.h in some architectures' bitops.h Zeng Zhaoxiu
2016-04-06  8:41   ` [PATCH v2 " zengzhaoxiu
2016-04-05 19:04 ` [PATCH V2 01/30] bitops: add parity functions Sam Ravnborg
2016-04-06  5:33   ` Zeng Zhaoxiu
2016-04-06  8:24     ` Sam Ravnborg
2016-04-06  8:22   ` [PATCH v2 " zengzhaoxiu
2016-04-06  8:46 ` [PATCH v2 03/30] Add alpha-specific " zengzhaoxiu
2016-04-06  8:53 ` [PATCH v2 04/30] Add blackfin-specific " zengzhaoxiu
2016-04-06  8:57 ` [PATCH v2 05/30] Add ia64-specific " zengzhaoxiu
2016-04-06  8:59 ` [PATCH v2 06/30] Add mips-specific " zengzhaoxiu
2016-04-06 10:23   ` zengzhaoxiu
2016-04-06  9:03 ` [PATCH v2 07/30] Add powerpc-specific " zengzhaoxiu
2016-04-06  9:07 ` [PATCH v2 08/30] Add sparc-specific " zengzhaoxiu
2016-04-06 18:44   ` Sam Ravnborg
2016-04-07  3:56     ` Zeng Zhaoxiu
2016-04-06  9:08 ` [PATCH v2 09/30] Add tile-specific " zengzhaoxiu
2016-04-06 13:27   ` Chris Metcalf
2016-04-07  3:55     ` Zeng Zhaoxiu
2016-04-06  9:14 ` [PATCH v2 10/30] Add x86-specific " zengzhaoxiu
2016-04-06 10:13   ` Borislav Petkov
2016-04-06 10:37     ` One Thousand Gnomes
2016-04-06 10:53       ` Borislav Petkov
2016-04-07  3:55         ` Zeng Zhaoxiu
2016-04-07  9:39           ` Borislav Petkov
2016-04-11  2:43       ` Zeng Zhaoxiu
2016-04-15  2:11         ` Borislav Petkov
2016-04-07  3:55     ` Zeng Zhaoxiu
2016-04-07  9:41       ` Borislav Petkov
2016-04-06 19:45   ` Andi Kleen
2016-04-07  3:56     ` Zeng Zhaoxiu
2016-04-07  6:31     ` Dmitry Vyukov
2016-04-07  9:43       ` Borislav Petkov
2016-05-04 18:46         ` [RFC PATCH] x86/hweight: Get rid of the special calling convention Borislav Petkov
2016-05-04 19:31           ` Brian Gerst
2016-05-04 19:33             ` H. Peter Anvin
2016-05-04 19:41               ` Borislav Petkov
2016-05-04 19:49                 ` H. Peter Anvin
2016-05-04 20:22                   ` Borislav Petkov
2016-05-04 20:51                     ` H. Peter Anvin
2016-05-04 21:09                     ` Andi Kleen
2016-05-05 13:02                     ` Denys Vlasenko
2016-05-05 14:04                       ` Borislav Petkov
2016-05-10 16:53                         ` [PATCH -v2] " Borislav Petkov
2016-05-10 17:23                           ` Peter Zijlstra
2016-05-10 19:02                             ` Borislav Petkov
2016-05-10 19:03                             ` H. Peter Anvin
2016-05-10 19:10                               ` Borislav Petkov
2016-05-10 22:30                                 ` H. Peter Anvin
2016-05-11  4:11                                   ` Borislav Petkov
2016-05-11 11:15                                     ` Brian Gerst
2016-05-11 11:24                                       ` Peter Zijlstra
2016-05-11 12:47                                         ` Borislav Petkov
2016-05-12  4:54                                         ` H. Peter Anvin
2016-05-12 11:57                                           ` Borislav Petkov
2016-05-12 12:14                                             ` Peter Zijlstra
2016-05-12 13:09                                               ` Borislav Petkov
2016-05-18 10:38                                                 ` Borislav Petkov
2016-04-07 14:10     ` [PATCH v2 10/30] Add x86-specific parity functions One Thousand Gnomes
2016-04-06  9:27 ` [PATCH v2 11/30] sunrpc: use parity8 zengzhaoxiu
2016-04-06  9:30 ` [PATCH v2 12/30] mips: use parity functions in cerr-sb1.c zengzhaoxiu
2016-04-06  9:36 ` [PATCH v2 13/30] bch: use parity32 zengzhaoxiu
2016-04-06  9:39 ` [PATCH v2 14/30] media: use parity8 in vivid-vbi-gen.c zengzhaoxiu
2016-04-06  9:41 ` [PATCH v2 15/30] media: use parity functions in saa7115 zengzhaoxiu
2016-04-06  9:43 ` [PATCH v2 16/30] input: use parity32 in grip_mp zengzhaoxiu
2016-04-06  9:44 ` [PATCH v2 17/30] input: use parity64 in sidewinder zengzhaoxiu
2016-04-06  9:45 ` [PATCH v2 18/30] input: use parity16 in ams_delta_serio zengzhaoxiu
2016-04-06  9:47 ` [PATCH v2 19/30] scsi: use parity32 in isci's phy zengzhaoxiu
2016-04-06  9:52 ` [PATCH v2 20/30] mtd: use parity16 in ssfdc zengzhaoxiu
2016-04-06  9:53 ` [PATCH v2 21/30] mtd: use parity functions in inftlcore zengzhaoxiu
2016-04-06  9:58 ` [PATCH v2 22/30] crypto: use parity functions in qat_hal zengzhaoxiu
2016-04-06 10:05 ` [PATCH v2 23/30] mtd: use parity16 in sm_ftl zengzhaoxiu
2016-04-06 10:11 ` [PATCH v2 24/30] ethernet: use parity8 in sun/niu.c zengzhaoxiu
2016-04-06 10:14 ` [PATCH v2 25/30] input: use parity8 in pcips2 zengzhaoxiu
2016-04-06 10:15 ` [PATCH v2 26/30] input: use parity8 in sa1111ps2 zengzhaoxiu
2016-04-06 10:16 ` [PATCH v2 27/30] iio: use parity32 in adxrs450 zengzhaoxiu
2016-04-10 14:37   ` Jonathan Cameron
2016-04-10 14:41     ` Lars-Peter Clausen
2016-04-10 15:13       ` Jonathan Cameron
2016-04-10 15:14         ` Jonathan Cameron
2016-04-06 10:18 ` [PATCH v2 28/30] serial: use parity32 in max3100 zengzhaoxiu
2016-04-06 10:25   ` Greg KH
2016-04-06 10:20 ` [PATCH v2 29/30] input: use parity8 in elantech zengzhaoxiu
2016-04-06 10:21 ` [PATCH v2 30/30] ethernet: use parity8 in broadcom/tg3.c zengzhaoxiu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).