diff options
author | Jack Lloyd <[email protected]> | 2017-01-27 20:44:25 -0500 |
---|---|---|
committer | Jack Lloyd <[email protected]> | 2017-01-29 17:32:47 -0500 |
commit | 2b848242fe4f6c7023e86d7e916c73af30fb9cf0 (patch) | |
tree | ab138d0a73230de92d123a0afce38c7e04453395 /src/tests | |
parent | 3cf1917b4e0ab45f853f1fe7cb7faed342987dd9 (diff) |
Add support for NEON in SIMD_4x32
Tested on qemu-aarch64
Diffstat (limited to 'src/tests')
-rw-r--r-- | src/tests/test_simd.cpp | 161 | ||||
-rw-r--r-- | src/tests/tests.cpp | 7 | ||||
-rw-r--r-- | src/tests/tests.h | 6 |
3 files changed, 174 insertions, 0 deletions
diff --git a/src/tests/test_simd.cpp b/src/tests/test_simd.cpp new file mode 100644 index 000000000..1465d9269 --- /dev/null +++ b/src/tests/test_simd.cpp @@ -0,0 +1,161 @@ +/* +* (C) 2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "tests.h" + +#if defined(BOTAN_HAS_SIMD_32) + #include <botan/internal/simd_32.h> + #include <botan/cpuid.h> +#endif + +namespace Botan_Tests { + +#if defined(BOTAN_HAS_SIMD_32) + +class SIMD_32_Tests : public Test + { + public: + std::vector<Test::Result> run() override + { + Test::Result result("SIMD_4x32"); + + if(Botan::CPUID::has_simd_32() == false) + { + result.test_note("Skipping SIMD_4x32 tests due to missing CPU support at runtime"); + return {result}; + } + + const uint32_t pat1 = 0xAABBCCDD; + const uint32_t pat2 = 0x87654321; + const uint32_t pat3 = 0x01234567; + const uint32_t pat4 = 0xC0D0E0F0; + + test_eq(result, "default init", Botan::SIMD_4x32(), 0, 0, 0, 0); + test_eq(result, "SIMD scalar constructor", Botan::SIMD_4x32(1,2,3,4), 1, 2, 3, 4); + + const Botan::SIMD_4x32 splat = Botan::SIMD_4x32::splat(pat1); + + test_eq(result, "splat", splat, pat1, pat1, pat1, pat1); + + const Botan::SIMD_4x32 input(pat1, pat2, pat3, pat4); + + Botan::SIMD_4x32 rol = input; + rol.rotate_left(3); + + test_eq(result, "rotate_left", rol, + Botan::rotate_left(pat1, 3), + Botan::rotate_left(pat2, 3), + Botan::rotate_left(pat3, 3), + Botan::rotate_left(pat4, 3)); + + Botan::SIMD_4x32 ror = input; + ror.rotate_right(9); + + test_eq(result, "rotate_right", ror, + Botan::rotate_right(pat1, 9), + Botan::rotate_right(pat2, 9), + Botan::rotate_right(pat3, 9), + Botan::rotate_right(pat4, 9)); + + Botan::SIMD_4x32 add = input + splat; + test_eq(result, "add +", add, pat1+pat1, pat2+pat1, pat3+pat1, pat4+pat1); + + add -= splat; + test_eq(result, "sub -=", add, pat1, pat2, pat3, pat4); + + add += splat; + test_eq(result, "add +=", add, pat1+pat1, pat2+pat1, pat3+pat1, pat4+pat1); + + test_eq(result, "xor", input ^ splat, 0, pat2^pat1, pat3^pat1, pat4^pat1); + test_eq(result, "or", input | splat, pat1, pat2 | pat1, pat3 | pat1, pat4 | pat1); + test_eq(result, "and", input & splat, pat1, pat2 & pat1, pat3 & pat1, pat4 & pat1); + + Botan::SIMD_4x32 blender = input; + blender |= splat; + test_eq(result, "|=", blender, pat1, pat2|pat1, pat3|pat1, pat4|pat1); + blender &= splat; + test_eq(result, "&=", blender, pat1, pat1, pat1, pat1); + blender ^= splat; + test_eq(result, "^=", blender, 0, 0, 0, 0); + + blender = ~blender; + test_eq(result, "~", blender, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF); + + blender = blender >> 23; + test_eq(result, ">>", blender, 0x1FF, 0x1FF, 0x1FF, 0x1FF); + + blender = blender << 27; + test_eq(result, "<<", blender, 0xF8000000, 0xF8000000, 0xF8000000, 0xF8000000); + + blender = ~blender; + test_eq(result, "~", blender, 0x7FFFFFF, 0x7FFFFFF, 0x7FFFFFF, 0x7FFFFFF); + + blender = input.andc(~blender); + test_eq(result, "andc", blender, + ~pat1 & 0xF8000000, ~pat2 & 0xF8000000, + ~pat3 & 0xF8000000, ~pat4 & 0xF8000000); + + test_eq(result, "bswap", input.bswap(), + Botan::reverse_bytes(pat1), + Botan::reverse_bytes(pat2), + Botan::reverse_bytes(pat3), + Botan::reverse_bytes(pat4)); + + Botan::SIMD_4x32 t1(pat1, pat2, pat3, pat4); + Botan::SIMD_4x32 t2(pat1+1, pat2+1, pat3+1, pat4+1); + Botan::SIMD_4x32 t3(pat1+2, pat2+2, pat3+2, pat4+2); + Botan::SIMD_4x32 t4(pat1+3, pat2+3, pat3+3, pat4+3); + + Botan::SIMD_4x32::transpose(t1, t2, t3, t4); + + test_eq(result, "transpose t1", t1, pat1, pat1+1, pat1+2, pat1+3); + test_eq(result, "transpose t2", t2, pat2, pat2+1, pat2+2, pat2+3); + test_eq(result, "transpose t3", t3, pat3, pat3+1, pat3+2, pat3+3); + test_eq(result, "transpose t4", t4, pat4, pat4+1, pat4+2, pat4+3); + + return {result}; + } + + private: + void test_eq(Test::Result& result, const std::string& op, + const Botan::SIMD_4x32& simd, + uint32_t exp0, uint32_t exp1, uint32_t exp2, uint32_t exp3) + { + uint8_t mem_be[16]; + simd.store_be(mem_be); + + result.test_int_eq("SIMD_4x32 " + op + " elem0 BE", Botan::make_uint32(mem_be[ 0], mem_be[ 1], mem_be[ 2], mem_be[ 3]), exp0); + result.test_int_eq("SIMD_4x32 " + op + " elem1 BE", Botan::make_uint32(mem_be[ 4], mem_be[ 5], mem_be[ 6], mem_be[ 7]), exp1); + result.test_int_eq("SIMD_4x32 " + op + " elem2 BE", Botan::make_uint32(mem_be[ 8], mem_be[ 9], mem_be[10], mem_be[11]), exp2); + result.test_int_eq("SIMD_4x32 " + op + " elem3 BE", Botan::make_uint32(mem_be[12], mem_be[13], mem_be[14], mem_be[15]), exp3); + + // Check load_be+store_be results in same value + const Botan::SIMD_4x32 reloaded_be = Botan::SIMD_4x32::load_be(mem_be); + uint8_t mem_be2[16]; + reloaded_be.store_be(mem_be2); + result.test_eq(nullptr, "SIMD_4x32 load_be", mem_be, 16, mem_be2, 16); + + uint8_t mem_le[16]; + simd.store_le(mem_le); + + result.test_int_eq("SIMD_4x32 " + op + " elem0 LE", Botan::make_uint32(mem_le[ 3], mem_le[ 2], mem_le[ 1], mem_le[ 0]), exp0); + result.test_int_eq("SIMD_4x32 " + op + " elem1 LE", Botan::make_uint32(mem_le[ 7], mem_le[ 6], mem_le[ 5], mem_le[ 4]), exp1); + result.test_int_eq("SIMD_4x32 " + op + " elem2 LE", Botan::make_uint32(mem_le[11], mem_le[10], mem_le[ 9], mem_le[ 8]), exp2); + result.test_int_eq("SIMD_4x32 " + op + " elem3 LE", Botan::make_uint32(mem_le[15], mem_le[14], mem_le[13], mem_le[12]), exp3); + + // Check load_le+store_le results in same value + const Botan::SIMD_4x32 reloaded_le = Botan::SIMD_4x32::load_le(mem_le); + uint8_t mem_le2[16]; + reloaded_le.store_le(mem_le2); + result.test_eq(nullptr, "SIMD_4x32 load_le", mem_le, 16, mem_le2, 16); + } + + }; + +BOTAN_REGISTER_TEST("simd_32", SIMD_32_Tests); +#endif + +} diff --git a/src/tests/tests.cpp b/src/tests/tests.cpp index 855e19f80..fa93397b2 100644 --- a/src/tests/tests.cpp +++ b/src/tests/tests.cpp @@ -799,6 +799,13 @@ std::vector<Botan::CPUID::CPUID_bits> map_cpuid_string(const std::string& tok) return {Botan::CPUID::CPUID_ALTIVEC_BIT}; #endif +#if defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY) + if(tok == "neon" || tok == "simd") + return {Botan::CPUID::CPUID_ARM_NEON_BIT}; +#endif + + BOTAN_UNUSED(tok); + return {}; } diff --git a/src/tests/tests.h b/src/tests/tests.h index aa5208325..ed7008c34 100644 --- a/src/tests/tests.h +++ b/src/tests/tests.h @@ -187,6 +187,12 @@ class Test return test_eq(what, static_cast<size_t>(x), static_cast<size_t>(y)); } + template<typename I1, typename I2> + bool test_int_eq(const std::string& what, I1 x, I2 y) + { + return test_eq(what.c_str(), static_cast<size_t>(x), static_cast<size_t>(y)); + } + bool test_lt(const std::string& what, size_t produced, size_t expected); bool test_lte(const std::string& what, size_t produced, size_t expected); bool test_gte(const std::string& what, size_t produced, size_t expected); |