swab() is massively over complicated and can be simplified by builtins.
The compilers provide builtin function to swap bytes.
* gcc:   https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html
* clang: https://clang.llvm.org/docs/LanguageExtensions.html
This patch simplify swab() with builtins and fallback for old compilers.

Signed-off-by: Lin Liu <[email protected]>
---
Cc: Andrew Cooper <[email protected]>
Cc: George Dunlap <[email protected]>
Cc: Ian Jackson <[email protected]>
Cc: Jan Beulich <[email protected]>
Cc: Julien Grall <[email protected]>
Cc: Stefano Stabellini <[email protected]>
Cc: Wei Liu <[email protected]>
Changes in v2:
- Add fallback for compilers without __builtin_bswap
- Implement with plain C instead of macros
---
 xen/include/xen/byteswap.h | 93 ++++++++++++++++++++++++++++++++++++++
 xen/include/xen/compiler.h | 12 +++++
 2 files changed, 105 insertions(+)
 create mode 100644 xen/include/xen/byteswap.h

diff --git a/xen/include/xen/byteswap.h b/xen/include/xen/byteswap.h
new file mode 100644
index 0000000000..848a4bbaee
--- /dev/null
+++ b/xen/include/xen/byteswap.h
@@ -0,0 +1,93 @@
+#ifndef _BYTESWAP_H
+#define _BYTESWAP_H
+
+#include <xen/types.h>
+
+#if !__has_builtin(__builtin_bswap16)
+static always_inline uint16_t __builtin_bswap16(uint16_t val)
+{
+    return ((val & 0x00FF) << 8) | ((val & 0xFF00) >> 8);
+}
+#endif
+
+#if !__has_builtin(__builtin_bswap32)
+static always_inline uint32_t __builtin_bswap32(uint32_t val)
+{
+    return ((val & 0x000000FF) << 24) |
+           ((val & 0x0000FF00) <<  8) |
+           ((val & 0x00FF0000) >>  8) |
+           ((val & 0xFF000000) >> 24);
+}
+#endif
+
+#if !__has_builtin(__builtin_bswap64)
+static always_inline uint64_t __builtin_bswap64(uint64_t val)
+{
+    return ((val & 0x00000000000000FF) << 56) |
+           ((val & 0x000000000000FF00) << 40) |
+           ((val & 0x0000000000FF0000) << 24) |
+           ((val & 0x00000000FF000000) <<  8) |
+           ((val & 0x000000FF00000000) >>  8) |
+           ((val & 0x0000FF0000000000) >> 24) |
+           ((val & 0x00FF000000000000) >> 40) |
+           ((val & 0xFF00000000000000) >> 56);
+}
+#endif
+
+#define bswap16(x) __builtin_bswap16(x)
+#define bswap32(x) __builtin_bswap32(x)
+#define bswap64(x) __builtin_bswap64(x)
+
+#define bswap_ul(x) bswap##BITS_PER_LONG(x)
+
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+
+#  ifndef __LITTLE_ENDIAN
+#    define __LITTLE_ENDIAN 1234
+#  endif
+
+#  ifndef __LITTLE_ENDIAN_BITFIELD
+#    define __LITTLE_ENDIAN_BITFIELD
+#  endif
+
+#  define cpu_to_le64(x) (x)
+#  define le64_to_cpu(x) (x)
+#  define cpu_to_le32(x) (x)
+#  define le32_to_cpu(x) (x)
+#  define cpu_to_le16(x) (x)
+#  define le16_to_cpu(x) (x)
+#  define cpu_to_be64(x) bswap64(x)
+#  define be64_to_cpu(x) bswap64(x)
+#  define cpu_to_be32(x) bswap32(x)
+#  define be32_to_cpu(x) bswap32(x)
+#  define cpu_to_be16(x) bswap16(x)
+#  define be16_to_cpu(x) bswap16(x)
+
+#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+
+#  ifndef __BIG_ENDIAN
+#    define __BIG_ENDIAN 4321
+#  endif
+
+#  ifndef __BIG_ENDIAN_BITFIELD
+#    define __BIG_ENDIAN_BITFIELD
+#  endif
+
+#  define cpu_to_le64(x) bswap64(x)
+#  define le64_to_cpu(x) bswap64(x)
+#  define cpu_to_le32(x) bswap32(x)
+#  define le32_to_cpu(x) bswap32(x)
+#  define cpu_to_le16(x) bswap16(x)
+#  define le16_to_cpu(x) bswap16(x)
+#  define cpu_to_be64(x) (x)
+#  define be64_to_cpu(x) (x)
+#  define cpu_to_be32(x) (x)
+#  define be32_to_cpu(x) (x)
+#  define cpu_to_be16(x) (x)
+#  define be16_to_cpu(x) (x)
+
+#else
+#  error "Unknown Endianness"
+#endif /* __BYTE_ORDER__ */
+
+#endif /* _LINUX_BITOPS_H */
diff --git a/xen/include/xen/compiler.h b/xen/include/xen/compiler.h
index 696c7eb89e..68f28082a5 100644
--- a/xen/include/xen/compiler.h
+++ b/xen/include/xen/compiler.h
@@ -179,4 +179,16 @@
 # define CLANG_DISABLE_WARN_GCC_COMPAT_END
 #endif
 
+#if (!defined(__clang__) && (__GNUC__ < 10))
+/*
+ * Backwards compatibility for GCC < 10.
+ * All supported versions of Clang support __has_builtin
+ * */
+#define __has_builtin(x) GCC_has ## x
+
+#define GCC_has__builtin_bswap16 (CONFIG_GCC_VERSION >= 40800)
+#define GCC_has__builtin_bswap32 (CONFIG_GCC_VERSION >= 40400)
+#define GCC_has__builtin_bswap64 (CONFIG_GCC_VERSION >= 40400)
+#endif
+
 #endif /* __LINUX_COMPILER_H */
-- 
2.27.0


Reply via email to