blob: 1f01e7c046e18b61bd38ef80aebc4bf6de2befbc [file] [log] [blame]
Nicolas Capens598f8d82016-09-26 15:09:10 -04001// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
Ben Clayton1c82c7b2019-04-30 12:49:27 +010015#include "Coroutine.hpp"
Antonio Maiorano415d1812020-02-11 16:22:55 -050016#include "Print.hpp"
Ben Clayton713b8d32019-12-17 20:37:56 +000017#include "Reactor.hpp"
Nicolas Capens598f8d82016-09-26 15:09:10 -040018
Nicolas Capens228b05d2016-10-12 15:27:04 -040019#include "gtest/gtest.h"
Nicolas Capens598f8d82016-09-26 15:09:10 -040020
Antonio Maiorano4d402712020-02-25 10:36:02 -050021#include <array>
Antonio Maioranobf151b82019-12-03 09:49:14 -050022#include <cmath>
Nicolas Capensb3e5c442021-01-20 06:16:24 +000023#include <filesystem>
Antonio Maiorano10ff4332020-12-04 11:33:34 -050024#include <fstream>
Antonio Maiorano5ba2a5b2020-01-17 15:29:37 -050025#include <thread>
Ben Claytonb1243732019-02-27 23:56:18 +000026#include <tuple>
27
Nicolas Capens48461502018-08-06 14:20:45 -040028using namespace rr;
Nicolas Capens598f8d82016-09-26 15:09:10 -040029
Antonio Maiorano2195f7a2020-11-27 14:02:23 -050030std::string testName()
31{
32 auto info = ::testing::UnitTest::GetInstance()->current_test_info();
33 return std::string{ info->test_suite_name() } + "_" + info->name();
34}
35
Nicolas Capens7d9f76d2016-09-29 13:39:44 -040036int reference(int *p, int y)
37{
Nicolas Capens8820f642016-09-30 04:42:43 -040038 int x = p[-1];
Nicolas Capens7d9f76d2016-09-29 13:39:44 -040039 int z = 4;
40
41 for(int i = 0; i < 10; i++)
42 {
43 z += (2 << i) - (i / 3);
44 }
45
46 int sum = x + y + z;
Nicolas Capens228b05d2016-10-12 15:27:04 -040047
Nicolas Capens7d9f76d2016-09-29 13:39:44 -040048 return sum;
49}
50
Nicolas Capensc07dc4b2018-08-06 14:20:45 -040051TEST(ReactorUnitTests, Sample)
Nicolas Capens598f8d82016-09-26 15:09:10 -040052{
Ben Clayton713b8d32019-12-17 20:37:56 +000053 FunctionT<int(int *, int)> function;
Nicolas Capens598f8d82016-09-26 15:09:10 -040054 {
Nicolas Capens157ba262019-12-10 17:49:14 -050055 Pointer<Int> p = function.Arg<0>();
56 Int x = p[-1];
57 Int y = function.Arg<1>();
58 Int z = 4;
59
60 For(Int i = 0, i < 10, i++)
Nicolas Capens598f8d82016-09-26 15:09:10 -040061 {
Nicolas Capens157ba262019-12-10 17:49:14 -050062 z += (2 << i) - (i / 3);
Nicolas Capens598f8d82016-09-26 15:09:10 -040063 }
64
Nicolas Capens157ba262019-12-10 17:49:14 -050065 Float4 v;
66 v.z = As<Float>(z);
67 z = As<Int>(Float(Float4(v.xzxx).y));
Nicolas Capens598f8d82016-09-26 15:09:10 -040068
Nicolas Capens157ba262019-12-10 17:49:14 -050069 Int sum = x + y + z;
70
71 Return(sum);
Nicolas Capens598f8d82016-09-26 15:09:10 -040072 }
73
Antonio Maiorano2195f7a2020-11-27 14:02:23 -050074 auto routine = function(testName().c_str());
Nicolas Capens157ba262019-12-10 17:49:14 -050075
Nicolas Capensbdf2b722020-01-27 11:33:14 -050076 int one[2] = { 1, 0 };
77 int result = routine(&one[1], 2);
78 EXPECT_EQ(result, reference(&one[1], 2));
Nicolas Capens228b05d2016-10-12 15:27:04 -040079}
Nicolas Capens598f8d82016-09-26 15:09:10 -040080
Nicolas Capensc07dc4b2018-08-06 14:20:45 -040081TEST(ReactorUnitTests, Uninitialized)
Nicolas Capensf4452fc2016-12-12 13:08:06 -050082{
Nicolas Capens157ba262019-12-10 17:49:14 -050083 FunctionT<int()> function;
Nicolas Capensf4452fc2016-12-12 13:08:06 -050084 {
Nicolas Capens157ba262019-12-10 17:49:14 -050085 Int a;
86 Int z = 4;
87 Int q;
88 Int c;
89 Int p;
90 Bool b;
91
92 q += q;
93
94 If(b)
Nicolas Capensf4452fc2016-12-12 13:08:06 -050095 {
Nicolas Capens157ba262019-12-10 17:49:14 -050096 c = p;
Nicolas Capensf4452fc2016-12-12 13:08:06 -050097 }
98
Nicolas Capens157ba262019-12-10 17:49:14 -050099 Return(a + z + q + c);
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500100 }
101
Antonio Maiorano2195f7a2020-11-27 14:02:23 -0500102 auto routine = function(testName().c_str());
Nicolas Capens157ba262019-12-10 17:49:14 -0500103
Nicolas Capens4804ac82020-11-02 22:06:55 -0500104 if(!__has_feature(memory_sanitizer) || !REACTOR_ENABLE_MEMORY_SANITIZER_INSTRUMENTATION)
105 {
106 int result = routine();
107 EXPECT_EQ(result, result); // Anything is fine, just don't crash
108 }
109 else
110 {
111 // Optimizations may turn the conditional If() in the Reactor code
112 // into a conditional move or arithmetic operations, which would not
113 // trigger a MemorySanitizer error. However, in that case the equals
114 // operator below should trigger it before the abort is reached.
115 EXPECT_DEATH(
116 {
117 int result = routine();
118 if(result == 0) abort();
119 },
120 "MemorySanitizer: use-of-uninitialized-value");
121 }
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500122}
123
Nicolas Capens0192d152019-03-27 14:46:07 -0400124TEST(ReactorUnitTests, Unreachable)
125{
Nicolas Capens157ba262019-12-10 17:49:14 -0500126 FunctionT<int(int)> function;
Nicolas Capens0192d152019-03-27 14:46:07 -0400127 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500128 Int a = function.Arg<0>();
129 Int z = 4;
Nicolas Capens0192d152019-03-27 14:46:07 -0400130
Nicolas Capens157ba262019-12-10 17:49:14 -0500131 Return(a + z);
Nicolas Capens0192d152019-03-27 14:46:07 -0400132
Nicolas Capens157ba262019-12-10 17:49:14 -0500133 // Code beyond this point is unreachable but should not cause any
134 // compilation issues.
Nicolas Capens0192d152019-03-27 14:46:07 -0400135
Nicolas Capens157ba262019-12-10 17:49:14 -0500136 z += a;
Nicolas Capens0192d152019-03-27 14:46:07 -0400137 }
138
Antonio Maiorano2195f7a2020-11-27 14:02:23 -0500139 auto routine = function(testName().c_str());
Nicolas Capens157ba262019-12-10 17:49:14 -0500140
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500141 int result = routine(16);
142 EXPECT_EQ(result, 20);
Nicolas Capens0192d152019-03-27 14:46:07 -0400143}
144
145TEST(ReactorUnitTests, VariableAddress)
146{
Nicolas Capens157ba262019-12-10 17:49:14 -0500147 FunctionT<int(int)> function;
Nicolas Capens0192d152019-03-27 14:46:07 -0400148 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500149 Int a = function.Arg<0>();
150 Int z = 0;
151 Pointer<Int> p = &z;
152 *p = 4;
Nicolas Capens0192d152019-03-27 14:46:07 -0400153
Nicolas Capens157ba262019-12-10 17:49:14 -0500154 Return(a + z);
Nicolas Capens0192d152019-03-27 14:46:07 -0400155 }
156
Antonio Maiorano2195f7a2020-11-27 14:02:23 -0500157 auto routine = function(testName().c_str());
Nicolas Capens157ba262019-12-10 17:49:14 -0500158
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500159 int result = routine(16);
160 EXPECT_EQ(result, 20);
Nicolas Capens0192d152019-03-27 14:46:07 -0400161}
162
Nicolas Capensc07dc4b2018-08-06 14:20:45 -0400163TEST(ReactorUnitTests, SubVectorLoadStore)
Nicolas Capens23d99a42016-09-30 14:57:16 -0400164{
Ben Clayton713b8d32019-12-17 20:37:56 +0000165 FunctionT<int(void *, void *)> function;
Nicolas Capens23d99a42016-09-30 14:57:16 -0400166 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500167 Pointer<Byte> in = function.Arg<0>();
168 Pointer<Byte> out = function.Arg<1>();
169
Ben Clayton713b8d32019-12-17 20:37:56 +0000170 *Pointer<Int4>(out + 16 * 0) = *Pointer<Int4>(in + 16 * 0);
Nicolas Capens157ba262019-12-10 17:49:14 -0500171 *Pointer<Short4>(out + 16 * 1) = *Pointer<Short4>(in + 16 * 1);
Ben Clayton713b8d32019-12-17 20:37:56 +0000172 *Pointer<Byte8>(out + 16 * 2) = *Pointer<Byte8>(in + 16 * 2);
173 *Pointer<Byte4>(out + 16 * 3) = *Pointer<Byte4>(in + 16 * 3);
Nicolas Capens157ba262019-12-10 17:49:14 -0500174 *Pointer<Short2>(out + 16 * 4) = *Pointer<Short2>(in + 16 * 4);
175
176 Return(0);
177 }
178
Antonio Maiorano2195f7a2020-11-27 14:02:23 -0500179 auto routine = function(testName().c_str());
Nicolas Capens157ba262019-12-10 17:49:14 -0500180
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500181 int8_t in[16 * 5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
182 17, 18, 19, 20, 21, 22, 23, 24, 0, 0, 0, 0, 0, 0, 0, 0,
183 25, 26, 27, 28, 29, 30, 31, 32, 0, 0, 0, 0, 0, 0, 0, 0,
184 33, 34, 35, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
185 37, 38, 39, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
186
187 int8_t out[16 * 5] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
188 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
189 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
190 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
191 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
192
193 routine(in, out);
194
195 for(int row = 0; row < 5; row++)
Nicolas Capens157ba262019-12-10 17:49:14 -0500196 {
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500197 for(int col = 0; col < 16; col++)
Nicolas Capens23d99a42016-09-30 14:57:16 -0400198 {
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500199 int i = row * 16 + col;
Nicolas Capens23d99a42016-09-30 14:57:16 -0400200
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500201 if(in[i] == 0)
202 {
203 EXPECT_EQ(out[i], -1) << "Row " << row << " column " << col << " not left untouched.";
204 }
205 else
206 {
207 EXPECT_EQ(out[i], in[i]) << "Row " << row << " column " << col << " not equal to input.";
Nicolas Capens23d99a42016-09-30 14:57:16 -0400208 }
209 }
210 }
Nicolas Capens23d99a42016-09-30 14:57:16 -0400211}
212
Nicolas Capensc07dc4b2018-08-06 14:20:45 -0400213TEST(ReactorUnitTests, VectorConstant)
Nicolas Capens8dfd9a72016-10-13 17:44:51 -0400214{
Ben Clayton713b8d32019-12-17 20:37:56 +0000215 FunctionT<int(void *)> function;
Nicolas Capens8dfd9a72016-10-13 17:44:51 -0400216 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500217 Pointer<Byte> out = function.Arg<0>();
218
219 *Pointer<Int4>(out + 16 * 0) = Int4(0x04030201, 0x08070605, 0x0C0B0A09, 0x100F0E0D);
220 *Pointer<Short4>(out + 16 * 1) = Short4(0x1211, 0x1413, 0x1615, 0x1817);
221 *Pointer<Byte8>(out + 16 * 2) = Byte8(0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20);
222 *Pointer<Int2>(out + 16 * 3) = Int2(0x24232221, 0x28272625);
223
224 Return(0);
225 }
226
Antonio Maiorano2195f7a2020-11-27 14:02:23 -0500227 auto routine = function(testName().c_str());
Nicolas Capens157ba262019-12-10 17:49:14 -0500228
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500229 int8_t out[16 * 4] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
230 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
231 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
232 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
233
234 int8_t exp[16 * 4] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
235 17, 18, 19, 20, 21, 22, 23, 24, -1, -1, -1, -1, -1, -1, -1, -1,
236 25, 26, 27, 28, 29, 30, 31, 32, -1, -1, -1, -1, -1, -1, -1, -1,
237 33, 34, 35, 36, 37, 38, 39, 40, -1, -1, -1, -1, -1, -1, -1, -1 };
238
239 routine(out);
240
241 for(int row = 0; row < 4; row++)
Nicolas Capens157ba262019-12-10 17:49:14 -0500242 {
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500243 for(int col = 0; col < 16; col++)
Nicolas Capens8dfd9a72016-10-13 17:44:51 -0400244 {
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500245 int i = row * 16 + col;
Nicolas Capens8dfd9a72016-10-13 17:44:51 -0400246
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500247 EXPECT_EQ(out[i], exp[i]);
Nicolas Capens8dfd9a72016-10-13 17:44:51 -0400248 }
249 }
Nicolas Capens8dfd9a72016-10-13 17:44:51 -0400250}
251
Nicolas Capensc07dc4b2018-08-06 14:20:45 -0400252TEST(ReactorUnitTests, Concatenate)
Nicolas Capensc70a1162016-12-03 00:16:14 -0500253{
Ben Clayton713b8d32019-12-17 20:37:56 +0000254 FunctionT<int(void *)> function;
Nicolas Capensc70a1162016-12-03 00:16:14 -0500255 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500256 Pointer<Byte> out = function.Arg<0>();
257
Ben Clayton713b8d32019-12-17 20:37:56 +0000258 *Pointer<Int4>(out + 16 * 0) = Int4(Int2(0x04030201, 0x08070605), Int2(0x0C0B0A09, 0x100F0E0D));
Nicolas Capens157ba262019-12-10 17:49:14 -0500259 *Pointer<Short8>(out + 16 * 1) = Short8(Short4(0x0201, 0x0403, 0x0605, 0x0807), Short4(0x0A09, 0x0C0B, 0x0E0D, 0x100F));
260
261 Return(0);
262 }
263
Antonio Maiorano2195f7a2020-11-27 14:02:23 -0500264 auto routine = function(testName().c_str());
Nicolas Capens157ba262019-12-10 17:49:14 -0500265
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500266 int8_t ref[16 * 5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
267 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
268
269 int8_t out[16 * 5] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
270 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
271
272 routine(out);
273
274 for(int row = 0; row < 2; row++)
Nicolas Capens157ba262019-12-10 17:49:14 -0500275 {
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500276 for(int col = 0; col < 16; col++)
Nicolas Capensc70a1162016-12-03 00:16:14 -0500277 {
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500278 int i = row * 16 + col;
Nicolas Capensc70a1162016-12-03 00:16:14 -0500279
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500280 EXPECT_EQ(out[i], ref[i]) << "Row " << row << " column " << col << " not equal to reference.";
Nicolas Capensc70a1162016-12-03 00:16:14 -0500281 }
282 }
Nicolas Capensc70a1162016-12-03 00:16:14 -0500283}
284
Nicolas Capens133b87d2020-01-25 16:26:28 -0500285TEST(ReactorUnitTests, Cast)
286{
287 FunctionT<void(void *)> function;
288 {
289 Pointer<Byte> out = function.Arg<0>();
290
291 Int4 c = Int4(0x01020304, 0x05060708, 0x09101112, 0x13141516);
292 *Pointer<Short4>(out + 16 * 0) = Short4(c);
293 *Pointer<Byte4>(out + 16 * 1 + 0) = Byte4(c);
294 *Pointer<Byte4>(out + 16 * 1 + 4) = Byte4(As<Byte8>(c));
295 *Pointer<Byte4>(out + 16 * 1 + 8) = Byte4(As<Short4>(c));
296 }
297
Antonio Maiorano2195f7a2020-11-27 14:02:23 -0500298 auto routine = function(testName().c_str());
Nicolas Capens133b87d2020-01-25 16:26:28 -0500299
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500300 int out[2][4];
Nicolas Capens133b87d2020-01-25 16:26:28 -0500301
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500302 memset(&out, 0, sizeof(out));
Nicolas Capens133b87d2020-01-25 16:26:28 -0500303
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500304 routine(&out);
Nicolas Capens133b87d2020-01-25 16:26:28 -0500305
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500306 EXPECT_EQ(out[0][0], 0x07080304);
307 EXPECT_EQ(out[0][1], 0x15161112);
Nicolas Capens133b87d2020-01-25 16:26:28 -0500308
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500309 EXPECT_EQ(out[1][0], 0x16120804);
310 EXPECT_EQ(out[1][1], 0x01020304);
311 EXPECT_EQ(out[1][2], 0x06080204);
Nicolas Capens133b87d2020-01-25 16:26:28 -0500312}
313
314static uint16_t swizzleCode4(int i)
315{
316 auto x = (i >> 0) & 0x03;
317 auto y = (i >> 2) & 0x03;
318 auto z = (i >> 4) & 0x03;
319 auto w = (i >> 6) & 0x03;
320 return static_cast<uint16_t>((x << 12) | (y << 8) | (z << 4) | (w << 0));
321}
322
323TEST(ReactorUnitTests, Swizzle4)
324{
325 FunctionT<void(void *)> function;
326 {
327 Pointer<Byte> out = function.Arg<0>();
328
329 for(int i = 0; i < 256; i++)
330 {
331 *Pointer<Float4>(out + 16 * i) = Swizzle(Float4(1.0f, 2.0f, 3.0f, 4.0f), swizzleCode4(i));
332 }
333
334 for(int i = 0; i < 256; i++)
335 {
336 *Pointer<Float4>(out + 16 * (256 + i)) = ShuffleLowHigh(Float4(1.0f, 2.0f, 3.0f, 4.0f), Float4(5.0f, 6.0f, 7.0f, 8.0f), swizzleCode4(i));
337 }
338
339 *Pointer<Float4>(out + 16 * (512 + 0)) = UnpackLow(Float4(1.0f, 2.0f, 3.0f, 4.0f), Float4(5.0f, 6.0f, 7.0f, 8.0f));
340 *Pointer<Float4>(out + 16 * (512 + 1)) = UnpackHigh(Float4(1.0f, 2.0f, 3.0f, 4.0f), Float4(5.0f, 6.0f, 7.0f, 8.0f));
341 *Pointer<Int2>(out + 16 * (512 + 2)) = UnpackLow(Short4(1, 2, 3, 4), Short4(5, 6, 7, 8));
342 *Pointer<Int2>(out + 16 * (512 + 3)) = UnpackHigh(Short4(1, 2, 3, 4), Short4(5, 6, 7, 8));
343 *Pointer<Short4>(out + 16 * (512 + 4)) = UnpackLow(Byte8(1, 2, 3, 4, 5, 6, 7, 8), Byte8(9, 10, 11, 12, 13, 14, 15, 16));
344 *Pointer<Short4>(out + 16 * (512 + 5)) = UnpackHigh(Byte8(1, 2, 3, 4, 5, 6, 7, 8), Byte8(9, 10, 11, 12, 13, 14, 15, 16));
345
346 for(int i = 0; i < 256; i++)
347 {
348 *Pointer<Short4>(out + 16 * (512 + 6) + (8 * i)) =
349 Swizzle(Short4(1, 2, 3, 4), swizzleCode4(i));
350 }
351
352 for(int i = 0; i < 256; i++)
353 {
354 *Pointer<Int4>(out + 16 * (512 + 6 + i) + (8 * 256)) =
355 Swizzle(Int4(1, 2, 3, 4), swizzleCode4(i));
356 }
357 }
358
Antonio Maiorano2195f7a2020-11-27 14:02:23 -0500359 auto routine = function(testName().c_str());
Nicolas Capens133b87d2020-01-25 16:26:28 -0500360
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500361 struct
Nicolas Capens133b87d2020-01-25 16:26:28 -0500362 {
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500363 float f[256 + 256 + 2][4];
364 int i[388][4];
365 } out;
Nicolas Capens133b87d2020-01-25 16:26:28 -0500366
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500367 memset(&out, 0, sizeof(out));
Nicolas Capens133b87d2020-01-25 16:26:28 -0500368
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500369 routine(&out);
Nicolas Capens133b87d2020-01-25 16:26:28 -0500370
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500371 for(int i = 0; i < 256; i++)
372 {
373 EXPECT_EQ(out.f[i][0], float((i >> 0) & 0x03) + 1.0f);
374 EXPECT_EQ(out.f[i][1], float((i >> 2) & 0x03) + 1.0f);
375 EXPECT_EQ(out.f[i][2], float((i >> 4) & 0x03) + 1.0f);
376 EXPECT_EQ(out.f[i][3], float((i >> 6) & 0x03) + 1.0f);
377 }
Nicolas Capens133b87d2020-01-25 16:26:28 -0500378
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500379 for(int i = 0; i < 256; i++)
380 {
381 EXPECT_EQ(out.f[256 + i][0], float((i >> 0) & 0x03) + 1.0f);
382 EXPECT_EQ(out.f[256 + i][1], float((i >> 2) & 0x03) + 1.0f);
383 EXPECT_EQ(out.f[256 + i][2], float((i >> 4) & 0x03) + 5.0f);
384 EXPECT_EQ(out.f[256 + i][3], float((i >> 6) & 0x03) + 5.0f);
385 }
Nicolas Capens133b87d2020-01-25 16:26:28 -0500386
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500387 EXPECT_EQ(out.f[512 + 0][0], 1.0f);
388 EXPECT_EQ(out.f[512 + 0][1], 5.0f);
389 EXPECT_EQ(out.f[512 + 0][2], 2.0f);
390 EXPECT_EQ(out.f[512 + 0][3], 6.0f);
Nicolas Capens133b87d2020-01-25 16:26:28 -0500391
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500392 EXPECT_EQ(out.f[512 + 1][0], 3.0f);
393 EXPECT_EQ(out.f[512 + 1][1], 7.0f);
394 EXPECT_EQ(out.f[512 + 1][2], 4.0f);
395 EXPECT_EQ(out.f[512 + 1][3], 8.0f);
Nicolas Capens133b87d2020-01-25 16:26:28 -0500396
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500397 EXPECT_EQ(out.i[0][0], 0x00050001);
398 EXPECT_EQ(out.i[0][1], 0x00060002);
399 EXPECT_EQ(out.i[0][2], 0x00000000);
400 EXPECT_EQ(out.i[0][3], 0x00000000);
Nicolas Capens133b87d2020-01-25 16:26:28 -0500401
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500402 EXPECT_EQ(out.i[1][0], 0x00070003);
403 EXPECT_EQ(out.i[1][1], 0x00080004);
404 EXPECT_EQ(out.i[1][2], 0x00000000);
405 EXPECT_EQ(out.i[1][3], 0x00000000);
Nicolas Capens133b87d2020-01-25 16:26:28 -0500406
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500407 EXPECT_EQ(out.i[2][0], 0x0A020901);
408 EXPECT_EQ(out.i[2][1], 0x0C040B03);
409 EXPECT_EQ(out.i[2][2], 0x00000000);
410 EXPECT_EQ(out.i[2][3], 0x00000000);
Nicolas Capens133b87d2020-01-25 16:26:28 -0500411
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500412 EXPECT_EQ(out.i[3][0], 0x0E060D05);
413 EXPECT_EQ(out.i[3][1], 0x10080F07);
414 EXPECT_EQ(out.i[3][2], 0x00000000);
415 EXPECT_EQ(out.i[3][3], 0x00000000);
Nicolas Capens133b87d2020-01-25 16:26:28 -0500416
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500417 for(int i = 0; i < 256; i++)
418 {
419 EXPECT_EQ(out.i[4 + i / 2][0 + (i % 2) * 2] & 0xFFFF,
420 ((i >> 0) & 0x03) + 1);
421 EXPECT_EQ(out.i[4 + i / 2][0 + (i % 2) * 2] >> 16,
422 ((i >> 2) & 0x03) + 1);
423 EXPECT_EQ(out.i[4 + i / 2][1 + (i % 2) * 2] & 0xFFFF,
424 ((i >> 4) & 0x03) + 1);
425 EXPECT_EQ(out.i[4 + i / 2][1 + (i % 2) * 2] >> 16,
426 ((i >> 6) & 0x03) + 1);
427 }
Nicolas Capens133b87d2020-01-25 16:26:28 -0500428
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500429 for(int i = 0; i < 256; i++)
430 {
431 EXPECT_EQ(out.i[132 + i][0], ((i >> 0) & 0x03) + 1);
432 EXPECT_EQ(out.i[132 + i][1], ((i >> 2) & 0x03) + 1);
433 EXPECT_EQ(out.i[132 + i][2], ((i >> 4) & 0x03) + 1);
434 EXPECT_EQ(out.i[132 + i][3], ((i >> 6) & 0x03) + 1);
Nicolas Capens133b87d2020-01-25 16:26:28 -0500435 }
436}
437
Nicolas Capensc07dc4b2018-08-06 14:20:45 -0400438TEST(ReactorUnitTests, Swizzle)
Nicolas Capens363b61e2016-10-21 13:19:34 -0400439{
Nicolas Capens133b87d2020-01-25 16:26:28 -0500440 FunctionT<void(void *)> function;
Nicolas Capens363b61e2016-10-21 13:19:34 -0400441 {
Nicolas Capens133b87d2020-01-25 16:26:28 -0500442 Pointer<Byte> out = function.Arg<0>();
Nicolas Capens363b61e2016-10-21 13:19:34 -0400443
Nicolas Capens133b87d2020-01-25 16:26:28 -0500444 Int4 c = Int4(0x01020304, 0x05060708, 0x09101112, 0x13141516);
445 *Pointer<Byte16>(out + 16 * 0) = Swizzle(As<Byte16>(c), 0xFEDCBA9876543210ull);
446 *Pointer<Byte8>(out + 16 * 1) = Swizzle(As<Byte8>(c), 0x76543210u);
447 *Pointer<UShort8>(out + 16 * 2) = Swizzle(As<UShort8>(c), 0x76543210u);
448 }
Nicolas Capens363b61e2016-10-21 13:19:34 -0400449
Antonio Maiorano2195f7a2020-11-27 14:02:23 -0500450 auto routine = function(testName().c_str());
Nicolas Capens363b61e2016-10-21 13:19:34 -0400451
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500452 int out[3][4];
Nicolas Capens363b61e2016-10-21 13:19:34 -0400453
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500454 memset(&out, 0, sizeof(out));
Casey Dahlin9d56da22017-10-03 13:23:11 -0700455
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500456 routine(&out);
Casey Dahlin9d56da22017-10-03 13:23:11 -0700457
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500458 EXPECT_EQ(out[0][0], 0x16151413);
459 EXPECT_EQ(out[0][1], 0x12111009);
460 EXPECT_EQ(out[0][2], 0x08070605);
461 EXPECT_EQ(out[0][3], 0x04030201);
Nicolas Capens363b61e2016-10-21 13:19:34 -0400462
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500463 EXPECT_EQ(out[1][0], 0x08070605);
464 EXPECT_EQ(out[1][1], 0x04030201);
Nicolas Capens363b61e2016-10-21 13:19:34 -0400465
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500466 EXPECT_EQ(out[2][0], 0x15161314);
467 EXPECT_EQ(out[2][1], 0x11120910);
468 EXPECT_EQ(out[2][2], 0x07080506);
469 EXPECT_EQ(out[2][3], 0x03040102);
Nicolas Capens363b61e2016-10-21 13:19:34 -0400470}
471
Nicolas Capense5720882020-01-13 14:10:04 -0500472TEST(ReactorUnitTests, Shuffle)
David 'Digit' Turnerb9f03f42019-12-04 19:32:34 +0100473{
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500474 // |select| is [0aaa:0bbb:0ccc:0ddd] where |aaa|, |bbb|, |ccc|
475 // and |ddd| are 7-bit selection indices. For a total (1 << 12)
476 // possibilities.
477 const int kSelectRange = 1 << 12;
478
479 // Unfortunately, testing the whole kSelectRange results in a test
480 // that is far too slow to run, because LLVM spends exponentially more
481 // time optimizing the function below as the number of test cases
482 // increases.
483 //
484 // To work-around the problem, only test a subset of the range by
485 // skipping every kRangeIncrement value.
486 //
487 // Set this value to 1 if you want to test the whole implementation,
488 // which will take a little less than 2 minutes on a fast workstation.
489 //
490 // The default value here takes about 1390ms, which is a little more than
491 // what the Swizzle test takes (993 ms) on my machine. A non-power-of-2
492 // value ensures a better spread over possible values.
493 const int kRangeIncrement = 11;
494
495 auto rangeIndexToSelect = [](int i) {
496 return static_cast<unsigned short>(
497 (((i >> 9) & 7) << 0) |
498 (((i >> 6) & 7) << 4) |
499 (((i >> 3) & 7) << 8) |
500 (((i >> 0) & 7) << 12));
501 };
502
503 FunctionT<int(void *)> function;
David 'Digit' Turnerb9f03f42019-12-04 19:32:34 +0100504 {
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500505 Pointer<Byte> out = function.Arg<0>();
David 'Digit' Turnerb9f03f42019-12-04 19:32:34 +0100506
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500507 for(int i = 0; i < kSelectRange; i += kRangeIncrement)
David 'Digit' Turnerb9f03f42019-12-04 19:32:34 +0100508 {
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500509 unsigned short select = rangeIndexToSelect(i);
David 'Digit' Turnerb9f03f42019-12-04 19:32:34 +0100510
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500511 *Pointer<Float4>(out + 16 * i) = Shuffle(Float4(1.0f, 2.0f, 3.0f, 4.0f),
512 Float4(5.0f, 6.0f, 7.0f, 8.0f),
513 select);
David 'Digit' Turnerb9f03f42019-12-04 19:32:34 +0100514
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500515 *Pointer<Int4>(out + (kSelectRange + i) * 16) = Shuffle(Int4(10, 11, 12, 13),
516 Int4(14, 15, 16, 17),
517 select);
David 'Digit' Turnerb9f03f42019-12-04 19:32:34 +0100518
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500519 *Pointer<UInt4>(out + (2 * kSelectRange + i) * 16) = Shuffle(UInt4(100, 101, 102, 103),
520 UInt4(104, 105, 106, 107),
521 select);
David 'Digit' Turnerb9f03f42019-12-04 19:32:34 +0100522 }
523
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500524 Return(0);
525 }
David 'Digit' Turnerb9f03f42019-12-04 19:32:34 +0100526
Antonio Maiorano2195f7a2020-11-27 14:02:23 -0500527 auto routine = function(testName().c_str());
David 'Digit' Turnerb9f03f42019-12-04 19:32:34 +0100528
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500529 struct
530 {
531 float f[kSelectRange][4];
532 int i[kSelectRange][4];
533 unsigned u[kSelectRange][4];
534 } out;
David 'Digit' Turnerb9f03f42019-12-04 19:32:34 +0100535
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500536 memset(&out, 0, sizeof(out));
David 'Digit' Turnerb9f03f42019-12-04 19:32:34 +0100537
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500538 routine(&out);
David 'Digit' Turnerb9f03f42019-12-04 19:32:34 +0100539
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500540 for(int i = 0; i < kSelectRange; i += kRangeIncrement)
541 {
542 EXPECT_EQ(out.f[i][0], float(1.0f + (i & 7)));
543 EXPECT_EQ(out.f[i][1], float(1.0f + ((i >> 3) & 7)));
544 EXPECT_EQ(out.f[i][2], float(1.0f + ((i >> 6) & 7)));
545 EXPECT_EQ(out.f[i][3], float(1.0f + ((i >> 9) & 7)));
546 }
David 'Digit' Turnerb9f03f42019-12-04 19:32:34 +0100547
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500548 for(int i = 0; i < kSelectRange; i += kRangeIncrement)
549 {
550 EXPECT_EQ(out.i[i][0], int(10 + (i & 7)));
551 EXPECT_EQ(out.i[i][1], int(10 + ((i >> 3) & 7)));
552 EXPECT_EQ(out.i[i][2], int(10 + ((i >> 6) & 7)));
553 EXPECT_EQ(out.i[i][3], int(10 + ((i >> 9) & 7)));
554 }
555
556 for(int i = 0; i < kSelectRange; i += kRangeIncrement)
557 {
558 EXPECT_EQ(out.u[i][0], unsigned(100 + (i & 7)));
559 EXPECT_EQ(out.u[i][1], unsigned(100 + ((i >> 3) & 7)));
560 EXPECT_EQ(out.u[i][2], unsigned(100 + ((i >> 6) & 7)));
561 EXPECT_EQ(out.u[i][3], unsigned(100 + ((i >> 9) & 7)));
David 'Digit' Turnerb9f03f42019-12-04 19:32:34 +0100562 }
David 'Digit' Turnerb9f03f42019-12-04 19:32:34 +0100563}
564
Nicolas Capensc07dc4b2018-08-06 14:20:45 -0400565TEST(ReactorUnitTests, Branching)
Nicolas Capens9ed1a182016-10-24 09:52:23 -0400566{
Nicolas Capens157ba262019-12-10 17:49:14 -0500567 FunctionT<int()> function;
Nicolas Capens9ed1a182016-10-24 09:52:23 -0400568 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500569 Int x = 0;
570
571 For(Int i = 0, i < 8, i++)
Nicolas Capens9ed1a182016-10-24 09:52:23 -0400572 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500573 If(i < 2)
Nicolas Capens9ed1a182016-10-24 09:52:23 -0400574 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500575 x += 1;
576 }
577 Else If(i < 4)
578 {
579 x += 10;
580 }
581 Else If(i < 6)
582 {
583 x += 100;
584 }
585 Else
586 {
587 x += 1000;
Nicolas Capens9ed1a182016-10-24 09:52:23 -0400588 }
589
Nicolas Capens157ba262019-12-10 17:49:14 -0500590 For(Int i = 0, i < 5, i++)
Ben Clayton713b8d32019-12-17 20:37:56 +0000591 x += 10000;
Nicolas Capens157ba262019-12-10 17:49:14 -0500592 }
Nicolas Capensb0eb3772016-10-24 17:49:13 -0400593
Ben Clayton713b8d32019-12-17 20:37:56 +0000594 For(Int i = 0, i < 10, i++) for(int i = 0; i < 10; i++)
595 For(Int i = 0, i < 10, i++)
596 {
597 x += 1000000;
598 }
Nicolas Capens9ed1a182016-10-24 09:52:23 -0400599
Nicolas Capens157ba262019-12-10 17:49:14 -0500600 For(Int i = 0, i < 2, i++)
Ben Clayton713b8d32019-12-17 20:37:56 +0000601 If(x == 1000402222)
602 {
603 If(x != 1000402222)
604 x += 1000000000;
605 }
606 Else
607 x = -5;
Nicolas Capens9ed1a182016-10-24 09:52:23 -0400608
Nicolas Capens157ba262019-12-10 17:49:14 -0500609 Return(x);
610 }
Nicolas Capens9ed1a182016-10-24 09:52:23 -0400611
Antonio Maiorano2195f7a2020-11-27 14:02:23 -0500612 auto routine = function(testName().c_str());
Nicolas Capens9ed1a182016-10-24 09:52:23 -0400613
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500614 int result = routine();
Nicolas Capens157ba262019-12-10 17:49:14 -0500615
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500616 EXPECT_EQ(result, 1000402222);
Nicolas Capens9ed1a182016-10-24 09:52:23 -0400617}
618
Nicolas Capensc07dc4b2018-08-06 14:20:45 -0400619TEST(ReactorUnitTests, MinMax)
Nicolas Capens53a8a3f2016-10-26 00:23:12 -0400620{
Ben Clayton713b8d32019-12-17 20:37:56 +0000621 FunctionT<int(void *)> function;
Nicolas Capens53a8a3f2016-10-26 00:23:12 -0400622 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500623 Pointer<Byte> out = function.Arg<0>();
Nicolas Capens53a8a3f2016-10-26 00:23:12 -0400624
Nicolas Capens157ba262019-12-10 17:49:14 -0500625 *Pointer<Float4>(out + 16 * 0) = Min(Float4(1.0f, 0.0f, -0.0f, +0.0f), Float4(0.0f, 1.0f, +0.0f, -0.0f));
626 *Pointer<Float4>(out + 16 * 1) = Max(Float4(1.0f, 0.0f, -0.0f, +0.0f), Float4(0.0f, 1.0f, +0.0f, -0.0f));
Nicolas Capens53a8a3f2016-10-26 00:23:12 -0400627
Nicolas Capens157ba262019-12-10 17:49:14 -0500628 *Pointer<Int4>(out + 16 * 2) = Min(Int4(1, 0, -1, -0), Int4(0, 1, 0, +0));
629 *Pointer<Int4>(out + 16 * 3) = Max(Int4(1, 0, -1, -0), Int4(0, 1, 0, +0));
630 *Pointer<UInt4>(out + 16 * 4) = Min(UInt4(1, 0, -1, -0), UInt4(0, 1, 0, +0));
631 *Pointer<UInt4>(out + 16 * 5) = Max(UInt4(1, 0, -1, -0), UInt4(0, 1, 0, +0));
Nicolas Capens53a8a3f2016-10-26 00:23:12 -0400632
Nicolas Capens157ba262019-12-10 17:49:14 -0500633 *Pointer<Short4>(out + 16 * 6) = Min(Short4(1, 0, -1, -0), Short4(0, 1, 0, +0));
634 *Pointer<Short4>(out + 16 * 7) = Max(Short4(1, 0, -1, -0), Short4(0, 1, 0, +0));
635 *Pointer<UShort4>(out + 16 * 8) = Min(UShort4(1, 0, -1, -0), UShort4(0, 1, 0, +0));
636 *Pointer<UShort4>(out + 16 * 9) = Max(UShort4(1, 0, -1, -0), UShort4(0, 1, 0, +0));
Nicolas Capens53a8a3f2016-10-26 00:23:12 -0400637
Nicolas Capens157ba262019-12-10 17:49:14 -0500638 Return(0);
Nicolas Capens53a8a3f2016-10-26 00:23:12 -0400639 }
640
Antonio Maiorano2195f7a2020-11-27 14:02:23 -0500641 auto routine = function(testName().c_str());
Nicolas Capens157ba262019-12-10 17:49:14 -0500642
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500643 unsigned int out[10][4];
Nicolas Capens157ba262019-12-10 17:49:14 -0500644
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500645 memset(&out, 0, sizeof(out));
Nicolas Capens157ba262019-12-10 17:49:14 -0500646
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500647 routine(&out);
Nicolas Capens157ba262019-12-10 17:49:14 -0500648
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500649 EXPECT_EQ(out[0][0], 0x00000000u);
650 EXPECT_EQ(out[0][1], 0x00000000u);
651 EXPECT_EQ(out[0][2], 0x00000000u);
652 EXPECT_EQ(out[0][3], 0x80000000u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500653
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500654 EXPECT_EQ(out[1][0], 0x3F800000u);
655 EXPECT_EQ(out[1][1], 0x3F800000u);
656 EXPECT_EQ(out[1][2], 0x00000000u);
657 EXPECT_EQ(out[1][3], 0x80000000u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500658
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500659 EXPECT_EQ(out[2][0], 0x00000000u);
660 EXPECT_EQ(out[2][1], 0x00000000u);
661 EXPECT_EQ(out[2][2], 0xFFFFFFFFu);
662 EXPECT_EQ(out[2][3], 0x00000000u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500663
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500664 EXPECT_EQ(out[3][0], 0x00000001u);
665 EXPECT_EQ(out[3][1], 0x00000001u);
666 EXPECT_EQ(out[3][2], 0x00000000u);
667 EXPECT_EQ(out[3][3], 0x00000000u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500668
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500669 EXPECT_EQ(out[4][0], 0x00000000u);
670 EXPECT_EQ(out[4][1], 0x00000000u);
671 EXPECT_EQ(out[4][2], 0x00000000u);
672 EXPECT_EQ(out[4][3], 0x00000000u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500673
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500674 EXPECT_EQ(out[5][0], 0x00000001u);
675 EXPECT_EQ(out[5][1], 0x00000001u);
676 EXPECT_EQ(out[5][2], 0xFFFFFFFFu);
677 EXPECT_EQ(out[5][3], 0x00000000u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500678
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500679 EXPECT_EQ(out[6][0], 0x00000000u);
680 EXPECT_EQ(out[6][1], 0x0000FFFFu);
681 EXPECT_EQ(out[6][2], 0x00000000u);
682 EXPECT_EQ(out[6][3], 0x00000000u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500683
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500684 EXPECT_EQ(out[7][0], 0x00010001u);
685 EXPECT_EQ(out[7][1], 0x00000000u);
686 EXPECT_EQ(out[7][2], 0x00000000u);
687 EXPECT_EQ(out[7][3], 0x00000000u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500688
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500689 EXPECT_EQ(out[8][0], 0x00000000u);
690 EXPECT_EQ(out[8][1], 0x00000000u);
691 EXPECT_EQ(out[8][2], 0x00000000u);
692 EXPECT_EQ(out[8][3], 0x00000000u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500693
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500694 EXPECT_EQ(out[9][0], 0x00010001u);
695 EXPECT_EQ(out[9][1], 0x0000FFFFu);
696 EXPECT_EQ(out[9][2], 0x00000000u);
697 EXPECT_EQ(out[9][3], 0x00000000u);
Nicolas Capens53a8a3f2016-10-26 00:23:12 -0400698}
699
Nicolas Capensc07dc4b2018-08-06 14:20:45 -0400700TEST(ReactorUnitTests, NotNeg)
Nicolas Capensc5c0c332016-11-08 11:37:01 -0500701{
Ben Clayton713b8d32019-12-17 20:37:56 +0000702 FunctionT<int(void *)> function;
Nicolas Capensc5c0c332016-11-08 11:37:01 -0500703 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500704 Pointer<Byte> out = function.Arg<0>();
Nicolas Capensc5c0c332016-11-08 11:37:01 -0500705
Nicolas Capens157ba262019-12-10 17:49:14 -0500706 *Pointer<Int>(out + 16 * 0) = ~Int(0x55555555);
707 *Pointer<Short>(out + 16 * 1) = ~Short(0x5555);
708 *Pointer<Int4>(out + 16 * 2) = ~Int4(0x55555555, 0xAAAAAAAA, 0x00000000, 0xFFFFFFFF);
709 *Pointer<Short4>(out + 16 * 3) = ~Short4(0x5555, 0xAAAA, 0x0000, 0xFFFF);
Nicolas Capensc5c0c332016-11-08 11:37:01 -0500710
Nicolas Capens157ba262019-12-10 17:49:14 -0500711 *Pointer<Int>(out + 16 * 4) = -Int(0x55555555);
712 *Pointer<Short>(out + 16 * 5) = -Short(0x5555);
713 *Pointer<Int4>(out + 16 * 6) = -Int4(0x55555555, 0xAAAAAAAA, 0x00000000, 0xFFFFFFFF);
714 *Pointer<Short4>(out + 16 * 7) = -Short4(0x5555, 0xAAAA, 0x0000, 0xFFFF);
Nicolas Capensc5c0c332016-11-08 11:37:01 -0500715
Nicolas Capens157ba262019-12-10 17:49:14 -0500716 *Pointer<Float4>(out + 16 * 8) = -Float4(1.0f, -1.0f, 0.0f, -0.0f);
Nicolas Capensc5c0c332016-11-08 11:37:01 -0500717
Nicolas Capens157ba262019-12-10 17:49:14 -0500718 Return(0);
Nicolas Capensc5c0c332016-11-08 11:37:01 -0500719 }
720
Antonio Maiorano2195f7a2020-11-27 14:02:23 -0500721 auto routine = function(testName().c_str());
Nicolas Capens157ba262019-12-10 17:49:14 -0500722
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500723 unsigned int out[10][4];
Nicolas Capens157ba262019-12-10 17:49:14 -0500724
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500725 memset(&out, 0, sizeof(out));
Nicolas Capens157ba262019-12-10 17:49:14 -0500726
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500727 routine(&out);
Nicolas Capens157ba262019-12-10 17:49:14 -0500728
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500729 EXPECT_EQ(out[0][0], 0xAAAAAAAAu);
730 EXPECT_EQ(out[0][1], 0x00000000u);
731 EXPECT_EQ(out[0][2], 0x00000000u);
732 EXPECT_EQ(out[0][3], 0x00000000u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500733
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500734 EXPECT_EQ(out[1][0], 0x0000AAAAu);
735 EXPECT_EQ(out[1][1], 0x00000000u);
736 EXPECT_EQ(out[1][2], 0x00000000u);
737 EXPECT_EQ(out[1][3], 0x00000000u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500738
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500739 EXPECT_EQ(out[2][0], 0xAAAAAAAAu);
740 EXPECT_EQ(out[2][1], 0x55555555u);
741 EXPECT_EQ(out[2][2], 0xFFFFFFFFu);
742 EXPECT_EQ(out[2][3], 0x00000000u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500743
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500744 EXPECT_EQ(out[3][0], 0x5555AAAAu);
745 EXPECT_EQ(out[3][1], 0x0000FFFFu);
746 EXPECT_EQ(out[3][2], 0x00000000u);
747 EXPECT_EQ(out[3][3], 0x00000000u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500748
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500749 EXPECT_EQ(out[4][0], 0xAAAAAAABu);
750 EXPECT_EQ(out[4][1], 0x00000000u);
751 EXPECT_EQ(out[4][2], 0x00000000u);
752 EXPECT_EQ(out[4][3], 0x00000000u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500753
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500754 EXPECT_EQ(out[5][0], 0x0000AAABu);
755 EXPECT_EQ(out[5][1], 0x00000000u);
756 EXPECT_EQ(out[5][2], 0x00000000u);
757 EXPECT_EQ(out[5][3], 0x00000000u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500758
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500759 EXPECT_EQ(out[6][0], 0xAAAAAAABu);
760 EXPECT_EQ(out[6][1], 0x55555556u);
761 EXPECT_EQ(out[6][2], 0x00000000u);
762 EXPECT_EQ(out[6][3], 0x00000001u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500763
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500764 EXPECT_EQ(out[7][0], 0x5556AAABu);
765 EXPECT_EQ(out[7][1], 0x00010000u);
766 EXPECT_EQ(out[7][2], 0x00000000u);
767 EXPECT_EQ(out[7][3], 0x00000000u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500768
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500769 EXPECT_EQ(out[8][0], 0xBF800000u);
770 EXPECT_EQ(out[8][1], 0x3F800000u);
771 EXPECT_EQ(out[8][2], 0x80000000u);
772 EXPECT_EQ(out[8][3], 0x00000000u);
Nicolas Capensc5c0c332016-11-08 11:37:01 -0500773}
774
Nicolas Capenseeb81842021-01-12 17:44:40 -0500775TEST(ReactorUnitTests, RoundInt)
776{
777 FunctionT<int(void *)> function;
778 {
779 Pointer<Byte> out = function.Arg<0>();
780
781 *Pointer<Int4>(out + 0) = RoundInt(Float4(3.1f, 3.6f, -3.1f, -3.6f));
782 *Pointer<Int4>(out + 16) = RoundIntClamped(Float4(2147483648.0f, -2147483648.0f, 2147483520, -2147483520));
783
784 Return(0);
785 }
786
787 auto routine = function(testName().c_str());
788
789 int out[2][4];
790
791 memset(&out, 0, sizeof(out));
792
793 routine(&out);
794
795 EXPECT_EQ(out[0][0], 3);
796 EXPECT_EQ(out[0][1], 4);
797 EXPECT_EQ(out[0][2], -3);
798 EXPECT_EQ(out[0][3], -4);
799
800 // x86 returns 0x80000000 for values which cannot be represented in a 32-bit
801 // integer, but RoundIntClamped() clamps to ensure a positive value for
802 // positive input. ARM saturates to the largest representable integers.
803 EXPECT_GE(out[1][0], 2147483520);
804 EXPECT_LT(out[1][1], -2147483647);
805 EXPECT_EQ(out[1][2], 2147483520);
806 EXPECT_EQ(out[1][3], -2147483520);
807}
808
Nicolas Capenscf79a622019-12-09 17:07:41 -0500809TEST(ReactorUnitTests, FPtoUI)
810{
Ben Clayton713b8d32019-12-17 20:37:56 +0000811 FunctionT<int(void *)> function;
Nicolas Capenscf79a622019-12-09 17:07:41 -0500812 {
813 Pointer<Byte> out = function.Arg<0>();
814
Ben Clayton713b8d32019-12-17 20:37:56 +0000815 *Pointer<UInt>(out + 0) = UInt(Float(0xF0000000u));
816 *Pointer<UInt>(out + 4) = UInt(Float(0xC0000000u));
817 *Pointer<UInt>(out + 8) = UInt(Float(0x00000001u));
Nicolas Capenscf79a622019-12-09 17:07:41 -0500818 *Pointer<UInt>(out + 12) = UInt(Float(0xF000F000u));
819
820 *Pointer<UInt4>(out + 16) = UInt4(Float4(0xF0000000u, 0x80000000u, 0x00000000u, 0xCCCC0000u));
821
822 Return(0);
823 }
824
Antonio Maiorano2195f7a2020-11-27 14:02:23 -0500825 auto routine = function(testName().c_str());
Nicolas Capenscf79a622019-12-09 17:07:41 -0500826
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500827 unsigned int out[2][4];
Nicolas Capenscf79a622019-12-09 17:07:41 -0500828
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500829 memset(&out, 0, sizeof(out));
Nicolas Capenscf79a622019-12-09 17:07:41 -0500830
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500831 routine(&out);
Nicolas Capenscf79a622019-12-09 17:07:41 -0500832
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500833 EXPECT_EQ(out[0][0], 0xF0000000u);
834 EXPECT_EQ(out[0][1], 0xC0000000u);
835 EXPECT_EQ(out[0][2], 0x00000001u);
836 EXPECT_EQ(out[0][3], 0xF000F000u);
Nicolas Capenscf79a622019-12-09 17:07:41 -0500837
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500838 EXPECT_EQ(out[1][0], 0xF0000000u);
839 EXPECT_EQ(out[1][1], 0x80000000u);
840 EXPECT_EQ(out[1][2], 0x00000000u);
841 EXPECT_EQ(out[1][3], 0xCCCC0000u);
Nicolas Capenscf79a622019-12-09 17:07:41 -0500842}
843
Nicolas Capensc07dc4b2018-08-06 14:20:45 -0400844TEST(ReactorUnitTests, VectorCompare)
Nicolas Capens5e6ca092017-01-13 15:09:21 -0500845{
Ben Clayton713b8d32019-12-17 20:37:56 +0000846 FunctionT<int(void *)> function;
Nicolas Capens5e6ca092017-01-13 15:09:21 -0500847 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500848 Pointer<Byte> out = function.Arg<0>();
Nicolas Capens5e6ca092017-01-13 15:09:21 -0500849
Nicolas Capens157ba262019-12-10 17:49:14 -0500850 *Pointer<Int4>(out + 16 * 0) = CmpEQ(Float4(1.0f, 1.0f, -0.0f, +0.0f), Float4(0.0f, 1.0f, +0.0f, -0.0f));
851 *Pointer<Int4>(out + 16 * 1) = CmpEQ(Int4(1, 0, -1, -0), Int4(0, 1, 0, +0));
852 *Pointer<Byte8>(out + 16 * 2) = CmpEQ(SByte8(1, 2, 3, 4, 5, 6, 7, 8), SByte8(7, 6, 5, 4, 3, 2, 1, 0));
Nicolas Capens5e6ca092017-01-13 15:09:21 -0500853
Nicolas Capens157ba262019-12-10 17:49:14 -0500854 *Pointer<Int4>(out + 16 * 3) = CmpNLT(Float4(1.0f, 1.0f, -0.0f, +0.0f), Float4(0.0f, 1.0f, +0.0f, -0.0f));
855 *Pointer<Int4>(out + 16 * 4) = CmpNLT(Int4(1, 0, -1, -0), Int4(0, 1, 0, +0));
856 *Pointer<Byte8>(out + 16 * 5) = CmpGT(SByte8(1, 2, 3, 4, 5, 6, 7, 8), SByte8(7, 6, 5, 4, 3, 2, 1, 0));
Nicolas Capens5e6ca092017-01-13 15:09:21 -0500857
Nicolas Capens157ba262019-12-10 17:49:14 -0500858 Return(0);
Nicolas Capens5e6ca092017-01-13 15:09:21 -0500859 }
860
Antonio Maiorano2195f7a2020-11-27 14:02:23 -0500861 auto routine = function(testName().c_str());
Nicolas Capens157ba262019-12-10 17:49:14 -0500862
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500863 unsigned int out[6][4];
Nicolas Capens157ba262019-12-10 17:49:14 -0500864
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500865 memset(&out, 0, sizeof(out));
Nicolas Capens157ba262019-12-10 17:49:14 -0500866
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500867 routine(&out);
Nicolas Capens157ba262019-12-10 17:49:14 -0500868
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500869 EXPECT_EQ(out[0][0], 0x00000000u);
870 EXPECT_EQ(out[0][1], 0xFFFFFFFFu);
871 EXPECT_EQ(out[0][2], 0xFFFFFFFFu);
872 EXPECT_EQ(out[0][3], 0xFFFFFFFFu);
Nicolas Capens157ba262019-12-10 17:49:14 -0500873
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500874 EXPECT_EQ(out[1][0], 0x00000000u);
875 EXPECT_EQ(out[1][1], 0x00000000u);
876 EXPECT_EQ(out[1][2], 0x00000000u);
877 EXPECT_EQ(out[1][3], 0xFFFFFFFFu);
Nicolas Capens157ba262019-12-10 17:49:14 -0500878
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500879 EXPECT_EQ(out[2][0], 0xFF000000u);
880 EXPECT_EQ(out[2][1], 0x00000000u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500881
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500882 EXPECT_EQ(out[3][0], 0xFFFFFFFFu);
883 EXPECT_EQ(out[3][1], 0xFFFFFFFFu);
884 EXPECT_EQ(out[3][2], 0xFFFFFFFFu);
885 EXPECT_EQ(out[3][3], 0xFFFFFFFFu);
Nicolas Capens157ba262019-12-10 17:49:14 -0500886
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500887 EXPECT_EQ(out[4][0], 0xFFFFFFFFu);
888 EXPECT_EQ(out[4][1], 0x00000000u);
889 EXPECT_EQ(out[4][2], 0x00000000u);
890 EXPECT_EQ(out[4][3], 0xFFFFFFFFu);
Nicolas Capens157ba262019-12-10 17:49:14 -0500891
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500892 EXPECT_EQ(out[5][0], 0x00000000u);
893 EXPECT_EQ(out[5][1], 0xFFFFFFFFu);
Nicolas Capens5e6ca092017-01-13 15:09:21 -0500894}
895
Nicolas Capensc07dc4b2018-08-06 14:20:45 -0400896TEST(ReactorUnitTests, SaturatedAddAndSubtract)
Casey Dahlin642fc922017-09-28 17:18:41 -0700897{
Ben Clayton713b8d32019-12-17 20:37:56 +0000898 FunctionT<int(void *)> function;
Casey Dahlin642fc922017-09-28 17:18:41 -0700899 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500900 Pointer<Byte> out = function.Arg<0>();
Casey Dahlin642fc922017-09-28 17:18:41 -0700901
Nicolas Capens157ba262019-12-10 17:49:14 -0500902 *Pointer<Byte8>(out + 8 * 0) =
Ben Clayton713b8d32019-12-17 20:37:56 +0000903 AddSat(Byte8(1, 2, 3, 4, 5, 6, 7, 8),
904 Byte8(7, 6, 5, 4, 3, 2, 1, 0));
Nicolas Capens157ba262019-12-10 17:49:14 -0500905 *Pointer<Byte8>(out + 8 * 1) =
Ben Clayton713b8d32019-12-17 20:37:56 +0000906 AddSat(Byte8(0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE),
907 Byte8(7, 6, 5, 4, 3, 2, 1, 0));
Nicolas Capens157ba262019-12-10 17:49:14 -0500908 *Pointer<Byte8>(out + 8 * 2) =
Ben Clayton713b8d32019-12-17 20:37:56 +0000909 SubSat(Byte8(1, 2, 3, 4, 5, 6, 7, 8),
910 Byte8(7, 6, 5, 4, 3, 2, 1, 0));
Casey Dahlin642fc922017-09-28 17:18:41 -0700911
Nicolas Capens157ba262019-12-10 17:49:14 -0500912 *Pointer<SByte8>(out + 8 * 3) =
Ben Clayton713b8d32019-12-17 20:37:56 +0000913 AddSat(SByte8(1, 2, 3, 4, 5, 6, 7, 8),
914 SByte8(7, 6, 5, 4, 3, 2, 1, 0));
Nicolas Capens157ba262019-12-10 17:49:14 -0500915 *Pointer<SByte8>(out + 8 * 4) =
Ben Clayton713b8d32019-12-17 20:37:56 +0000916 AddSat(SByte8(0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E),
917 SByte8(7, 6, 5, 4, 3, 2, 1, 0));
Nicolas Capens157ba262019-12-10 17:49:14 -0500918 *Pointer<SByte8>(out + 8 * 5) =
Ben Clayton713b8d32019-12-17 20:37:56 +0000919 AddSat(SByte8(0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88),
920 SByte8(-7, -6, -5, -4, -3, -2, -1, -0));
Nicolas Capens157ba262019-12-10 17:49:14 -0500921 *Pointer<SByte8>(out + 8 * 6) =
Ben Clayton713b8d32019-12-17 20:37:56 +0000922 SubSat(SByte8(0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88),
923 SByte8(7, 6, 5, 4, 3, 2, 1, 0));
Casey Dahlin642fc922017-09-28 17:18:41 -0700924
Nicolas Capens157ba262019-12-10 17:49:14 -0500925 *Pointer<Short4>(out + 8 * 7) =
Ben Clayton713b8d32019-12-17 20:37:56 +0000926 AddSat(Short4(1, 2, 3, 4), Short4(3, 2, 1, 0));
Nicolas Capens157ba262019-12-10 17:49:14 -0500927 *Pointer<Short4>(out + 8 * 8) =
Ben Clayton713b8d32019-12-17 20:37:56 +0000928 AddSat(Short4(0x7FFE, 0x7FFE, 0x7FFE, 0x7FFE),
929 Short4(3, 2, 1, 0));
Nicolas Capens157ba262019-12-10 17:49:14 -0500930 *Pointer<Short4>(out + 8 * 9) =
Ben Clayton713b8d32019-12-17 20:37:56 +0000931 AddSat(Short4(0x8001, 0x8002, 0x8003, 0x8004),
932 Short4(-3, -2, -1, -0));
Nicolas Capens157ba262019-12-10 17:49:14 -0500933 *Pointer<Short4>(out + 8 * 10) =
Ben Clayton713b8d32019-12-17 20:37:56 +0000934 SubSat(Short4(0x8001, 0x8002, 0x8003, 0x8004),
935 Short4(3, 2, 1, 0));
Casey Dahlin642fc922017-09-28 17:18:41 -0700936
Nicolas Capens157ba262019-12-10 17:49:14 -0500937 *Pointer<UShort4>(out + 8 * 11) =
Ben Clayton713b8d32019-12-17 20:37:56 +0000938 AddSat(UShort4(1, 2, 3, 4), UShort4(3, 2, 1, 0));
Nicolas Capens157ba262019-12-10 17:49:14 -0500939 *Pointer<UShort4>(out + 8 * 12) =
Ben Clayton713b8d32019-12-17 20:37:56 +0000940 AddSat(UShort4(0xFFFE, 0xFFFE, 0xFFFE, 0xFFFE),
941 UShort4(3, 2, 1, 0));
Nicolas Capens157ba262019-12-10 17:49:14 -0500942 *Pointer<UShort4>(out + 8 * 13) =
Ben Clayton713b8d32019-12-17 20:37:56 +0000943 SubSat(UShort4(1, 2, 3, 4), UShort4(3, 2, 1, 0));
Casey Dahlin642fc922017-09-28 17:18:41 -0700944
Nicolas Capens157ba262019-12-10 17:49:14 -0500945 Return(0);
Casey Dahlin642fc922017-09-28 17:18:41 -0700946 }
947
Antonio Maiorano2195f7a2020-11-27 14:02:23 -0500948 auto routine = function(testName().c_str());
Nicolas Capens157ba262019-12-10 17:49:14 -0500949
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500950 unsigned int out[14][2];
Nicolas Capens157ba262019-12-10 17:49:14 -0500951
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500952 memset(&out, 0, sizeof(out));
Nicolas Capens157ba262019-12-10 17:49:14 -0500953
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500954 routine(&out);
Nicolas Capens157ba262019-12-10 17:49:14 -0500955
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500956 EXPECT_EQ(out[0][0], 0x08080808u);
957 EXPECT_EQ(out[0][1], 0x08080808u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500958
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500959 EXPECT_EQ(out[1][0], 0xFFFFFFFFu);
960 EXPECT_EQ(out[1][1], 0xFEFFFFFFu);
Nicolas Capens157ba262019-12-10 17:49:14 -0500961
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500962 EXPECT_EQ(out[2][0], 0x00000000u);
963 EXPECT_EQ(out[2][1], 0x08060402u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500964
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500965 EXPECT_EQ(out[3][0], 0x08080808u);
966 EXPECT_EQ(out[3][1], 0x08080808u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500967
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500968 EXPECT_EQ(out[4][0], 0x7F7F7F7Fu);
969 EXPECT_EQ(out[4][1], 0x7E7F7F7Fu);
Nicolas Capens157ba262019-12-10 17:49:14 -0500970
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500971 EXPECT_EQ(out[5][0], 0x80808080u);
972 EXPECT_EQ(out[5][1], 0x88868482u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500973
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500974 EXPECT_EQ(out[6][0], 0x80808080u);
975 EXPECT_EQ(out[6][1], 0x88868482u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500976
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500977 EXPECT_EQ(out[7][0], 0x00040004u);
978 EXPECT_EQ(out[7][1], 0x00040004u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500979
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500980 EXPECT_EQ(out[8][0], 0x7FFF7FFFu);
981 EXPECT_EQ(out[8][1], 0x7FFE7FFFu);
Nicolas Capens157ba262019-12-10 17:49:14 -0500982
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500983 EXPECT_EQ(out[9][0], 0x80008000u);
984 EXPECT_EQ(out[9][1], 0x80048002u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500985
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500986 EXPECT_EQ(out[10][0], 0x80008000u);
987 EXPECT_EQ(out[10][1], 0x80048002u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500988
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500989 EXPECT_EQ(out[11][0], 0x00040004u);
990 EXPECT_EQ(out[11][1], 0x00040004u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500991
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500992 EXPECT_EQ(out[12][0], 0xFFFFFFFFu);
993 EXPECT_EQ(out[12][1], 0xFFFEFFFFu);
Nicolas Capens157ba262019-12-10 17:49:14 -0500994
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500995 EXPECT_EQ(out[13][0], 0x00000000u);
996 EXPECT_EQ(out[13][1], 0x00040002u);
Casey Dahlin642fc922017-09-28 17:18:41 -0700997}
998
Nicolas Capensc07dc4b2018-08-06 14:20:45 -0400999TEST(ReactorUnitTests, Unpack)
Casey Dahlin4e759e42017-09-29 13:43:18 -07001000{
Ben Clayton713b8d32019-12-17 20:37:56 +00001001 FunctionT<int(void *, void *)> function;
Casey Dahlin4e759e42017-09-29 13:43:18 -07001002 {
Nicolas Capens157ba262019-12-10 17:49:14 -05001003 Pointer<Byte> in = function.Arg<0>();
1004 Pointer<Byte> out = function.Arg<1>();
Casey Dahlin4e759e42017-09-29 13:43:18 -07001005
Nicolas Capens157ba262019-12-10 17:49:14 -05001006 Byte4 test_byte_a = *Pointer<Byte4>(in + 4 * 0);
1007 Byte4 test_byte_b = *Pointer<Byte4>(in + 4 * 1);
Casey Dahlin4e759e42017-09-29 13:43:18 -07001008
Nicolas Capens157ba262019-12-10 17:49:14 -05001009 *Pointer<Short4>(out + 8 * 0) =
Ben Clayton713b8d32019-12-17 20:37:56 +00001010 Unpack(test_byte_a, test_byte_b);
Casey Dahlin4e759e42017-09-29 13:43:18 -07001011
Nicolas Capens157ba262019-12-10 17:49:14 -05001012 *Pointer<Short4>(out + 8 * 1) = Unpack(test_byte_a);
Casey Dahlin4e759e42017-09-29 13:43:18 -07001013
Nicolas Capens157ba262019-12-10 17:49:14 -05001014 Return(0);
Casey Dahlin4e759e42017-09-29 13:43:18 -07001015 }
1016
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05001017 auto routine = function(testName().c_str());
Nicolas Capens157ba262019-12-10 17:49:14 -05001018
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001019 unsigned int in[1][2];
1020 unsigned int out[2][2];
Nicolas Capens157ba262019-12-10 17:49:14 -05001021
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001022 memset(&out, 0, sizeof(out));
Nicolas Capens157ba262019-12-10 17:49:14 -05001023
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001024 in[0][0] = 0xABCDEF12u;
1025 in[0][1] = 0x34567890u;
Nicolas Capens157ba262019-12-10 17:49:14 -05001026
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001027 routine(&in, &out);
Nicolas Capens157ba262019-12-10 17:49:14 -05001028
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001029 EXPECT_EQ(out[0][0], 0x78EF9012u);
1030 EXPECT_EQ(out[0][1], 0x34AB56CDu);
Nicolas Capens157ba262019-12-10 17:49:14 -05001031
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001032 EXPECT_EQ(out[1][0], 0xEFEF1212u);
1033 EXPECT_EQ(out[1][1], 0xABABCDCDu);
Casey Dahlin4e759e42017-09-29 13:43:18 -07001034}
1035
Nicolas Capensc07dc4b2018-08-06 14:20:45 -04001036TEST(ReactorUnitTests, Pack)
Casey Dahlin11658122017-09-29 16:32:32 -07001037{
Ben Clayton713b8d32019-12-17 20:37:56 +00001038 FunctionT<int(void *)> function;
Casey Dahlin11658122017-09-29 16:32:32 -07001039 {
Nicolas Capens157ba262019-12-10 17:49:14 -05001040 Pointer<Byte> out = function.Arg<0>();
Casey Dahlin11658122017-09-29 16:32:32 -07001041
Nicolas Capens157ba262019-12-10 17:49:14 -05001042 *Pointer<SByte8>(out + 8 * 0) =
Ben Clayton713b8d32019-12-17 20:37:56 +00001043 PackSigned(Short4(-1, -2, 1, 2),
1044 Short4(3, 4, -3, -4));
Casey Dahlin11658122017-09-29 16:32:32 -07001045
Nicolas Capens157ba262019-12-10 17:49:14 -05001046 *Pointer<Byte8>(out + 8 * 1) =
Ben Clayton713b8d32019-12-17 20:37:56 +00001047 PackUnsigned(Short4(-1, -2, 1, 2),
1048 Short4(3, 4, -3, -4));
Casey Dahlin11658122017-09-29 16:32:32 -07001049
Nicolas Capens157ba262019-12-10 17:49:14 -05001050 *Pointer<Short8>(out + 8 * 2) =
Ben Clayton713b8d32019-12-17 20:37:56 +00001051 PackSigned(Int4(-1, -2, 1, 2),
1052 Int4(3, 4, -3, -4));
Casey Dahlin11658122017-09-29 16:32:32 -07001053
Nicolas Capens157ba262019-12-10 17:49:14 -05001054 *Pointer<UShort8>(out + 8 * 4) =
Ben Clayton713b8d32019-12-17 20:37:56 +00001055 PackUnsigned(Int4(-1, -2, 1, 2),
1056 Int4(3, 4, -3, -4));
Casey Dahlin11658122017-09-29 16:32:32 -07001057
Nicolas Capens157ba262019-12-10 17:49:14 -05001058 Return(0);
Casey Dahlin11658122017-09-29 16:32:32 -07001059 }
1060
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05001061 auto routine = function(testName().c_str());
Nicolas Capens157ba262019-12-10 17:49:14 -05001062
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001063 unsigned int out[6][2];
Nicolas Capens157ba262019-12-10 17:49:14 -05001064
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001065 memset(&out, 0, sizeof(out));
Nicolas Capens157ba262019-12-10 17:49:14 -05001066
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001067 routine(&out);
Nicolas Capens157ba262019-12-10 17:49:14 -05001068
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001069 EXPECT_EQ(out[0][0], 0x0201FEFFu);
1070 EXPECT_EQ(out[0][1], 0xFCFD0403u);
Nicolas Capens157ba262019-12-10 17:49:14 -05001071
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001072 EXPECT_EQ(out[1][0], 0x02010000u);
1073 EXPECT_EQ(out[1][1], 0x00000403u);
Nicolas Capens157ba262019-12-10 17:49:14 -05001074
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001075 EXPECT_EQ(out[2][0], 0xFFFEFFFFu);
1076 EXPECT_EQ(out[2][1], 0x00020001u);
Nicolas Capens157ba262019-12-10 17:49:14 -05001077
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001078 EXPECT_EQ(out[3][0], 0x00040003u);
1079 EXPECT_EQ(out[3][1], 0xFFFCFFFDu);
Nicolas Capens157ba262019-12-10 17:49:14 -05001080
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001081 EXPECT_EQ(out[4][0], 0x00000000u);
1082 EXPECT_EQ(out[4][1], 0x00020001u);
Nicolas Capens157ba262019-12-10 17:49:14 -05001083
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001084 EXPECT_EQ(out[5][0], 0x00040003u);
1085 EXPECT_EQ(out[5][1], 0x00000000u);
Casey Dahlin11658122017-09-29 16:32:32 -07001086}
1087
Nicolas Capensc07dc4b2018-08-06 14:20:45 -04001088TEST(ReactorUnitTests, MulHigh)
Nicolas Capens92593eb2018-02-14 14:52:49 -05001089{
Ben Clayton713b8d32019-12-17 20:37:56 +00001090 FunctionT<int(void *)> function;
Casey Dahlin36fad3c2017-10-02 15:02:02 -07001091 {
Nicolas Capens157ba262019-12-10 17:49:14 -05001092 Pointer<Byte> out = function.Arg<0>();
Casey Dahlin36fad3c2017-10-02 15:02:02 -07001093
Nicolas Capens157ba262019-12-10 17:49:14 -05001094 *Pointer<Short4>(out + 16 * 0) =
Ben Clayton713b8d32019-12-17 20:37:56 +00001095 MulHigh(Short4(0x01AA, 0x02DD, 0x03EE, 0xF422),
1096 Short4(0x01BB, 0x02CC, 0x03FF, 0xF411));
Nicolas Capens157ba262019-12-10 17:49:14 -05001097 *Pointer<UShort4>(out + 16 * 1) =
Ben Clayton713b8d32019-12-17 20:37:56 +00001098 MulHigh(UShort4(0x01AA, 0x02DD, 0x03EE, 0xF422),
1099 UShort4(0x01BB, 0x02CC, 0x03FF, 0xF411));
Casey Dahlin36fad3c2017-10-02 15:02:02 -07001100
Nicolas Capens157ba262019-12-10 17:49:14 -05001101 *Pointer<Int4>(out + 16 * 2) =
Ben Clayton713b8d32019-12-17 20:37:56 +00001102 MulHigh(Int4(0x000001AA, 0x000002DD, 0xC8000000, 0xF8000000),
1103 Int4(0x000001BB, 0x84000000, 0x000003EE, 0xD7000000));
Nicolas Capens157ba262019-12-10 17:49:14 -05001104 *Pointer<UInt4>(out + 16 * 3) =
Ben Clayton713b8d32019-12-17 20:37:56 +00001105 MulHigh(UInt4(0x000001AAu, 0x000002DDu, 0xC8000000u, 0xD8000000u),
1106 UInt4(0x000001BBu, 0x84000000u, 0x000003EEu, 0xD7000000u));
Chris Forbesaa8f6992019-03-01 14:18:30 -08001107
Nicolas Capens157ba262019-12-10 17:49:14 -05001108 *Pointer<Int4>(out + 16 * 4) =
Ben Clayton713b8d32019-12-17 20:37:56 +00001109 MulHigh(Int4(0x7FFFFFFF, 0x7FFFFFFF, 0x80008000, 0xFFFFFFFF),
1110 Int4(0x7FFFFFFF, 0x80000000, 0x80008000, 0xFFFFFFFF));
Nicolas Capens157ba262019-12-10 17:49:14 -05001111 *Pointer<UInt4>(out + 16 * 5) =
Ben Clayton713b8d32019-12-17 20:37:56 +00001112 MulHigh(UInt4(0x7FFFFFFFu, 0x7FFFFFFFu, 0x80008000u, 0xFFFFFFFFu),
1113 UInt4(0x7FFFFFFFu, 0x80000000u, 0x80008000u, 0xFFFFFFFFu));
Chris Forbesaa8f6992019-03-01 14:18:30 -08001114
Nicolas Capens157ba262019-12-10 17:49:14 -05001115 // (U)Short8 variants currently unimplemented.
Chris Forbesaa8f6992019-03-01 14:18:30 -08001116
Nicolas Capens157ba262019-12-10 17:49:14 -05001117 Return(0);
Casey Dahlin36fad3c2017-10-02 15:02:02 -07001118 }
1119
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05001120 auto routine = function(testName().c_str());
Nicolas Capens157ba262019-12-10 17:49:14 -05001121
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001122 unsigned int out[6][4];
Nicolas Capens157ba262019-12-10 17:49:14 -05001123
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001124 memset(&out, 0, sizeof(out));
Nicolas Capens157ba262019-12-10 17:49:14 -05001125
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001126 routine(&out);
Nicolas Capens157ba262019-12-10 17:49:14 -05001127
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001128 EXPECT_EQ(out[0][0], 0x00080002u);
1129 EXPECT_EQ(out[0][1], 0x008D000Fu);
Nicolas Capens157ba262019-12-10 17:49:14 -05001130
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001131 EXPECT_EQ(out[1][0], 0x00080002u);
1132 EXPECT_EQ(out[1][1], 0xE8C0000Fu);
Nicolas Capens157ba262019-12-10 17:49:14 -05001133
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001134 EXPECT_EQ(out[2][0], 0x00000000u);
1135 EXPECT_EQ(out[2][1], 0xFFFFFE9Cu);
1136 EXPECT_EQ(out[2][2], 0xFFFFFF23u);
1137 EXPECT_EQ(out[2][3], 0x01480000u);
Nicolas Capens157ba262019-12-10 17:49:14 -05001138
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001139 EXPECT_EQ(out[3][0], 0x00000000u);
1140 EXPECT_EQ(out[3][1], 0x00000179u);
1141 EXPECT_EQ(out[3][2], 0x00000311u);
1142 EXPECT_EQ(out[3][3], 0xB5680000u);
Nicolas Capens157ba262019-12-10 17:49:14 -05001143
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001144 EXPECT_EQ(out[4][0], 0x3FFFFFFFu);
1145 EXPECT_EQ(out[4][1], 0xC0000000u);
1146 EXPECT_EQ(out[4][2], 0x3FFF8000u);
1147 EXPECT_EQ(out[4][3], 0x00000000u);
Nicolas Capens157ba262019-12-10 17:49:14 -05001148
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001149 EXPECT_EQ(out[5][0], 0x3FFFFFFFu);
1150 EXPECT_EQ(out[5][1], 0x3FFFFFFFu);
1151 EXPECT_EQ(out[5][2], 0x40008000u);
1152 EXPECT_EQ(out[5][3], 0xFFFFFFFEu);
Casey Dahlin36fad3c2017-10-02 15:02:02 -07001153}
1154
Nicolas Capensc07dc4b2018-08-06 14:20:45 -04001155TEST(ReactorUnitTests, MulAdd)
Nicolas Capens92593eb2018-02-14 14:52:49 -05001156{
Ben Clayton713b8d32019-12-17 20:37:56 +00001157 FunctionT<int(void *)> function;
Casey Dahlinb098c542017-10-03 11:24:01 -07001158 {
Nicolas Capens157ba262019-12-10 17:49:14 -05001159 Pointer<Byte> out = function.Arg<0>();
Casey Dahlinb098c542017-10-03 11:24:01 -07001160
Nicolas Capens157ba262019-12-10 17:49:14 -05001161 *Pointer<Int2>(out + 8 * 0) =
Ben Clayton713b8d32019-12-17 20:37:56 +00001162 MulAdd(Short4(0x1aa, 0x2dd, 0x3ee, 0xF422),
1163 Short4(0x1bb, 0x2cc, 0x3ff, 0xF411));
Casey Dahlinb098c542017-10-03 11:24:01 -07001164
Nicolas Capens157ba262019-12-10 17:49:14 -05001165 // (U)Short8 variant is mentioned but unimplemented
1166 Return(0);
Casey Dahlinb098c542017-10-03 11:24:01 -07001167 }
1168
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05001169 auto routine = function(testName().c_str());
Nicolas Capens157ba262019-12-10 17:49:14 -05001170
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001171 unsigned int out[1][2];
Nicolas Capens157ba262019-12-10 17:49:14 -05001172
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001173 memset(&out, 0, sizeof(out));
Nicolas Capens157ba262019-12-10 17:49:14 -05001174
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001175 routine(&out);
Nicolas Capens157ba262019-12-10 17:49:14 -05001176
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001177 EXPECT_EQ(out[0][0], 0x000AE34Au);
1178 EXPECT_EQ(out[0][1], 0x009D5254u);
Casey Dahlinb098c542017-10-03 11:24:01 -07001179}
1180
Ben Clayton204a4102019-07-31 13:17:47 +01001181TEST(ReactorUnitTests, PointersEqual)
1182{
Ben Clayton713b8d32019-12-17 20:37:56 +00001183 FunctionT<int(void *, void *)> function;
Ben Clayton204a4102019-07-31 13:17:47 +01001184 {
1185 Pointer<Byte> ptrA = function.Arg<0>();
1186 Pointer<Byte> ptrB = function.Arg<1>();
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001187 If(ptrA == ptrB)
Ben Clayton204a4102019-07-31 13:17:47 +01001188 {
1189 Return(1);
1190 }
1191 Else
1192 {
1193 Return(0);
1194 }
1195 }
1196
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05001197 auto routine = function(testName().c_str());
Ben Clayton713b8d32019-12-17 20:37:56 +00001198 int *a = reinterpret_cast<int *>(uintptr_t(0x0000000000000000));
1199 int *b = reinterpret_cast<int *>(uintptr_t(0x00000000F0000000));
1200 int *c = reinterpret_cast<int *>(uintptr_t(0xF000000000000000));
Antonio Maiorano03935ae2019-10-29 16:20:27 -04001201 EXPECT_EQ(routine(&a, &a), 1);
1202 EXPECT_EQ(routine(&b, &b), 1);
1203 EXPECT_EQ(routine(&c, &c), 1);
Ben Clayton204a4102019-07-31 13:17:47 +01001204
Antonio Maiorano03935ae2019-10-29 16:20:27 -04001205 EXPECT_EQ(routine(&a, &b), 0);
1206 EXPECT_EQ(routine(&b, &a), 0);
1207 EXPECT_EQ(routine(&b, &c), 0);
1208 EXPECT_EQ(routine(&c, &b), 0);
1209 EXPECT_EQ(routine(&c, &a), 0);
1210 EXPECT_EQ(routine(&a, &c), 0);
Ben Clayton204a4102019-07-31 13:17:47 +01001211}
1212
Antonio Maiorano29ba7a02019-10-11 15:23:56 -04001213TEST(ReactorUnitTests, Args_2Mixed)
1214{
1215 // 2 mixed type args
Antonio Maiorano03935ae2019-10-29 16:20:27 -04001216 FunctionT<float(int, float)> function;
Antonio Maiorano29ba7a02019-10-11 15:23:56 -04001217 {
1218 Int a = function.Arg<0>();
1219 Float b = function.Arg<1>();
1220 Return(Float(a) + b);
1221 }
1222
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05001223 if(auto routine = function(testName().c_str()))
Antonio Maiorano29ba7a02019-10-11 15:23:56 -04001224 {
Antonio Maiorano03935ae2019-10-29 16:20:27 -04001225 float result = routine(1, 2.f);
Antonio Maiorano29ba7a02019-10-11 15:23:56 -04001226 EXPECT_EQ(result, 3.f);
1227 }
1228}
1229
1230TEST(ReactorUnitTests, Args_4Mixed)
1231{
1232 // 4 mixed type args (max register allocation on Windows)
Antonio Maiorano03935ae2019-10-29 16:20:27 -04001233 FunctionT<float(int, float, int, float)> function;
Antonio Maiorano29ba7a02019-10-11 15:23:56 -04001234 {
1235 Int a = function.Arg<0>();
1236 Float b = function.Arg<1>();
1237 Int c = function.Arg<2>();
1238 Float d = function.Arg<3>();
1239 Return(Float(a) + b + Float(c) + d);
1240 }
1241
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05001242 if(auto routine = function(testName().c_str()))
Antonio Maiorano29ba7a02019-10-11 15:23:56 -04001243 {
Antonio Maiorano03935ae2019-10-29 16:20:27 -04001244 float result = routine(1, 2.f, 3, 4.f);
Antonio Maiorano29ba7a02019-10-11 15:23:56 -04001245 EXPECT_EQ(result, 10.f);
1246 }
1247}
1248
1249TEST(ReactorUnitTests, Args_5Mixed)
1250{
1251 // 5 mixed type args (5th spills over to stack on Windows)
Antonio Maiorano03935ae2019-10-29 16:20:27 -04001252 FunctionT<float(int, float, int, float, int)> function;
Antonio Maiorano29ba7a02019-10-11 15:23:56 -04001253 {
1254 Int a = function.Arg<0>();
1255 Float b = function.Arg<1>();
1256 Int c = function.Arg<2>();
1257 Float d = function.Arg<3>();
1258 Int e = function.Arg<4>();
1259 Return(Float(a) + b + Float(c) + d + Float(e));
1260 }
1261
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05001262 if(auto routine = function(testName().c_str()))
Antonio Maiorano29ba7a02019-10-11 15:23:56 -04001263 {
Antonio Maiorano03935ae2019-10-29 16:20:27 -04001264 float result = routine(1, 2.f, 3, 4.f, 5);
Antonio Maiorano29ba7a02019-10-11 15:23:56 -04001265 EXPECT_EQ(result, 15.f);
1266 }
1267}
1268
1269TEST(ReactorUnitTests, Args_GreaterThan5Mixed)
1270{
1271 // >5 mixed type args
Antonio Maiorano03935ae2019-10-29 16:20:27 -04001272 FunctionT<float(int, float, int, float, int, float, int, float, int, float)> function;
Antonio Maiorano29ba7a02019-10-11 15:23:56 -04001273 {
1274 Int a = function.Arg<0>();
1275 Float b = function.Arg<1>();
1276 Int c = function.Arg<2>();
1277 Float d = function.Arg<3>();
1278 Int e = function.Arg<4>();
1279 Float f = function.Arg<5>();
1280 Int g = function.Arg<6>();
1281 Float h = function.Arg<7>();
1282 Int i = function.Arg<8>();
1283 Float j = function.Arg<9>();
1284 Return(Float(a) + b + Float(c) + d + Float(e) + f + Float(g) + h + Float(i) + j);
1285 }
1286
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05001287 if(auto routine = function(testName().c_str()))
Antonio Maiorano29ba7a02019-10-11 15:23:56 -04001288 {
Antonio Maiorano03935ae2019-10-29 16:20:27 -04001289 float result = routine(1, 2.f, 3, 4.f, 5, 6.f, 7, 8.f, 9, 10.f);
Antonio Maiorano29ba7a02019-10-11 15:23:56 -04001290 EXPECT_EQ(result, 55.f);
1291 }
1292}
1293
Antonio Maiorano4d402712020-02-25 10:36:02 -05001294// This test was written because on Windows with Subzero, we would get a crash when executing a function
1295// with a large number of local variables. The problem was that on Windows, 4K pages are allocated as
1296// needed for the stack whenever an access is made in a "guard page", at which point the page is committed,
1297// and the next 4K page becomes the guard page. If a stack access is made that's beyond the guard page,
1298// a regular page fault occurs. To fix this, Subzero (and any compiler) now emits a call to __chkstk with
1299// the stack size in EAX, so that it can probe the stack in 4K increments up to that size, committing the
1300// required pages. See https://docs.microsoft.com/en-us/windows/win32/devnotes/-win32-chkstk.
1301TEST(ReactorUnitTests, LargeStack)
1302{
Antonio Maiorano4d402712020-02-25 10:36:02 -05001303 // An empirically large enough value to access outside the guard pages
1304 constexpr int ArrayByteSize = 24 * 1024;
1305 constexpr int ArraySize = ArrayByteSize / sizeof(int32_t);
1306
1307 FunctionT<void(int32_t * v)> function;
1308 {
1309 // Allocate a stack array large enough that writing to the first element will reach beyond
1310 // the guard page.
1311 Array<Int, ArraySize> largeStackArray;
1312 for(int i = 0; i < ArraySize; ++i)
1313 {
1314 largeStackArray[i] = i;
1315 }
1316
1317 Pointer<Int> in = function.Arg<0>();
1318 for(int i = 0; i < ArraySize; ++i)
1319 {
1320 in[i] = largeStackArray[i];
1321 }
1322 }
1323
Antonio Maioranob1dd7f72020-11-23 11:19:34 -05001324 // LLVM takes very long to generate this routine when InstructionCombining
1325 // and O2 optimizations are enabled. Disable for now.
1326 // TODO(b/174031014): Remove this once we fix LLVM taking so long
1327 auto cfg = Config::Edit{}
1328 .remove(Optimization::Pass::InstructionCombining)
1329 .set(Optimization::Level::None);
1330
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05001331 auto routine = function(cfg, testName().c_str());
Antonio Maioranob1dd7f72020-11-23 11:19:34 -05001332
Antonio Maiorano4d402712020-02-25 10:36:02 -05001333 std::array<int32_t, ArraySize> v;
1334
1335 // Run this in a thread, so that we get the default reserved stack size (8K on Win64).
1336 std::thread t([&] {
1337 routine(v.data());
1338 });
1339 t.join();
1340
1341 for(int i = 0; i < ArraySize; ++i)
1342 {
1343 EXPECT_EQ(v[i], i);
1344 }
Antonio Maiorano4d402712020-02-25 10:36:02 -05001345}
1346
Ben Claytond853c122019-04-16 17:51:49 -04001347TEST(ReactorUnitTests, Call)
1348{
Ben Claytond853c122019-04-16 17:51:49 -04001349 struct Class
1350 {
Ben Clayton51f08312019-11-08 14:39:26 +00001351 static int Callback(Class *p, int i, float f)
Ben Claytond853c122019-04-16 17:51:49 -04001352 {
Ben Clayton51f08312019-11-08 14:39:26 +00001353 p->i = i;
1354 p->f = f;
Ben Claytond853c122019-04-16 17:51:49 -04001355 return i + int(f);
1356 }
1357
1358 int i = 0;
1359 float f = 0.0f;
1360 };
1361
Ben Clayton713b8d32019-12-17 20:37:56 +00001362 FunctionT<int(void *)> function;
Ben Claytond853c122019-04-16 17:51:49 -04001363 {
Ben Clayton51f08312019-11-08 14:39:26 +00001364 Pointer<Byte> c = function.Arg<0>();
1365 auto res = Call(Class::Callback, c, 10, 20.0f);
1366 Return(res);
Ben Claytond853c122019-04-16 17:51:49 -04001367 }
Ben Clayton51f08312019-11-08 14:39:26 +00001368
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05001369 auto routine = function(testName().c_str());
Ben Clayton51f08312019-11-08 14:39:26 +00001370
1371 Class c;
1372 int res = routine(&c);
1373 EXPECT_EQ(res, 30);
1374 EXPECT_EQ(c.i, 10);
1375 EXPECT_EQ(c.f, 20.0f);
1376}
1377
Ben Claytonb7eb3a82019-11-19 00:43:50 +00001378TEST(ReactorUnitTests, CallMemberFunction)
1379{
Ben Claytonb7eb3a82019-11-19 00:43:50 +00001380 struct Class
1381 {
1382 int Callback(int argI, float argF)
1383 {
1384 i = argI;
1385 f = argF;
1386 return i + int(f);
1387 }
1388
1389 int i = 0;
1390 float f = 0.0f;
1391 };
1392
1393 Class c;
1394
1395 FunctionT<int()> function;
1396 {
1397 auto res = Call(&Class::Callback, &c, 10, 20.0f);
1398 Return(res);
1399 }
1400
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05001401 auto routine = function(testName().c_str());
Ben Claytonb7eb3a82019-11-19 00:43:50 +00001402
1403 int res = routine();
1404 EXPECT_EQ(res, 30);
1405 EXPECT_EQ(c.i, 10);
1406 EXPECT_EQ(c.f, 20.0f);
1407}
1408
1409TEST(ReactorUnitTests, CallMemberFunctionIndirect)
1410{
Ben Claytonb7eb3a82019-11-19 00:43:50 +00001411 struct Class
1412 {
1413 int Callback(int argI, float argF)
1414 {
1415 i = argI;
1416 f = argF;
1417 return i + int(f);
1418 }
1419
1420 int i = 0;
1421 float f = 0.0f;
1422 };
1423
Ben Clayton713b8d32019-12-17 20:37:56 +00001424 FunctionT<int(void *)> function;
Ben Claytonb7eb3a82019-11-19 00:43:50 +00001425 {
1426 Pointer<Byte> c = function.Arg<0>();
1427 auto res = Call(&Class::Callback, c, 10, 20.0f);
1428 Return(res);
1429 }
1430
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05001431 auto routine = function(testName().c_str());
Ben Claytonb7eb3a82019-11-19 00:43:50 +00001432
1433 Class c;
1434 int res = routine(&c);
1435 EXPECT_EQ(res, 30);
1436 EXPECT_EQ(c.i, 10);
1437 EXPECT_EQ(c.f, 20.0f);
1438}
1439
Ben Clayton51f08312019-11-08 14:39:26 +00001440TEST(ReactorUnitTests, CallImplicitCast)
1441{
Ben Clayton51f08312019-11-08 14:39:26 +00001442 struct Class
1443 {
Ben Clayton713b8d32019-12-17 20:37:56 +00001444 static void Callback(Class *c, const char *s)
Ben Clayton51f08312019-11-08 14:39:26 +00001445 {
1446 c->str = s;
1447 }
1448 std::string str;
1449 };
1450
Ben Clayton713b8d32019-12-17 20:37:56 +00001451 FunctionT<void(Class * c, const char *s)> function;
Ben Clayton51f08312019-11-08 14:39:26 +00001452 {
1453 Pointer<Byte> c = function.Arg<0>();
1454 Pointer<Byte> s = function.Arg<1>();
1455 Call(Class::Callback, c, s);
1456 }
1457
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05001458 auto routine = function(testName().c_str());
Ben Clayton51f08312019-11-08 14:39:26 +00001459
1460 Class c;
1461 routine(&c, "hello world");
1462 EXPECT_EQ(c.str, "hello world");
Antonio Maioranob7dad7d2019-10-11 15:26:58 -04001463}
Ben Claytond853c122019-04-16 17:51:49 -04001464
Antonio Maiorano16ae92a2020-03-10 10:53:24 -04001465TEST(ReactorUnitTests, CallBoolReturnFunction)
1466{
1467 struct Class
1468 {
1469 static bool IsEven(int a)
1470 {
1471 return a % 2 == 0;
1472 }
1473 };
1474
1475 FunctionT<int(int)> function;
1476 {
1477 Int a = function.Arg<0>();
1478 Bool res = Call(Class::IsEven, a);
1479 If(res)
1480 {
1481 Return(1);
1482 }
1483 Return(0);
1484 }
1485
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05001486 auto routine = function(testName().c_str());
Antonio Maiorano16ae92a2020-03-10 10:53:24 -04001487
1488 for(int i = 0; i < 10; ++i)
1489 {
1490 EXPECT_EQ(routine(i), i % 2 == 0);
1491 }
1492}
1493
Antonio Maiorano01386d12019-11-20 14:43:48 -05001494TEST(ReactorUnitTests, Call_Args4)
1495{
1496 struct Class
1497 {
1498 static int Func(int a, int b, int c, int d)
1499 {
1500 return a + b + c + d;
1501 }
1502 };
1503
1504 {
1505 FunctionT<int()> function;
1506 {
1507 auto res = Call(Class::Func, 1, 2, 3, 4);
1508 Return(res);
1509 }
1510
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05001511 auto routine = function(testName().c_str());
Antonio Maiorano01386d12019-11-20 14:43:48 -05001512
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001513 int res = routine();
1514 EXPECT_EQ(res, 1 + 2 + 3 + 4);
Antonio Maiorano01386d12019-11-20 14:43:48 -05001515 }
1516}
1517
1518TEST(ReactorUnitTests, Call_Args5)
1519{
1520 struct Class
1521 {
1522 static int Func(int a, int b, int c, int d, int e)
1523 {
1524 return a + b + c + d + e;
1525 }
1526 };
1527
1528 {
1529 FunctionT<int()> function;
1530 {
1531 auto res = Call(Class::Func, 1, 2, 3, 4, 5);
1532 Return(res);
1533 }
1534
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05001535 auto routine = function(testName().c_str());
Antonio Maiorano01386d12019-11-20 14:43:48 -05001536
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001537 int res = routine();
1538 EXPECT_EQ(res, 1 + 2 + 3 + 4 + 5);
Antonio Maiorano01386d12019-11-20 14:43:48 -05001539 }
1540}
1541
1542TEST(ReactorUnitTests, Call_ArgsMany)
1543{
1544 struct Class
1545 {
1546 static int Func(int a, int b, int c, int d, int e, int f, int g, int h)
1547 {
1548 return a + b + c + d + e + f + g + h;
1549 }
1550 };
1551
1552 {
1553 FunctionT<int()> function;
1554 {
1555 auto res = Call(Class::Func, 1, 2, 3, 4, 5, 6, 7, 8);
1556 Return(res);
1557 }
1558
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05001559 auto routine = function(testName().c_str());
Antonio Maiorano01386d12019-11-20 14:43:48 -05001560
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001561 int res = routine();
1562 EXPECT_EQ(res, 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8);
Antonio Maiorano01386d12019-11-20 14:43:48 -05001563 }
1564}
1565
1566TEST(ReactorUnitTests, Call_ArgsMixed)
1567{
1568 struct Class
1569 {
Ben Clayton713b8d32019-12-17 20:37:56 +00001570 static int Func(int a, float b, int *c, float *d, int e, float f, int *g, float *h)
Antonio Maiorano01386d12019-11-20 14:43:48 -05001571 {
1572 return a + b + *c + *d + e + f + *g + *h;
1573 }
1574 };
1575
1576 {
1577 FunctionT<int()> function;
1578 {
1579 Int c(3);
1580 Float d(4);
1581 Int g(7);
1582 Float h(8);
1583 auto res = Call(Class::Func, 1, 2.f, &c, &d, 5, 6.f, &g, &h);
1584 Return(res);
1585 }
1586
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05001587 auto routine = function(testName().c_str());
Antonio Maiorano01386d12019-11-20 14:43:48 -05001588
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001589 int res = routine();
1590 EXPECT_EQ(res, 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8);
Antonio Maiorano01386d12019-11-20 14:43:48 -05001591 }
1592}
1593
1594TEST(ReactorUnitTests, Call_ArgsPointer)
1595{
1596 struct Class
1597 {
1598 static int Func(int *a)
1599 {
1600 return *a;
1601 }
1602 };
1603
1604 {
1605 FunctionT<int()> function;
1606 {
1607 Int a(12345);
1608 auto res = Call(Class::Func, &a);
1609 Return(res);
1610 }
1611
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05001612 auto routine = function(testName().c_str());
Antonio Maiorano01386d12019-11-20 14:43:48 -05001613
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001614 int res = routine();
1615 EXPECT_EQ(res, 12345);
Antonio Maiorano01386d12019-11-20 14:43:48 -05001616 }
1617}
1618
Antonio Maioranob7dad7d2019-10-11 15:26:58 -04001619TEST(ReactorUnitTests, CallExternalCallRoutine)
1620{
Antonio Maioranob7dad7d2019-10-11 15:26:58 -04001621 // routine1 calls Class::Func, passing it a pointer to routine2, and Class::Func calls routine2
1622
1623 auto routine2 = [] {
Antonio Maiorano03935ae2019-10-29 16:20:27 -04001624 FunctionT<float(float, int)> function;
Antonio Maioranob7dad7d2019-10-11 15:26:58 -04001625 {
1626 Float a = function.Arg<0>();
1627 Int b = function.Arg<1>();
1628 Return(a + Float(b));
1629 }
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05001630 return function("%s2", testName().c_str());
Antonio Maioranob7dad7d2019-10-11 15:26:58 -04001631 }();
1632
1633 struct Class
1634 {
Ben Clayton713b8d32019-12-17 20:37:56 +00001635 static float Func(void *p, float a, int b)
Antonio Maioranob7dad7d2019-10-11 15:26:58 -04001636 {
Ben Clayton713b8d32019-12-17 20:37:56 +00001637 auto funcToCall = reinterpret_cast<float (*)(float, int)>(p);
Antonio Maioranob7dad7d2019-10-11 15:26:58 -04001638 return funcToCall(a, b);
1639 }
1640 };
1641
1642 auto routine1 = [] {
Ben Clayton713b8d32019-12-17 20:37:56 +00001643 FunctionT<float(void *, float, int)> function;
Antonio Maioranob7dad7d2019-10-11 15:26:58 -04001644 {
1645 Pointer<Byte> funcToCall = function.Arg<0>();
1646 Float a = function.Arg<1>();
1647 Int b = function.Arg<2>();
1648 Float result = Call(Class::Func, funcToCall, a, b);
1649 Return(result);
1650 }
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05001651 return function(testName().c_str());
Antonio Maioranob7dad7d2019-10-11 15:26:58 -04001652 }();
1653
Ben Clayton713b8d32019-12-17 20:37:56 +00001654 float result = routine1((void *)routine2.getEntry(), 12.f, 13);
Antonio Maioranob7dad7d2019-10-11 15:26:58 -04001655 EXPECT_EQ(result, 25.f);
Ben Claytond853c122019-04-16 17:51:49 -04001656}
1657
Stephen White17078c72019-02-27 14:39:14 -05001658// Check that a complex generated function which utilizes all 8 or 16 XMM
1659// registers computes the correct result.
1660// (Note that due to MSC's lack of support for inline assembly in x64,
Ben Claytonb1243732019-02-27 23:56:18 +00001661// this test does not actually check that the register contents are
Stephen White17078c72019-02-27 14:39:14 -05001662// preserved, just that the generated function computes the correct value.
1663// It's necessary to inspect the registers in a debugger to actually verify.)
1664TEST(ReactorUnitTests, PreserveXMMRegisters)
1665{
Ben Clayton713b8d32019-12-17 20:37:56 +00001666 FunctionT<void(void *, void *)> function;
1667 {
1668 Pointer<Byte> in = function.Arg<0>();
1669 Pointer<Byte> out = function.Arg<1>();
Stephen White17078c72019-02-27 14:39:14 -05001670
Ben Clayton713b8d32019-12-17 20:37:56 +00001671 Float4 a = *Pointer<Float4>(in + 16 * 0);
1672 Float4 b = *Pointer<Float4>(in + 16 * 1);
1673 Float4 c = *Pointer<Float4>(in + 16 * 2);
1674 Float4 d = *Pointer<Float4>(in + 16 * 3);
1675 Float4 e = *Pointer<Float4>(in + 16 * 4);
1676 Float4 f = *Pointer<Float4>(in + 16 * 5);
1677 Float4 g = *Pointer<Float4>(in + 16 * 6);
1678 Float4 h = *Pointer<Float4>(in + 16 * 7);
1679 Float4 i = *Pointer<Float4>(in + 16 * 8);
1680 Float4 j = *Pointer<Float4>(in + 16 * 9);
1681 Float4 k = *Pointer<Float4>(in + 16 * 10);
1682 Float4 l = *Pointer<Float4>(in + 16 * 11);
1683 Float4 m = *Pointer<Float4>(in + 16 * 12);
1684 Float4 n = *Pointer<Float4>(in + 16 * 13);
1685 Float4 o = *Pointer<Float4>(in + 16 * 14);
1686 Float4 p = *Pointer<Float4>(in + 16 * 15);
Stephen White17078c72019-02-27 14:39:14 -05001687
Ben Clayton713b8d32019-12-17 20:37:56 +00001688 Float4 ab = a + b;
1689 Float4 cd = c + d;
1690 Float4 ef = e + f;
1691 Float4 gh = g + h;
1692 Float4 ij = i + j;
1693 Float4 kl = k + l;
1694 Float4 mn = m + n;
1695 Float4 op = o + p;
Stephen White17078c72019-02-27 14:39:14 -05001696
Ben Clayton713b8d32019-12-17 20:37:56 +00001697 Float4 abcd = ab + cd;
1698 Float4 efgh = ef + gh;
1699 Float4 ijkl = ij + kl;
1700 Float4 mnop = mn + op;
Stephen White17078c72019-02-27 14:39:14 -05001701
Ben Clayton713b8d32019-12-17 20:37:56 +00001702 Float4 abcdefgh = abcd + efgh;
1703 Float4 ijklmnop = ijkl + mnop;
1704 Float4 sum = abcdefgh + ijklmnop;
1705 *Pointer<Float4>(out) = sum;
1706 Return();
1707 }
Stephen White17078c72019-02-27 14:39:14 -05001708
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05001709 auto routine = function(testName().c_str());
Ben Clayton713b8d32019-12-17 20:37:56 +00001710 assert(routine);
Nicolas Capens157ba262019-12-10 17:49:14 -05001711
Ben Clayton713b8d32019-12-17 20:37:56 +00001712 float input[64] = { 1.0f, 0.0f, 0.0f, 0.0f,
1713 -1.0f, 1.0f, -1.0f, 0.0f,
1714 1.0f, 2.0f, -2.0f, 0.0f,
1715 -1.0f, 3.0f, -3.0f, 0.0f,
1716 1.0f, 4.0f, -4.0f, 0.0f,
1717 -1.0f, 5.0f, -5.0f, 0.0f,
1718 1.0f, 6.0f, -6.0f, 0.0f,
1719 -1.0f, 7.0f, -7.0f, 0.0f,
1720 1.0f, 8.0f, -8.0f, 0.0f,
1721 -1.0f, 9.0f, -9.0f, 0.0f,
1722 1.0f, 10.0f, -10.0f, 0.0f,
1723 -1.0f, 11.0f, -11.0f, 0.0f,
1724 1.0f, 12.0f, -12.0f, 0.0f,
1725 -1.0f, 13.0f, -13.0f, 0.0f,
1726 1.0f, 14.0f, -14.0f, 0.0f,
1727 -1.0f, 15.0f, -15.0f, 0.0f };
Nicolas Capens157ba262019-12-10 17:49:14 -05001728
Ben Clayton713b8d32019-12-17 20:37:56 +00001729 float result[4];
Nicolas Capens157ba262019-12-10 17:49:14 -05001730
Ben Clayton713b8d32019-12-17 20:37:56 +00001731 routine(input, result);
Nicolas Capens157ba262019-12-10 17:49:14 -05001732
Ben Clayton713b8d32019-12-17 20:37:56 +00001733 EXPECT_EQ(result[0], 0.0f);
1734 EXPECT_EQ(result[1], 120.0f);
1735 EXPECT_EQ(result[2], -120.0f);
1736 EXPECT_EQ(result[3], 0.0f);
Stephen White17078c72019-02-27 14:39:14 -05001737}
1738
Ben Clayton713b8d32019-12-17 20:37:56 +00001739template<typename T>
Ben Clayton51f08312019-11-08 14:39:26 +00001740class CToReactorTCastTest : public ::testing::Test
Nicolas Capensf0d22ad2019-03-15 17:22:42 -04001741{
Ben Claytonf3b57972019-03-15 09:56:47 +00001742public:
1743 using CType = typename std::tuple_element<0, T>::type;
1744 using ReactorType = typename std::tuple_element<1, T>::type;
1745};
1746
Ben Clayton713b8d32019-12-17 20:37:56 +00001747using CToReactorTCastTestTypes = ::testing::Types< // Subset of types that can be used as arguments.
1748 // std::pair<bool, Bool>, FIXME(capn): Not supported as argument type by Subzero.
1749 // std::pair<uint8_t, Byte>, FIXME(capn): Not supported as argument type by Subzero.
1750 // std::pair<int8_t, SByte>, FIXME(capn): Not supported as argument type by Subzero.
1751 // std::pair<int16_t, Short>, FIXME(capn): Not supported as argument type by Subzero.
1752 // std::pair<uint16_t, UShort>, FIXME(capn): Not supported as argument type by Subzero.
1753 std::pair<int, Int>,
1754 std::pair<unsigned int, UInt>,
1755 std::pair<float, Float>>;
Ben Claytonf3b57972019-03-15 09:56:47 +00001756
Ben Clayton51f08312019-11-08 14:39:26 +00001757TYPED_TEST_SUITE(CToReactorTCastTest, CToReactorTCastTestTypes);
Ben Claytonf3b57972019-03-15 09:56:47 +00001758
Ben Clayton51f08312019-11-08 14:39:26 +00001759TYPED_TEST(CToReactorTCastTest, Casts)
Nicolas Capensf0d22ad2019-03-15 17:22:42 -04001760{
Ben Claytonf3b57972019-03-15 09:56:47 +00001761 using CType = typename TestFixture::CType;
1762 using ReactorType = typename TestFixture::ReactorType;
1763
Ben Clayton6897e9b2019-07-16 17:27:27 +01001764 std::shared_ptr<Routine> routine;
Ben Claytonf3b57972019-03-15 09:56:47 +00001765
1766 {
Ben Clayton713b8d32019-12-17 20:37:56 +00001767 Function<Int(ReactorType)> function;
Ben Claytonf3b57972019-03-15 09:56:47 +00001768 {
1769 ReactorType a = function.template Arg<0>();
1770 ReactorType b = CType{};
1771 RValue<ReactorType> c = RValue<ReactorType>(CType{});
1772 Bool same = (a == b) && (a == c);
Ben Clayton713b8d32019-12-17 20:37:56 +00001773 Return(IfThenElse(same, Int(1), Int(0))); // TODO: Ability to use Bools as return values.
Ben Claytonf3b57972019-03-15 09:56:47 +00001774 }
1775
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05001776 routine = function(testName().c_str());
Ben Claytonf3b57972019-03-15 09:56:47 +00001777
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001778 auto callable = (int (*)(CType))routine->getEntry();
1779 CType in = {};
1780 EXPECT_EQ(callable(in), 1);
Ben Claytonf3b57972019-03-15 09:56:47 +00001781 }
Ben Claytonf3b57972019-03-15 09:56:47 +00001782}
1783
Ben Clayton713b8d32019-12-17 20:37:56 +00001784template<typename T>
Nicolas Capensf0d22ad2019-03-15 17:22:42 -04001785class GEPTest : public ::testing::Test
1786{
Ben Claytonb1243732019-02-27 23:56:18 +00001787public:
1788 using CType = typename std::tuple_element<0, T>::type;
1789 using ReactorType = typename std::tuple_element<1, T>::type;
1790};
1791
Ben Clayton713b8d32019-12-17 20:37:56 +00001792using GEPTestTypes = ::testing::Types<
1793 std::pair<bool, Bool>,
1794 std::pair<int8_t, Byte>,
1795 std::pair<int8_t, SByte>,
1796 std::pair<int8_t[4], Byte4>,
1797 std::pair<int8_t[4], SByte4>,
1798 std::pair<int8_t[8], Byte8>,
1799 std::pair<int8_t[8], SByte8>,
1800 std::pair<int8_t[16], Byte16>,
1801 std::pair<int8_t[16], SByte16>,
1802 std::pair<int16_t, Short>,
1803 std::pair<int16_t, UShort>,
1804 std::pair<int16_t[2], Short2>,
1805 std::pair<int16_t[2], UShort2>,
1806 std::pair<int16_t[4], Short4>,
1807 std::pair<int16_t[4], UShort4>,
1808 std::pair<int16_t[8], Short8>,
1809 std::pair<int16_t[8], UShort8>,
1810 std::pair<int, Int>,
1811 std::pair<int, UInt>,
1812 std::pair<int[2], Int2>,
1813 std::pair<int[2], UInt2>,
1814 std::pair<int[4], Int4>,
1815 std::pair<int[4], UInt4>,
1816 std::pair<int64_t, Long>,
1817 std::pair<int16_t, Half>,
1818 std::pair<float, Float>,
1819 std::pair<float[2], Float2>,
1820 std::pair<float[4], Float4>>;
Ben Claytonb1243732019-02-27 23:56:18 +00001821
Alexis Hetu79d4ac92019-06-03 11:31:46 -04001822TYPED_TEST_SUITE(GEPTest, GEPTestTypes);
Ben Claytonb1243732019-02-27 23:56:18 +00001823
Nicolas Capensf0d22ad2019-03-15 17:22:42 -04001824TYPED_TEST(GEPTest, PtrOffsets)
1825{
Ben Claytonb1243732019-02-27 23:56:18 +00001826 using CType = typename TestFixture::CType;
1827 using ReactorType = typename TestFixture::ReactorType;
1828
Ben Clayton6897e9b2019-07-16 17:27:27 +01001829 std::shared_ptr<Routine> routine;
Ben Claytonb1243732019-02-27 23:56:18 +00001830
1831 {
Ben Clayton713b8d32019-12-17 20:37:56 +00001832 Function<Pointer<ReactorType>(Pointer<ReactorType>, Int)> function;
Ben Claytonb1243732019-02-27 23:56:18 +00001833 {
1834 Pointer<ReactorType> pointer = function.template Arg<0>();
1835 Int index = function.template Arg<1>();
1836 Return(&pointer[index]);
1837 }
1838
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05001839 routine = function(testName().c_str());
Ben Claytonb1243732019-02-27 23:56:18 +00001840
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001841 auto callable = (CType * (*)(CType *, unsigned int)) routine->getEntry();
1842
1843 union PtrInt
Ben Claytonb1243732019-02-27 23:56:18 +00001844 {
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001845 CType *p;
1846 size_t i;
1847 };
Ben Claytonb1243732019-02-27 23:56:18 +00001848
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001849 PtrInt base;
1850 base.i = 0x10000;
Ben Claytonb1243732019-02-27 23:56:18 +00001851
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001852 for(int i = 0; i < 5; i++)
1853 {
1854 PtrInt reference;
1855 reference.p = &base.p[i];
Ben Claytonb1243732019-02-27 23:56:18 +00001856
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001857 PtrInt result;
1858 result.p = callable(base.p, i);
Ben Claytonb1243732019-02-27 23:56:18 +00001859
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001860 auto expect = reference.i - base.i;
1861 auto got = result.i - base.i;
Ben Claytonb1243732019-02-27 23:56:18 +00001862
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001863 EXPECT_EQ(got, expect) << "i:" << i;
Ben Claytonb1243732019-02-27 23:56:18 +00001864 }
1865 }
Ben Claytonb1243732019-02-27 23:56:18 +00001866}
1867
Nicolas Capensd2af84f2020-05-14 10:55:21 -04001868static const std::vector<int> fibonacci = {
1869 0,
1870 1,
1871 1,
1872 2,
1873 3,
1874 5,
1875 8,
1876 13,
1877 21,
1878 34,
1879 55,
1880 89,
1881 144,
1882 233,
1883 377,
1884 610,
1885 987,
1886 1597,
1887 2584,
1888 4181,
1889 6765,
1890 10946,
1891 17711,
1892 28657,
1893 46368,
1894 75025,
1895 121393,
1896 196418,
1897 317811,
1898};
1899
Antonio Maiorano8bce0672020-02-28 13:13:45 -05001900TEST(ReactorUnitTests, Fibonacci)
1901{
1902 FunctionT<int(int)> function;
1903 {
1904 Int n = function.Arg<0>();
1905 Int current = 0;
1906 Int next = 1;
1907 For(Int i = 0, i < n, i++)
1908 {
1909 auto tmp = current + next;
1910 current = next;
1911 next = tmp;
1912 }
1913 Return(current);
1914 }
1915
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05001916 auto routine = function(testName().c_str());
Antonio Maiorano8bce0672020-02-28 13:13:45 -05001917
1918 for(size_t i = 0; i < fibonacci.size(); i++)
1919 {
1920 EXPECT_EQ(routine(i), fibonacci[i]);
1921 }
1922}
1923
Ben Clayton1c82c7b2019-04-30 12:49:27 +01001924TEST(ReactorUnitTests, Coroutines_Fibonacci)
1925{
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001926 if(!rr::Caps.CoroutinesSupported)
Ben Clayton1c82c7b2019-04-30 12:49:27 +01001927 {
1928 SUCCEED() << "Coroutines not supported";
1929 return;
1930 }
1931
1932 Coroutine<int()> function;
1933 {
1934 Yield(Int(0));
1935 Yield(Int(1));
1936 Int current = 1;
1937 Int next = 1;
Ben Clayton713b8d32019-12-17 20:37:56 +00001938 While(true)
1939 {
Ben Clayton1c82c7b2019-04-30 12:49:27 +01001940 Yield(next);
1941 auto tmp = current + next;
1942 current = next;
1943 next = tmp;
1944 }
1945 }
Antonio Maiorano3fba1ac2020-11-27 14:55:22 -05001946 function.finalize(testName().c_str());
Ben Clayton1c82c7b2019-04-30 12:49:27 +01001947
1948 auto coroutine = function();
1949
Antonio Maiorano8bce0672020-02-28 13:13:45 -05001950 for(size_t i = 0; i < fibonacci.size(); i++)
Ben Clayton1c82c7b2019-04-30 12:49:27 +01001951 {
1952 int out = 0;
1953 EXPECT_EQ(coroutine->await(out), true);
Antonio Maiorano8bce0672020-02-28 13:13:45 -05001954 EXPECT_EQ(out, fibonacci[i]);
Ben Clayton1c82c7b2019-04-30 12:49:27 +01001955 }
1956}
1957
1958TEST(ReactorUnitTests, Coroutines_Parameters)
1959{
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001960 if(!rr::Caps.CoroutinesSupported)
Ben Clayton1c82c7b2019-04-30 12:49:27 +01001961 {
1962 SUCCEED() << "Coroutines not supported";
1963 return;
1964 }
1965
Ben Clayton713b8d32019-12-17 20:37:56 +00001966 Coroutine<uint8_t(uint8_t * data, int count)> function;
Ben Clayton1c82c7b2019-04-30 12:49:27 +01001967 {
1968 Pointer<Byte> data = function.Arg<0>();
1969 Int count = function.Arg<1>();
1970
1971 For(Int i = 0, i < count, i++)
1972 {
1973 Yield(data[i]);
1974 }
1975 }
Antonio Maiorano3fba1ac2020-11-27 14:55:22 -05001976 function.finalize(testName().c_str());
Ben Clayton1c82c7b2019-04-30 12:49:27 +01001977
Ben Clayton713b8d32019-12-17 20:37:56 +00001978 uint8_t data[] = { 10, 20, 30 };
Ben Clayton1c82c7b2019-04-30 12:49:27 +01001979 auto coroutine = function(&data[0], 3);
1980
1981 uint8_t out = 0;
1982 EXPECT_EQ(coroutine->await(out), true);
Ben Clayton713b8d32019-12-17 20:37:56 +00001983 EXPECT_EQ(out, 10);
1984 out = 0;
Ben Clayton1c82c7b2019-04-30 12:49:27 +01001985 EXPECT_EQ(coroutine->await(out), true);
Ben Clayton713b8d32019-12-17 20:37:56 +00001986 EXPECT_EQ(out, 20);
1987 out = 0;
Ben Clayton1c82c7b2019-04-30 12:49:27 +01001988 EXPECT_EQ(coroutine->await(out), true);
Ben Clayton713b8d32019-12-17 20:37:56 +00001989 EXPECT_EQ(out, 30);
1990 out = 99;
Ben Clayton1c82c7b2019-04-30 12:49:27 +01001991 EXPECT_EQ(coroutine->await(out), false);
1992 EXPECT_EQ(out, 99);
1993 EXPECT_EQ(coroutine->await(out), false);
1994 EXPECT_EQ(out, 99);
1995}
1996
Antonio Maiorano5ba2a5b2020-01-17 15:29:37 -05001997// This test was written because Subzero's handling of vector types
1998// failed when more than one function is generated, as is the case
1999// with coroutines.
2000TEST(ReactorUnitTests, Coroutines_Vectors)
2001{
2002 if(!rr::Caps.CoroutinesSupported)
2003 {
2004 SUCCEED() << "Coroutines not supported";
2005 return;
2006 }
2007
2008 Coroutine<int()> function;
2009 {
2010 Int4 a{ 1, 2, 3, 4 };
2011 Yield(rr::Extract(a, 2));
2012 Int4 b{ 5, 6, 7, 8 };
2013 Yield(rr::Extract(b, 1));
2014 Int4 c{ 9, 10, 11, 12 };
2015 Yield(rr::Extract(c, 1));
2016 }
Antonio Maiorano3fba1ac2020-11-27 14:55:22 -05002017 function.finalize(testName().c_str());
Antonio Maiorano5ba2a5b2020-01-17 15:29:37 -05002018
2019 auto coroutine = function();
2020
2021 int out;
2022 coroutine->await(out);
2023 EXPECT_EQ(out, 3);
2024 coroutine->await(out);
2025 EXPECT_EQ(out, 6);
2026 coroutine->await(out);
2027 EXPECT_EQ(out, 10);
2028}
2029
2030// This test was written to make sure a coroutine without a Yield()
2031// works correctly, by executing like a regular function with no
2032// return (the return type is ignored).
2033// We also run it twice to ensure per instance and/or global state
2034// is properly cleaned up in between.
2035TEST(ReactorUnitTests, Coroutines_NoYield)
2036{
2037 if(!rr::Caps.CoroutinesSupported)
2038 {
2039 SUCCEED() << "Coroutines not supported";
2040 return;
2041 }
2042
2043 for(int i = 0; i < 2; ++i)
2044 {
2045 Coroutine<int()> function;
2046 {
2047 Int a;
2048 a = 4;
2049 }
Antonio Maiorano3fba1ac2020-11-27 14:55:22 -05002050 function.finalize(testName().c_str());
Antonio Maiorano5ba2a5b2020-01-17 15:29:37 -05002051
2052 auto coroutine = function();
2053 int out;
2054 EXPECT_EQ(coroutine->await(out), false);
2055 }
2056}
2057
2058// Test generating one coroutine, and executing it on multiple threads. This makes
2059// sure the implementation manages per-call instance data correctly.
2060TEST(ReactorUnitTests, Coroutines_Parallel)
2061{
2062 if(!rr::Caps.CoroutinesSupported)
2063 {
2064 SUCCEED() << "Coroutines not supported";
2065 return;
2066 }
2067
2068 Coroutine<int()> function;
2069 {
2070 Yield(Int(0));
2071 Yield(Int(1));
2072 Int current = 1;
2073 Int next = 1;
2074 While(true)
2075 {
2076 Yield(next);
2077 auto tmp = current + next;
2078 current = next;
2079 next = tmp;
2080 }
2081 }
2082
2083 // Must call on same thread that creates the coroutine
Antonio Maiorano3fba1ac2020-11-27 14:55:22 -05002084 function.finalize(testName().c_str());
Antonio Maiorano5ba2a5b2020-01-17 15:29:37 -05002085
Antonio Maiorano5ba2a5b2020-01-17 15:29:37 -05002086 std::vector<std::thread> threads;
2087 const size_t numThreads = 100;
2088
2089 for(size_t t = 0; t < numThreads; ++t)
2090 {
2091 threads.emplace_back([&] {
2092 auto coroutine = function();
2093
Antonio Maiorano8bce0672020-02-28 13:13:45 -05002094 for(size_t i = 0; i < fibonacci.size(); i++)
Antonio Maiorano5ba2a5b2020-01-17 15:29:37 -05002095 {
2096 int out = 0;
2097 EXPECT_EQ(coroutine->await(out), true);
Antonio Maiorano8bce0672020-02-28 13:13:45 -05002098 EXPECT_EQ(out, fibonacci[i]);
Antonio Maiorano5ba2a5b2020-01-17 15:29:37 -05002099 }
2100 });
2101 }
2102
2103 for(auto &t : threads)
2104 {
2105 t.join();
2106 }
2107}
2108
Ben Clayton713b8d32019-12-17 20:37:56 +00002109template<typename TestFuncType, typename RefFuncType, typename TestValueType>
Antonio Maioranobf151b82019-12-03 09:49:14 -05002110struct IntrinsicTestParams
2111{
Ben Clayton713b8d32019-12-17 20:37:56 +00002112 std::function<TestFuncType> testFunc; // Function we're testing (Reactor)
2113 std::function<RefFuncType> refFunc; // Reference function to test against (C)
2114 std::vector<TestValueType> testValues; // Values to input to functions
Antonio Maioranobf151b82019-12-03 09:49:14 -05002115};
2116
2117using IntrinsicTestParams_Float = IntrinsicTestParams<RValue<Float>(RValue<Float>), float(float), float>;
2118using IntrinsicTestParams_Float4 = IntrinsicTestParams<RValue<Float4>(RValue<Float4>), float(float), float>;
2119using IntrinsicTestParams_Float4_Float4 = IntrinsicTestParams<RValue<Float4>(RValue<Float4>, RValue<Float4>), float(float, float), std::pair<float, float>>;
2120
Antonio Maiorano9c14bda2020-09-18 16:33:36 -04002121// TODO(b/147818976): Each function has its own precision requirements for Vulkan, sometimes broken down
2122// by input range. These are currently validated by deqp, but we can improve our own tests as well.
2123// See https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#spirvenv-precision-operation
2124constexpr double INTRINSIC_PRECISION = 1e-4;
2125
Antonio Maioranobf151b82019-12-03 09:49:14 -05002126struct IntrinsicTest_Float : public testing::TestWithParam<IntrinsicTestParams_Float>
2127{
2128 void test()
2129 {
2130 FunctionT<float(float)> function;
2131 {
2132 Return(GetParam().testFunc((Float(function.Arg<0>()))));
2133 }
2134
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05002135 auto routine = function(testName().c_str());
Antonio Maioranobf151b82019-12-03 09:49:14 -05002136
Ben Clayton713b8d32019-12-17 20:37:56 +00002137 for(auto &&v : GetParam().testValues)
Antonio Maioranobf151b82019-12-03 09:49:14 -05002138 {
2139 SCOPED_TRACE(v);
Antonio Maiorano9c14bda2020-09-18 16:33:36 -04002140 EXPECT_NEAR(routine(v), GetParam().refFunc(v), INTRINSIC_PRECISION);
Antonio Maioranobf151b82019-12-03 09:49:14 -05002141 }
2142 }
2143};
2144
Nicolas Capensd2af84f2020-05-14 10:55:21 -04002145using float4 = float[4];
2146using int4 = int[4];
2147
2148// TODO: Move to Reactor.hpp
2149template<>
2150struct rr::CToReactor<int[4]>
2151{
2152 using type = Int4;
2153 static Int4 cast(float[4]);
2154};
2155
2156// Value type wrapper around a <type>[4] (i.e. float4, int4)
2157template<typename T>
2158struct type4_value
2159{
2160 using E = typename std::remove_pointer_t<std::decay_t<T>>;
2161
2162 type4_value() = default;
2163 explicit type4_value(E rep)
2164 : v{ rep, rep, rep, rep }
2165 {}
2166 type4_value(E x, E y, E z, E w)
2167 : v{ x, y, z, w }
2168 {}
2169
2170 bool operator==(const type4_value &rhs) const
2171 {
2172 return std::equal(std::begin(v), std::end(v), rhs.v);
2173 }
2174
2175 // For gtest printing
2176 friend std::ostream &operator<<(std::ostream &os, const type4_value &value)
2177 {
2178 return os << "[" << value.v[0] << ", " << value.v[1] << ", " << value.v[2] << ", " << value.v[3] << "]";
2179 }
2180
2181 T v;
2182};
2183
2184using float4_value = type4_value<float4>;
2185using int4_value = type4_value<int4>;
2186
2187// Invoke a void(type4_value<T>*) routine on &v.v, returning wrapped result in v
2188template<typename RoutineType, typename T>
2189type4_value<T> invokeRoutine(RoutineType &routine, type4_value<T> v)
2190{
2191 routine(&v.v);
2192 return v;
2193}
2194
2195// Invoke a void(type4_value<T>*, type4_value<T>*) routine on &v1.v, &v2.v returning wrapped result in v1
2196template<typename RoutineType, typename T>
2197type4_value<T> invokeRoutine(RoutineType &routine, type4_value<T> v1, type4_value<T> v2)
2198{
2199 routine(&v1.v, &v2.v);
2200 return v1;
2201}
2202
Antonio Maioranobf151b82019-12-03 09:49:14 -05002203struct IntrinsicTest_Float4 : public testing::TestWithParam<IntrinsicTestParams_Float4>
2204{
2205 void test()
2206 {
Ben Clayton713b8d32019-12-17 20:37:56 +00002207 FunctionT<void(float4 *)> function;
Antonio Maioranobf151b82019-12-03 09:49:14 -05002208 {
2209 Pointer<Float4> a = function.Arg<0>();
2210 *a = GetParam().testFunc(*a);
2211 Return();
2212 }
2213
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05002214 auto routine = function(testName().c_str());
Antonio Maioranobf151b82019-12-03 09:49:14 -05002215
Ben Clayton713b8d32019-12-17 20:37:56 +00002216 for(auto &&v : GetParam().testValues)
Antonio Maioranobf151b82019-12-03 09:49:14 -05002217 {
2218 SCOPED_TRACE(v);
2219 float4_value result = invokeRoutine(routine, float4_value{ v });
2220 float4_value expected = float4_value{ GetParam().refFunc(v) };
Antonio Maiorano9c14bda2020-09-18 16:33:36 -04002221 EXPECT_NEAR(result.v[0], expected.v[0], INTRINSIC_PRECISION);
2222 EXPECT_NEAR(result.v[1], expected.v[1], INTRINSIC_PRECISION);
2223 EXPECT_NEAR(result.v[2], expected.v[2], INTRINSIC_PRECISION);
2224 EXPECT_NEAR(result.v[3], expected.v[3], INTRINSIC_PRECISION);
Antonio Maioranobf151b82019-12-03 09:49:14 -05002225 }
2226 }
2227};
2228
2229struct IntrinsicTest_Float4_Float4 : public testing::TestWithParam<IntrinsicTestParams_Float4_Float4>
2230{
2231 void test()
2232 {
Ben Clayton713b8d32019-12-17 20:37:56 +00002233 FunctionT<void(float4 *, float4 *)> function;
Antonio Maioranobf151b82019-12-03 09:49:14 -05002234 {
2235 Pointer<Float4> a = function.Arg<0>();
2236 Pointer<Float4> b = function.Arg<1>();
2237 *a = GetParam().testFunc(*a, *b);
2238 Return();
2239 }
2240
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05002241 auto routine = function(testName().c_str());
Antonio Maioranobf151b82019-12-03 09:49:14 -05002242
Ben Clayton713b8d32019-12-17 20:37:56 +00002243 for(auto &&v : GetParam().testValues)
Antonio Maioranobf151b82019-12-03 09:49:14 -05002244 {
2245 SCOPED_TRACE(v);
2246 float4_value result = invokeRoutine(routine, float4_value{ v.first }, float4_value{ v.second });
2247 float4_value expected = float4_value{ GetParam().refFunc(v.first, v.second) };
Antonio Maiorano9c14bda2020-09-18 16:33:36 -04002248 EXPECT_NEAR(result.v[0], expected.v[0], INTRINSIC_PRECISION);
2249 EXPECT_NEAR(result.v[1], expected.v[1], INTRINSIC_PRECISION);
2250 EXPECT_NEAR(result.v[2], expected.v[2], INTRINSIC_PRECISION);
2251 EXPECT_NEAR(result.v[3], expected.v[3], INTRINSIC_PRECISION);
Antonio Maioranobf151b82019-12-03 09:49:14 -05002252 }
2253 }
2254};
2255
Antonio Maiorano2d7ca9c2020-02-07 16:47:02 -05002256// clang-format off
2257INSTANTIATE_TEST_SUITE_P(IntrinsicTestParams_Float, IntrinsicTest_Float, testing::Values(
Antonio Maiorano9c14bda2020-09-18 16:33:36 -04002258 IntrinsicTestParams_Float{ [](Float v) { return rr::Exp2(v); }, exp2f, {0.f, 1.f, 123.f} },
2259 IntrinsicTestParams_Float{ [](Float v) { return rr::Log2(v); }, log2f, {1.f, 123.f} },
2260 IntrinsicTestParams_Float{ [](Float v) { return rr::Sqrt(v); }, sqrtf, {0.f, 1.f, 123.f} }
Antonio Maiorano2d7ca9c2020-02-07 16:47:02 -05002261));
2262// clang-format on
Antonio Maioranobf151b82019-12-03 09:49:14 -05002263
Antonio Maiorano2d7ca9c2020-02-07 16:47:02 -05002264// TODO(b/149110874) Use coshf/sinhf when we've implemented SpirV versions at the SpirV level
Antonio Maiorano0aef6452020-02-07 16:50:44 -05002265float vulkan_sinhf(float a)
2266{
2267 return ((expf(a) - expf(-a)) / 2);
2268}
2269float vulkan_coshf(float a)
2270{
2271 return ((expf(a) + expf(-a)) / 2);
2272}
2273
Antonio Maiorano2d7ca9c2020-02-07 16:47:02 -05002274// clang-format off
Nicolas Capensd2af84f2020-05-14 10:55:21 -04002275constexpr float PI = 3.141592653589793f;
Antonio Maiorano2d7ca9c2020-02-07 16:47:02 -05002276INSTANTIATE_TEST_SUITE_P(IntrinsicTestParams_Float4, IntrinsicTest_Float4, testing::Values(
Antonio Maiorano9c14bda2020-09-18 16:33:36 -04002277 IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Sin(v); }, sinf, {0.f, 1.f, PI, 123.f} },
2278 IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Cos(v); }, cosf, {0.f, 1.f, PI, 123.f} },
2279 IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Tan(v); }, tanf, {0.f, 1.f, PI, 123.f} },
2280 IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Asin(v, Precision::Full); }, asinf, {0.f, 1.f, -1.f} },
2281 IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Acos(v, Precision::Full); }, acosf, {0.f, 1.f, -1.f} },
2282 IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Atan(v); }, atanf, {0.f, 1.f, PI, 123.f} },
2283 IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Sinh(v); }, vulkan_sinhf, {0.f, 1.f, PI} },
2284 IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Cosh(v); }, vulkan_coshf, {0.f, 1.f, PI} },
2285 IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Tanh(v); }, tanhf, {0.f, 1.f, PI} },
2286 IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Asinh(v); }, asinhf, {0.f, 1.f, PI, 123.f} },
2287 IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Acosh(v); }, acoshf, { 1.f, PI, 123.f} },
2288 IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Atanh(v); }, atanhf, {0.f, 0.9999f, -0.9999f} },
2289 IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Exp(v); }, expf, {0.f, 1.f, PI} },
2290 IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Log(v); }, logf, {1.f, PI, 123.f} },
2291 IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Exp2(v); }, exp2f, {0.f, 1.f, PI, 123.f} },
2292 IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Log2(v); }, log2f, {1.f, PI, 123.f} },
2293 IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Sqrt(v); }, sqrtf, {0.f, 1.f, PI, 123.f} }
Antonio Maiorano2d7ca9c2020-02-07 16:47:02 -05002294));
2295// clang-format on
Antonio Maioranobf151b82019-12-03 09:49:14 -05002296
Antonio Maiorano2d7ca9c2020-02-07 16:47:02 -05002297// clang-format off
2298INSTANTIATE_TEST_SUITE_P(IntrinsicTestParams_Float4_Float4, IntrinsicTest_Float4_Float4, testing::Values(
Antonio Maiorano9c14bda2020-09-18 16:33:36 -04002299 IntrinsicTestParams_Float4_Float4{ [](RValue<Float4> v1, RValue<Float4> v2) { return Atan2(v1, v2); }, atan2f, { {0.f, 0.f}, {0.f, -1.f}, {-1.f, 0.f}, {123.f, 123.f} } },
2300 IntrinsicTestParams_Float4_Float4{ [](RValue<Float4> v1, RValue<Float4> v2) { return Pow(v1, v2); }, powf, { {1.f, 0.f}, {1.f, -1.f}, {-1.f, 0.f} } }
Antonio Maiorano2d7ca9c2020-02-07 16:47:02 -05002301));
2302// clang-format on
Antonio Maioranobf151b82019-12-03 09:49:14 -05002303
Ben Clayton713b8d32019-12-17 20:37:56 +00002304TEST_P(IntrinsicTest_Float, Test)
2305{
2306 test();
2307}
2308TEST_P(IntrinsicTest_Float4, Test)
2309{
2310 test();
2311}
2312TEST_P(IntrinsicTest_Float4_Float4, Test)
2313{
2314 test();
2315}
Antonio Maioranobf151b82019-12-03 09:49:14 -05002316
2317TEST(ReactorUnitTests, Intrinsics_Ctlz)
2318{
2319 // ctlz: counts number of leading zeros
2320
2321 {
2322 Function<UInt(UInt x)> function;
2323 {
2324 UInt x = function.Arg<0>();
2325 Return(rr::Ctlz(x, false));
2326 }
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05002327 auto routine = function(testName().c_str());
Antonio Maioranobf151b82019-12-03 09:49:14 -05002328 auto callable = (uint32_t(*)(uint32_t))routine->getEntry();
2329
Ben Clayton713b8d32019-12-17 20:37:56 +00002330 for(uint32_t i = 0; i < 31; ++i)
2331 {
Antonio Maioranobf151b82019-12-03 09:49:14 -05002332 uint32_t result = callable(1 << i);
2333 EXPECT_EQ(result, 31 - i);
2334 }
2335
2336 // Input 0 should return 32 for isZeroUndef == false
2337 {
2338 uint32_t result = callable(0);
2339 EXPECT_EQ(result, 32u);
2340 }
2341 }
2342
2343 {
2344 Function<Void(Pointer<UInt4>, UInt x)> function;
2345 {
2346 Pointer<UInt4> out = function.Arg<0>();
2347 UInt x = function.Arg<1>();
2348 *out = rr::Ctlz(UInt4(x), false);
2349 }
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05002350 auto routine = function(testName().c_str());
Ben Clayton713b8d32019-12-17 20:37:56 +00002351 auto callable = (void (*)(uint32_t *, uint32_t))routine->getEntry();
Antonio Maioranobf151b82019-12-03 09:49:14 -05002352
2353 uint32_t x[4];
2354
Ben Clayton713b8d32019-12-17 20:37:56 +00002355 for(uint32_t i = 0; i < 31; ++i)
2356 {
Antonio Maioranobf151b82019-12-03 09:49:14 -05002357 callable(x, 1 << i);
2358 EXPECT_EQ(x[0], 31 - i);
2359 EXPECT_EQ(x[1], 31 - i);
2360 EXPECT_EQ(x[2], 31 - i);
2361 EXPECT_EQ(x[3], 31 - i);
2362 }
2363
2364 // Input 0 should return 32 for isZeroUndef == false
2365 {
2366 callable(x, 0);
2367 EXPECT_EQ(x[0], 32u);
2368 EXPECT_EQ(x[1], 32u);
2369 EXPECT_EQ(x[2], 32u);
2370 EXPECT_EQ(x[3], 32u);
2371 }
2372 }
2373}
2374
2375TEST(ReactorUnitTests, Intrinsics_Cttz)
2376{
2377 // cttz: counts number of trailing zeros
2378
2379 {
2380 Function<UInt(UInt x)> function;
2381 {
2382 UInt x = function.Arg<0>();
2383 Return(rr::Cttz(x, false));
2384 }
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05002385 auto routine = function(testName().c_str());
Antonio Maioranobf151b82019-12-03 09:49:14 -05002386 auto callable = (uint32_t(*)(uint32_t))routine->getEntry();
2387
Ben Clayton713b8d32019-12-17 20:37:56 +00002388 for(uint32_t i = 0; i < 31; ++i)
2389 {
Antonio Maioranobf151b82019-12-03 09:49:14 -05002390 uint32_t result = callable(1 << i);
2391 EXPECT_EQ(result, i);
2392 }
2393
2394 // Input 0 should return 32 for isZeroUndef == false
2395 {
2396 uint32_t result = callable(0);
2397 EXPECT_EQ(result, 32u);
2398 }
2399 }
2400
2401 {
2402 Function<Void(Pointer<UInt4>, UInt x)> function;
2403 {
2404 Pointer<UInt4> out = function.Arg<0>();
2405 UInt x = function.Arg<1>();
2406 *out = rr::Cttz(UInt4(x), false);
2407 }
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05002408 auto routine = function(testName().c_str());
Ben Clayton713b8d32019-12-17 20:37:56 +00002409 auto callable = (void (*)(uint32_t *, uint32_t))routine->getEntry();
Antonio Maioranobf151b82019-12-03 09:49:14 -05002410
2411 uint32_t x[4];
2412
Ben Clayton713b8d32019-12-17 20:37:56 +00002413 for(uint32_t i = 0; i < 31; ++i)
2414 {
Antonio Maioranobf151b82019-12-03 09:49:14 -05002415 callable(x, 1 << i);
2416 EXPECT_EQ(x[0], i);
2417 EXPECT_EQ(x[1], i);
2418 EXPECT_EQ(x[2], i);
2419 EXPECT_EQ(x[3], i);
2420 }
2421
2422 // Input 0 should return 32 for isZeroUndef == false
2423 {
2424 callable(x, 0);
2425 EXPECT_EQ(x[0], 32u);
2426 EXPECT_EQ(x[1], 32u);
2427 EXPECT_EQ(x[2], 32u);
2428 EXPECT_EQ(x[3], 32u);
2429 }
2430 }
2431}
2432
2433TEST(ReactorUnitTests, Intrinsics_Scatter)
2434{
2435 Function<Void(Pointer<Float> base, Pointer<Float4> val, Pointer<Int4> offsets)> function;
2436 {
2437 Pointer<Float> base = function.Arg<0>();
2438 Pointer<Float4> val = function.Arg<1>();
2439 Pointer<Int4> offsets = function.Arg<2>();
2440
2441 auto mask = Int4(~0, ~0, ~0, ~0);
2442 unsigned int alignment = 1;
2443 Scatter(base, *val, *offsets, mask, alignment);
2444 }
2445
Ben Clayton713b8d32019-12-17 20:37:56 +00002446 float buffer[16] = { 0 };
Antonio Maioranobf151b82019-12-03 09:49:14 -05002447
2448 constexpr auto elemSize = sizeof(buffer[0]);
2449
Ben Clayton713b8d32019-12-17 20:37:56 +00002450 int offsets[] = {
2451 1 * elemSize,
2452 6 * elemSize,
2453 11 * elemSize,
2454 13 * elemSize
Antonio Maioranobf151b82019-12-03 09:49:14 -05002455 };
2456
Ben Clayton713b8d32019-12-17 20:37:56 +00002457 float val[4] = { 10, 60, 110, 130 };
Antonio Maioranobf151b82019-12-03 09:49:14 -05002458
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05002459 auto routine = function(testName().c_str());
Ben Clayton713b8d32019-12-17 20:37:56 +00002460 auto entry = (void (*)(float *, float *, int *))routine->getEntry();
Antonio Maioranobf151b82019-12-03 09:49:14 -05002461
2462 entry(buffer, val, offsets);
2463
2464 EXPECT_EQ(buffer[offsets[0] / sizeof(buffer[0])], 10);
2465 EXPECT_EQ(buffer[offsets[1] / sizeof(buffer[0])], 60);
2466 EXPECT_EQ(buffer[offsets[2] / sizeof(buffer[0])], 110);
2467 EXPECT_EQ(buffer[offsets[3] / sizeof(buffer[0])], 130);
2468}
2469
2470TEST(ReactorUnitTests, Intrinsics_Gather)
2471{
2472 Function<Void(Pointer<Float> base, Pointer<Int4> offsets, Pointer<Float4> result)> function;
2473 {
2474 Pointer<Float> base = function.Arg<0>();
2475 Pointer<Int4> offsets = function.Arg<1>();
2476 Pointer<Float4> result = function.Arg<2>();
2477
2478 auto mask = Int4(~0, ~0, ~0, ~0);
2479 unsigned int alignment = 1;
2480 bool zeroMaskedLanes = true;
2481 *result = Gather(base, *offsets, mask, alignment, zeroMaskedLanes);
2482 }
2483
Ben Clayton713b8d32019-12-17 20:37:56 +00002484 float buffer[] = {
Antonio Maioranobf151b82019-12-03 09:49:14 -05002485 0, 10, 20, 30,
2486 40, 50, 60, 70,
2487 80, 90, 100, 110,
2488 120, 130, 140, 150
2489 };
2490
2491 constexpr auto elemSize = sizeof(buffer[0]);
2492
Ben Clayton713b8d32019-12-17 20:37:56 +00002493 int offsets[] = {
2494 1 * elemSize,
2495 6 * elemSize,
2496 11 * elemSize,
2497 13 * elemSize
Antonio Maioranobf151b82019-12-03 09:49:14 -05002498 };
2499
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05002500 auto routine = function(testName().c_str());
Ben Clayton713b8d32019-12-17 20:37:56 +00002501 auto entry = (void (*)(float *, int *, float *))routine->getEntry();
Antonio Maioranobf151b82019-12-03 09:49:14 -05002502
2503 float result[4] = {};
2504 entry(buffer, offsets, result);
2505
2506 EXPECT_EQ(result[0], 10);
2507 EXPECT_EQ(result[1], 60);
2508 EXPECT_EQ(result[2], 110);
2509 EXPECT_EQ(result[3], 130);
2510}
2511
Antonio Maiorano7ffda5b2019-11-20 15:31:51 -05002512TEST(ReactorUnitTests, ExtractFromRValue)
2513{
2514 Function<Void(Pointer<Int4> values, Pointer<Int4> result)> function;
2515 {
2516 Pointer<Int4> vIn = function.Arg<0>();
2517 Pointer<Int4> resultIn = function.Arg<1>();
2518
2519 RValue<Int4> v = *vIn;
2520
2521 Int4 result(678);
2522
2523 If(Extract(v, 0) == 42)
2524 {
2525 result = Insert(result, 1, 0);
2526 }
2527
2528 If(Extract(v, 1) == 42)
2529 {
2530 result = Insert(result, 1, 1);
2531 }
2532
2533 *resultIn = result;
2534
2535 Return();
2536 }
2537
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05002538 auto routine = function(testName().c_str());
Ben Clayton713b8d32019-12-17 20:37:56 +00002539 auto entry = (void (*)(int *, int *))routine->getEntry();
Antonio Maiorano7ffda5b2019-11-20 15:31:51 -05002540
2541 int v[4] = { 42, 42, 42, 42 };
2542 int result[4] = { 99, 99, 99, 99 };
2543 entry(v, result);
2544 EXPECT_EQ(result[0], 1);
2545 EXPECT_EQ(result[1], 1);
2546 EXPECT_EQ(result[2], 678);
2547 EXPECT_EQ(result[3], 678);
2548}
2549
Antonio Maiorano370cba52019-12-31 11:36:07 -05002550TEST(ReactorUnitTests, AddAtomic)
2551{
2552 FunctionT<uint32_t(uint32_t * p, uint32_t a)> function;
2553 {
2554 Pointer<UInt> p = function.Arg<0>();
2555 UInt a = function.Arg<1>();
2556 UInt r = rr::AddAtomic(p, a, std::memory_order_relaxed);
2557 Return(r);
2558 }
2559
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05002560 auto routine = function(testName().c_str());
Antonio Maiorano370cba52019-12-31 11:36:07 -05002561 uint32_t x = 123;
2562 uint32_t y = 456;
2563 uint32_t prevX = routine(&x, y);
2564 EXPECT_EQ(prevX, 123u);
2565 EXPECT_EQ(x, 579u);
2566}
2567
2568TEST(ReactorUnitTests, SubAtomic)
2569{
2570 FunctionT<uint32_t(uint32_t * p, uint32_t a)> function;
2571 {
2572 Pointer<UInt> p = function.Arg<0>();
2573 UInt a = function.Arg<1>();
2574 UInt r = rr::SubAtomic(p, a, std::memory_order_relaxed);
2575 Return(r);
2576 }
2577
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05002578 auto routine = function(testName().c_str());
Antonio Maiorano370cba52019-12-31 11:36:07 -05002579 uint32_t x = 456;
2580 uint32_t y = 123;
2581 uint32_t prevX = routine(&x, y);
2582 EXPECT_EQ(prevX, 456u);
2583 EXPECT_EQ(x, 333u);
2584}
2585
2586TEST(ReactorUnitTests, AndAtomic)
2587{
2588 FunctionT<uint32_t(uint32_t * p, uint32_t a)> function;
2589 {
2590 Pointer<UInt> p = function.Arg<0>();
2591 UInt a = function.Arg<1>();
2592 UInt r = rr::AndAtomic(p, a, std::memory_order_relaxed);
2593 Return(r);
2594 }
2595
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05002596 auto routine = function(testName().c_str());
Antonio Maiorano370cba52019-12-31 11:36:07 -05002597 uint32_t x = 0b1111'0000;
2598 uint32_t y = 0b1010'1100;
2599 uint32_t prevX = routine(&x, y);
2600 EXPECT_EQ(prevX, 0b1111'0000u);
2601 EXPECT_EQ(x, 0b1010'0000u);
2602}
2603
2604TEST(ReactorUnitTests, OrAtomic)
2605{
2606 FunctionT<uint32_t(uint32_t * p, uint32_t a)> function;
2607 {
2608 Pointer<UInt> p = function.Arg<0>();
2609 UInt a = function.Arg<1>();
2610 UInt r = rr::OrAtomic(p, a, std::memory_order_relaxed);
2611 Return(r);
2612 }
2613
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05002614 auto routine = function(testName().c_str());
Antonio Maiorano370cba52019-12-31 11:36:07 -05002615 uint32_t x = 0b1111'0000;
2616 uint32_t y = 0b1010'1100;
2617 uint32_t prevX = routine(&x, y);
2618 EXPECT_EQ(prevX, 0b1111'0000u);
2619 EXPECT_EQ(x, 0b1111'1100u);
2620}
2621
2622TEST(ReactorUnitTests, XorAtomic)
2623{
2624 FunctionT<uint32_t(uint32_t * p, uint32_t a)> function;
2625 {
2626 Pointer<UInt> p = function.Arg<0>();
2627 UInt a = function.Arg<1>();
2628 UInt r = rr::XorAtomic(p, a, std::memory_order_relaxed);
2629 Return(r);
2630 }
2631
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05002632 auto routine = function(testName().c_str());
Antonio Maiorano370cba52019-12-31 11:36:07 -05002633 uint32_t x = 0b1111'0000;
2634 uint32_t y = 0b1010'1100;
2635 uint32_t prevX = routine(&x, y);
2636 EXPECT_EQ(prevX, 0b1111'0000u);
2637 EXPECT_EQ(x, 0b0101'1100u);
2638}
2639
2640TEST(ReactorUnitTests, MinAtomic)
2641{
2642 {
2643 FunctionT<uint32_t(uint32_t * p, uint32_t a)> function;
2644 {
2645 Pointer<UInt> p = function.Arg<0>();
2646 UInt a = function.Arg<1>();
2647 UInt r = rr::MinAtomic(p, a, std::memory_order_relaxed);
2648 Return(r);
2649 }
2650
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05002651 auto routine = function(testName().c_str());
Antonio Maiorano370cba52019-12-31 11:36:07 -05002652 uint32_t x = 123;
2653 uint32_t y = 100;
2654 uint32_t prevX = routine(&x, y);
2655 EXPECT_EQ(prevX, 123u);
2656 EXPECT_EQ(x, 100u);
2657 }
2658
2659 {
2660 FunctionT<int32_t(int32_t * p, int32_t a)> function;
2661 {
2662 Pointer<Int> p = function.Arg<0>();
2663 Int a = function.Arg<1>();
2664 Int r = rr::MinAtomic(p, a, std::memory_order_relaxed);
2665 Return(r);
2666 }
2667
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05002668 auto routine = function(testName().c_str());
Antonio Maiorano370cba52019-12-31 11:36:07 -05002669 int32_t x = -123;
2670 int32_t y = -200;
2671 int32_t prevX = routine(&x, y);
2672 EXPECT_EQ(prevX, -123);
2673 EXPECT_EQ(x, -200);
2674 }
2675}
2676
2677TEST(ReactorUnitTests, MaxAtomic)
2678{
2679 {
2680 FunctionT<uint32_t(uint32_t * p, uint32_t a)> function;
2681 {
2682 Pointer<UInt> p = function.Arg<0>();
2683 UInt a = function.Arg<1>();
2684 UInt r = rr::MaxAtomic(p, a, std::memory_order_relaxed);
2685 Return(r);
2686 }
2687
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05002688 auto routine = function(testName().c_str());
Antonio Maiorano370cba52019-12-31 11:36:07 -05002689 uint32_t x = 123;
2690 uint32_t y = 100;
2691 uint32_t prevX = routine(&x, y);
2692 EXPECT_EQ(prevX, 123u);
2693 EXPECT_EQ(x, 123u);
2694 }
2695
2696 {
2697 FunctionT<int32_t(int32_t * p, int32_t a)> function;
2698 {
2699 Pointer<Int> p = function.Arg<0>();
2700 Int a = function.Arg<1>();
2701 Int r = rr::MaxAtomic(p, a, std::memory_order_relaxed);
2702 Return(r);
2703 }
2704
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05002705 auto routine = function(testName().c_str());
Antonio Maiorano370cba52019-12-31 11:36:07 -05002706 int32_t x = -123;
2707 int32_t y = -200;
2708 int32_t prevX = routine(&x, y);
2709 EXPECT_EQ(prevX, -123);
2710 EXPECT_EQ(x, -123);
2711 }
2712}
2713
2714TEST(ReactorUnitTests, ExchangeAtomic)
2715{
2716 FunctionT<uint32_t(uint32_t * p, uint32_t a)> function;
2717 {
2718 Pointer<UInt> p = function.Arg<0>();
2719 UInt a = function.Arg<1>();
2720 UInt r = rr::ExchangeAtomic(p, a, std::memory_order_relaxed);
2721 Return(r);
2722 }
2723
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05002724 auto routine = function(testName().c_str());
Antonio Maiorano370cba52019-12-31 11:36:07 -05002725 uint32_t x = 123;
2726 uint32_t y = 456;
2727 uint32_t prevX = routine(&x, y);
2728 EXPECT_EQ(prevX, 123u);
2729 EXPECT_EQ(x, y);
2730}
2731
2732TEST(ReactorUnitTests, CompareExchangeAtomic)
2733{
2734 FunctionT<uint32_t(uint32_t * x, uint32_t y, uint32_t compare)> function;
2735 {
2736 Pointer<UInt> x = function.Arg<0>();
2737 UInt y = function.Arg<1>();
2738 UInt compare = function.Arg<2>();
2739 UInt r = rr::CompareExchangeAtomic(x, y, compare, std::memory_order_relaxed, std::memory_order_relaxed);
2740 Return(r);
2741 }
2742
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05002743 auto routine = function(testName().c_str());
Antonio Maiorano370cba52019-12-31 11:36:07 -05002744 uint32_t x = 123;
2745 uint32_t y = 456;
2746 uint32_t compare = 123;
2747 uint32_t prevX = routine(&x, y, compare);
2748 EXPECT_EQ(prevX, 123u);
2749 EXPECT_EQ(x, y);
2750
2751 x = 123;
2752 y = 456;
2753 compare = 456;
2754 prevX = routine(&x, y, compare);
2755 EXPECT_EQ(prevX, 123u);
2756 EXPECT_EQ(x, 123u);
2757}
2758
Antonio Maiorano5ef91b82020-01-21 15:10:22 -05002759TEST(ReactorUnitTests, SRem)
2760{
2761 FunctionT<void(int4 *, int4 *)> function;
2762 {
2763 Pointer<Int4> a = function.Arg<0>();
2764 Pointer<Int4> b = function.Arg<1>();
2765 *a = *a % *b;
2766 }
2767
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05002768 auto routine = function(testName().c_str());
Antonio Maiorano5ef91b82020-01-21 15:10:22 -05002769
2770 int4_value result = invokeRoutine(routine, int4_value{ 10, 11, 12, 13 }, int4_value{ 3, 3, 3, 3 });
2771 int4_value expected = int4_value{ 10 % 3, 11 % 3, 12 % 3, 13 % 3 };
2772 EXPECT_FLOAT_EQ(result.v[0], expected.v[0]);
2773 EXPECT_FLOAT_EQ(result.v[1], expected.v[1]);
2774 EXPECT_FLOAT_EQ(result.v[2], expected.v[2]);
2775 EXPECT_FLOAT_EQ(result.v[3], expected.v[3]);
2776}
2777
2778TEST(ReactorUnitTests, FRem)
2779{
2780 FunctionT<void(float4 *, float4 *)> function;
2781 {
2782 Pointer<Float4> a = function.Arg<0>();
2783 Pointer<Float4> b = function.Arg<1>();
2784 *a = *a % *b;
2785 }
2786
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05002787 auto routine = function(testName().c_str());
Antonio Maiorano5ef91b82020-01-21 15:10:22 -05002788
2789 float4_value result = invokeRoutine(routine, float4_value{ 10.1f, 11.2f, 12.3f, 13.4f }, float4_value{ 3.f, 3.f, 3.f, 3.f });
2790 float4_value expected = float4_value{ fmodf(10.1f, 3.f), fmodf(11.2f, 3.f), fmodf(12.3f, 3.f), fmodf(13.4f, 3.f) };
2791 EXPECT_FLOAT_EQ(result.v[0], expected.v[0]);
2792 EXPECT_FLOAT_EQ(result.v[1], expected.v[1]);
2793 EXPECT_FLOAT_EQ(result.v[2], expected.v[2]);
2794 EXPECT_FLOAT_EQ(result.v[3], expected.v[3]);
2795}
2796
Antonio Maiorano02a39532020-01-21 15:15:34 -05002797// Subzero's load instruction assumes that a Constant ptr value is an offset, rather than an absolute
2798// pointer, and would fail during codegen. This was fixed by casting the constant to a non-const
2799// variable, and loading from it instead. This test makes sure this works.
2800TEST(ReactorUnitTests, LoadFromConstantData)
2801{
2802 const int value = 123;
2803
2804 FunctionT<int()> function;
2805 {
2806 auto p = Pointer<Int>{ ConstantData(&value, sizeof(value)) };
2807 Int v = *p;
2808 Return(v);
2809 }
2810
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05002811 const int result = function(testName().c_str())();
Antonio Maiorano02a39532020-01-21 15:15:34 -05002812 EXPECT_EQ(result, value);
2813}
2814
Ben Clayton20cf5c52019-07-01 11:13:27 +01002815TEST(ReactorUnitTests, Multithreaded_Function)
2816{
Ben Clayton587fbb92020-04-27 16:25:03 +01002817 constexpr int numThreads = 8;
2818 constexpr int numLoops = 16;
Ben Clayton20cf5c52019-07-01 11:13:27 +01002819
2820 auto threads = std::unique_ptr<std::thread[]>(new std::thread[numThreads]);
2821 auto results = std::unique_ptr<int[]>(new int[numThreads * numLoops]);
2822
2823 for(int t = 0; t < numThreads; t++)
2824 {
2825 auto threadFunc = [&](int t) {
2826 for(int l = 0; l < numLoops; l++)
2827 {
2828 FunctionT<int(int, int)> function;
2829 {
2830 Int a = function.Arg<0>();
2831 Int b = function.Arg<1>();
2832 Return((a << 16) | b);
2833 }
2834
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05002835 auto f = function("%s_thread%d_loop%d", testName().c_str(), t, l);
Ben Clayton20cf5c52019-07-01 11:13:27 +01002836 results[t * numLoops + l] = f(t, l);
2837 }
2838 };
2839 threads[t] = std::thread(threadFunc, t);
2840 }
2841
2842 for(int t = 0; t < numThreads; t++)
2843 {
2844 threads[t].join();
2845 }
2846
2847 for(int t = 0; t < numThreads; t++)
2848 {
2849 for(int l = 0; l < numLoops; l++)
2850 {
2851 auto expect = (t << 16) | l;
2852 auto result = results[t * numLoops + l];
2853 EXPECT_EQ(result, expect);
2854 }
2855 }
2856}
2857
2858TEST(ReactorUnitTests, Multithreaded_Coroutine)
2859{
2860 if(!rr::Caps.CoroutinesSupported)
2861 {
2862 SUCCEED() << "Coroutines not supported";
2863 return;
2864 }
2865
Ben Clayton587fbb92020-04-27 16:25:03 +01002866 constexpr int numThreads = 8;
2867 constexpr int numLoops = 16;
Ben Clayton20cf5c52019-07-01 11:13:27 +01002868
2869 struct Result
2870 {
2871 bool yieldReturns[3];
2872 int yieldValues[3];
2873 };
2874
2875 auto threads = std::unique_ptr<std::thread[]>(new std::thread[numThreads]);
2876 auto results = std::unique_ptr<Result[]>(new Result[numThreads * numLoops]);
2877
2878 for(int t = 0; t < numThreads; t++)
2879 {
2880 auto threadFunc = [&](int t) {
2881 for(int l = 0; l < numLoops; l++)
2882 {
2883 Coroutine<int(int, int)> function;
2884 {
2885 Int a = function.Arg<0>();
2886 Int b = function.Arg<1>();
2887 Yield(a);
2888 Yield(b);
2889 }
Antonio Maiorano3fba1ac2020-11-27 14:55:22 -05002890 function.finalize((testName() + "_thread" + std::to_string(t) + "_loop" + std::to_string(l)).c_str());
Ben Clayton20cf5c52019-07-01 11:13:27 +01002891
2892 auto coroutine = function(t, l);
2893
2894 auto &result = results[t * numLoops + l];
2895 result = {};
2896 result.yieldReturns[0] = coroutine->await(result.yieldValues[0]);
2897 result.yieldReturns[1] = coroutine->await(result.yieldValues[1]);
2898 result.yieldReturns[2] = coroutine->await(result.yieldValues[2]);
2899 }
2900 };
2901 threads[t] = std::thread(threadFunc, t);
2902 }
2903
2904 for(int t = 0; t < numThreads; t++)
2905 {
2906 threads[t].join();
2907 }
2908
2909 for(int t = 0; t < numThreads; t++)
2910 {
2911 for(int l = 0; l < numLoops; l++)
2912 {
2913 auto const &result = results[t * numLoops + l];
2914 EXPECT_EQ(result.yieldReturns[0], true);
2915 EXPECT_EQ(result.yieldValues[0], t);
2916 EXPECT_EQ(result.yieldReturns[1], true);
2917 EXPECT_EQ(result.yieldValues[1], l);
2918 EXPECT_EQ(result.yieldReturns[2], false);
2919 EXPECT_EQ(result.yieldValues[2], 0);
2920 }
2921 }
2922}
2923
Nicolas Capensd2af84f2020-05-14 10:55:21 -04002924// For gtest printing of pairs
2925namespace std {
2926template<typename T, typename U>
2927std::ostream &operator<<(std::ostream &os, const std::pair<T, U> &value)
2928{
2929 return os << "{ " << value.first << ", " << value.second << " }";
2930}
2931} // namespace std
2932
2933class StdOutCapture
2934{
2935public:
2936 ~StdOutCapture()
2937 {
2938 stopIfCapturing();
2939 }
2940
2941 void start()
2942 {
2943 stopIfCapturing();
2944 capturing = true;
2945 testing::internal::CaptureStdout();
2946 }
2947
2948 std::string stop()
2949 {
2950 assert(capturing);
2951 capturing = false;
2952 return testing::internal::GetCapturedStdout();
2953 }
2954
2955private:
2956 void stopIfCapturing()
2957 {
2958 if(capturing)
2959 {
2960 // This stops the capture
2961 testing::internal::GetCapturedStdout();
2962 }
2963 }
2964
2965 bool capturing = false;
2966};
2967
2968std::vector<std::string> split(const std::string &s)
2969{
2970 std::vector<std::string> result;
2971 std::istringstream iss(s);
2972 for(std::string line; std::getline(iss, line);)
2973 {
2974 result.push_back(line);
2975 }
2976 return result;
2977}
2978
2979TEST(ReactorUnitTests, PrintPrimitiveTypes)
2980{
2981#if defined(ENABLE_RR_PRINT) && !defined(ENABLE_RR_EMIT_PRINT_LOCATION)
2982 FunctionT<void()> function;
2983 {
2984 bool b(true);
2985 int8_t i8(-1);
2986 uint8_t ui8(1);
2987 int16_t i16(-1);
2988 uint16_t ui16(1);
2989 int32_t i32(-1);
2990 uint32_t ui32(1);
2991 int64_t i64(-1);
2992 uint64_t ui64(1);
2993 float f(1);
2994 double d(2);
2995 const char *cstr = "const char*";
2996 std::string str = "std::string";
2997 int *p = nullptr;
2998
2999 RR_WATCH(b);
3000 RR_WATCH(i8);
3001 RR_WATCH(ui8);
3002 RR_WATCH(i16);
3003 RR_WATCH(ui16);
3004 RR_WATCH(i32);
3005 RR_WATCH(ui32);
3006 RR_WATCH(i64);
3007 RR_WATCH(ui64);
3008 RR_WATCH(f);
3009 RR_WATCH(d);
3010 RR_WATCH(cstr);
3011 RR_WATCH(str);
3012 RR_WATCH(p);
3013 }
3014
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05003015 auto routine = function(testName().c_str());
Nicolas Capensd2af84f2020-05-14 10:55:21 -04003016
3017 char pNullptr[64];
3018 snprintf(pNullptr, sizeof(pNullptr), " p: %p", nullptr);
3019
3020 const char *expected[] = {
3021 " b: true",
3022 " i8: -1",
3023 " ui8: 1",
3024 " i16: -1",
3025 " ui16: 1",
3026 " i32: -1",
3027 " ui32: 1",
3028 " i64: -1",
3029 " ui64: 1",
3030 " f: 1.000000",
3031 " d: 2.000000",
3032 " cstr: const char*",
3033 " str: std::string",
3034 pNullptr,
3035 };
3036 constexpr size_t expectedSize = sizeof(expected) / sizeof(expected[0]);
3037
3038 StdOutCapture capture;
3039 capture.start();
3040 routine();
3041 auto output = split(capture.stop());
3042 for(size_t i = 0, j = 1; i < expectedSize; ++i, j += 2)
3043 {
3044 ASSERT_EQ(expected[i], output[j]);
3045 }
3046
3047#endif
3048}
3049
3050TEST(ReactorUnitTests, PrintReactorTypes)
3051{
3052#if defined(ENABLE_RR_PRINT) && !defined(ENABLE_RR_EMIT_PRINT_LOCATION)
3053 FunctionT<void()> function;
3054 {
3055 Bool b(true);
3056 Int i(-1);
3057 Int2 i2(-1, -2);
3058 Int4 i4(-1, -2, -3, -4);
3059 UInt ui(1);
3060 UInt2 ui2(1, 2);
3061 UInt4 ui4(1, 2, 3, 4);
3062 Short s(-1);
3063 Short4 s4(-1, -2, -3, -4);
3064 UShort us(1);
3065 UShort4 us4(1, 2, 3, 4);
3066 Float f(1);
3067 Float4 f4(1, 2, 3, 4);
3068 Long l(i);
3069 Pointer<Int> pi = nullptr;
3070 RValue<Int> rvi = i;
3071 Byte by('a');
3072 Byte4 by4(i4);
3073
3074 RR_WATCH(b);
3075 RR_WATCH(i);
3076 RR_WATCH(i2);
3077 RR_WATCH(i4);
3078 RR_WATCH(ui);
3079 RR_WATCH(ui2);
3080 RR_WATCH(ui4);
3081 RR_WATCH(s);
3082 RR_WATCH(s4);
3083 RR_WATCH(us);
3084 RR_WATCH(us4);
3085 RR_WATCH(f);
3086 RR_WATCH(f4);
3087 RR_WATCH(l);
3088 RR_WATCH(pi);
3089 RR_WATCH(rvi);
3090 RR_WATCH(by);
3091 RR_WATCH(by4);
3092 }
3093
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05003094 auto routine = function(testName().c_str());
Nicolas Capensd2af84f2020-05-14 10:55:21 -04003095
3096 char piNullptr[64];
3097 snprintf(piNullptr, sizeof(piNullptr), " pi: %p", nullptr);
3098
3099 const char *expected[] = {
3100 " b: true",
3101 " i: -1",
3102 " i2: [-1, -2]",
3103 " i4: [-1, -2, -3, -4]",
3104 " ui: 1",
3105 " ui2: [1, 2]",
3106 " ui4: [1, 2, 3, 4]",
3107 " s: -1",
3108 " s4: [-1, -2, -3, -4]",
3109 " us: 1",
3110 " us4: [1, 2, 3, 4]",
3111 " f: 1.000000",
3112 " f4: [1.000000, 2.000000, 3.000000, 4.000000]",
3113 " l: -1",
3114 piNullptr,
3115 " rvi: -1",
3116 " by: 97",
3117 " by4: [255, 254, 253, 252]",
3118 };
3119 constexpr size_t expectedSize = sizeof(expected) / sizeof(expected[0]);
3120
3121 StdOutCapture capture;
3122 capture.start();
3123 routine();
3124 auto output = split(capture.stop());
3125 for(size_t i = 0, j = 1; i < expectedSize; ++i, j += 2)
3126 {
3127 ASSERT_EQ(expected[i], output[j]);
3128 }
3129
3130#endif
3131}
3132
Antonio Maiorano04bd4d82020-10-05 16:34:04 -04003133// Test constant <op> variable
3134template<typename T, typename Func>
3135T Arithmetic_LhsConstArg(T arg1, T arg2, Func f)
3136{
3137 using ReactorT = CToReactorT<T>;
3138
3139 FunctionT<T(T)> function;
3140 {
3141 ReactorT lhs = arg1;
3142 ReactorT rhs = function.template Arg<0>();
3143 ReactorT result = f(lhs, rhs);
3144 Return(result);
3145 }
3146
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05003147 auto routine = function(testName().c_str());
Antonio Maiorano04bd4d82020-10-05 16:34:04 -04003148 return routine(arg2);
3149}
3150
3151// Test variable <op> constant
3152template<typename T, typename Func>
3153T Arithmetic_RhsConstArg(T arg1, T arg2, Func f)
3154{
3155 using ReactorT = CToReactorT<T>;
3156
3157 FunctionT<T(T)> function;
3158 {
3159 ReactorT lhs = function.template Arg<0>();
3160 ReactorT rhs = arg2;
3161 ReactorT result = f(lhs, rhs);
3162 Return(result);
3163 }
3164
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05003165 auto routine = function(testName().c_str());
Antonio Maiorano04bd4d82020-10-05 16:34:04 -04003166 return routine(arg1);
3167}
3168
3169// Test constant <op> constant
3170template<typename T, typename Func>
3171T Arithmetic_TwoConstArgs(T arg1, T arg2, Func f)
3172{
3173 using ReactorT = CToReactorT<T>;
3174
3175 FunctionT<T()> function;
3176 {
3177 ReactorT lhs = arg1;
3178 ReactorT rhs = arg2;
3179 ReactorT result = f(lhs, rhs);
3180 Return(result);
3181 }
3182
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05003183 auto routine = function(testName().c_str());
Antonio Maiorano04bd4d82020-10-05 16:34:04 -04003184 return routine();
3185}
3186
3187template<typename T, typename Func>
3188void Arithmetic_ConstArgs(T arg1, T arg2, T expected, Func f)
3189{
3190 SCOPED_TRACE(std::to_string(arg1) + " <op> " + std::to_string(arg2) + " = " + std::to_string(expected));
3191 T result{};
3192 result = Arithmetic_LhsConstArg(arg1, arg2, std::forward<Func>(f));
3193 EXPECT_EQ(result, expected);
3194 result = Arithmetic_RhsConstArg(arg1, arg2, std::forward<Func>(f));
3195 EXPECT_EQ(result, expected);
3196 result = Arithmetic_TwoConstArgs(arg1, arg2, std::forward<Func>(f));
3197 EXPECT_EQ(result, expected);
3198}
3199
3200// Test that we generate valid code for when one or both args to arithmetic operations
3201// are constant. In particular, we want to validate the case for two const args, as
3202// often lowered instructions do not support this case.
3203TEST(ReactorUnitTests, Arithmetic_ConstantArgs)
3204{
3205 Arithmetic_ConstArgs(2, 3, 5, [](auto c1, auto c2) { return c1 + c2; });
3206 Arithmetic_ConstArgs(5, 3, 2, [](auto c1, auto c2) { return c1 - c2; });
3207 Arithmetic_ConstArgs(2, 3, 6, [](auto c1, auto c2) { return c1 * c2; });
3208 Arithmetic_ConstArgs(6, 3, 2, [](auto c1, auto c2) { return c1 / c2; });
3209 Arithmetic_ConstArgs(0xF0F0, 0xAAAA, 0xA0A0, [](auto c1, auto c2) { return c1 & c2; });
3210 Arithmetic_ConstArgs(0xF0F0, 0xAAAA, 0xFAFA, [](auto c1, auto c2) { return c1 | c2; });
3211 Arithmetic_ConstArgs(0xF0F0, 0xAAAA, 0x5A5A, [](auto c1, auto c2) { return c1 ^ c2; });
3212
3213 Arithmetic_ConstArgs(2.f, 3.f, 5.f, [](auto c1, auto c2) { return c1 + c2; });
3214 Arithmetic_ConstArgs(5.f, 3.f, 2.f, [](auto c1, auto c2) { return c1 - c2; });
3215 Arithmetic_ConstArgs(2.f, 3.f, 6.f, [](auto c1, auto c2) { return c1 * c2; });
3216 Arithmetic_ConstArgs(6.f, 3.f, 2.f, [](auto c1, auto c2) { return c1 / c2; });
3217}
3218
Antonio Maiorano6c839a62020-11-06 11:19:24 -05003219// Test for Subzero bad code-gen that was fixed in swiftshader-cl/50008
3220// This tests the case of copying enough arguments to local variables so that the locals
3221// get spilled to the stack when no more registers remain, and making sure these copies
3222// are generated correctly. Without the aforementioned fix, this fails 100% on Windows x86.
3223TEST(ReactorUnitTests, SpillLocalCopiesOfArgs)
3224{
3225 struct Helpers
3226 {
3227 static bool True() { return true; }
3228 };
3229
3230 const int numLoops = 5; // 2 should be enough, but loop more to make sure
3231
3232 FunctionT<int(int, int, int, int, int, int, int, int, int, int, int, int)> function;
3233 {
3234 Int result = 0;
3235 Int a1 = function.Arg<0>();
3236 Int a2 = function.Arg<1>();
3237 Int a3 = function.Arg<2>();
3238 Int a4 = function.Arg<3>();
3239 Int a5 = function.Arg<4>();
3240 Int a6 = function.Arg<5>();
3241 Int a7 = function.Arg<6>();
3242 Int a8 = function.Arg<7>();
3243 Int a9 = function.Arg<8>();
3244 Int a10 = function.Arg<9>();
3245 Int a11 = function.Arg<10>();
3246 Int a12 = function.Arg<11>();
3247
3248 for(int i = 0; i < numLoops; ++i)
3249 {
3250 // Copy all arguments to locals so that Ice::LocalVariableSplitter::handleSimpleVarAssign
3251 // creates Variable copies of arguments. We loop so that we create enough of these so
3252 // that some spill over to the stack.
3253 Int i1 = a1;
3254 Int i2 = a2;
3255 Int i3 = a3;
3256 Int i4 = a4;
3257 Int i5 = a5;
3258 Int i6 = a6;
3259 Int i7 = a7;
3260 Int i8 = a8;
3261 Int i9 = a9;
3262 Int i10 = a10;
3263 Int i11 = a11;
3264 Int i12 = a12;
3265
3266 // Forcibly materialize all variables so that Ice::Variable instances are created for each
3267 // local; otherwise, Reactor r-value optimizations kick in, and the locals are elided.
3268 Variable::materializeAll();
3269
3270 // We also need to create a separate block that uses the variables declared above
3271 // so that rr::optimize() doesn't optimize them out when attempting to eliminate stores
3272 // followed by a load in the same block.
3273 If(Call(Helpers::True))
3274 {
3275 result += (i1 + i2 + i3 + i4 + i5 + i6 + i7 + i8 + i9 + i10 + i11 + i12);
3276 }
3277 }
3278
3279 Return(result);
3280 }
3281
Antonio Maiorano2195f7a2020-11-27 14:02:23 -05003282 auto routine = function(testName().c_str());
Antonio Maiorano6c839a62020-11-06 11:19:24 -05003283 int result = routine(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);
3284 int expected = numLoops * (1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12);
3285 EXPECT_EQ(result, expected);
3286}
3287
Nicolas Capensb3e5c442021-01-20 06:16:24 +00003288#if defined(ENABLE_RR_EMIT_ASM_FILE)
Antonio Maiorano10ff4332020-12-04 11:33:34 -05003289TEST(ReactorUnitTests, EmitAsm)
3290{
3291 // Only supported by LLVM for now
3292 if(BackendName().find("LLVM") == std::string::npos) return;
3293
3294 namespace fs = std::filesystem;
3295
3296 FunctionT<int(void)> function;
3297 {
3298 Int sum;
3299 For(Int i = 0, i < 10, i++)
3300 {
3301 sum += i;
3302 }
3303 Return(sum);
3304 }
3305
3306 auto routine = function(testName().c_str());
3307
3308 // Returns path to first match of filename in current directory
3309 auto findFile = [](const std::string filename) -> fs::path {
3310 for(auto &p : fs::directory_iterator("."))
3311 {
3312 if(!p.is_regular_file())
3313 continue;
3314 auto currFilename = p.path().filename().string();
3315 auto index = currFilename.find(testName());
3316 if(index != std::string::npos)
3317 {
3318 return p.path();
3319 }
3320 }
3321 return {};
3322 };
3323
3324 fs::path path = findFile(testName());
3325 EXPECT_FALSE(path.empty());
3326
3327 // Make sure an asm file was created
3328 std::ifstream fin(path);
3329 EXPECT_TRUE(fin);
3330
3331 // Make sure address of routine is in the file
3332 auto findAddressInFile = [](std::ifstream &fin, size_t address) {
3333 std::string addressString = [&] {
3334 std::stringstream addressSS;
3335 addressSS << "0x" << std::uppercase << std::hex << address;
3336 return addressSS.str();
3337 }();
3338
3339 std::string token;
3340 while(fin >> token)
3341 {
3342 if(token.find(addressString) != std::string::npos)
3343 return true;
3344 }
3345 return false;
3346 };
3347
3348 size_t address = reinterpret_cast<size_t>(routine.getEntry());
3349 EXPECT_TRUE(findAddressInFile(fin, address));
3350
3351 // Delete the file in case subsequent runs generate one with a different sequence number
3352 fin.close();
3353 std::filesystem::remove(path);
3354}
3355#endif
3356
Ben Clayton351be422019-04-30 12:26:57 +01003357////////////////////////////////
3358// Trait compile time checks. //
3359////////////////////////////////
3360
Ben Clayton51f08312019-11-08 14:39:26 +00003361// Assert CToReactorT resolves to expected types.
Ben Clayton713b8d32019-12-17 20:37:56 +00003362static_assert(std::is_same<CToReactorT<void>, Void>::value, "");
3363static_assert(std::is_same<CToReactorT<bool>, Bool>::value, "");
3364static_assert(std::is_same<CToReactorT<uint8_t>, Byte>::value, "");
3365static_assert(std::is_same<CToReactorT<int8_t>, SByte>::value, "");
3366static_assert(std::is_same<CToReactorT<int16_t>, Short>::value, "");
Ben Clayton51f08312019-11-08 14:39:26 +00003367static_assert(std::is_same<CToReactorT<uint16_t>, UShort>::value, "");
Ben Clayton713b8d32019-12-17 20:37:56 +00003368static_assert(std::is_same<CToReactorT<int32_t>, Int>::value, "");
Ben Clayton51f08312019-11-08 14:39:26 +00003369static_assert(std::is_same<CToReactorT<uint64_t>, Long>::value, "");
3370static_assert(std::is_same<CToReactorT<uint32_t>, UInt>::value, "");
Ben Clayton713b8d32019-12-17 20:37:56 +00003371static_assert(std::is_same<CToReactorT<float>, Float>::value, "");
Ben Clayton351be422019-04-30 12:26:57 +01003372
Ben Clayton51f08312019-11-08 14:39:26 +00003373// Assert CToReactorT for known pointer types resolves to expected types.
Ben Clayton713b8d32019-12-17 20:37:56 +00003374static_assert(std::is_same<CToReactorT<void *>, Pointer<Byte>>::value, "");
3375static_assert(std::is_same<CToReactorT<bool *>, Pointer<Bool>>::value, "");
3376static_assert(std::is_same<CToReactorT<uint8_t *>, Pointer<Byte>>::value, "");
3377static_assert(std::is_same<CToReactorT<int8_t *>, Pointer<SByte>>::value, "");
3378static_assert(std::is_same<CToReactorT<int16_t *>, Pointer<Short>>::value, "");
3379static_assert(std::is_same<CToReactorT<uint16_t *>, Pointer<UShort>>::value, "");
3380static_assert(std::is_same<CToReactorT<int32_t *>, Pointer<Int>>::value, "");
3381static_assert(std::is_same<CToReactorT<uint64_t *>, Pointer<Long>>::value, "");
3382static_assert(std::is_same<CToReactorT<uint32_t *>, Pointer<UInt>>::value, "");
3383static_assert(std::is_same<CToReactorT<float *>, Pointer<Float>>::value, "");
3384static_assert(std::is_same<CToReactorT<uint16_t **>, Pointer<Pointer<UShort>>>::value, "");
3385static_assert(std::is_same<CToReactorT<uint16_t ***>, Pointer<Pointer<Pointer<UShort>>>>::value, "");
Ben Clayton351be422019-04-30 12:26:57 +01003386
Ben Clayton51f08312019-11-08 14:39:26 +00003387// Assert CToReactorT for unknown pointer types resolves to Pointer<Byte>.
Ben Clayton713b8d32019-12-17 20:37:56 +00003388struct S
3389{};
3390static_assert(std::is_same<CToReactorT<S *>, Pointer<Byte>>::value, "");
3391static_assert(std::is_same<CToReactorT<S **>, Pointer<Pointer<Byte>>>::value, "");
3392static_assert(std::is_same<CToReactorT<S ***>, Pointer<Pointer<Pointer<Byte>>>>::value, "");
Ben Clayton351be422019-04-30 12:26:57 +01003393
3394// Assert IsRValue<> resolves true for RValue<> types.
3395static_assert(IsRValue<RValue<Void>>::value, "");
3396static_assert(IsRValue<RValue<Bool>>::value, "");
3397static_assert(IsRValue<RValue<Byte>>::value, "");
3398static_assert(IsRValue<RValue<SByte>>::value, "");
3399static_assert(IsRValue<RValue<Short>>::value, "");
3400static_assert(IsRValue<RValue<UShort>>::value, "");
3401static_assert(IsRValue<RValue<Int>>::value, "");
3402static_assert(IsRValue<RValue<Long>>::value, "");
3403static_assert(IsRValue<RValue<UInt>>::value, "");
3404static_assert(IsRValue<RValue<Float>>::value, "");
3405
3406// Assert IsLValue<> resolves true for LValue types.
3407static_assert(IsLValue<Bool>::value, "");
3408static_assert(IsLValue<Byte>::value, "");
3409static_assert(IsLValue<SByte>::value, "");
3410static_assert(IsLValue<Short>::value, "");
3411static_assert(IsLValue<UShort>::value, "");
3412static_assert(IsLValue<Int>::value, "");
3413static_assert(IsLValue<Long>::value, "");
3414static_assert(IsLValue<UInt>::value, "");
3415static_assert(IsLValue<Float>::value, "");
3416
Ben Clayton208ed402019-05-03 22:30:03 +01003417// Assert IsReference<> resolves true for Reference types.
3418static_assert(IsReference<Reference<Bool>>::value, "");
3419static_assert(IsReference<Reference<Byte>>::value, "");
3420static_assert(IsReference<Reference<SByte>>::value, "");
3421static_assert(IsReference<Reference<Short>>::value, "");
3422static_assert(IsReference<Reference<UShort>>::value, "");
3423static_assert(IsReference<Reference<Int>>::value, "");
3424static_assert(IsReference<Reference<Long>>::value, "");
3425static_assert(IsReference<Reference<UInt>>::value, "");
3426static_assert(IsReference<Reference<Float>>::value, "");
3427
Ben Clayton351be422019-04-30 12:26:57 +01003428// Assert IsRValue<> resolves false for LValue types.
3429static_assert(!IsRValue<Void>::value, "");
3430static_assert(!IsRValue<Bool>::value, "");
3431static_assert(!IsRValue<Byte>::value, "");
3432static_assert(!IsRValue<SByte>::value, "");
3433static_assert(!IsRValue<Short>::value, "");
3434static_assert(!IsRValue<UShort>::value, "");
3435static_assert(!IsRValue<Int>::value, "");
3436static_assert(!IsRValue<Long>::value, "");
3437static_assert(!IsRValue<UInt>::value, "");
3438static_assert(!IsRValue<Float>::value, "");
3439
Ben Clayton208ed402019-05-03 22:30:03 +01003440// Assert IsRValue<> resolves false for Reference types.
3441static_assert(!IsRValue<Reference<Void>>::value, "");
3442static_assert(!IsRValue<Reference<Bool>>::value, "");
3443static_assert(!IsRValue<Reference<Byte>>::value, "");
3444static_assert(!IsRValue<Reference<SByte>>::value, "");
3445static_assert(!IsRValue<Reference<Short>>::value, "");
3446static_assert(!IsRValue<Reference<UShort>>::value, "");
3447static_assert(!IsRValue<Reference<Int>>::value, "");
3448static_assert(!IsRValue<Reference<Long>>::value, "");
3449static_assert(!IsRValue<Reference<UInt>>::value, "");
3450static_assert(!IsRValue<Reference<Float>>::value, "");
3451
Ben Clayton351be422019-04-30 12:26:57 +01003452// Assert IsRValue<> resolves false for C types.
3453static_assert(!IsRValue<void>::value, "");
3454static_assert(!IsRValue<bool>::value, "");
3455static_assert(!IsRValue<uint8_t>::value, "");
3456static_assert(!IsRValue<int8_t>::value, "");
3457static_assert(!IsRValue<int16_t>::value, "");
3458static_assert(!IsRValue<uint16_t>::value, "");
3459static_assert(!IsRValue<int32_t>::value, "");
3460static_assert(!IsRValue<uint64_t>::value, "");
3461static_assert(!IsRValue<uint32_t>::value, "");
3462static_assert(!IsRValue<float>::value, "");
3463
3464// Assert IsLValue<> resolves false for RValue<> types.
3465static_assert(!IsLValue<RValue<Void>>::value, "");
3466static_assert(!IsLValue<RValue<Bool>>::value, "");
3467static_assert(!IsLValue<RValue<Byte>>::value, "");
3468static_assert(!IsLValue<RValue<SByte>>::value, "");
3469static_assert(!IsLValue<RValue<Short>>::value, "");
3470static_assert(!IsLValue<RValue<UShort>>::value, "");
3471static_assert(!IsLValue<RValue<Int>>::value, "");
3472static_assert(!IsLValue<RValue<Long>>::value, "");
3473static_assert(!IsLValue<RValue<UInt>>::value, "");
3474static_assert(!IsLValue<RValue<Float>>::value, "");
3475
3476// Assert IsLValue<> resolves false for Void type.
3477static_assert(!IsLValue<Void>::value, "");
3478
Ben Clayton208ed402019-05-03 22:30:03 +01003479// Assert IsLValue<> resolves false for Reference<> types.
3480static_assert(!IsLValue<Reference<Void>>::value, "");
3481static_assert(!IsLValue<Reference<Bool>>::value, "");
3482static_assert(!IsLValue<Reference<Byte>>::value, "");
3483static_assert(!IsLValue<Reference<SByte>>::value, "");
3484static_assert(!IsLValue<Reference<Short>>::value, "");
3485static_assert(!IsLValue<Reference<UShort>>::value, "");
3486static_assert(!IsLValue<Reference<Int>>::value, "");
3487static_assert(!IsLValue<Reference<Long>>::value, "");
3488static_assert(!IsLValue<Reference<UInt>>::value, "");
3489static_assert(!IsLValue<Reference<Float>>::value, "");
3490
Ben Clayton351be422019-04-30 12:26:57 +01003491// Assert IsLValue<> resolves false for C types.
3492static_assert(!IsLValue<void>::value, "");
3493static_assert(!IsLValue<bool>::value, "");
3494static_assert(!IsLValue<uint8_t>::value, "");
3495static_assert(!IsLValue<int8_t>::value, "");
3496static_assert(!IsLValue<int16_t>::value, "");
3497static_assert(!IsLValue<uint16_t>::value, "");
3498static_assert(!IsLValue<int32_t>::value, "");
3499static_assert(!IsLValue<uint64_t>::value, "");
3500static_assert(!IsLValue<uint32_t>::value, "");
3501static_assert(!IsLValue<float>::value, "");
3502
3503// Assert IsDefined<> resolves true for RValue<> types.
3504static_assert(IsDefined<RValue<Void>>::value, "");
3505static_assert(IsDefined<RValue<Bool>>::value, "");
3506static_assert(IsDefined<RValue<Byte>>::value, "");
3507static_assert(IsDefined<RValue<SByte>>::value, "");
3508static_assert(IsDefined<RValue<Short>>::value, "");
3509static_assert(IsDefined<RValue<UShort>>::value, "");
3510static_assert(IsDefined<RValue<Int>>::value, "");
3511static_assert(IsDefined<RValue<Long>>::value, "");
3512static_assert(IsDefined<RValue<UInt>>::value, "");
3513static_assert(IsDefined<RValue<Float>>::value, "");
3514
3515// Assert IsDefined<> resolves true for LValue types.
3516static_assert(IsDefined<Void>::value, "");
3517static_assert(IsDefined<Bool>::value, "");
3518static_assert(IsDefined<Byte>::value, "");
3519static_assert(IsDefined<SByte>::value, "");
3520static_assert(IsDefined<Short>::value, "");
3521static_assert(IsDefined<UShort>::value, "");
3522static_assert(IsDefined<Int>::value, "");
3523static_assert(IsDefined<Long>::value, "");
3524static_assert(IsDefined<UInt>::value, "");
3525static_assert(IsDefined<Float>::value, "");
3526
Ben Clayton208ed402019-05-03 22:30:03 +01003527// Assert IsDefined<> resolves true for Reference<> types.
3528static_assert(IsDefined<Reference<Bool>>::value, "");
3529static_assert(IsDefined<Reference<Byte>>::value, "");
3530static_assert(IsDefined<Reference<SByte>>::value, "");
3531static_assert(IsDefined<Reference<Short>>::value, "");
3532static_assert(IsDefined<Reference<UShort>>::value, "");
3533static_assert(IsDefined<Reference<Int>>::value, "");
3534static_assert(IsDefined<Reference<Long>>::value, "");
3535static_assert(IsDefined<Reference<UInt>>::value, "");
3536static_assert(IsDefined<Reference<Float>>::value, "");
3537
Ben Clayton351be422019-04-30 12:26:57 +01003538// Assert IsDefined<> resolves true for C types.
3539static_assert(IsDefined<void>::value, "");
3540static_assert(IsDefined<bool>::value, "");
3541static_assert(IsDefined<uint8_t>::value, "");
3542static_assert(IsDefined<int8_t>::value, "");
3543static_assert(IsDefined<int16_t>::value, "");
3544static_assert(IsDefined<uint16_t>::value, "");
3545static_assert(IsDefined<int32_t>::value, "");
3546static_assert(IsDefined<uint64_t>::value, "");
3547static_assert(IsDefined<uint32_t>::value, "");
3548static_assert(IsDefined<float>::value, "");