aboutsummaryrefslogtreecommitdiffstats
path: root/src/tests/test_simd.cpp
blob: 3603cb8e992a9b7046c1a8519d5e75dc6506d2d8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
/*
* (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>
   #include <botan/rotate.h>
#endif

namespace Botan_Tests {

#if defined(BOTAN_HAS_SIMD_32)

class SIMD_32_Tests final : 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.rotl<3>();

         test_eq(result, "rotl", rol,
                 Botan::rotl<3>(pat1),
                 Botan::rotl<3>(pat2),
                 Botan::rotl<3>(pat3),
                 Botan::rotl<3>(pat4));

         Botan::SIMD_4x32 ror = input.rotr<9>();

         test_eq(result, "rotr", ror,
                 Botan::rotr<9>(pat1),
                 Botan::rotr<9>(pat2),
                 Botan::rotr<9>(pat3),
                 Botan::rotr<9>(pat4));

         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.shr<23>();
         test_eq(result, ">>", blender, 0x1FF, 0x1FF, 0x1FF, 0x1FF);

         blender = blender.shl<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 arr_be[16 + 15];
         uint8_t arr_be2[16 + 15];
         uint8_t arr_le[16 + 15];
         uint8_t arr_le2[16 + 15];

         for(size_t misalignment = 0; misalignment != 16; ++misalignment)
            {
            uint8_t* mem_be  = arr_be  + misalignment;
            uint8_t* mem_be2 = arr_be2 + misalignment;
            uint8_t* mem_le  = arr_le  + misalignment;
            uint8_t* mem_le2 = arr_le2 + misalignment;

            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);
            reloaded_be.store_be(mem_be2);
            result.test_eq(nullptr, "SIMD_4x32 load_be", mem_be, 16, mem_be2, 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);
            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

}