Repository: randombit/botan
Pull request #2097 (2019-09-05 00:34:29)

Remove the scalar SIMD_4x32 implementation
On platforms without a SIMD engine, the scalar version does offer some slight performance increase due to unrolling but is probably not worth it in terms of code size.

codecov-io: # [Codecov](https://codecov.io/gh/randombit/botan/pull/2097?src=pr&el=h1) Report
> Merging [#2097](https://codecov.io/gh/randombit/botan/pull/2097?src=pr&el=desc) into [master](https://codecov.io/gh/randombit/botan/commit/ec3d4f70d8c77cc78af8da6397b2b1b63070ef48?src=pr&el=desc) will **increase** coverage by `<.01%`.
> The diff coverage is `n/a`.

[![Impacted file tree graph](https://codecov.io/gh/randombit/botan/pull/2097/graphs/tree.svg?width=650&token=VR6iYmSPH8&height=150&src=pr)](https://codecov.io/gh/randombit/botan/pull/2097?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master    #2097      +/-   ##
==========================================
+ Coverage   92.36%   92.37%   +<.01%     
==========================================
  Files         545      545              
  Lines       59261    59261              
  Branches     6244     6244              
==========================================
+ Hits        54739    54741       +2     
+ Misses       4522     4520       -2
```


| [Impacted Files](https://codecov.io/gh/randombit/botan/pull/2097?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [src/tests/test\_simd.cpp](https://codecov.io/gh/randombit/botan/pull/2097/diff?src=pr&el=tree#diff-c3JjL3Rlc3RzL3Rlc3Rfc2ltZC5jcHA=) | `98.01% <ø> (ø)` | :arrow_up: |
| [src/lib/asn1/asn1\_obj.cpp](https://codecov.io/gh/randombit/botan/pull/2097/diff?src=pr&el=tree#diff-c3JjL2xpYi9hc24xL2FzbjFfb2JqLmNwcA==) | `94.04% <0%> (-1.2%)` | :arrow_down: |
| [src/lib/pubkey/dl\_group/dl\_group.cpp](https://codecov.io/gh/randombit/botan/pull/2097/diff?src=pr&el=tree#diff-c3JjL2xpYi9wdWJrZXkvZGxfZ3JvdXAvZGxfZ3JvdXAuY3Bw) | `92.12% <0%> (-1.19%)` | :arrow_down: |
| [src/lib/pubkey/mce/mceliece\_key.cpp](https://codecov.io/gh/randombit/botan/pull/2097/diff?src=pr&el=tree#diff-c3JjL2xpYi9wdWJrZXkvbWNlL21jZWxpZWNlX2tleS5jcHA=) | `86.51% <0%> (+1.12%)` | :arrow_up: |
| [src/lib/asn1/der\_enc.cpp](https://codecov.io/gh/randombit/botan/pull/2097/diff?src=pr&el=tree#diff-c3JjL2xpYi9hc24xL2Rlcl9lbmMuY3Bw) | `86.33% <0%> (+2.48%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/randombit/botan/pull/2097?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/randombit/botan/pull/2097?src=pr&el=footer). Last update [ec3d4f7...28e9dd7](https://codecov.io/gh/randombit/botan/pull/2097?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/src/lib/utils/simd/info.txt b/src/lib/utils/simd/info.txt
index 7784902a6..4a7044afc 100644
--- a/src/lib/utils/simd/info.txt
+++ b/src/lib/utils/simd/info.txt
@@ -5,3 +5,23 @@ SIMD_32 -> 20131128
 <header:internal>
 simd_32.h
 </header:internal>
+
+<isa>
+x86_32:sse2
+x86_64:sse2
+x32:sse2
+arm32:neon
+arm64:neon
+ppc32:altivec
+ppc64:altivec
+</isa>
+
+<arch>
+x86_32
+x86_64
+x32
+arm32
+arm64
+ppc32
+ppc64
+</arch>
diff --git a/src/lib/utils/simd/simd_32.h b/src/lib/utils/simd/simd_32.h
index de02e84f1..4c1599842 100644
--- a/src/lib/utils/simd/simd_32.h
+++ b/src/lib/utils/simd/simd_32.h
@@ -1,6 +1,6 @@
 /*
 * Lightweight wrappers for SIMD operations
-* (C) 2009,2011,2016,2017 Jack Lloyd
+* (C) 2009,2011,2016,2017,2019 Jack Lloyd
 *
 * Botan is released under the Simplified BSD License (see license.txt)
 */
@@ -9,26 +9,26 @@
 #define BOTAN_SIMD_32_H_
 
 #include <botan/types.h>
-#include <botan/loadstor.h>
-#include <botan/bswap.h>
-#include <botan/cpuid.h>
 
 #if defined(BOTAN_TARGET_SUPPORTS_SSE2)
   #include <emmintrin.h>
   #define BOTAN_SIMD_USE_SSE2
 
 #elif defined(BOTAN_TARGET_SUPPORTS_ALTIVEC)
+  #include <botan/bswap.h>
+  #include <botan/loadstor.h>
   #include <altivec.h>
   #undef vector
   #undef bool
   #define BOTAN_SIMD_USE_ALTIVEC
 
 #elif defined(BOTAN_TARGET_SUPPORTS_NEON)
+  #include <botan/cpuid.h>
   #include <arm_neon.h>
   #define BOTAN_SIMD_USE_NEON
 
 #else
-  #include <botan/rotate.h>
+  #error "No SIMD instruction set enabled"
 #endif
 
 namespace Botan {
@@ -39,8 +39,6 @@ namespace Botan {
    typedef __vector unsigned int native_simd_type;
 #elif defined(BOTAN_SIMD_USE_NEON)
    typedef uint32x4_t native_simd_type;
-#else
-   typedef struct { uint32_t val[4]; } native_simd_type;
 #endif
 
 /**
@@ -74,11 +72,6 @@ class SIMD_4x32 final
          m_simd = vec_splat_u32(0);
 #elif defined(BOTAN_SIMD_USE_NEON)
          m_simd = vdupq_n_u32(0);
-#else
-         m_simd.val[0] = 0;
-         m_simd.val[1] = 0;
-         m_simd.val[2] = 0;
-         m_simd.val[3] = 0;
 #endif
          }
 
@@ -94,11 +87,6 @@ class SIMD_4x32 final
          m_simd = val;
 #elif defined(BOTAN_SIMD_USE_NEON)
          m_simd = vld1q_u32(B);
-#else
-         m_simd.val[0] = B[0];
-         m_simd.val[1] = B[1];
-         m_simd.val[2] = B[2];
-         m_simd.val[3] = B[3];
 #endif
          }
 
@@ -116,11 +104,6 @@ class SIMD_4x32 final
          // Better way to do this?
          const uint32_t B[4] = { B0, B1, B2, B3 };
          m_simd = vld1q_u32(B);
-#else
-         m_simd.val[0] = B0;
-         m_simd.val[1] = B1;
-         m_simd.val[2] = B2;
-         m_simd.val[3] = B3;
 #endif
          }
 
@@ -131,7 +114,7 @@ class SIMD_4x32 final
          {
 #if defined(BOTAN_SIMD_USE_SSE2)
          return SIMD_4x32(_mm_set1_epi32(B));
-#elif defined(BOTAN_SIMD_USE_ARM)
+#elif defined(BOTAN_SIMD_USE_NEON)
          return SIMD_4x32(vdupq_n_u32(B));
 #else
          return SIMD_4x32(B, B, B, B);
@@ -145,8 +128,8 @@ class SIMD_4x32 final
          {
 #if defined(BOTAN_SIMD_USE_SSE2)
          return SIMD_4x32(_mm_set1_epi8(B));
-#elif defined(BOTAN_SIMD_USE_ARM)
-         return SIMD_4x32(vdupq_n_u8(B));
+#elif defined(BOTAN_SIMD_USE_NEON)
+         return SIMD_4x32(vreinterpretq_u32_u8(vdupq_n_u8(B)));
 #else
          const uint32_t B4 = make_uint32(B, B, B, B);
          return SIMD_4x32(B4, B4, B4, B4);
@@ -161,28 +144,13 @@ class SIMD_4x32 final
 #if defined(BOTAN_SIMD_USE_SSE2)
          return SIMD_4x32(_mm_loadu_si128(reinterpret_cast<const __m128i*>(in)));
 #elif defined(BOTAN_SIMD_USE_ALTIVEC)
-
          uint32_t R[4];
          Botan::load_le(R, static_cast<const uint8_t*>(in), 4);
          return SIMD_4x32(R);
-
 #elif defined(BOTAN_SIMD_USE_NEON)
-
          SIMD_4x32 l(vld1q_u32(static_cast<const uint32_t*>(in)));
-
-#if defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN)
-         return l.bswap();
-#elif defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN)
-         return l;
-#else
          return CPUID::is_big_endian() ? l.bswap() : l;
 #endif
-
-#else
-         SIMD_4x32 out;
-         Botan::load_le(out.m_simd.val, static_cast<const uint8_t*>(in), 4);
-         return out;
-#endif
          }
 
       /**
@@ -199,22 +167,9 @@ class SIMD_4x32 final
          return SIMD_4x32(R);
 
 #elif defined(BOTAN_SIMD_USE_NEON)
-
          SIMD_4x32 l(vld1q_u32(static_cast<const uint32_t*>(in)));
-
-#if defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN)
-         return l.bswap();
-#elif defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN)
-         return l;
-#else
          return CPUID::is_little_endian() ? l.bswap() : l;
 #endif
-
-#else
-         SIMD_4x32 out;
-         Botan::load_be(out.m_simd.val, static_cast<const uint8_t*>(in), 4);
-         return out;
-#endif
          }
 
       void store_le(uint32_t out[]) const
@@ -241,12 +196,6 @@ class SIMD_4x32 final
          Botan::store_le(out, vec.R[0], vec.R[1], vec.R[2], vec.R[3]);
 
 #elif defined(BOTAN_SIMD_USE_NEON)
-
-#if defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN)
-         vst1q_u8(out, vreinterpretq_u8_u32(m_simd));
-#elif defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN)
-         vst1q_u8(out, vreinterpretq_u8_u32(bswap().m_simd));
-#else
          if(CPUID::is_little_endian())
             {
             vst1q_u8(out, vreinterpretq_u8_u32(m_simd));
@@ -256,10 +205,6 @@ class SIMD_4x32 final
             vst1q_u8(out, vreinterpretq_u8_u32(bswap().m_simd));
             }
 #endif
-
-#else
-         Botan::store_le(out, m_simd.val[0], m_simd.val[1], m_simd.val[2], m_simd.val[3]);
-#endif
          }
 
       /**
@@ -281,12 +226,6 @@ class SIMD_4x32 final
          Botan::store_be(out, vec.R[0], vec.R[1], vec.R[2], vec.R[3]);
 
 #elif defined(BOTAN_SIMD_USE_NEON)
-
-#if defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN)
-         vst1q_u8(out, vreinterpretq_u8_u32(m_simd);
-#elif defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN)
-         vst1q_u8(out, vreinterpretq_u8_u32(bswap().m_simd));
-#else
          if(CPUID::is_little_endian())
             {
             vst1q_u8(out, vreinterpretq_u8_u32(bswap().m_simd));
@@ -296,10 +235,6 @@ class SIMD_4x32 final
             vst1q_u8(out, vreinterpretq_u8_u32(m_simd));
             }
 #endif
-
-#else
-         Botan::store_be(out, m_simd.val[0], m_simd.val[1], m_simd.val[2], m_simd.val[3]);
-#endif
          }
 
       /*
@@ -336,12 +271,7 @@ class SIMD_4x32 final
 
 #elif defined(BOTAN_SIMD_USE_NEON)
 
-         #if defined(BOTAN_TARGET_ARCH_IS_ARM32)
-
-         return SIMD_4x32(vorrq_u32(vshlq_n_u32(m_simd, static_cast<int>(ROT)),
-                                    vshrq_n_u32(m_simd, static_cast<int>(32-ROT))));
-
-         #else
+#if defined(BOTAN_TARGET_ARCH_IS_ARM64)
 
          BOTAN_IF_CONSTEXPR(ROT == 8)
             {
@@ -353,19 +283,9 @@ class SIMD_4x32 final
             {
             return SIMD_4x32(vreinterpretq_u32_u16(vrev32q_u16(vreinterpretq_u16_u32(m_simd))));
             }
-         else
-            {
-            return SIMD_4x32(vorrq_u32(vshlq_n_u32(m_simd, static_cast<int>(ROT)),
-                                       vshrq_n_u32(m_simd, static_cast<int>(32-ROT))));
-            }
-
-         #endif
-
-#else
-         return SIMD_4x32(Botan::rotl<ROT>(m_simd.val[0]),
-                          Botan::rotl<ROT>(m_simd.val[1]),
-                          Botan::rotl<ROT>(m_simd.val[2]),
-                          Botan::rotl<ROT>(m_simd.val[3]));
+#endif
+         return SIMD_4x32(vorrq_u32(vshlq_n_u32(m_simd, static_cast<int>(ROT)),
+                                    vshrq_n_u32(m_simd, static_cast<int>(32-ROT))));
 #endif
          }
 
@@ -436,11 +356,6 @@ class SIMD_4x32 final
          m_simd = vec_add(m_simd, other.m_simd);
 #elif defined(BOTAN_SIMD_USE_NEON)
          m_simd = vaddq_u32(m_simd, other.m_simd);
-#else
-         m_simd.val[0] += other.m_simd.val[0];
-         m_simd.val[1] += other.m_simd.val[1];
-         m_simd.val[2] += other.m_simd.val[2];
-         m_simd.val[3] += other.m_simd.val[3];
 #endif
          }
 
@@ -452,11 +367,6 @@ class SIMD_4x32 final
          m_simd = vec_sub(m_simd, other.m_simd);
 #elif defined(BOTAN_SIMD_USE_NEON)
          m_simd = vsubq_u32(m_simd, other.m_simd);
-#else
-         m_simd.val[0] -= other.m_simd.val[0];
-         m_simd.val[1] -= other.m_simd.val[1];
-         m_simd.val[2] -= other.m_simd.val[2];
-         m_simd.val[3] -= other.m_simd.val[3];
 #endif
          }
 
@@ -469,11 +379,6 @@ class SIMD_4x32 final
          m_simd = vec_xor(m_simd, other.m_simd);
 #elif defined(BOTAN_SIMD_USE_NEON)
          m_simd = veorq_u32(m_simd, other.m_simd);
-#else
-         m_simd.val[0] ^= other.m_simd.val[0];
-         m_simd.val[1] ^= other.m_simd.val[1];
-         m_simd.val[2] ^= other.m_simd.val[2];
-         m_simd.val[3] ^= other.m_simd.val[3];
 #endif
          }
 
@@ -485,11 +390,6 @@ class SIMD_4x32 final
          m_simd = vec_or(m_simd, other.m_simd);
 #elif defined(BOTAN_SIMD_USE_NEON)
          m_simd = vorrq_u32(m_simd, other.m_simd);
-#else
-         m_simd.val[0] |= other.m_simd.val[0];
-         m_simd.val[1] |= other.m_simd.val[1];
-         m_simd.val[2] |= other.m_simd.val[2];
-         m_simd.val[3] |= other.m_simd.val[3];
 #endif
          }
 
@@ -501,11 +401,6 @@ class SIMD_4x32 final
          m_simd = vec_and(m_simd, other.m_simd);
 #elif defined(BOTAN_SIMD_USE_NEON)
          m_simd = vandq_u32(m_simd, other.m_simd);
-#else
-         m_simd.val[0] &= other.m_simd.val[0];
-         m_simd.val[1] &= other.m_simd.val[1];
-         m_simd.val[2] &= other.m_simd.val[2];
-         m_simd.val[3] &= other.m_simd.val[3];
 #endif
          }
 
@@ -521,11 +416,6 @@ class SIMD_4x32 final
          return SIMD_4x32(vec_sl(m_simd, shifts));
 #elif defined(BOTAN_SIMD_USE_NEON)
          return SIMD_4x32(vshlq_n_u32(m_simd, SHIFT));
-#else
-         return SIMD_4x32(m_simd.val[0] << SHIFT,
-                          m_simd.val[1] << SHIFT,
-                          m_simd.val[2] << SHIFT,
-                          m_simd.val[3] << SHIFT);
 #endif
          }
 
@@ -540,10 +430,6 @@ class SIMD_4x32 final
          return SIMD_4x32(vec_sr(m_simd, shifts));
 #elif defined(BOTAN_SIMD_USE_NEON)
          return SIMD_4x32(vshrq_n_u32(m_simd, SHIFT));
-#else
-         return SIMD_4x32(m_simd.val[0] >> SHIFT, m_simd.val[1] >> SHIFT,
-                          m_simd.val[2] >> SHIFT, m_simd.val[3] >> SHIFT);
-
 #endif
          }
 
@@ -555,8 +441,6 @@ class SIMD_4x32 final
          return SIMD_4x32(vec_nor(m_simd, m_simd));
 #elif defined(BOTAN_SIMD_USE_NEON)
          return SIMD_4x32(vmvnq_u32(m_simd));
-#else
-         return SIMD_4x32(~m_simd.val[0], ~m_simd.val[1], ~m_simd.val[2], ~m_simd.val[3]);
 #endif
          }
 
@@ -574,11 +458,6 @@ class SIMD_4x32 final
 #elif defined(BOTAN_SIMD_USE_NEON)
          // NEON is also a & ~b
          return SIMD_4x32(vbicq_u32(other.m_simd, m_simd));
-#else
-         return SIMD_4x32((~m_simd.val[0]) & other.m_simd.val[0],
-                          (~m_simd.val[1]) & other.m_simd.val[1],
-                          (~m_simd.val[2]) & other.m_simd.val[2],
-                          (~m_simd.val[3]) & other.m_simd.val[3]);
 #endif
          }
 
@@ -606,15 +485,7 @@ class SIMD_4x32 final
          return SIMD_4x32(vec.R[0], vec.R[1], vec.R[2], vec.R[3]);
 
 #elif defined(BOTAN_SIMD_USE_NEON)
-
          return SIMD_4x32(vreinterpretq_u32_u8(vrev32q_u8(vreinterpretq_u8_u32(m_simd))));
-
-#else
-         // scalar
-         return SIMD_4x32(reverse_bytes(m_simd.val[0]),
-                          reverse_bytes(m_simd.val[1]),
-                          reverse_bytes(m_simd.val[2]),
-                          reverse_bytes(m_simd.val[3]));
 #endif
          }
 
@@ -644,10 +515,8 @@ class SIMD_4x32 final
          B1.m_simd = vec_mergel(T0, T1);
          B2.m_simd = vec_mergeh(T2, T3);
          B3.m_simd = vec_mergel(T2, T3);
-#elif defined(BOTAN_SIMD_USE_NEON)
-
-#if defined(BOTAN_TARGET_ARCH_IS_ARM32)
 
+#elif defined(BOTAN_SIMD_USE_NEON) && defined(BOTAN_TARGET_ARCH_IS_ARM32)
          const uint32x4x2_t T0 = vzipq_u32(B0.m_simd, B2.m_simd);
          const uint32x4x2_t T1 = vzipq_u32(B1.m_simd, B3.m_simd);
          const uint32x4x2_t O0 = vzipq_u32(T0.val[0], T1.val[0]);
@@ -658,32 +527,17 @@ class SIMD_4x32 final
          B2.m_simd = O1.val[0];
          B3.m_simd = O1.val[1];
 
-#elif defined(BOTAN_TARGET_ARCH_IS_ARM64)
+#elif defined(BOTAN_SIMD_USE_NEON) && defined(BOTAN_TARGET_ARCH_IS_ARM64)
          const uint32x4_t T0 = vzip1q_u32(B0.m_simd, B2.m_simd);
          const uint32x4_t T2 = vzip2q_u32(B0.m_simd, B2.m_simd);
-
          const uint32x4_t T1 = vzip1q_u32(B1.m_simd, B3.m_simd);
          const uint32x4_t T3 = vzip2q_u32(B1.m_simd, B3.m_simd);
 
          B0.m_simd = vzip1q_u32(T0, T1);
          B1.m_simd = vzip2q_u32(T0, T1);
-
          B2.m_simd = vzip1q_u32(T2, T3);
          B3.m_simd = vzip2q_u32(T2, T3);
 #endif
-
-#else
-         // scalar
-         SIMD_4x32 T0(B0.m_simd.val[0], B1.m_simd.val[0], B2.m_simd.val[0], B3.m_simd.val[0]);
-         SIMD_4x32 T1(B0.m_simd.val[1], B1.m_simd.val[1], B2.m_simd.val[1], B3.m_simd.val[1]);
-         SIMD_4x32 T2(B0.m_simd.val[2], B1.m_simd.val[2], B2.m_simd.val[2], B3.m_simd.val[2]);
-         SIMD_4x32 T3(B0.m_simd.val[3], B1.m_simd.val[3], B2.m_simd.val[3], B3.m_simd.val[3]);
-
-         B0 = T0;
-         B1 = T1;
-         B2 = T2;
-         B3 = T3;
-#endif
          }
 
       native_simd_type raw() const { return m_simd; }
diff --git a/src/scripts/ci_build.py b/src/scripts/ci_build.py
index 970ffbcbf..756bc880b 100755
--- a/src/scripts/ci_build.py
+++ b/src/scripts/ci_build.py
@@ -206,6 +206,7 @@ def determine_flags(target, target_os, target_cpu, target_cc, cc_bin, ccache, ro
                 flags += ['--cpu=mips64', '--with-endian=big']
                 cc_bin = 'mips64-linux-gnuabi64-g++'
                 test_prefix = ['qemu-mips64', '-L', '/usr/mips64-linux-gnuabi64/']
+                test_cmd.remove('simd_32') # no SIMD on MIPS
             else:
                 raise Exception("Unknown cross target '%s' for Linux" % (target))
     else:


Test patch:
diff --git a/src/tests/test_simd.cpp b/src/tests/test_simd.cpp
index 3603cb8e9..95f310201 100644
--- a/src/tests/test_simd.cpp
+++ b/src/tests/test_simd.cpp
@@ -10,6 +10,8 @@
    #include <botan/internal/simd_32.h>
    #include <botan/cpuid.h>
    #include <botan/rotate.h>
+   #include <botan/loadstor.h>
+   #include <botan/bswap.h>
 #endif
 
 namespace Botan_Tests {