blob: e66611bd76d0922700f6e7946f659912de71b69b [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>
Antonio Maiorano5ba2a5b2020-01-17 15:29:37 -050023#include <thread>
Ben Claytonb1243732019-02-27 23:56:18 +000024#include <tuple>
25
Nicolas Capens48461502018-08-06 14:20:45 -040026using namespace rr;
Nicolas Capens598f8d82016-09-26 15:09:10 -040027
Nicolas Capens7d9f76d2016-09-29 13:39:44 -040028int reference(int *p, int y)
29{
Nicolas Capens8820f642016-09-30 04:42:43 -040030 int x = p[-1];
Nicolas Capens7d9f76d2016-09-29 13:39:44 -040031 int z = 4;
32
33 for(int i = 0; i < 10; i++)
34 {
35 z += (2 << i) - (i / 3);
36 }
37
38 int sum = x + y + z;
Nicolas Capens228b05d2016-10-12 15:27:04 -040039
Nicolas Capens7d9f76d2016-09-29 13:39:44 -040040 return sum;
41}
42
Nicolas Capensc07dc4b2018-08-06 14:20:45 -040043TEST(ReactorUnitTests, Sample)
Nicolas Capens598f8d82016-09-26 15:09:10 -040044{
Ben Clayton713b8d32019-12-17 20:37:56 +000045 FunctionT<int(int *, int)> function;
Nicolas Capens598f8d82016-09-26 15:09:10 -040046 {
Nicolas Capens157ba262019-12-10 17:49:14 -050047 Pointer<Int> p = function.Arg<0>();
48 Int x = p[-1];
49 Int y = function.Arg<1>();
50 Int z = 4;
51
52 For(Int i = 0, i < 10, i++)
Nicolas Capens598f8d82016-09-26 15:09:10 -040053 {
Nicolas Capens157ba262019-12-10 17:49:14 -050054 z += (2 << i) - (i / 3);
Nicolas Capens598f8d82016-09-26 15:09:10 -040055 }
56
Nicolas Capens157ba262019-12-10 17:49:14 -050057 Float4 v;
58 v.z = As<Float>(z);
59 z = As<Int>(Float(Float4(v.xzxx).y));
Nicolas Capens598f8d82016-09-26 15:09:10 -040060
Nicolas Capens157ba262019-12-10 17:49:14 -050061 Int sum = x + y + z;
62
63 Return(sum);
Nicolas Capens598f8d82016-09-26 15:09:10 -040064 }
65
Nicolas Capens157ba262019-12-10 17:49:14 -050066 auto routine = function("one");
67
Nicolas Capensbdf2b722020-01-27 11:33:14 -050068 int one[2] = { 1, 0 };
69 int result = routine(&one[1], 2);
70 EXPECT_EQ(result, reference(&one[1], 2));
Nicolas Capens228b05d2016-10-12 15:27:04 -040071}
Nicolas Capens598f8d82016-09-26 15:09:10 -040072
Nicolas Capensc07dc4b2018-08-06 14:20:45 -040073TEST(ReactorUnitTests, Uninitialized)
Nicolas Capensf4452fc2016-12-12 13:08:06 -050074{
Nicolas Capens157ba262019-12-10 17:49:14 -050075 FunctionT<int()> function;
Nicolas Capensf4452fc2016-12-12 13:08:06 -050076 {
Nicolas Capens157ba262019-12-10 17:49:14 -050077 Int a;
78 Int z = 4;
79 Int q;
80 Int c;
81 Int p;
82 Bool b;
83
84 q += q;
85
86 If(b)
Nicolas Capensf4452fc2016-12-12 13:08:06 -050087 {
Nicolas Capens157ba262019-12-10 17:49:14 -050088 c = p;
Nicolas Capensf4452fc2016-12-12 13:08:06 -050089 }
90
Nicolas Capens157ba262019-12-10 17:49:14 -050091 Return(a + z + q + c);
Nicolas Capensf4452fc2016-12-12 13:08:06 -050092 }
93
Nicolas Capens157ba262019-12-10 17:49:14 -050094 auto routine = function("one");
95
Nicolas Capens4804ac82020-11-02 22:06:55 -050096 if(!__has_feature(memory_sanitizer) || !REACTOR_ENABLE_MEMORY_SANITIZER_INSTRUMENTATION)
97 {
98 int result = routine();
99 EXPECT_EQ(result, result); // Anything is fine, just don't crash
100 }
101 else
102 {
103 // Optimizations may turn the conditional If() in the Reactor code
104 // into a conditional move or arithmetic operations, which would not
105 // trigger a MemorySanitizer error. However, in that case the equals
106 // operator below should trigger it before the abort is reached.
107 EXPECT_DEATH(
108 {
109 int result = routine();
110 if(result == 0) abort();
111 },
112 "MemorySanitizer: use-of-uninitialized-value");
113 }
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500114}
115
Nicolas Capens0192d152019-03-27 14:46:07 -0400116TEST(ReactorUnitTests, Unreachable)
117{
Nicolas Capens157ba262019-12-10 17:49:14 -0500118 FunctionT<int(int)> function;
Nicolas Capens0192d152019-03-27 14:46:07 -0400119 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500120 Int a = function.Arg<0>();
121 Int z = 4;
Nicolas Capens0192d152019-03-27 14:46:07 -0400122
Nicolas Capens157ba262019-12-10 17:49:14 -0500123 Return(a + z);
Nicolas Capens0192d152019-03-27 14:46:07 -0400124
Nicolas Capens157ba262019-12-10 17:49:14 -0500125 // Code beyond this point is unreachable but should not cause any
126 // compilation issues.
Nicolas Capens0192d152019-03-27 14:46:07 -0400127
Nicolas Capens157ba262019-12-10 17:49:14 -0500128 z += a;
Nicolas Capens0192d152019-03-27 14:46:07 -0400129 }
130
Nicolas Capens157ba262019-12-10 17:49:14 -0500131 auto routine = function("one");
132
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500133 int result = routine(16);
134 EXPECT_EQ(result, 20);
Nicolas Capens0192d152019-03-27 14:46:07 -0400135}
136
137TEST(ReactorUnitTests, VariableAddress)
138{
Nicolas Capens157ba262019-12-10 17:49:14 -0500139 FunctionT<int(int)> function;
Nicolas Capens0192d152019-03-27 14:46:07 -0400140 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500141 Int a = function.Arg<0>();
142 Int z = 0;
143 Pointer<Int> p = &z;
144 *p = 4;
Nicolas Capens0192d152019-03-27 14:46:07 -0400145
Nicolas Capens157ba262019-12-10 17:49:14 -0500146 Return(a + z);
Nicolas Capens0192d152019-03-27 14:46:07 -0400147 }
148
Nicolas Capens157ba262019-12-10 17:49:14 -0500149 auto routine = function("one");
150
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500151 int result = routine(16);
152 EXPECT_EQ(result, 20);
Nicolas Capens0192d152019-03-27 14:46:07 -0400153}
154
Nicolas Capensc07dc4b2018-08-06 14:20:45 -0400155TEST(ReactorUnitTests, SubVectorLoadStore)
Nicolas Capens23d99a42016-09-30 14:57:16 -0400156{
Ben Clayton713b8d32019-12-17 20:37:56 +0000157 FunctionT<int(void *, void *)> function;
Nicolas Capens23d99a42016-09-30 14:57:16 -0400158 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500159 Pointer<Byte> in = function.Arg<0>();
160 Pointer<Byte> out = function.Arg<1>();
161
Ben Clayton713b8d32019-12-17 20:37:56 +0000162 *Pointer<Int4>(out + 16 * 0) = *Pointer<Int4>(in + 16 * 0);
Nicolas Capens157ba262019-12-10 17:49:14 -0500163 *Pointer<Short4>(out + 16 * 1) = *Pointer<Short4>(in + 16 * 1);
Ben Clayton713b8d32019-12-17 20:37:56 +0000164 *Pointer<Byte8>(out + 16 * 2) = *Pointer<Byte8>(in + 16 * 2);
165 *Pointer<Byte4>(out + 16 * 3) = *Pointer<Byte4>(in + 16 * 3);
Nicolas Capens157ba262019-12-10 17:49:14 -0500166 *Pointer<Short2>(out + 16 * 4) = *Pointer<Short2>(in + 16 * 4);
167
168 Return(0);
169 }
170
171 auto routine = function("one");
172
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500173 int8_t in[16 * 5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
174 17, 18, 19, 20, 21, 22, 23, 24, 0, 0, 0, 0, 0, 0, 0, 0,
175 25, 26, 27, 28, 29, 30, 31, 32, 0, 0, 0, 0, 0, 0, 0, 0,
176 33, 34, 35, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
177 37, 38, 39, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
178
179 int8_t out[16 * 5] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
180 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
181 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
182 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
183 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
184
185 routine(in, out);
186
187 for(int row = 0; row < 5; row++)
Nicolas Capens157ba262019-12-10 17:49:14 -0500188 {
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500189 for(int col = 0; col < 16; col++)
Nicolas Capens23d99a42016-09-30 14:57:16 -0400190 {
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500191 int i = row * 16 + col;
Nicolas Capens23d99a42016-09-30 14:57:16 -0400192
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500193 if(in[i] == 0)
194 {
195 EXPECT_EQ(out[i], -1) << "Row " << row << " column " << col << " not left untouched.";
196 }
197 else
198 {
199 EXPECT_EQ(out[i], in[i]) << "Row " << row << " column " << col << " not equal to input.";
Nicolas Capens23d99a42016-09-30 14:57:16 -0400200 }
201 }
202 }
Nicolas Capens23d99a42016-09-30 14:57:16 -0400203}
204
Nicolas Capensc07dc4b2018-08-06 14:20:45 -0400205TEST(ReactorUnitTests, VectorConstant)
Nicolas Capens8dfd9a72016-10-13 17:44:51 -0400206{
Ben Clayton713b8d32019-12-17 20:37:56 +0000207 FunctionT<int(void *)> function;
Nicolas Capens8dfd9a72016-10-13 17:44:51 -0400208 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500209 Pointer<Byte> out = function.Arg<0>();
210
211 *Pointer<Int4>(out + 16 * 0) = Int4(0x04030201, 0x08070605, 0x0C0B0A09, 0x100F0E0D);
212 *Pointer<Short4>(out + 16 * 1) = Short4(0x1211, 0x1413, 0x1615, 0x1817);
213 *Pointer<Byte8>(out + 16 * 2) = Byte8(0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20);
214 *Pointer<Int2>(out + 16 * 3) = Int2(0x24232221, 0x28272625);
215
216 Return(0);
217 }
218
219 auto routine = function("one");
220
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500221 int8_t out[16 * 4] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
222 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
223 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
224 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
225
226 int8_t exp[16 * 4] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
227 17, 18, 19, 20, 21, 22, 23, 24, -1, -1, -1, -1, -1, -1, -1, -1,
228 25, 26, 27, 28, 29, 30, 31, 32, -1, -1, -1, -1, -1, -1, -1, -1,
229 33, 34, 35, 36, 37, 38, 39, 40, -1, -1, -1, -1, -1, -1, -1, -1 };
230
231 routine(out);
232
233 for(int row = 0; row < 4; row++)
Nicolas Capens157ba262019-12-10 17:49:14 -0500234 {
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500235 for(int col = 0; col < 16; col++)
Nicolas Capens8dfd9a72016-10-13 17:44:51 -0400236 {
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500237 int i = row * 16 + col;
Nicolas Capens8dfd9a72016-10-13 17:44:51 -0400238
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500239 EXPECT_EQ(out[i], exp[i]);
Nicolas Capens8dfd9a72016-10-13 17:44:51 -0400240 }
241 }
Nicolas Capens8dfd9a72016-10-13 17:44:51 -0400242}
243
Nicolas Capensc07dc4b2018-08-06 14:20:45 -0400244TEST(ReactorUnitTests, Concatenate)
Nicolas Capensc70a1162016-12-03 00:16:14 -0500245{
Ben Clayton713b8d32019-12-17 20:37:56 +0000246 FunctionT<int(void *)> function;
Nicolas Capensc70a1162016-12-03 00:16:14 -0500247 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500248 Pointer<Byte> out = function.Arg<0>();
249
Ben Clayton713b8d32019-12-17 20:37:56 +0000250 *Pointer<Int4>(out + 16 * 0) = Int4(Int2(0x04030201, 0x08070605), Int2(0x0C0B0A09, 0x100F0E0D));
Nicolas Capens157ba262019-12-10 17:49:14 -0500251 *Pointer<Short8>(out + 16 * 1) = Short8(Short4(0x0201, 0x0403, 0x0605, 0x0807), Short4(0x0A09, 0x0C0B, 0x0E0D, 0x100F));
252
253 Return(0);
254 }
255
256 auto routine = function("one");
257
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500258 int8_t ref[16 * 5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
259 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
260
261 int8_t out[16 * 5] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
262 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
263
264 routine(out);
265
266 for(int row = 0; row < 2; row++)
Nicolas Capens157ba262019-12-10 17:49:14 -0500267 {
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500268 for(int col = 0; col < 16; col++)
Nicolas Capensc70a1162016-12-03 00:16:14 -0500269 {
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500270 int i = row * 16 + col;
Nicolas Capensc70a1162016-12-03 00:16:14 -0500271
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500272 EXPECT_EQ(out[i], ref[i]) << "Row " << row << " column " << col << " not equal to reference.";
Nicolas Capensc70a1162016-12-03 00:16:14 -0500273 }
274 }
Nicolas Capensc70a1162016-12-03 00:16:14 -0500275}
276
Nicolas Capens133b87d2020-01-25 16:26:28 -0500277TEST(ReactorUnitTests, Cast)
278{
279 FunctionT<void(void *)> function;
280 {
281 Pointer<Byte> out = function.Arg<0>();
282
283 Int4 c = Int4(0x01020304, 0x05060708, 0x09101112, 0x13141516);
284 *Pointer<Short4>(out + 16 * 0) = Short4(c);
285 *Pointer<Byte4>(out + 16 * 1 + 0) = Byte4(c);
286 *Pointer<Byte4>(out + 16 * 1 + 4) = Byte4(As<Byte8>(c));
287 *Pointer<Byte4>(out + 16 * 1 + 8) = Byte4(As<Short4>(c));
288 }
289
290 auto routine = function("one");
291
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500292 int out[2][4];
Nicolas Capens133b87d2020-01-25 16:26:28 -0500293
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500294 memset(&out, 0, sizeof(out));
Nicolas Capens133b87d2020-01-25 16:26:28 -0500295
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500296 routine(&out);
Nicolas Capens133b87d2020-01-25 16:26:28 -0500297
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500298 EXPECT_EQ(out[0][0], 0x07080304);
299 EXPECT_EQ(out[0][1], 0x15161112);
Nicolas Capens133b87d2020-01-25 16:26:28 -0500300
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500301 EXPECT_EQ(out[1][0], 0x16120804);
302 EXPECT_EQ(out[1][1], 0x01020304);
303 EXPECT_EQ(out[1][2], 0x06080204);
Nicolas Capens133b87d2020-01-25 16:26:28 -0500304}
305
306static uint16_t swizzleCode4(int i)
307{
308 auto x = (i >> 0) & 0x03;
309 auto y = (i >> 2) & 0x03;
310 auto z = (i >> 4) & 0x03;
311 auto w = (i >> 6) & 0x03;
312 return static_cast<uint16_t>((x << 12) | (y << 8) | (z << 4) | (w << 0));
313}
314
315TEST(ReactorUnitTests, Swizzle4)
316{
317 FunctionT<void(void *)> function;
318 {
319 Pointer<Byte> out = function.Arg<0>();
320
321 for(int i = 0; i < 256; i++)
322 {
323 *Pointer<Float4>(out + 16 * i) = Swizzle(Float4(1.0f, 2.0f, 3.0f, 4.0f), swizzleCode4(i));
324 }
325
326 for(int i = 0; i < 256; i++)
327 {
328 *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));
329 }
330
331 *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));
332 *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));
333 *Pointer<Int2>(out + 16 * (512 + 2)) = UnpackLow(Short4(1, 2, 3, 4), Short4(5, 6, 7, 8));
334 *Pointer<Int2>(out + 16 * (512 + 3)) = UnpackHigh(Short4(1, 2, 3, 4), Short4(5, 6, 7, 8));
335 *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));
336 *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));
337
338 for(int i = 0; i < 256; i++)
339 {
340 *Pointer<Short4>(out + 16 * (512 + 6) + (8 * i)) =
341 Swizzle(Short4(1, 2, 3, 4), swizzleCode4(i));
342 }
343
344 for(int i = 0; i < 256; i++)
345 {
346 *Pointer<Int4>(out + 16 * (512 + 6 + i) + (8 * 256)) =
347 Swizzle(Int4(1, 2, 3, 4), swizzleCode4(i));
348 }
349 }
350
351 auto routine = function("one");
352
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500353 struct
Nicolas Capens133b87d2020-01-25 16:26:28 -0500354 {
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500355 float f[256 + 256 + 2][4];
356 int i[388][4];
357 } out;
Nicolas Capens133b87d2020-01-25 16:26:28 -0500358
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500359 memset(&out, 0, sizeof(out));
Nicolas Capens133b87d2020-01-25 16:26:28 -0500360
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500361 routine(&out);
Nicolas Capens133b87d2020-01-25 16:26:28 -0500362
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500363 for(int i = 0; i < 256; i++)
364 {
365 EXPECT_EQ(out.f[i][0], float((i >> 0) & 0x03) + 1.0f);
366 EXPECT_EQ(out.f[i][1], float((i >> 2) & 0x03) + 1.0f);
367 EXPECT_EQ(out.f[i][2], float((i >> 4) & 0x03) + 1.0f);
368 EXPECT_EQ(out.f[i][3], float((i >> 6) & 0x03) + 1.0f);
369 }
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[256 + i][0], float((i >> 0) & 0x03) + 1.0f);
374 EXPECT_EQ(out.f[256 + i][1], float((i >> 2) & 0x03) + 1.0f);
375 EXPECT_EQ(out.f[256 + i][2], float((i >> 4) & 0x03) + 5.0f);
376 EXPECT_EQ(out.f[256 + i][3], float((i >> 6) & 0x03) + 5.0f);
377 }
Nicolas Capens133b87d2020-01-25 16:26:28 -0500378
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500379 EXPECT_EQ(out.f[512 + 0][0], 1.0f);
380 EXPECT_EQ(out.f[512 + 0][1], 5.0f);
381 EXPECT_EQ(out.f[512 + 0][2], 2.0f);
382 EXPECT_EQ(out.f[512 + 0][3], 6.0f);
Nicolas Capens133b87d2020-01-25 16:26:28 -0500383
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500384 EXPECT_EQ(out.f[512 + 1][0], 3.0f);
385 EXPECT_EQ(out.f[512 + 1][1], 7.0f);
386 EXPECT_EQ(out.f[512 + 1][2], 4.0f);
387 EXPECT_EQ(out.f[512 + 1][3], 8.0f);
Nicolas Capens133b87d2020-01-25 16:26:28 -0500388
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500389 EXPECT_EQ(out.i[0][0], 0x00050001);
390 EXPECT_EQ(out.i[0][1], 0x00060002);
391 EXPECT_EQ(out.i[0][2], 0x00000000);
392 EXPECT_EQ(out.i[0][3], 0x00000000);
Nicolas Capens133b87d2020-01-25 16:26:28 -0500393
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500394 EXPECT_EQ(out.i[1][0], 0x00070003);
395 EXPECT_EQ(out.i[1][1], 0x00080004);
396 EXPECT_EQ(out.i[1][2], 0x00000000);
397 EXPECT_EQ(out.i[1][3], 0x00000000);
Nicolas Capens133b87d2020-01-25 16:26:28 -0500398
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500399 EXPECT_EQ(out.i[2][0], 0x0A020901);
400 EXPECT_EQ(out.i[2][1], 0x0C040B03);
401 EXPECT_EQ(out.i[2][2], 0x00000000);
402 EXPECT_EQ(out.i[2][3], 0x00000000);
Nicolas Capens133b87d2020-01-25 16:26:28 -0500403
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500404 EXPECT_EQ(out.i[3][0], 0x0E060D05);
405 EXPECT_EQ(out.i[3][1], 0x10080F07);
406 EXPECT_EQ(out.i[3][2], 0x00000000);
407 EXPECT_EQ(out.i[3][3], 0x00000000);
Nicolas Capens133b87d2020-01-25 16:26:28 -0500408
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500409 for(int i = 0; i < 256; i++)
410 {
411 EXPECT_EQ(out.i[4 + i / 2][0 + (i % 2) * 2] & 0xFFFF,
412 ((i >> 0) & 0x03) + 1);
413 EXPECT_EQ(out.i[4 + i / 2][0 + (i % 2) * 2] >> 16,
414 ((i >> 2) & 0x03) + 1);
415 EXPECT_EQ(out.i[4 + i / 2][1 + (i % 2) * 2] & 0xFFFF,
416 ((i >> 4) & 0x03) + 1);
417 EXPECT_EQ(out.i[4 + i / 2][1 + (i % 2) * 2] >> 16,
418 ((i >> 6) & 0x03) + 1);
419 }
Nicolas Capens133b87d2020-01-25 16:26:28 -0500420
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500421 for(int i = 0; i < 256; i++)
422 {
423 EXPECT_EQ(out.i[132 + i][0], ((i >> 0) & 0x03) + 1);
424 EXPECT_EQ(out.i[132 + i][1], ((i >> 2) & 0x03) + 1);
425 EXPECT_EQ(out.i[132 + i][2], ((i >> 4) & 0x03) + 1);
426 EXPECT_EQ(out.i[132 + i][3], ((i >> 6) & 0x03) + 1);
Nicolas Capens133b87d2020-01-25 16:26:28 -0500427 }
428}
429
Nicolas Capensc07dc4b2018-08-06 14:20:45 -0400430TEST(ReactorUnitTests, Swizzle)
Nicolas Capens363b61e2016-10-21 13:19:34 -0400431{
Nicolas Capens133b87d2020-01-25 16:26:28 -0500432 FunctionT<void(void *)> function;
Nicolas Capens363b61e2016-10-21 13:19:34 -0400433 {
Nicolas Capens133b87d2020-01-25 16:26:28 -0500434 Pointer<Byte> out = function.Arg<0>();
Nicolas Capens363b61e2016-10-21 13:19:34 -0400435
Nicolas Capens133b87d2020-01-25 16:26:28 -0500436 Int4 c = Int4(0x01020304, 0x05060708, 0x09101112, 0x13141516);
437 *Pointer<Byte16>(out + 16 * 0) = Swizzle(As<Byte16>(c), 0xFEDCBA9876543210ull);
438 *Pointer<Byte8>(out + 16 * 1) = Swizzle(As<Byte8>(c), 0x76543210u);
439 *Pointer<UShort8>(out + 16 * 2) = Swizzle(As<UShort8>(c), 0x76543210u);
440 }
Nicolas Capens363b61e2016-10-21 13:19:34 -0400441
Nicolas Capens133b87d2020-01-25 16:26:28 -0500442 auto routine = function("one");
Nicolas Capens363b61e2016-10-21 13:19:34 -0400443
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500444 int out[3][4];
Nicolas Capens363b61e2016-10-21 13:19:34 -0400445
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500446 memset(&out, 0, sizeof(out));
Casey Dahlin9d56da22017-10-03 13:23:11 -0700447
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500448 routine(&out);
Casey Dahlin9d56da22017-10-03 13:23:11 -0700449
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500450 EXPECT_EQ(out[0][0], 0x16151413);
451 EXPECT_EQ(out[0][1], 0x12111009);
452 EXPECT_EQ(out[0][2], 0x08070605);
453 EXPECT_EQ(out[0][3], 0x04030201);
Nicolas Capens363b61e2016-10-21 13:19:34 -0400454
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500455 EXPECT_EQ(out[1][0], 0x08070605);
456 EXPECT_EQ(out[1][1], 0x04030201);
Nicolas Capens363b61e2016-10-21 13:19:34 -0400457
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500458 EXPECT_EQ(out[2][0], 0x15161314);
459 EXPECT_EQ(out[2][1], 0x11120910);
460 EXPECT_EQ(out[2][2], 0x07080506);
461 EXPECT_EQ(out[2][3], 0x03040102);
Nicolas Capens363b61e2016-10-21 13:19:34 -0400462}
463
Nicolas Capense5720882020-01-13 14:10:04 -0500464TEST(ReactorUnitTests, Shuffle)
David 'Digit' Turnerb9f03f42019-12-04 19:32:34 +0100465{
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500466 // |select| is [0aaa:0bbb:0ccc:0ddd] where |aaa|, |bbb|, |ccc|
467 // and |ddd| are 7-bit selection indices. For a total (1 << 12)
468 // possibilities.
469 const int kSelectRange = 1 << 12;
470
471 // Unfortunately, testing the whole kSelectRange results in a test
472 // that is far too slow to run, because LLVM spends exponentially more
473 // time optimizing the function below as the number of test cases
474 // increases.
475 //
476 // To work-around the problem, only test a subset of the range by
477 // skipping every kRangeIncrement value.
478 //
479 // Set this value to 1 if you want to test the whole implementation,
480 // which will take a little less than 2 minutes on a fast workstation.
481 //
482 // The default value here takes about 1390ms, which is a little more than
483 // what the Swizzle test takes (993 ms) on my machine. A non-power-of-2
484 // value ensures a better spread over possible values.
485 const int kRangeIncrement = 11;
486
487 auto rangeIndexToSelect = [](int i) {
488 return static_cast<unsigned short>(
489 (((i >> 9) & 7) << 0) |
490 (((i >> 6) & 7) << 4) |
491 (((i >> 3) & 7) << 8) |
492 (((i >> 0) & 7) << 12));
493 };
494
495 FunctionT<int(void *)> function;
David 'Digit' Turnerb9f03f42019-12-04 19:32:34 +0100496 {
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500497 Pointer<Byte> out = function.Arg<0>();
David 'Digit' Turnerb9f03f42019-12-04 19:32:34 +0100498
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500499 for(int i = 0; i < kSelectRange; i += kRangeIncrement)
David 'Digit' Turnerb9f03f42019-12-04 19:32:34 +0100500 {
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500501 unsigned short select = rangeIndexToSelect(i);
David 'Digit' Turnerb9f03f42019-12-04 19:32:34 +0100502
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500503 *Pointer<Float4>(out + 16 * i) = Shuffle(Float4(1.0f, 2.0f, 3.0f, 4.0f),
504 Float4(5.0f, 6.0f, 7.0f, 8.0f),
505 select);
David 'Digit' Turnerb9f03f42019-12-04 19:32:34 +0100506
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500507 *Pointer<Int4>(out + (kSelectRange + i) * 16) = Shuffle(Int4(10, 11, 12, 13),
508 Int4(14, 15, 16, 17),
509 select);
David 'Digit' Turnerb9f03f42019-12-04 19:32:34 +0100510
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500511 *Pointer<UInt4>(out + (2 * kSelectRange + i) * 16) = Shuffle(UInt4(100, 101, 102, 103),
512 UInt4(104, 105, 106, 107),
513 select);
David 'Digit' Turnerb9f03f42019-12-04 19:32:34 +0100514 }
515
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500516 Return(0);
517 }
David 'Digit' Turnerb9f03f42019-12-04 19:32:34 +0100518
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500519 auto routine = function("one");
David 'Digit' Turnerb9f03f42019-12-04 19:32:34 +0100520
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500521 struct
522 {
523 float f[kSelectRange][4];
524 int i[kSelectRange][4];
525 unsigned u[kSelectRange][4];
526 } out;
David 'Digit' Turnerb9f03f42019-12-04 19:32:34 +0100527
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500528 memset(&out, 0, sizeof(out));
David 'Digit' Turnerb9f03f42019-12-04 19:32:34 +0100529
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500530 routine(&out);
David 'Digit' Turnerb9f03f42019-12-04 19:32:34 +0100531
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500532 for(int i = 0; i < kSelectRange; i += kRangeIncrement)
533 {
534 EXPECT_EQ(out.f[i][0], float(1.0f + (i & 7)));
535 EXPECT_EQ(out.f[i][1], float(1.0f + ((i >> 3) & 7)));
536 EXPECT_EQ(out.f[i][2], float(1.0f + ((i >> 6) & 7)));
537 EXPECT_EQ(out.f[i][3], float(1.0f + ((i >> 9) & 7)));
538 }
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.i[i][0], int(10 + (i & 7)));
543 EXPECT_EQ(out.i[i][1], int(10 + ((i >> 3) & 7)));
544 EXPECT_EQ(out.i[i][2], int(10 + ((i >> 6) & 7)));
545 EXPECT_EQ(out.i[i][3], int(10 + ((i >> 9) & 7)));
546 }
547
548 for(int i = 0; i < kSelectRange; i += kRangeIncrement)
549 {
550 EXPECT_EQ(out.u[i][0], unsigned(100 + (i & 7)));
551 EXPECT_EQ(out.u[i][1], unsigned(100 + ((i >> 3) & 7)));
552 EXPECT_EQ(out.u[i][2], unsigned(100 + ((i >> 6) & 7)));
553 EXPECT_EQ(out.u[i][3], unsigned(100 + ((i >> 9) & 7)));
David 'Digit' Turnerb9f03f42019-12-04 19:32:34 +0100554 }
David 'Digit' Turnerb9f03f42019-12-04 19:32:34 +0100555}
556
Nicolas Capensc07dc4b2018-08-06 14:20:45 -0400557TEST(ReactorUnitTests, Branching)
Nicolas Capens9ed1a182016-10-24 09:52:23 -0400558{
Nicolas Capens157ba262019-12-10 17:49:14 -0500559 FunctionT<int()> function;
Nicolas Capens9ed1a182016-10-24 09:52:23 -0400560 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500561 Int x = 0;
562
563 For(Int i = 0, i < 8, i++)
Nicolas Capens9ed1a182016-10-24 09:52:23 -0400564 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500565 If(i < 2)
Nicolas Capens9ed1a182016-10-24 09:52:23 -0400566 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500567 x += 1;
568 }
569 Else If(i < 4)
570 {
571 x += 10;
572 }
573 Else If(i < 6)
574 {
575 x += 100;
576 }
577 Else
578 {
579 x += 1000;
Nicolas Capens9ed1a182016-10-24 09:52:23 -0400580 }
581
Nicolas Capens157ba262019-12-10 17:49:14 -0500582 For(Int i = 0, i < 5, i++)
Ben Clayton713b8d32019-12-17 20:37:56 +0000583 x += 10000;
Nicolas Capens157ba262019-12-10 17:49:14 -0500584 }
Nicolas Capensb0eb3772016-10-24 17:49:13 -0400585
Ben Clayton713b8d32019-12-17 20:37:56 +0000586 For(Int i = 0, i < 10, i++) for(int i = 0; i < 10; i++)
587 For(Int i = 0, i < 10, i++)
588 {
589 x += 1000000;
590 }
Nicolas Capens9ed1a182016-10-24 09:52:23 -0400591
Nicolas Capens157ba262019-12-10 17:49:14 -0500592 For(Int i = 0, i < 2, i++)
Ben Clayton713b8d32019-12-17 20:37:56 +0000593 If(x == 1000402222)
594 {
595 If(x != 1000402222)
596 x += 1000000000;
597 }
598 Else
599 x = -5;
Nicolas Capens9ed1a182016-10-24 09:52:23 -0400600
Nicolas Capens157ba262019-12-10 17:49:14 -0500601 Return(x);
602 }
Nicolas Capens9ed1a182016-10-24 09:52:23 -0400603
Nicolas Capens157ba262019-12-10 17:49:14 -0500604 auto routine = function("one");
Nicolas Capens9ed1a182016-10-24 09:52:23 -0400605
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500606 int result = routine();
Nicolas Capens157ba262019-12-10 17:49:14 -0500607
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500608 EXPECT_EQ(result, 1000402222);
Nicolas Capens9ed1a182016-10-24 09:52:23 -0400609}
610
Nicolas Capensc07dc4b2018-08-06 14:20:45 -0400611TEST(ReactorUnitTests, MinMax)
Nicolas Capens53a8a3f2016-10-26 00:23:12 -0400612{
Ben Clayton713b8d32019-12-17 20:37:56 +0000613 FunctionT<int(void *)> function;
Nicolas Capens53a8a3f2016-10-26 00:23:12 -0400614 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500615 Pointer<Byte> out = function.Arg<0>();
Nicolas Capens53a8a3f2016-10-26 00:23:12 -0400616
Nicolas Capens157ba262019-12-10 17:49:14 -0500617 *Pointer<Float4>(out + 16 * 0) = Min(Float4(1.0f, 0.0f, -0.0f, +0.0f), Float4(0.0f, 1.0f, +0.0f, -0.0f));
618 *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 -0400619
Nicolas Capens157ba262019-12-10 17:49:14 -0500620 *Pointer<Int4>(out + 16 * 2) = Min(Int4(1, 0, -1, -0), Int4(0, 1, 0, +0));
621 *Pointer<Int4>(out + 16 * 3) = Max(Int4(1, 0, -1, -0), Int4(0, 1, 0, +0));
622 *Pointer<UInt4>(out + 16 * 4) = Min(UInt4(1, 0, -1, -0), UInt4(0, 1, 0, +0));
623 *Pointer<UInt4>(out + 16 * 5) = Max(UInt4(1, 0, -1, -0), UInt4(0, 1, 0, +0));
Nicolas Capens53a8a3f2016-10-26 00:23:12 -0400624
Nicolas Capens157ba262019-12-10 17:49:14 -0500625 *Pointer<Short4>(out + 16 * 6) = Min(Short4(1, 0, -1, -0), Short4(0, 1, 0, +0));
626 *Pointer<Short4>(out + 16 * 7) = Max(Short4(1, 0, -1, -0), Short4(0, 1, 0, +0));
627 *Pointer<UShort4>(out + 16 * 8) = Min(UShort4(1, 0, -1, -0), UShort4(0, 1, 0, +0));
628 *Pointer<UShort4>(out + 16 * 9) = Max(UShort4(1, 0, -1, -0), UShort4(0, 1, 0, +0));
Nicolas Capens53a8a3f2016-10-26 00:23:12 -0400629
Nicolas Capens157ba262019-12-10 17:49:14 -0500630 Return(0);
Nicolas Capens53a8a3f2016-10-26 00:23:12 -0400631 }
632
Nicolas Capens157ba262019-12-10 17:49:14 -0500633 auto routine = function("one");
634
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500635 unsigned int out[10][4];
Nicolas Capens157ba262019-12-10 17:49:14 -0500636
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500637 memset(&out, 0, sizeof(out));
Nicolas Capens157ba262019-12-10 17:49:14 -0500638
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500639 routine(&out);
Nicolas Capens157ba262019-12-10 17:49:14 -0500640
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500641 EXPECT_EQ(out[0][0], 0x00000000u);
642 EXPECT_EQ(out[0][1], 0x00000000u);
643 EXPECT_EQ(out[0][2], 0x00000000u);
644 EXPECT_EQ(out[0][3], 0x80000000u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500645
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500646 EXPECT_EQ(out[1][0], 0x3F800000u);
647 EXPECT_EQ(out[1][1], 0x3F800000u);
648 EXPECT_EQ(out[1][2], 0x00000000u);
649 EXPECT_EQ(out[1][3], 0x80000000u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500650
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500651 EXPECT_EQ(out[2][0], 0x00000000u);
652 EXPECT_EQ(out[2][1], 0x00000000u);
653 EXPECT_EQ(out[2][2], 0xFFFFFFFFu);
654 EXPECT_EQ(out[2][3], 0x00000000u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500655
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500656 EXPECT_EQ(out[3][0], 0x00000001u);
657 EXPECT_EQ(out[3][1], 0x00000001u);
658 EXPECT_EQ(out[3][2], 0x00000000u);
659 EXPECT_EQ(out[3][3], 0x00000000u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500660
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500661 EXPECT_EQ(out[4][0], 0x00000000u);
662 EXPECT_EQ(out[4][1], 0x00000000u);
663 EXPECT_EQ(out[4][2], 0x00000000u);
664 EXPECT_EQ(out[4][3], 0x00000000u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500665
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500666 EXPECT_EQ(out[5][0], 0x00000001u);
667 EXPECT_EQ(out[5][1], 0x00000001u);
668 EXPECT_EQ(out[5][2], 0xFFFFFFFFu);
669 EXPECT_EQ(out[5][3], 0x00000000u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500670
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500671 EXPECT_EQ(out[6][0], 0x00000000u);
672 EXPECT_EQ(out[6][1], 0x0000FFFFu);
673 EXPECT_EQ(out[6][2], 0x00000000u);
674 EXPECT_EQ(out[6][3], 0x00000000u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500675
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500676 EXPECT_EQ(out[7][0], 0x00010001u);
677 EXPECT_EQ(out[7][1], 0x00000000u);
678 EXPECT_EQ(out[7][2], 0x00000000u);
679 EXPECT_EQ(out[7][3], 0x00000000u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500680
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500681 EXPECT_EQ(out[8][0], 0x00000000u);
682 EXPECT_EQ(out[8][1], 0x00000000u);
683 EXPECT_EQ(out[8][2], 0x00000000u);
684 EXPECT_EQ(out[8][3], 0x00000000u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500685
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500686 EXPECT_EQ(out[9][0], 0x00010001u);
687 EXPECT_EQ(out[9][1], 0x0000FFFFu);
688 EXPECT_EQ(out[9][2], 0x00000000u);
689 EXPECT_EQ(out[9][3], 0x00000000u);
Nicolas Capens53a8a3f2016-10-26 00:23:12 -0400690}
691
Nicolas Capensc07dc4b2018-08-06 14:20:45 -0400692TEST(ReactorUnitTests, NotNeg)
Nicolas Capensc5c0c332016-11-08 11:37:01 -0500693{
Ben Clayton713b8d32019-12-17 20:37:56 +0000694 FunctionT<int(void *)> function;
Nicolas Capensc5c0c332016-11-08 11:37:01 -0500695 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500696 Pointer<Byte> out = function.Arg<0>();
Nicolas Capensc5c0c332016-11-08 11:37:01 -0500697
Nicolas Capens157ba262019-12-10 17:49:14 -0500698 *Pointer<Int>(out + 16 * 0) = ~Int(0x55555555);
699 *Pointer<Short>(out + 16 * 1) = ~Short(0x5555);
700 *Pointer<Int4>(out + 16 * 2) = ~Int4(0x55555555, 0xAAAAAAAA, 0x00000000, 0xFFFFFFFF);
701 *Pointer<Short4>(out + 16 * 3) = ~Short4(0x5555, 0xAAAA, 0x0000, 0xFFFF);
Nicolas Capensc5c0c332016-11-08 11:37:01 -0500702
Nicolas Capens157ba262019-12-10 17:49:14 -0500703 *Pointer<Int>(out + 16 * 4) = -Int(0x55555555);
704 *Pointer<Short>(out + 16 * 5) = -Short(0x5555);
705 *Pointer<Int4>(out + 16 * 6) = -Int4(0x55555555, 0xAAAAAAAA, 0x00000000, 0xFFFFFFFF);
706 *Pointer<Short4>(out + 16 * 7) = -Short4(0x5555, 0xAAAA, 0x0000, 0xFFFF);
Nicolas Capensc5c0c332016-11-08 11:37:01 -0500707
Nicolas Capens157ba262019-12-10 17:49:14 -0500708 *Pointer<Float4>(out + 16 * 8) = -Float4(1.0f, -1.0f, 0.0f, -0.0f);
Nicolas Capensc5c0c332016-11-08 11:37:01 -0500709
Nicolas Capens157ba262019-12-10 17:49:14 -0500710 Return(0);
Nicolas Capensc5c0c332016-11-08 11:37:01 -0500711 }
712
Nicolas Capens157ba262019-12-10 17:49:14 -0500713 auto routine = function("one");
714
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500715 unsigned int out[10][4];
Nicolas Capens157ba262019-12-10 17:49:14 -0500716
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500717 memset(&out, 0, sizeof(out));
Nicolas Capens157ba262019-12-10 17:49:14 -0500718
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500719 routine(&out);
Nicolas Capens157ba262019-12-10 17:49:14 -0500720
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500721 EXPECT_EQ(out[0][0], 0xAAAAAAAAu);
722 EXPECT_EQ(out[0][1], 0x00000000u);
723 EXPECT_EQ(out[0][2], 0x00000000u);
724 EXPECT_EQ(out[0][3], 0x00000000u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500725
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500726 EXPECT_EQ(out[1][0], 0x0000AAAAu);
727 EXPECT_EQ(out[1][1], 0x00000000u);
728 EXPECT_EQ(out[1][2], 0x00000000u);
729 EXPECT_EQ(out[1][3], 0x00000000u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500730
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500731 EXPECT_EQ(out[2][0], 0xAAAAAAAAu);
732 EXPECT_EQ(out[2][1], 0x55555555u);
733 EXPECT_EQ(out[2][2], 0xFFFFFFFFu);
734 EXPECT_EQ(out[2][3], 0x00000000u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500735
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500736 EXPECT_EQ(out[3][0], 0x5555AAAAu);
737 EXPECT_EQ(out[3][1], 0x0000FFFFu);
738 EXPECT_EQ(out[3][2], 0x00000000u);
739 EXPECT_EQ(out[3][3], 0x00000000u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500740
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500741 EXPECT_EQ(out[4][0], 0xAAAAAAABu);
742 EXPECT_EQ(out[4][1], 0x00000000u);
743 EXPECT_EQ(out[4][2], 0x00000000u);
744 EXPECT_EQ(out[4][3], 0x00000000u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500745
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500746 EXPECT_EQ(out[5][0], 0x0000AAABu);
747 EXPECT_EQ(out[5][1], 0x00000000u);
748 EXPECT_EQ(out[5][2], 0x00000000u);
749 EXPECT_EQ(out[5][3], 0x00000000u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500750
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500751 EXPECT_EQ(out[6][0], 0xAAAAAAABu);
752 EXPECT_EQ(out[6][1], 0x55555556u);
753 EXPECT_EQ(out[6][2], 0x00000000u);
754 EXPECT_EQ(out[6][3], 0x00000001u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500755
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500756 EXPECT_EQ(out[7][0], 0x5556AAABu);
757 EXPECT_EQ(out[7][1], 0x00010000u);
758 EXPECT_EQ(out[7][2], 0x00000000u);
759 EXPECT_EQ(out[7][3], 0x00000000u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500760
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500761 EXPECT_EQ(out[8][0], 0xBF800000u);
762 EXPECT_EQ(out[8][1], 0x3F800000u);
763 EXPECT_EQ(out[8][2], 0x80000000u);
764 EXPECT_EQ(out[8][3], 0x00000000u);
Nicolas Capensc5c0c332016-11-08 11:37:01 -0500765}
766
Nicolas Capenscf79a622019-12-09 17:07:41 -0500767TEST(ReactorUnitTests, FPtoUI)
768{
Ben Clayton713b8d32019-12-17 20:37:56 +0000769 FunctionT<int(void *)> function;
Nicolas Capenscf79a622019-12-09 17:07:41 -0500770 {
771 Pointer<Byte> out = function.Arg<0>();
772
Ben Clayton713b8d32019-12-17 20:37:56 +0000773 *Pointer<UInt>(out + 0) = UInt(Float(0xF0000000u));
774 *Pointer<UInt>(out + 4) = UInt(Float(0xC0000000u));
775 *Pointer<UInt>(out + 8) = UInt(Float(0x00000001u));
Nicolas Capenscf79a622019-12-09 17:07:41 -0500776 *Pointer<UInt>(out + 12) = UInt(Float(0xF000F000u));
777
778 *Pointer<UInt4>(out + 16) = UInt4(Float4(0xF0000000u, 0x80000000u, 0x00000000u, 0xCCCC0000u));
779
780 Return(0);
781 }
782
783 auto routine = function("one");
784
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500785 unsigned int out[2][4];
Nicolas Capenscf79a622019-12-09 17:07:41 -0500786
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500787 memset(&out, 0, sizeof(out));
Nicolas Capenscf79a622019-12-09 17:07:41 -0500788
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500789 routine(&out);
Nicolas Capenscf79a622019-12-09 17:07:41 -0500790
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500791 EXPECT_EQ(out[0][0], 0xF0000000u);
792 EXPECT_EQ(out[0][1], 0xC0000000u);
793 EXPECT_EQ(out[0][2], 0x00000001u);
794 EXPECT_EQ(out[0][3], 0xF000F000u);
Nicolas Capenscf79a622019-12-09 17:07:41 -0500795
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500796 EXPECT_EQ(out[1][0], 0xF0000000u);
797 EXPECT_EQ(out[1][1], 0x80000000u);
798 EXPECT_EQ(out[1][2], 0x00000000u);
799 EXPECT_EQ(out[1][3], 0xCCCC0000u);
Nicolas Capenscf79a622019-12-09 17:07:41 -0500800}
801
Nicolas Capensc07dc4b2018-08-06 14:20:45 -0400802TEST(ReactorUnitTests, VectorCompare)
Nicolas Capens5e6ca092017-01-13 15:09:21 -0500803{
Ben Clayton713b8d32019-12-17 20:37:56 +0000804 FunctionT<int(void *)> function;
Nicolas Capens5e6ca092017-01-13 15:09:21 -0500805 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500806 Pointer<Byte> out = function.Arg<0>();
Nicolas Capens5e6ca092017-01-13 15:09:21 -0500807
Nicolas Capens157ba262019-12-10 17:49:14 -0500808 *Pointer<Int4>(out + 16 * 0) = CmpEQ(Float4(1.0f, 1.0f, -0.0f, +0.0f), Float4(0.0f, 1.0f, +0.0f, -0.0f));
809 *Pointer<Int4>(out + 16 * 1) = CmpEQ(Int4(1, 0, -1, -0), Int4(0, 1, 0, +0));
810 *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 -0500811
Nicolas Capens157ba262019-12-10 17:49:14 -0500812 *Pointer<Int4>(out + 16 * 3) = CmpNLT(Float4(1.0f, 1.0f, -0.0f, +0.0f), Float4(0.0f, 1.0f, +0.0f, -0.0f));
813 *Pointer<Int4>(out + 16 * 4) = CmpNLT(Int4(1, 0, -1, -0), Int4(0, 1, 0, +0));
814 *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 -0500815
Nicolas Capens157ba262019-12-10 17:49:14 -0500816 Return(0);
Nicolas Capens5e6ca092017-01-13 15:09:21 -0500817 }
818
Nicolas Capens157ba262019-12-10 17:49:14 -0500819 auto routine = function("one");
820
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500821 unsigned int out[6][4];
Nicolas Capens157ba262019-12-10 17:49:14 -0500822
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500823 memset(&out, 0, sizeof(out));
Nicolas Capens157ba262019-12-10 17:49:14 -0500824
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500825 routine(&out);
Nicolas Capens157ba262019-12-10 17:49:14 -0500826
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500827 EXPECT_EQ(out[0][0], 0x00000000u);
828 EXPECT_EQ(out[0][1], 0xFFFFFFFFu);
829 EXPECT_EQ(out[0][2], 0xFFFFFFFFu);
830 EXPECT_EQ(out[0][3], 0xFFFFFFFFu);
Nicolas Capens157ba262019-12-10 17:49:14 -0500831
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500832 EXPECT_EQ(out[1][0], 0x00000000u);
833 EXPECT_EQ(out[1][1], 0x00000000u);
834 EXPECT_EQ(out[1][2], 0x00000000u);
835 EXPECT_EQ(out[1][3], 0xFFFFFFFFu);
Nicolas Capens157ba262019-12-10 17:49:14 -0500836
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500837 EXPECT_EQ(out[2][0], 0xFF000000u);
838 EXPECT_EQ(out[2][1], 0x00000000u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500839
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500840 EXPECT_EQ(out[3][0], 0xFFFFFFFFu);
841 EXPECT_EQ(out[3][1], 0xFFFFFFFFu);
842 EXPECT_EQ(out[3][2], 0xFFFFFFFFu);
843 EXPECT_EQ(out[3][3], 0xFFFFFFFFu);
Nicolas Capens157ba262019-12-10 17:49:14 -0500844
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500845 EXPECT_EQ(out[4][0], 0xFFFFFFFFu);
846 EXPECT_EQ(out[4][1], 0x00000000u);
847 EXPECT_EQ(out[4][2], 0x00000000u);
848 EXPECT_EQ(out[4][3], 0xFFFFFFFFu);
Nicolas Capens157ba262019-12-10 17:49:14 -0500849
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500850 EXPECT_EQ(out[5][0], 0x00000000u);
851 EXPECT_EQ(out[5][1], 0xFFFFFFFFu);
Nicolas Capens5e6ca092017-01-13 15:09:21 -0500852}
853
Nicolas Capensc07dc4b2018-08-06 14:20:45 -0400854TEST(ReactorUnitTests, SaturatedAddAndSubtract)
Casey Dahlin642fc922017-09-28 17:18:41 -0700855{
Ben Clayton713b8d32019-12-17 20:37:56 +0000856 FunctionT<int(void *)> function;
Casey Dahlin642fc922017-09-28 17:18:41 -0700857 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500858 Pointer<Byte> out = function.Arg<0>();
Casey Dahlin642fc922017-09-28 17:18:41 -0700859
Nicolas Capens157ba262019-12-10 17:49:14 -0500860 *Pointer<Byte8>(out + 8 * 0) =
Ben Clayton713b8d32019-12-17 20:37:56 +0000861 AddSat(Byte8(1, 2, 3, 4, 5, 6, 7, 8),
862 Byte8(7, 6, 5, 4, 3, 2, 1, 0));
Nicolas Capens157ba262019-12-10 17:49:14 -0500863 *Pointer<Byte8>(out + 8 * 1) =
Ben Clayton713b8d32019-12-17 20:37:56 +0000864 AddSat(Byte8(0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE),
865 Byte8(7, 6, 5, 4, 3, 2, 1, 0));
Nicolas Capens157ba262019-12-10 17:49:14 -0500866 *Pointer<Byte8>(out + 8 * 2) =
Ben Clayton713b8d32019-12-17 20:37:56 +0000867 SubSat(Byte8(1, 2, 3, 4, 5, 6, 7, 8),
868 Byte8(7, 6, 5, 4, 3, 2, 1, 0));
Casey Dahlin642fc922017-09-28 17:18:41 -0700869
Nicolas Capens157ba262019-12-10 17:49:14 -0500870 *Pointer<SByte8>(out + 8 * 3) =
Ben Clayton713b8d32019-12-17 20:37:56 +0000871 AddSat(SByte8(1, 2, 3, 4, 5, 6, 7, 8),
872 SByte8(7, 6, 5, 4, 3, 2, 1, 0));
Nicolas Capens157ba262019-12-10 17:49:14 -0500873 *Pointer<SByte8>(out + 8 * 4) =
Ben Clayton713b8d32019-12-17 20:37:56 +0000874 AddSat(SByte8(0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E),
875 SByte8(7, 6, 5, 4, 3, 2, 1, 0));
Nicolas Capens157ba262019-12-10 17:49:14 -0500876 *Pointer<SByte8>(out + 8 * 5) =
Ben Clayton713b8d32019-12-17 20:37:56 +0000877 AddSat(SByte8(0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88),
878 SByte8(-7, -6, -5, -4, -3, -2, -1, -0));
Nicolas Capens157ba262019-12-10 17:49:14 -0500879 *Pointer<SByte8>(out + 8 * 6) =
Ben Clayton713b8d32019-12-17 20:37:56 +0000880 SubSat(SByte8(0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88),
881 SByte8(7, 6, 5, 4, 3, 2, 1, 0));
Casey Dahlin642fc922017-09-28 17:18:41 -0700882
Nicolas Capens157ba262019-12-10 17:49:14 -0500883 *Pointer<Short4>(out + 8 * 7) =
Ben Clayton713b8d32019-12-17 20:37:56 +0000884 AddSat(Short4(1, 2, 3, 4), Short4(3, 2, 1, 0));
Nicolas Capens157ba262019-12-10 17:49:14 -0500885 *Pointer<Short4>(out + 8 * 8) =
Ben Clayton713b8d32019-12-17 20:37:56 +0000886 AddSat(Short4(0x7FFE, 0x7FFE, 0x7FFE, 0x7FFE),
887 Short4(3, 2, 1, 0));
Nicolas Capens157ba262019-12-10 17:49:14 -0500888 *Pointer<Short4>(out + 8 * 9) =
Ben Clayton713b8d32019-12-17 20:37:56 +0000889 AddSat(Short4(0x8001, 0x8002, 0x8003, 0x8004),
890 Short4(-3, -2, -1, -0));
Nicolas Capens157ba262019-12-10 17:49:14 -0500891 *Pointer<Short4>(out + 8 * 10) =
Ben Clayton713b8d32019-12-17 20:37:56 +0000892 SubSat(Short4(0x8001, 0x8002, 0x8003, 0x8004),
893 Short4(3, 2, 1, 0));
Casey Dahlin642fc922017-09-28 17:18:41 -0700894
Nicolas Capens157ba262019-12-10 17:49:14 -0500895 *Pointer<UShort4>(out + 8 * 11) =
Ben Clayton713b8d32019-12-17 20:37:56 +0000896 AddSat(UShort4(1, 2, 3, 4), UShort4(3, 2, 1, 0));
Nicolas Capens157ba262019-12-10 17:49:14 -0500897 *Pointer<UShort4>(out + 8 * 12) =
Ben Clayton713b8d32019-12-17 20:37:56 +0000898 AddSat(UShort4(0xFFFE, 0xFFFE, 0xFFFE, 0xFFFE),
899 UShort4(3, 2, 1, 0));
Nicolas Capens157ba262019-12-10 17:49:14 -0500900 *Pointer<UShort4>(out + 8 * 13) =
Ben Clayton713b8d32019-12-17 20:37:56 +0000901 SubSat(UShort4(1, 2, 3, 4), UShort4(3, 2, 1, 0));
Casey Dahlin642fc922017-09-28 17:18:41 -0700902
Nicolas Capens157ba262019-12-10 17:49:14 -0500903 Return(0);
Casey Dahlin642fc922017-09-28 17:18:41 -0700904 }
905
Nicolas Capens157ba262019-12-10 17:49:14 -0500906 auto routine = function("one");
907
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500908 unsigned int out[14][2];
Nicolas Capens157ba262019-12-10 17:49:14 -0500909
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500910 memset(&out, 0, sizeof(out));
Nicolas Capens157ba262019-12-10 17:49:14 -0500911
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500912 routine(&out);
Nicolas Capens157ba262019-12-10 17:49:14 -0500913
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500914 EXPECT_EQ(out[0][0], 0x08080808u);
915 EXPECT_EQ(out[0][1], 0x08080808u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500916
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500917 EXPECT_EQ(out[1][0], 0xFFFFFFFFu);
918 EXPECT_EQ(out[1][1], 0xFEFFFFFFu);
Nicolas Capens157ba262019-12-10 17:49:14 -0500919
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500920 EXPECT_EQ(out[2][0], 0x00000000u);
921 EXPECT_EQ(out[2][1], 0x08060402u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500922
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500923 EXPECT_EQ(out[3][0], 0x08080808u);
924 EXPECT_EQ(out[3][1], 0x08080808u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500925
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500926 EXPECT_EQ(out[4][0], 0x7F7F7F7Fu);
927 EXPECT_EQ(out[4][1], 0x7E7F7F7Fu);
Nicolas Capens157ba262019-12-10 17:49:14 -0500928
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500929 EXPECT_EQ(out[5][0], 0x80808080u);
930 EXPECT_EQ(out[5][1], 0x88868482u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500931
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500932 EXPECT_EQ(out[6][0], 0x80808080u);
933 EXPECT_EQ(out[6][1], 0x88868482u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500934
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500935 EXPECT_EQ(out[7][0], 0x00040004u);
936 EXPECT_EQ(out[7][1], 0x00040004u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500937
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500938 EXPECT_EQ(out[8][0], 0x7FFF7FFFu);
939 EXPECT_EQ(out[8][1], 0x7FFE7FFFu);
Nicolas Capens157ba262019-12-10 17:49:14 -0500940
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500941 EXPECT_EQ(out[9][0], 0x80008000u);
942 EXPECT_EQ(out[9][1], 0x80048002u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500943
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500944 EXPECT_EQ(out[10][0], 0x80008000u);
945 EXPECT_EQ(out[10][1], 0x80048002u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500946
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500947 EXPECT_EQ(out[11][0], 0x00040004u);
948 EXPECT_EQ(out[11][1], 0x00040004u);
Nicolas Capens157ba262019-12-10 17:49:14 -0500949
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500950 EXPECT_EQ(out[12][0], 0xFFFFFFFFu);
951 EXPECT_EQ(out[12][1], 0xFFFEFFFFu);
Nicolas Capens157ba262019-12-10 17:49:14 -0500952
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500953 EXPECT_EQ(out[13][0], 0x00000000u);
954 EXPECT_EQ(out[13][1], 0x00040002u);
Casey Dahlin642fc922017-09-28 17:18:41 -0700955}
956
Nicolas Capensc07dc4b2018-08-06 14:20:45 -0400957TEST(ReactorUnitTests, Unpack)
Casey Dahlin4e759e42017-09-29 13:43:18 -0700958{
Ben Clayton713b8d32019-12-17 20:37:56 +0000959 FunctionT<int(void *, void *)> function;
Casey Dahlin4e759e42017-09-29 13:43:18 -0700960 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500961 Pointer<Byte> in = function.Arg<0>();
962 Pointer<Byte> out = function.Arg<1>();
Casey Dahlin4e759e42017-09-29 13:43:18 -0700963
Nicolas Capens157ba262019-12-10 17:49:14 -0500964 Byte4 test_byte_a = *Pointer<Byte4>(in + 4 * 0);
965 Byte4 test_byte_b = *Pointer<Byte4>(in + 4 * 1);
Casey Dahlin4e759e42017-09-29 13:43:18 -0700966
Nicolas Capens157ba262019-12-10 17:49:14 -0500967 *Pointer<Short4>(out + 8 * 0) =
Ben Clayton713b8d32019-12-17 20:37:56 +0000968 Unpack(test_byte_a, test_byte_b);
Casey Dahlin4e759e42017-09-29 13:43:18 -0700969
Nicolas Capens157ba262019-12-10 17:49:14 -0500970 *Pointer<Short4>(out + 8 * 1) = Unpack(test_byte_a);
Casey Dahlin4e759e42017-09-29 13:43:18 -0700971
Nicolas Capens157ba262019-12-10 17:49:14 -0500972 Return(0);
Casey Dahlin4e759e42017-09-29 13:43:18 -0700973 }
974
Nicolas Capens157ba262019-12-10 17:49:14 -0500975 auto routine = function("one");
976
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500977 unsigned int in[1][2];
978 unsigned int out[2][2];
Nicolas Capens157ba262019-12-10 17:49:14 -0500979
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500980 memset(&out, 0, sizeof(out));
Nicolas Capens157ba262019-12-10 17:49:14 -0500981
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500982 in[0][0] = 0xABCDEF12u;
983 in[0][1] = 0x34567890u;
Nicolas Capens157ba262019-12-10 17:49:14 -0500984
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500985 routine(&in, &out);
Nicolas Capens157ba262019-12-10 17:49:14 -0500986
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500987 EXPECT_EQ(out[0][0], 0x78EF9012u);
988 EXPECT_EQ(out[0][1], 0x34AB56CDu);
Nicolas Capens157ba262019-12-10 17:49:14 -0500989
Nicolas Capensbdf2b722020-01-27 11:33:14 -0500990 EXPECT_EQ(out[1][0], 0xEFEF1212u);
991 EXPECT_EQ(out[1][1], 0xABABCDCDu);
Casey Dahlin4e759e42017-09-29 13:43:18 -0700992}
993
Nicolas Capensc07dc4b2018-08-06 14:20:45 -0400994TEST(ReactorUnitTests, Pack)
Casey Dahlin11658122017-09-29 16:32:32 -0700995{
Ben Clayton713b8d32019-12-17 20:37:56 +0000996 FunctionT<int(void *)> function;
Casey Dahlin11658122017-09-29 16:32:32 -0700997 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500998 Pointer<Byte> out = function.Arg<0>();
Casey Dahlin11658122017-09-29 16:32:32 -0700999
Nicolas Capens157ba262019-12-10 17:49:14 -05001000 *Pointer<SByte8>(out + 8 * 0) =
Ben Clayton713b8d32019-12-17 20:37:56 +00001001 PackSigned(Short4(-1, -2, 1, 2),
1002 Short4(3, 4, -3, -4));
Casey Dahlin11658122017-09-29 16:32:32 -07001003
Nicolas Capens157ba262019-12-10 17:49:14 -05001004 *Pointer<Byte8>(out + 8 * 1) =
Ben Clayton713b8d32019-12-17 20:37:56 +00001005 PackUnsigned(Short4(-1, -2, 1, 2),
1006 Short4(3, 4, -3, -4));
Casey Dahlin11658122017-09-29 16:32:32 -07001007
Nicolas Capens157ba262019-12-10 17:49:14 -05001008 *Pointer<Short8>(out + 8 * 2) =
Ben Clayton713b8d32019-12-17 20:37:56 +00001009 PackSigned(Int4(-1, -2, 1, 2),
1010 Int4(3, 4, -3, -4));
Casey Dahlin11658122017-09-29 16:32:32 -07001011
Nicolas Capens157ba262019-12-10 17:49:14 -05001012 *Pointer<UShort8>(out + 8 * 4) =
Ben Clayton713b8d32019-12-17 20:37:56 +00001013 PackUnsigned(Int4(-1, -2, 1, 2),
1014 Int4(3, 4, -3, -4));
Casey Dahlin11658122017-09-29 16:32:32 -07001015
Nicolas Capens157ba262019-12-10 17:49:14 -05001016 Return(0);
Casey Dahlin11658122017-09-29 16:32:32 -07001017 }
1018
Nicolas Capens157ba262019-12-10 17:49:14 -05001019 auto routine = function("one");
1020
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001021 unsigned int out[6][2];
Nicolas Capens157ba262019-12-10 17:49:14 -05001022
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001023 memset(&out, 0, sizeof(out));
Nicolas Capens157ba262019-12-10 17:49:14 -05001024
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001025 routine(&out);
Nicolas Capens157ba262019-12-10 17:49:14 -05001026
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001027 EXPECT_EQ(out[0][0], 0x0201FEFFu);
1028 EXPECT_EQ(out[0][1], 0xFCFD0403u);
Nicolas Capens157ba262019-12-10 17:49:14 -05001029
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001030 EXPECT_EQ(out[1][0], 0x02010000u);
1031 EXPECT_EQ(out[1][1], 0x00000403u);
Nicolas Capens157ba262019-12-10 17:49:14 -05001032
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001033 EXPECT_EQ(out[2][0], 0xFFFEFFFFu);
1034 EXPECT_EQ(out[2][1], 0x00020001u);
Nicolas Capens157ba262019-12-10 17:49:14 -05001035
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001036 EXPECT_EQ(out[3][0], 0x00040003u);
1037 EXPECT_EQ(out[3][1], 0xFFFCFFFDu);
Nicolas Capens157ba262019-12-10 17:49:14 -05001038
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001039 EXPECT_EQ(out[4][0], 0x00000000u);
1040 EXPECT_EQ(out[4][1], 0x00020001u);
Nicolas Capens157ba262019-12-10 17:49:14 -05001041
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001042 EXPECT_EQ(out[5][0], 0x00040003u);
1043 EXPECT_EQ(out[5][1], 0x00000000u);
Casey Dahlin11658122017-09-29 16:32:32 -07001044}
1045
Nicolas Capensc07dc4b2018-08-06 14:20:45 -04001046TEST(ReactorUnitTests, MulHigh)
Nicolas Capens92593eb2018-02-14 14:52:49 -05001047{
Ben Clayton713b8d32019-12-17 20:37:56 +00001048 FunctionT<int(void *)> function;
Casey Dahlin36fad3c2017-10-02 15:02:02 -07001049 {
Nicolas Capens157ba262019-12-10 17:49:14 -05001050 Pointer<Byte> out = function.Arg<0>();
Casey Dahlin36fad3c2017-10-02 15:02:02 -07001051
Nicolas Capens157ba262019-12-10 17:49:14 -05001052 *Pointer<Short4>(out + 16 * 0) =
Ben Clayton713b8d32019-12-17 20:37:56 +00001053 MulHigh(Short4(0x01AA, 0x02DD, 0x03EE, 0xF422),
1054 Short4(0x01BB, 0x02CC, 0x03FF, 0xF411));
Nicolas Capens157ba262019-12-10 17:49:14 -05001055 *Pointer<UShort4>(out + 16 * 1) =
Ben Clayton713b8d32019-12-17 20:37:56 +00001056 MulHigh(UShort4(0x01AA, 0x02DD, 0x03EE, 0xF422),
1057 UShort4(0x01BB, 0x02CC, 0x03FF, 0xF411));
Casey Dahlin36fad3c2017-10-02 15:02:02 -07001058
Nicolas Capens157ba262019-12-10 17:49:14 -05001059 *Pointer<Int4>(out + 16 * 2) =
Ben Clayton713b8d32019-12-17 20:37:56 +00001060 MulHigh(Int4(0x000001AA, 0x000002DD, 0xC8000000, 0xF8000000),
1061 Int4(0x000001BB, 0x84000000, 0x000003EE, 0xD7000000));
Nicolas Capens157ba262019-12-10 17:49:14 -05001062 *Pointer<UInt4>(out + 16 * 3) =
Ben Clayton713b8d32019-12-17 20:37:56 +00001063 MulHigh(UInt4(0x000001AAu, 0x000002DDu, 0xC8000000u, 0xD8000000u),
1064 UInt4(0x000001BBu, 0x84000000u, 0x000003EEu, 0xD7000000u));
Chris Forbesaa8f6992019-03-01 14:18:30 -08001065
Nicolas Capens157ba262019-12-10 17:49:14 -05001066 *Pointer<Int4>(out + 16 * 4) =
Ben Clayton713b8d32019-12-17 20:37:56 +00001067 MulHigh(Int4(0x7FFFFFFF, 0x7FFFFFFF, 0x80008000, 0xFFFFFFFF),
1068 Int4(0x7FFFFFFF, 0x80000000, 0x80008000, 0xFFFFFFFF));
Nicolas Capens157ba262019-12-10 17:49:14 -05001069 *Pointer<UInt4>(out + 16 * 5) =
Ben Clayton713b8d32019-12-17 20:37:56 +00001070 MulHigh(UInt4(0x7FFFFFFFu, 0x7FFFFFFFu, 0x80008000u, 0xFFFFFFFFu),
1071 UInt4(0x7FFFFFFFu, 0x80000000u, 0x80008000u, 0xFFFFFFFFu));
Chris Forbesaa8f6992019-03-01 14:18:30 -08001072
Nicolas Capens157ba262019-12-10 17:49:14 -05001073 // (U)Short8 variants currently unimplemented.
Chris Forbesaa8f6992019-03-01 14:18:30 -08001074
Nicolas Capens157ba262019-12-10 17:49:14 -05001075 Return(0);
Casey Dahlin36fad3c2017-10-02 15:02:02 -07001076 }
1077
Nicolas Capens157ba262019-12-10 17:49:14 -05001078 auto routine = function("one");
1079
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001080 unsigned int out[6][4];
Nicolas Capens157ba262019-12-10 17:49:14 -05001081
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001082 memset(&out, 0, sizeof(out));
Nicolas Capens157ba262019-12-10 17:49:14 -05001083
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001084 routine(&out);
Nicolas Capens157ba262019-12-10 17:49:14 -05001085
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001086 EXPECT_EQ(out[0][0], 0x00080002u);
1087 EXPECT_EQ(out[0][1], 0x008D000Fu);
Nicolas Capens157ba262019-12-10 17:49:14 -05001088
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001089 EXPECT_EQ(out[1][0], 0x00080002u);
1090 EXPECT_EQ(out[1][1], 0xE8C0000Fu);
Nicolas Capens157ba262019-12-10 17:49:14 -05001091
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001092 EXPECT_EQ(out[2][0], 0x00000000u);
1093 EXPECT_EQ(out[2][1], 0xFFFFFE9Cu);
1094 EXPECT_EQ(out[2][2], 0xFFFFFF23u);
1095 EXPECT_EQ(out[2][3], 0x01480000u);
Nicolas Capens157ba262019-12-10 17:49:14 -05001096
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001097 EXPECT_EQ(out[3][0], 0x00000000u);
1098 EXPECT_EQ(out[3][1], 0x00000179u);
1099 EXPECT_EQ(out[3][2], 0x00000311u);
1100 EXPECT_EQ(out[3][3], 0xB5680000u);
Nicolas Capens157ba262019-12-10 17:49:14 -05001101
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001102 EXPECT_EQ(out[4][0], 0x3FFFFFFFu);
1103 EXPECT_EQ(out[4][1], 0xC0000000u);
1104 EXPECT_EQ(out[4][2], 0x3FFF8000u);
1105 EXPECT_EQ(out[4][3], 0x00000000u);
Nicolas Capens157ba262019-12-10 17:49:14 -05001106
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001107 EXPECT_EQ(out[5][0], 0x3FFFFFFFu);
1108 EXPECT_EQ(out[5][1], 0x3FFFFFFFu);
1109 EXPECT_EQ(out[5][2], 0x40008000u);
1110 EXPECT_EQ(out[5][3], 0xFFFFFFFEu);
Casey Dahlin36fad3c2017-10-02 15:02:02 -07001111}
1112
Nicolas Capensc07dc4b2018-08-06 14:20:45 -04001113TEST(ReactorUnitTests, MulAdd)
Nicolas Capens92593eb2018-02-14 14:52:49 -05001114{
Ben Clayton713b8d32019-12-17 20:37:56 +00001115 FunctionT<int(void *)> function;
Casey Dahlinb098c542017-10-03 11:24:01 -07001116 {
Nicolas Capens157ba262019-12-10 17:49:14 -05001117 Pointer<Byte> out = function.Arg<0>();
Casey Dahlinb098c542017-10-03 11:24:01 -07001118
Nicolas Capens157ba262019-12-10 17:49:14 -05001119 *Pointer<Int2>(out + 8 * 0) =
Ben Clayton713b8d32019-12-17 20:37:56 +00001120 MulAdd(Short4(0x1aa, 0x2dd, 0x3ee, 0xF422),
1121 Short4(0x1bb, 0x2cc, 0x3ff, 0xF411));
Casey Dahlinb098c542017-10-03 11:24:01 -07001122
Nicolas Capens157ba262019-12-10 17:49:14 -05001123 // (U)Short8 variant is mentioned but unimplemented
1124 Return(0);
Casey Dahlinb098c542017-10-03 11:24:01 -07001125 }
1126
Nicolas Capens157ba262019-12-10 17:49:14 -05001127 auto routine = function("one");
1128
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001129 unsigned int out[1][2];
Nicolas Capens157ba262019-12-10 17:49:14 -05001130
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001131 memset(&out, 0, sizeof(out));
Nicolas Capens157ba262019-12-10 17:49:14 -05001132
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001133 routine(&out);
Nicolas Capens157ba262019-12-10 17:49:14 -05001134
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001135 EXPECT_EQ(out[0][0], 0x000AE34Au);
1136 EXPECT_EQ(out[0][1], 0x009D5254u);
Casey Dahlinb098c542017-10-03 11:24:01 -07001137}
1138
Ben Clayton204a4102019-07-31 13:17:47 +01001139TEST(ReactorUnitTests, PointersEqual)
1140{
Ben Clayton713b8d32019-12-17 20:37:56 +00001141 FunctionT<int(void *, void *)> function;
Ben Clayton204a4102019-07-31 13:17:47 +01001142 {
1143 Pointer<Byte> ptrA = function.Arg<0>();
1144 Pointer<Byte> ptrB = function.Arg<1>();
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001145 If(ptrA == ptrB)
Ben Clayton204a4102019-07-31 13:17:47 +01001146 {
1147 Return(1);
1148 }
1149 Else
1150 {
1151 Return(0);
1152 }
1153 }
1154
1155 auto routine = function("one");
Ben Clayton713b8d32019-12-17 20:37:56 +00001156 int *a = reinterpret_cast<int *>(uintptr_t(0x0000000000000000));
1157 int *b = reinterpret_cast<int *>(uintptr_t(0x00000000F0000000));
1158 int *c = reinterpret_cast<int *>(uintptr_t(0xF000000000000000));
Antonio Maiorano03935ae2019-10-29 16:20:27 -04001159 EXPECT_EQ(routine(&a, &a), 1);
1160 EXPECT_EQ(routine(&b, &b), 1);
1161 EXPECT_EQ(routine(&c, &c), 1);
Ben Clayton204a4102019-07-31 13:17:47 +01001162
Antonio Maiorano03935ae2019-10-29 16:20:27 -04001163 EXPECT_EQ(routine(&a, &b), 0);
1164 EXPECT_EQ(routine(&b, &a), 0);
1165 EXPECT_EQ(routine(&b, &c), 0);
1166 EXPECT_EQ(routine(&c, &b), 0);
1167 EXPECT_EQ(routine(&c, &a), 0);
1168 EXPECT_EQ(routine(&a, &c), 0);
Ben Clayton204a4102019-07-31 13:17:47 +01001169}
1170
Antonio Maiorano29ba7a02019-10-11 15:23:56 -04001171TEST(ReactorUnitTests, Args_2Mixed)
1172{
1173 // 2 mixed type args
Antonio Maiorano03935ae2019-10-29 16:20:27 -04001174 FunctionT<float(int, float)> function;
Antonio Maiorano29ba7a02019-10-11 15:23:56 -04001175 {
1176 Int a = function.Arg<0>();
1177 Float b = function.Arg<1>();
1178 Return(Float(a) + b);
1179 }
1180
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001181 if(auto routine = function("one"))
Antonio Maiorano29ba7a02019-10-11 15:23:56 -04001182 {
Antonio Maiorano03935ae2019-10-29 16:20:27 -04001183 float result = routine(1, 2.f);
Antonio Maiorano29ba7a02019-10-11 15:23:56 -04001184 EXPECT_EQ(result, 3.f);
1185 }
1186}
1187
1188TEST(ReactorUnitTests, Args_4Mixed)
1189{
1190 // 4 mixed type args (max register allocation on Windows)
Antonio Maiorano03935ae2019-10-29 16:20:27 -04001191 FunctionT<float(int, float, int, float)> function;
Antonio Maiorano29ba7a02019-10-11 15:23:56 -04001192 {
1193 Int a = function.Arg<0>();
1194 Float b = function.Arg<1>();
1195 Int c = function.Arg<2>();
1196 Float d = function.Arg<3>();
1197 Return(Float(a) + b + Float(c) + d);
1198 }
1199
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001200 if(auto routine = function("one"))
Antonio Maiorano29ba7a02019-10-11 15:23:56 -04001201 {
Antonio Maiorano03935ae2019-10-29 16:20:27 -04001202 float result = routine(1, 2.f, 3, 4.f);
Antonio Maiorano29ba7a02019-10-11 15:23:56 -04001203 EXPECT_EQ(result, 10.f);
1204 }
1205}
1206
1207TEST(ReactorUnitTests, Args_5Mixed)
1208{
1209 // 5 mixed type args (5th spills over to stack on Windows)
Antonio Maiorano03935ae2019-10-29 16:20:27 -04001210 FunctionT<float(int, float, int, float, int)> function;
Antonio Maiorano29ba7a02019-10-11 15:23:56 -04001211 {
1212 Int a = function.Arg<0>();
1213 Float b = function.Arg<1>();
1214 Int c = function.Arg<2>();
1215 Float d = function.Arg<3>();
1216 Int e = function.Arg<4>();
1217 Return(Float(a) + b + Float(c) + d + Float(e));
1218 }
1219
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001220 if(auto routine = function("one"))
Antonio Maiorano29ba7a02019-10-11 15:23:56 -04001221 {
Antonio Maiorano03935ae2019-10-29 16:20:27 -04001222 float result = routine(1, 2.f, 3, 4.f, 5);
Antonio Maiorano29ba7a02019-10-11 15:23:56 -04001223 EXPECT_EQ(result, 15.f);
1224 }
1225}
1226
1227TEST(ReactorUnitTests, Args_GreaterThan5Mixed)
1228{
1229 // >5 mixed type args
Antonio Maiorano03935ae2019-10-29 16:20:27 -04001230 FunctionT<float(int, float, int, float, int, float, int, float, int, float)> function;
Antonio Maiorano29ba7a02019-10-11 15:23:56 -04001231 {
1232 Int a = function.Arg<0>();
1233 Float b = function.Arg<1>();
1234 Int c = function.Arg<2>();
1235 Float d = function.Arg<3>();
1236 Int e = function.Arg<4>();
1237 Float f = function.Arg<5>();
1238 Int g = function.Arg<6>();
1239 Float h = function.Arg<7>();
1240 Int i = function.Arg<8>();
1241 Float j = function.Arg<9>();
1242 Return(Float(a) + b + Float(c) + d + Float(e) + f + Float(g) + h + Float(i) + j);
1243 }
1244
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001245 if(auto routine = function("one"))
Antonio Maiorano29ba7a02019-10-11 15:23:56 -04001246 {
Antonio Maiorano03935ae2019-10-29 16:20:27 -04001247 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 -04001248 EXPECT_EQ(result, 55.f);
1249 }
1250}
1251
Antonio Maiorano4d402712020-02-25 10:36:02 -05001252// This test was written because on Windows with Subzero, we would get a crash when executing a function
1253// with a large number of local variables. The problem was that on Windows, 4K pages are allocated as
1254// needed for the stack whenever an access is made in a "guard page", at which point the page is committed,
1255// and the next 4K page becomes the guard page. If a stack access is made that's beyond the guard page,
1256// a regular page fault occurs. To fix this, Subzero (and any compiler) now emits a call to __chkstk with
1257// the stack size in EAX, so that it can probe the stack in 4K increments up to that size, committing the
1258// required pages. See https://docs.microsoft.com/en-us/windows/win32/devnotes/-win32-chkstk.
1259TEST(ReactorUnitTests, LargeStack)
1260{
1261#if defined(_WIN32)
1262 // An empirically large enough value to access outside the guard pages
1263 constexpr int ArrayByteSize = 24 * 1024;
1264 constexpr int ArraySize = ArrayByteSize / sizeof(int32_t);
1265
1266 FunctionT<void(int32_t * v)> function;
1267 {
1268 // Allocate a stack array large enough that writing to the first element will reach beyond
1269 // the guard page.
1270 Array<Int, ArraySize> largeStackArray;
1271 for(int i = 0; i < ArraySize; ++i)
1272 {
1273 largeStackArray[i] = i;
1274 }
1275
1276 Pointer<Int> in = function.Arg<0>();
1277 for(int i = 0; i < ArraySize; ++i)
1278 {
1279 in[i] = largeStackArray[i];
1280 }
1281 }
1282
1283 auto routine = function("one");
1284 std::array<int32_t, ArraySize> v;
1285
1286 // Run this in a thread, so that we get the default reserved stack size (8K on Win64).
1287 std::thread t([&] {
1288 routine(v.data());
1289 });
1290 t.join();
1291
1292 for(int i = 0; i < ArraySize; ++i)
1293 {
1294 EXPECT_EQ(v[i], i);
1295 }
1296#endif
1297}
1298
Ben Claytond853c122019-04-16 17:51:49 -04001299TEST(ReactorUnitTests, Call)
1300{
Ben Claytond853c122019-04-16 17:51:49 -04001301 struct Class
1302 {
Ben Clayton51f08312019-11-08 14:39:26 +00001303 static int Callback(Class *p, int i, float f)
Ben Claytond853c122019-04-16 17:51:49 -04001304 {
Ben Clayton51f08312019-11-08 14:39:26 +00001305 p->i = i;
1306 p->f = f;
Ben Claytond853c122019-04-16 17:51:49 -04001307 return i + int(f);
1308 }
1309
1310 int i = 0;
1311 float f = 0.0f;
1312 };
1313
Ben Clayton713b8d32019-12-17 20:37:56 +00001314 FunctionT<int(void *)> function;
Ben Claytond853c122019-04-16 17:51:49 -04001315 {
Ben Clayton51f08312019-11-08 14:39:26 +00001316 Pointer<Byte> c = function.Arg<0>();
1317 auto res = Call(Class::Callback, c, 10, 20.0f);
1318 Return(res);
Ben Claytond853c122019-04-16 17:51:49 -04001319 }
Ben Clayton51f08312019-11-08 14:39:26 +00001320
1321 auto routine = function("one");
1322
1323 Class c;
1324 int res = routine(&c);
1325 EXPECT_EQ(res, 30);
1326 EXPECT_EQ(c.i, 10);
1327 EXPECT_EQ(c.f, 20.0f);
1328}
1329
Ben Claytonb7eb3a82019-11-19 00:43:50 +00001330TEST(ReactorUnitTests, CallMemberFunction)
1331{
Ben Claytonb7eb3a82019-11-19 00:43:50 +00001332 struct Class
1333 {
1334 int Callback(int argI, float argF)
1335 {
1336 i = argI;
1337 f = argF;
1338 return i + int(f);
1339 }
1340
1341 int i = 0;
1342 float f = 0.0f;
1343 };
1344
1345 Class c;
1346
1347 FunctionT<int()> function;
1348 {
1349 auto res = Call(&Class::Callback, &c, 10, 20.0f);
1350 Return(res);
1351 }
1352
1353 auto routine = function("one");
1354
1355 int res = routine();
1356 EXPECT_EQ(res, 30);
1357 EXPECT_EQ(c.i, 10);
1358 EXPECT_EQ(c.f, 20.0f);
1359}
1360
1361TEST(ReactorUnitTests, CallMemberFunctionIndirect)
1362{
Ben Claytonb7eb3a82019-11-19 00:43:50 +00001363 struct Class
1364 {
1365 int Callback(int argI, float argF)
1366 {
1367 i = argI;
1368 f = argF;
1369 return i + int(f);
1370 }
1371
1372 int i = 0;
1373 float f = 0.0f;
1374 };
1375
Ben Clayton713b8d32019-12-17 20:37:56 +00001376 FunctionT<int(void *)> function;
Ben Claytonb7eb3a82019-11-19 00:43:50 +00001377 {
1378 Pointer<Byte> c = function.Arg<0>();
1379 auto res = Call(&Class::Callback, c, 10, 20.0f);
1380 Return(res);
1381 }
1382
1383 auto routine = function("one");
1384
1385 Class c;
1386 int res = routine(&c);
1387 EXPECT_EQ(res, 30);
1388 EXPECT_EQ(c.i, 10);
1389 EXPECT_EQ(c.f, 20.0f);
1390}
1391
Ben Clayton51f08312019-11-08 14:39:26 +00001392TEST(ReactorUnitTests, CallImplicitCast)
1393{
Ben Clayton51f08312019-11-08 14:39:26 +00001394 struct Class
1395 {
Ben Clayton713b8d32019-12-17 20:37:56 +00001396 static void Callback(Class *c, const char *s)
Ben Clayton51f08312019-11-08 14:39:26 +00001397 {
1398 c->str = s;
1399 }
1400 std::string str;
1401 };
1402
Ben Clayton713b8d32019-12-17 20:37:56 +00001403 FunctionT<void(Class * c, const char *s)> function;
Ben Clayton51f08312019-11-08 14:39:26 +00001404 {
1405 Pointer<Byte> c = function.Arg<0>();
1406 Pointer<Byte> s = function.Arg<1>();
1407 Call(Class::Callback, c, s);
1408 }
1409
1410 auto routine = function("one");
1411
1412 Class c;
1413 routine(&c, "hello world");
1414 EXPECT_EQ(c.str, "hello world");
Antonio Maioranob7dad7d2019-10-11 15:26:58 -04001415}
Ben Claytond853c122019-04-16 17:51:49 -04001416
Antonio Maiorano16ae92a2020-03-10 10:53:24 -04001417TEST(ReactorUnitTests, CallBoolReturnFunction)
1418{
1419 struct Class
1420 {
1421 static bool IsEven(int a)
1422 {
1423 return a % 2 == 0;
1424 }
1425 };
1426
1427 FunctionT<int(int)> function;
1428 {
1429 Int a = function.Arg<0>();
1430 Bool res = Call(Class::IsEven, a);
1431 If(res)
1432 {
1433 Return(1);
1434 }
1435 Return(0);
1436 }
1437
1438 auto routine = function("one");
1439
1440 for(int i = 0; i < 10; ++i)
1441 {
1442 EXPECT_EQ(routine(i), i % 2 == 0);
1443 }
1444}
1445
Antonio Maiorano01386d12019-11-20 14:43:48 -05001446TEST(ReactorUnitTests, Call_Args4)
1447{
1448 struct Class
1449 {
1450 static int Func(int a, int b, int c, int d)
1451 {
1452 return a + b + c + d;
1453 }
1454 };
1455
1456 {
1457 FunctionT<int()> function;
1458 {
1459 auto res = Call(Class::Func, 1, 2, 3, 4);
1460 Return(res);
1461 }
1462
1463 auto routine = function("one");
1464
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001465 int res = routine();
1466 EXPECT_EQ(res, 1 + 2 + 3 + 4);
Antonio Maiorano01386d12019-11-20 14:43:48 -05001467 }
1468}
1469
1470TEST(ReactorUnitTests, Call_Args5)
1471{
1472 struct Class
1473 {
1474 static int Func(int a, int b, int c, int d, int e)
1475 {
1476 return a + b + c + d + e;
1477 }
1478 };
1479
1480 {
1481 FunctionT<int()> function;
1482 {
1483 auto res = Call(Class::Func, 1, 2, 3, 4, 5);
1484 Return(res);
1485 }
1486
1487 auto routine = function("one");
1488
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001489 int res = routine();
1490 EXPECT_EQ(res, 1 + 2 + 3 + 4 + 5);
Antonio Maiorano01386d12019-11-20 14:43:48 -05001491 }
1492}
1493
1494TEST(ReactorUnitTests, Call_ArgsMany)
1495{
1496 struct Class
1497 {
1498 static int Func(int a, int b, int c, int d, int e, int f, int g, int h)
1499 {
1500 return a + b + c + d + e + f + g + h;
1501 }
1502 };
1503
1504 {
1505 FunctionT<int()> function;
1506 {
1507 auto res = Call(Class::Func, 1, 2, 3, 4, 5, 6, 7, 8);
1508 Return(res);
1509 }
1510
1511 auto routine = function("one");
1512
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001513 int res = routine();
1514 EXPECT_EQ(res, 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8);
Antonio Maiorano01386d12019-11-20 14:43:48 -05001515 }
1516}
1517
1518TEST(ReactorUnitTests, Call_ArgsMixed)
1519{
1520 struct Class
1521 {
Ben Clayton713b8d32019-12-17 20:37:56 +00001522 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 -05001523 {
1524 return a + b + *c + *d + e + f + *g + *h;
1525 }
1526 };
1527
1528 {
1529 FunctionT<int()> function;
1530 {
1531 Int c(3);
1532 Float d(4);
1533 Int g(7);
1534 Float h(8);
1535 auto res = Call(Class::Func, 1, 2.f, &c, &d, 5, 6.f, &g, &h);
1536 Return(res);
1537 }
1538
1539 auto routine = function("one");
1540
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001541 int res = routine();
1542 EXPECT_EQ(res, 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8);
Antonio Maiorano01386d12019-11-20 14:43:48 -05001543 }
1544}
1545
1546TEST(ReactorUnitTests, Call_ArgsPointer)
1547{
1548 struct Class
1549 {
1550 static int Func(int *a)
1551 {
1552 return *a;
1553 }
1554 };
1555
1556 {
1557 FunctionT<int()> function;
1558 {
1559 Int a(12345);
1560 auto res = Call(Class::Func, &a);
1561 Return(res);
1562 }
1563
1564 auto routine = function("one");
1565
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001566 int res = routine();
1567 EXPECT_EQ(res, 12345);
Antonio Maiorano01386d12019-11-20 14:43:48 -05001568 }
1569}
1570
Antonio Maioranob7dad7d2019-10-11 15:26:58 -04001571TEST(ReactorUnitTests, CallExternalCallRoutine)
1572{
Antonio Maioranob7dad7d2019-10-11 15:26:58 -04001573 // routine1 calls Class::Func, passing it a pointer to routine2, and Class::Func calls routine2
1574
1575 auto routine2 = [] {
Antonio Maiorano03935ae2019-10-29 16:20:27 -04001576 FunctionT<float(float, int)> function;
Antonio Maioranob7dad7d2019-10-11 15:26:58 -04001577 {
1578 Float a = function.Arg<0>();
1579 Int b = function.Arg<1>();
1580 Return(a + Float(b));
1581 }
1582 return function("two");
1583 }();
1584
1585 struct Class
1586 {
Ben Clayton713b8d32019-12-17 20:37:56 +00001587 static float Func(void *p, float a, int b)
Antonio Maioranob7dad7d2019-10-11 15:26:58 -04001588 {
Ben Clayton713b8d32019-12-17 20:37:56 +00001589 auto funcToCall = reinterpret_cast<float (*)(float, int)>(p);
Antonio Maioranob7dad7d2019-10-11 15:26:58 -04001590 return funcToCall(a, b);
1591 }
1592 };
1593
1594 auto routine1 = [] {
Ben Clayton713b8d32019-12-17 20:37:56 +00001595 FunctionT<float(void *, float, int)> function;
Antonio Maioranob7dad7d2019-10-11 15:26:58 -04001596 {
1597 Pointer<Byte> funcToCall = function.Arg<0>();
1598 Float a = function.Arg<1>();
1599 Int b = function.Arg<2>();
1600 Float result = Call(Class::Func, funcToCall, a, b);
1601 Return(result);
1602 }
1603 return function("one");
1604 }();
1605
Ben Clayton713b8d32019-12-17 20:37:56 +00001606 float result = routine1((void *)routine2.getEntry(), 12.f, 13);
Antonio Maioranob7dad7d2019-10-11 15:26:58 -04001607 EXPECT_EQ(result, 25.f);
Ben Claytond853c122019-04-16 17:51:49 -04001608}
1609
Stephen White17078c72019-02-27 14:39:14 -05001610// Check that a complex generated function which utilizes all 8 or 16 XMM
1611// registers computes the correct result.
1612// (Note that due to MSC's lack of support for inline assembly in x64,
Ben Claytonb1243732019-02-27 23:56:18 +00001613// this test does not actually check that the register contents are
Stephen White17078c72019-02-27 14:39:14 -05001614// preserved, just that the generated function computes the correct value.
1615// It's necessary to inspect the registers in a debugger to actually verify.)
1616TEST(ReactorUnitTests, PreserveXMMRegisters)
1617{
Ben Clayton713b8d32019-12-17 20:37:56 +00001618 FunctionT<void(void *, void *)> function;
1619 {
1620 Pointer<Byte> in = function.Arg<0>();
1621 Pointer<Byte> out = function.Arg<1>();
Stephen White17078c72019-02-27 14:39:14 -05001622
Ben Clayton713b8d32019-12-17 20:37:56 +00001623 Float4 a = *Pointer<Float4>(in + 16 * 0);
1624 Float4 b = *Pointer<Float4>(in + 16 * 1);
1625 Float4 c = *Pointer<Float4>(in + 16 * 2);
1626 Float4 d = *Pointer<Float4>(in + 16 * 3);
1627 Float4 e = *Pointer<Float4>(in + 16 * 4);
1628 Float4 f = *Pointer<Float4>(in + 16 * 5);
1629 Float4 g = *Pointer<Float4>(in + 16 * 6);
1630 Float4 h = *Pointer<Float4>(in + 16 * 7);
1631 Float4 i = *Pointer<Float4>(in + 16 * 8);
1632 Float4 j = *Pointer<Float4>(in + 16 * 9);
1633 Float4 k = *Pointer<Float4>(in + 16 * 10);
1634 Float4 l = *Pointer<Float4>(in + 16 * 11);
1635 Float4 m = *Pointer<Float4>(in + 16 * 12);
1636 Float4 n = *Pointer<Float4>(in + 16 * 13);
1637 Float4 o = *Pointer<Float4>(in + 16 * 14);
1638 Float4 p = *Pointer<Float4>(in + 16 * 15);
Stephen White17078c72019-02-27 14:39:14 -05001639
Ben Clayton713b8d32019-12-17 20:37:56 +00001640 Float4 ab = a + b;
1641 Float4 cd = c + d;
1642 Float4 ef = e + f;
1643 Float4 gh = g + h;
1644 Float4 ij = i + j;
1645 Float4 kl = k + l;
1646 Float4 mn = m + n;
1647 Float4 op = o + p;
Stephen White17078c72019-02-27 14:39:14 -05001648
Ben Clayton713b8d32019-12-17 20:37:56 +00001649 Float4 abcd = ab + cd;
1650 Float4 efgh = ef + gh;
1651 Float4 ijkl = ij + kl;
1652 Float4 mnop = mn + op;
Stephen White17078c72019-02-27 14:39:14 -05001653
Ben Clayton713b8d32019-12-17 20:37:56 +00001654 Float4 abcdefgh = abcd + efgh;
1655 Float4 ijklmnop = ijkl + mnop;
1656 Float4 sum = abcdefgh + ijklmnop;
1657 *Pointer<Float4>(out) = sum;
1658 Return();
1659 }
Stephen White17078c72019-02-27 14:39:14 -05001660
Ben Clayton713b8d32019-12-17 20:37:56 +00001661 auto routine = function("one");
1662 assert(routine);
Nicolas Capens157ba262019-12-10 17:49:14 -05001663
Ben Clayton713b8d32019-12-17 20:37:56 +00001664 float input[64] = { 1.0f, 0.0f, 0.0f, 0.0f,
1665 -1.0f, 1.0f, -1.0f, 0.0f,
1666 1.0f, 2.0f, -2.0f, 0.0f,
1667 -1.0f, 3.0f, -3.0f, 0.0f,
1668 1.0f, 4.0f, -4.0f, 0.0f,
1669 -1.0f, 5.0f, -5.0f, 0.0f,
1670 1.0f, 6.0f, -6.0f, 0.0f,
1671 -1.0f, 7.0f, -7.0f, 0.0f,
1672 1.0f, 8.0f, -8.0f, 0.0f,
1673 -1.0f, 9.0f, -9.0f, 0.0f,
1674 1.0f, 10.0f, -10.0f, 0.0f,
1675 -1.0f, 11.0f, -11.0f, 0.0f,
1676 1.0f, 12.0f, -12.0f, 0.0f,
1677 -1.0f, 13.0f, -13.0f, 0.0f,
1678 1.0f, 14.0f, -14.0f, 0.0f,
1679 -1.0f, 15.0f, -15.0f, 0.0f };
Nicolas Capens157ba262019-12-10 17:49:14 -05001680
Ben Clayton713b8d32019-12-17 20:37:56 +00001681 float result[4];
Nicolas Capens157ba262019-12-10 17:49:14 -05001682
Ben Clayton713b8d32019-12-17 20:37:56 +00001683 routine(input, result);
Nicolas Capens157ba262019-12-10 17:49:14 -05001684
Ben Clayton713b8d32019-12-17 20:37:56 +00001685 EXPECT_EQ(result[0], 0.0f);
1686 EXPECT_EQ(result[1], 120.0f);
1687 EXPECT_EQ(result[2], -120.0f);
1688 EXPECT_EQ(result[3], 0.0f);
Stephen White17078c72019-02-27 14:39:14 -05001689}
1690
Ben Clayton713b8d32019-12-17 20:37:56 +00001691template<typename T>
Ben Clayton51f08312019-11-08 14:39:26 +00001692class CToReactorTCastTest : public ::testing::Test
Nicolas Capensf0d22ad2019-03-15 17:22:42 -04001693{
Ben Claytonf3b57972019-03-15 09:56:47 +00001694public:
1695 using CType = typename std::tuple_element<0, T>::type;
1696 using ReactorType = typename std::tuple_element<1, T>::type;
1697};
1698
Ben Clayton713b8d32019-12-17 20:37:56 +00001699using CToReactorTCastTestTypes = ::testing::Types< // Subset of types that can be used as arguments.
1700 // std::pair<bool, Bool>, FIXME(capn): Not supported as argument type by Subzero.
1701 // std::pair<uint8_t, Byte>, FIXME(capn): Not supported as argument type by Subzero.
1702 // std::pair<int8_t, SByte>, FIXME(capn): Not supported as argument type by Subzero.
1703 // std::pair<int16_t, Short>, FIXME(capn): Not supported as argument type by Subzero.
1704 // std::pair<uint16_t, UShort>, FIXME(capn): Not supported as argument type by Subzero.
1705 std::pair<int, Int>,
1706 std::pair<unsigned int, UInt>,
1707 std::pair<float, Float>>;
Ben Claytonf3b57972019-03-15 09:56:47 +00001708
Ben Clayton51f08312019-11-08 14:39:26 +00001709TYPED_TEST_SUITE(CToReactorTCastTest, CToReactorTCastTestTypes);
Ben Claytonf3b57972019-03-15 09:56:47 +00001710
Ben Clayton51f08312019-11-08 14:39:26 +00001711TYPED_TEST(CToReactorTCastTest, Casts)
Nicolas Capensf0d22ad2019-03-15 17:22:42 -04001712{
Ben Claytonf3b57972019-03-15 09:56:47 +00001713 using CType = typename TestFixture::CType;
1714 using ReactorType = typename TestFixture::ReactorType;
1715
Ben Clayton6897e9b2019-07-16 17:27:27 +01001716 std::shared_ptr<Routine> routine;
Ben Claytonf3b57972019-03-15 09:56:47 +00001717
1718 {
Ben Clayton713b8d32019-12-17 20:37:56 +00001719 Function<Int(ReactorType)> function;
Ben Claytonf3b57972019-03-15 09:56:47 +00001720 {
1721 ReactorType a = function.template Arg<0>();
1722 ReactorType b = CType{};
1723 RValue<ReactorType> c = RValue<ReactorType>(CType{});
1724 Bool same = (a == b) && (a == c);
Ben Clayton713b8d32019-12-17 20:37:56 +00001725 Return(IfThenElse(same, Int(1), Int(0))); // TODO: Ability to use Bools as return values.
Ben Claytonf3b57972019-03-15 09:56:47 +00001726 }
1727
1728 routine = function("one");
1729
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001730 auto callable = (int (*)(CType))routine->getEntry();
1731 CType in = {};
1732 EXPECT_EQ(callable(in), 1);
Ben Claytonf3b57972019-03-15 09:56:47 +00001733 }
Ben Claytonf3b57972019-03-15 09:56:47 +00001734}
1735
Ben Clayton713b8d32019-12-17 20:37:56 +00001736template<typename T>
Nicolas Capensf0d22ad2019-03-15 17:22:42 -04001737class GEPTest : public ::testing::Test
1738{
Ben Claytonb1243732019-02-27 23:56:18 +00001739public:
1740 using CType = typename std::tuple_element<0, T>::type;
1741 using ReactorType = typename std::tuple_element<1, T>::type;
1742};
1743
Ben Clayton713b8d32019-12-17 20:37:56 +00001744using GEPTestTypes = ::testing::Types<
1745 std::pair<bool, Bool>,
1746 std::pair<int8_t, Byte>,
1747 std::pair<int8_t, SByte>,
1748 std::pair<int8_t[4], Byte4>,
1749 std::pair<int8_t[4], SByte4>,
1750 std::pair<int8_t[8], Byte8>,
1751 std::pair<int8_t[8], SByte8>,
1752 std::pair<int8_t[16], Byte16>,
1753 std::pair<int8_t[16], SByte16>,
1754 std::pair<int16_t, Short>,
1755 std::pair<int16_t, UShort>,
1756 std::pair<int16_t[2], Short2>,
1757 std::pair<int16_t[2], UShort2>,
1758 std::pair<int16_t[4], Short4>,
1759 std::pair<int16_t[4], UShort4>,
1760 std::pair<int16_t[8], Short8>,
1761 std::pair<int16_t[8], UShort8>,
1762 std::pair<int, Int>,
1763 std::pair<int, UInt>,
1764 std::pair<int[2], Int2>,
1765 std::pair<int[2], UInt2>,
1766 std::pair<int[4], Int4>,
1767 std::pair<int[4], UInt4>,
1768 std::pair<int64_t, Long>,
1769 std::pair<int16_t, Half>,
1770 std::pair<float, Float>,
1771 std::pair<float[2], Float2>,
1772 std::pair<float[4], Float4>>;
Ben Claytonb1243732019-02-27 23:56:18 +00001773
Alexis Hetu79d4ac92019-06-03 11:31:46 -04001774TYPED_TEST_SUITE(GEPTest, GEPTestTypes);
Ben Claytonb1243732019-02-27 23:56:18 +00001775
Nicolas Capensf0d22ad2019-03-15 17:22:42 -04001776TYPED_TEST(GEPTest, PtrOffsets)
1777{
Ben Claytonb1243732019-02-27 23:56:18 +00001778 using CType = typename TestFixture::CType;
1779 using ReactorType = typename TestFixture::ReactorType;
1780
Ben Clayton6897e9b2019-07-16 17:27:27 +01001781 std::shared_ptr<Routine> routine;
Ben Claytonb1243732019-02-27 23:56:18 +00001782
1783 {
Ben Clayton713b8d32019-12-17 20:37:56 +00001784 Function<Pointer<ReactorType>(Pointer<ReactorType>, Int)> function;
Ben Claytonb1243732019-02-27 23:56:18 +00001785 {
1786 Pointer<ReactorType> pointer = function.template Arg<0>();
1787 Int index = function.template Arg<1>();
1788 Return(&pointer[index]);
1789 }
1790
1791 routine = function("one");
1792
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001793 auto callable = (CType * (*)(CType *, unsigned int)) routine->getEntry();
1794
1795 union PtrInt
Ben Claytonb1243732019-02-27 23:56:18 +00001796 {
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001797 CType *p;
1798 size_t i;
1799 };
Ben Claytonb1243732019-02-27 23:56:18 +00001800
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001801 PtrInt base;
1802 base.i = 0x10000;
Ben Claytonb1243732019-02-27 23:56:18 +00001803
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001804 for(int i = 0; i < 5; i++)
1805 {
1806 PtrInt reference;
1807 reference.p = &base.p[i];
Ben Claytonb1243732019-02-27 23:56:18 +00001808
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001809 PtrInt result;
1810 result.p = callable(base.p, i);
Ben Claytonb1243732019-02-27 23:56:18 +00001811
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001812 auto expect = reference.i - base.i;
1813 auto got = result.i - base.i;
Ben Claytonb1243732019-02-27 23:56:18 +00001814
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001815 EXPECT_EQ(got, expect) << "i:" << i;
Ben Claytonb1243732019-02-27 23:56:18 +00001816 }
1817 }
Ben Claytonb1243732019-02-27 23:56:18 +00001818}
1819
Nicolas Capensd2af84f2020-05-14 10:55:21 -04001820static const std::vector<int> fibonacci = {
1821 0,
1822 1,
1823 1,
1824 2,
1825 3,
1826 5,
1827 8,
1828 13,
1829 21,
1830 34,
1831 55,
1832 89,
1833 144,
1834 233,
1835 377,
1836 610,
1837 987,
1838 1597,
1839 2584,
1840 4181,
1841 6765,
1842 10946,
1843 17711,
1844 28657,
1845 46368,
1846 75025,
1847 121393,
1848 196418,
1849 317811,
1850};
1851
Antonio Maiorano8bce0672020-02-28 13:13:45 -05001852TEST(ReactorUnitTests, Fibonacci)
1853{
1854 FunctionT<int(int)> function;
1855 {
1856 Int n = function.Arg<0>();
1857 Int current = 0;
1858 Int next = 1;
1859 For(Int i = 0, i < n, i++)
1860 {
1861 auto tmp = current + next;
1862 current = next;
1863 next = tmp;
1864 }
1865 Return(current);
1866 }
1867
1868 auto routine = function("one");
1869
1870 for(size_t i = 0; i < fibonacci.size(); i++)
1871 {
1872 EXPECT_EQ(routine(i), fibonacci[i]);
1873 }
1874}
1875
Ben Clayton1c82c7b2019-04-30 12:49:27 +01001876TEST(ReactorUnitTests, Coroutines_Fibonacci)
1877{
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001878 if(!rr::Caps.CoroutinesSupported)
Ben Clayton1c82c7b2019-04-30 12:49:27 +01001879 {
1880 SUCCEED() << "Coroutines not supported";
1881 return;
1882 }
1883
1884 Coroutine<int()> function;
1885 {
1886 Yield(Int(0));
1887 Yield(Int(1));
1888 Int current = 1;
1889 Int next = 1;
Ben Clayton713b8d32019-12-17 20:37:56 +00001890 While(true)
1891 {
Ben Clayton1c82c7b2019-04-30 12:49:27 +01001892 Yield(next);
1893 auto tmp = current + next;
1894 current = next;
1895 next = tmp;
1896 }
1897 }
1898
1899 auto coroutine = function();
1900
Antonio Maiorano8bce0672020-02-28 13:13:45 -05001901 for(size_t i = 0; i < fibonacci.size(); i++)
Ben Clayton1c82c7b2019-04-30 12:49:27 +01001902 {
1903 int out = 0;
1904 EXPECT_EQ(coroutine->await(out), true);
Antonio Maiorano8bce0672020-02-28 13:13:45 -05001905 EXPECT_EQ(out, fibonacci[i]);
Ben Clayton1c82c7b2019-04-30 12:49:27 +01001906 }
1907}
1908
1909TEST(ReactorUnitTests, Coroutines_Parameters)
1910{
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001911 if(!rr::Caps.CoroutinesSupported)
Ben Clayton1c82c7b2019-04-30 12:49:27 +01001912 {
1913 SUCCEED() << "Coroutines not supported";
1914 return;
1915 }
1916
Ben Clayton713b8d32019-12-17 20:37:56 +00001917 Coroutine<uint8_t(uint8_t * data, int count)> function;
Ben Clayton1c82c7b2019-04-30 12:49:27 +01001918 {
1919 Pointer<Byte> data = function.Arg<0>();
1920 Int count = function.Arg<1>();
1921
1922 For(Int i = 0, i < count, i++)
1923 {
1924 Yield(data[i]);
1925 }
1926 }
1927
Ben Clayton713b8d32019-12-17 20:37:56 +00001928 uint8_t data[] = { 10, 20, 30 };
Ben Clayton1c82c7b2019-04-30 12:49:27 +01001929 auto coroutine = function(&data[0], 3);
1930
1931 uint8_t out = 0;
1932 EXPECT_EQ(coroutine->await(out), true);
Ben Clayton713b8d32019-12-17 20:37:56 +00001933 EXPECT_EQ(out, 10);
1934 out = 0;
Ben Clayton1c82c7b2019-04-30 12:49:27 +01001935 EXPECT_EQ(coroutine->await(out), true);
Ben Clayton713b8d32019-12-17 20:37:56 +00001936 EXPECT_EQ(out, 20);
1937 out = 0;
Ben Clayton1c82c7b2019-04-30 12:49:27 +01001938 EXPECT_EQ(coroutine->await(out), true);
Ben Clayton713b8d32019-12-17 20:37:56 +00001939 EXPECT_EQ(out, 30);
1940 out = 99;
Ben Clayton1c82c7b2019-04-30 12:49:27 +01001941 EXPECT_EQ(coroutine->await(out), false);
1942 EXPECT_EQ(out, 99);
1943 EXPECT_EQ(coroutine->await(out), false);
1944 EXPECT_EQ(out, 99);
1945}
1946
Antonio Maiorano5ba2a5b2020-01-17 15:29:37 -05001947// This test was written because Subzero's handling of vector types
1948// failed when more than one function is generated, as is the case
1949// with coroutines.
1950TEST(ReactorUnitTests, Coroutines_Vectors)
1951{
1952 if(!rr::Caps.CoroutinesSupported)
1953 {
1954 SUCCEED() << "Coroutines not supported";
1955 return;
1956 }
1957
1958 Coroutine<int()> function;
1959 {
1960 Int4 a{ 1, 2, 3, 4 };
1961 Yield(rr::Extract(a, 2));
1962 Int4 b{ 5, 6, 7, 8 };
1963 Yield(rr::Extract(b, 1));
1964 Int4 c{ 9, 10, 11, 12 };
1965 Yield(rr::Extract(c, 1));
1966 }
1967
1968 auto coroutine = function();
1969
1970 int out;
1971 coroutine->await(out);
1972 EXPECT_EQ(out, 3);
1973 coroutine->await(out);
1974 EXPECT_EQ(out, 6);
1975 coroutine->await(out);
1976 EXPECT_EQ(out, 10);
1977}
1978
1979// This test was written to make sure a coroutine without a Yield()
1980// works correctly, by executing like a regular function with no
1981// return (the return type is ignored).
1982// We also run it twice to ensure per instance and/or global state
1983// is properly cleaned up in between.
1984TEST(ReactorUnitTests, Coroutines_NoYield)
1985{
1986 if(!rr::Caps.CoroutinesSupported)
1987 {
1988 SUCCEED() << "Coroutines not supported";
1989 return;
1990 }
1991
1992 for(int i = 0; i < 2; ++i)
1993 {
1994 Coroutine<int()> function;
1995 {
1996 Int a;
1997 a = 4;
1998 }
1999
2000 auto coroutine = function();
2001 int out;
2002 EXPECT_EQ(coroutine->await(out), false);
2003 }
2004}
2005
2006// Test generating one coroutine, and executing it on multiple threads. This makes
2007// sure the implementation manages per-call instance data correctly.
2008TEST(ReactorUnitTests, Coroutines_Parallel)
2009{
2010 if(!rr::Caps.CoroutinesSupported)
2011 {
2012 SUCCEED() << "Coroutines not supported";
2013 return;
2014 }
2015
2016 Coroutine<int()> function;
2017 {
2018 Yield(Int(0));
2019 Yield(Int(1));
2020 Int current = 1;
2021 Int next = 1;
2022 While(true)
2023 {
2024 Yield(next);
2025 auto tmp = current + next;
2026 current = next;
2027 next = tmp;
2028 }
2029 }
2030
2031 // Must call on same thread that creates the coroutine
2032 function.finalize();
2033
Antonio Maiorano5ba2a5b2020-01-17 15:29:37 -05002034 std::vector<std::thread> threads;
2035 const size_t numThreads = 100;
2036
2037 for(size_t t = 0; t < numThreads; ++t)
2038 {
2039 threads.emplace_back([&] {
2040 auto coroutine = function();
2041
Antonio Maiorano8bce0672020-02-28 13:13:45 -05002042 for(size_t i = 0; i < fibonacci.size(); i++)
Antonio Maiorano5ba2a5b2020-01-17 15:29:37 -05002043 {
2044 int out = 0;
2045 EXPECT_EQ(coroutine->await(out), true);
Antonio Maiorano8bce0672020-02-28 13:13:45 -05002046 EXPECT_EQ(out, fibonacci[i]);
Antonio Maiorano5ba2a5b2020-01-17 15:29:37 -05002047 }
2048 });
2049 }
2050
2051 for(auto &t : threads)
2052 {
2053 t.join();
2054 }
2055}
2056
Ben Clayton713b8d32019-12-17 20:37:56 +00002057template<typename TestFuncType, typename RefFuncType, typename TestValueType>
Antonio Maioranobf151b82019-12-03 09:49:14 -05002058struct IntrinsicTestParams
2059{
Ben Clayton713b8d32019-12-17 20:37:56 +00002060 std::function<TestFuncType> testFunc; // Function we're testing (Reactor)
2061 std::function<RefFuncType> refFunc; // Reference function to test against (C)
2062 std::vector<TestValueType> testValues; // Values to input to functions
Antonio Maioranobf151b82019-12-03 09:49:14 -05002063};
2064
2065using IntrinsicTestParams_Float = IntrinsicTestParams<RValue<Float>(RValue<Float>), float(float), float>;
2066using IntrinsicTestParams_Float4 = IntrinsicTestParams<RValue<Float4>(RValue<Float4>), float(float), float>;
2067using IntrinsicTestParams_Float4_Float4 = IntrinsicTestParams<RValue<Float4>(RValue<Float4>, RValue<Float4>), float(float, float), std::pair<float, float>>;
2068
Antonio Maiorano9c14bda2020-09-18 16:33:36 -04002069// TODO(b/147818976): Each function has its own precision requirements for Vulkan, sometimes broken down
2070// by input range. These are currently validated by deqp, but we can improve our own tests as well.
2071// See https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#spirvenv-precision-operation
2072constexpr double INTRINSIC_PRECISION = 1e-4;
2073
Antonio Maioranobf151b82019-12-03 09:49:14 -05002074struct IntrinsicTest_Float : public testing::TestWithParam<IntrinsicTestParams_Float>
2075{
2076 void test()
2077 {
2078 FunctionT<float(float)> function;
2079 {
2080 Return(GetParam().testFunc((Float(function.Arg<0>()))));
2081 }
2082
2083 auto routine = function("one");
2084
Ben Clayton713b8d32019-12-17 20:37:56 +00002085 for(auto &&v : GetParam().testValues)
Antonio Maioranobf151b82019-12-03 09:49:14 -05002086 {
2087 SCOPED_TRACE(v);
Antonio Maiorano9c14bda2020-09-18 16:33:36 -04002088 EXPECT_NEAR(routine(v), GetParam().refFunc(v), INTRINSIC_PRECISION);
Antonio Maioranobf151b82019-12-03 09:49:14 -05002089 }
2090 }
2091};
2092
Nicolas Capensd2af84f2020-05-14 10:55:21 -04002093using float4 = float[4];
2094using int4 = int[4];
2095
2096// TODO: Move to Reactor.hpp
2097template<>
2098struct rr::CToReactor<int[4]>
2099{
2100 using type = Int4;
2101 static Int4 cast(float[4]);
2102};
2103
2104// Value type wrapper around a <type>[4] (i.e. float4, int4)
2105template<typename T>
2106struct type4_value
2107{
2108 using E = typename std::remove_pointer_t<std::decay_t<T>>;
2109
2110 type4_value() = default;
2111 explicit type4_value(E rep)
2112 : v{ rep, rep, rep, rep }
2113 {}
2114 type4_value(E x, E y, E z, E w)
2115 : v{ x, y, z, w }
2116 {}
2117
2118 bool operator==(const type4_value &rhs) const
2119 {
2120 return std::equal(std::begin(v), std::end(v), rhs.v);
2121 }
2122
2123 // For gtest printing
2124 friend std::ostream &operator<<(std::ostream &os, const type4_value &value)
2125 {
2126 return os << "[" << value.v[0] << ", " << value.v[1] << ", " << value.v[2] << ", " << value.v[3] << "]";
2127 }
2128
2129 T v;
2130};
2131
2132using float4_value = type4_value<float4>;
2133using int4_value = type4_value<int4>;
2134
2135// Invoke a void(type4_value<T>*) routine on &v.v, returning wrapped result in v
2136template<typename RoutineType, typename T>
2137type4_value<T> invokeRoutine(RoutineType &routine, type4_value<T> v)
2138{
2139 routine(&v.v);
2140 return v;
2141}
2142
2143// Invoke a void(type4_value<T>*, type4_value<T>*) routine on &v1.v, &v2.v returning wrapped result in v1
2144template<typename RoutineType, typename T>
2145type4_value<T> invokeRoutine(RoutineType &routine, type4_value<T> v1, type4_value<T> v2)
2146{
2147 routine(&v1.v, &v2.v);
2148 return v1;
2149}
2150
Antonio Maioranobf151b82019-12-03 09:49:14 -05002151struct IntrinsicTest_Float4 : public testing::TestWithParam<IntrinsicTestParams_Float4>
2152{
2153 void test()
2154 {
Ben Clayton713b8d32019-12-17 20:37:56 +00002155 FunctionT<void(float4 *)> function;
Antonio Maioranobf151b82019-12-03 09:49:14 -05002156 {
2157 Pointer<Float4> a = function.Arg<0>();
2158 *a = GetParam().testFunc(*a);
2159 Return();
2160 }
2161
2162 auto routine = function("one");
2163
Ben Clayton713b8d32019-12-17 20:37:56 +00002164 for(auto &&v : GetParam().testValues)
Antonio Maioranobf151b82019-12-03 09:49:14 -05002165 {
2166 SCOPED_TRACE(v);
2167 float4_value result = invokeRoutine(routine, float4_value{ v });
2168 float4_value expected = float4_value{ GetParam().refFunc(v) };
Antonio Maiorano9c14bda2020-09-18 16:33:36 -04002169 EXPECT_NEAR(result.v[0], expected.v[0], INTRINSIC_PRECISION);
2170 EXPECT_NEAR(result.v[1], expected.v[1], INTRINSIC_PRECISION);
2171 EXPECT_NEAR(result.v[2], expected.v[2], INTRINSIC_PRECISION);
2172 EXPECT_NEAR(result.v[3], expected.v[3], INTRINSIC_PRECISION);
Antonio Maioranobf151b82019-12-03 09:49:14 -05002173 }
2174 }
2175};
2176
2177struct IntrinsicTest_Float4_Float4 : public testing::TestWithParam<IntrinsicTestParams_Float4_Float4>
2178{
2179 void test()
2180 {
Ben Clayton713b8d32019-12-17 20:37:56 +00002181 FunctionT<void(float4 *, float4 *)> function;
Antonio Maioranobf151b82019-12-03 09:49:14 -05002182 {
2183 Pointer<Float4> a = function.Arg<0>();
2184 Pointer<Float4> b = function.Arg<1>();
2185 *a = GetParam().testFunc(*a, *b);
2186 Return();
2187 }
2188
2189 auto routine = function("one");
2190
Ben Clayton713b8d32019-12-17 20:37:56 +00002191 for(auto &&v : GetParam().testValues)
Antonio Maioranobf151b82019-12-03 09:49:14 -05002192 {
2193 SCOPED_TRACE(v);
2194 float4_value result = invokeRoutine(routine, float4_value{ v.first }, float4_value{ v.second });
2195 float4_value expected = float4_value{ GetParam().refFunc(v.first, v.second) };
Antonio Maiorano9c14bda2020-09-18 16:33:36 -04002196 EXPECT_NEAR(result.v[0], expected.v[0], INTRINSIC_PRECISION);
2197 EXPECT_NEAR(result.v[1], expected.v[1], INTRINSIC_PRECISION);
2198 EXPECT_NEAR(result.v[2], expected.v[2], INTRINSIC_PRECISION);
2199 EXPECT_NEAR(result.v[3], expected.v[3], INTRINSIC_PRECISION);
Antonio Maioranobf151b82019-12-03 09:49:14 -05002200 }
2201 }
2202};
2203
Antonio Maiorano2d7ca9c2020-02-07 16:47:02 -05002204// clang-format off
2205INSTANTIATE_TEST_SUITE_P(IntrinsicTestParams_Float, IntrinsicTest_Float, testing::Values(
Antonio Maiorano9c14bda2020-09-18 16:33:36 -04002206 IntrinsicTestParams_Float{ [](Float v) { return rr::Exp2(v); }, exp2f, {0.f, 1.f, 123.f} },
2207 IntrinsicTestParams_Float{ [](Float v) { return rr::Log2(v); }, log2f, {1.f, 123.f} },
2208 IntrinsicTestParams_Float{ [](Float v) { return rr::Sqrt(v); }, sqrtf, {0.f, 1.f, 123.f} }
Antonio Maiorano2d7ca9c2020-02-07 16:47:02 -05002209));
2210// clang-format on
Antonio Maioranobf151b82019-12-03 09:49:14 -05002211
Antonio Maiorano2d7ca9c2020-02-07 16:47:02 -05002212// TODO(b/149110874) Use coshf/sinhf when we've implemented SpirV versions at the SpirV level
Antonio Maiorano0aef6452020-02-07 16:50:44 -05002213float vulkan_sinhf(float a)
2214{
2215 return ((expf(a) - expf(-a)) / 2);
2216}
2217float vulkan_coshf(float a)
2218{
2219 return ((expf(a) + expf(-a)) / 2);
2220}
2221
Antonio Maiorano2d7ca9c2020-02-07 16:47:02 -05002222// clang-format off
Nicolas Capensd2af84f2020-05-14 10:55:21 -04002223constexpr float PI = 3.141592653589793f;
Antonio Maiorano2d7ca9c2020-02-07 16:47:02 -05002224INSTANTIATE_TEST_SUITE_P(IntrinsicTestParams_Float4, IntrinsicTest_Float4, testing::Values(
Antonio Maiorano9c14bda2020-09-18 16:33:36 -04002225 IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Sin(v); }, sinf, {0.f, 1.f, PI, 123.f} },
2226 IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Cos(v); }, cosf, {0.f, 1.f, PI, 123.f} },
2227 IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Tan(v); }, tanf, {0.f, 1.f, PI, 123.f} },
2228 IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Asin(v, Precision::Full); }, asinf, {0.f, 1.f, -1.f} },
2229 IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Acos(v, Precision::Full); }, acosf, {0.f, 1.f, -1.f} },
2230 IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Atan(v); }, atanf, {0.f, 1.f, PI, 123.f} },
2231 IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Sinh(v); }, vulkan_sinhf, {0.f, 1.f, PI} },
2232 IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Cosh(v); }, vulkan_coshf, {0.f, 1.f, PI} },
2233 IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Tanh(v); }, tanhf, {0.f, 1.f, PI} },
2234 IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Asinh(v); }, asinhf, {0.f, 1.f, PI, 123.f} },
2235 IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Acosh(v); }, acoshf, { 1.f, PI, 123.f} },
2236 IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Atanh(v); }, atanhf, {0.f, 0.9999f, -0.9999f} },
2237 IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Exp(v); }, expf, {0.f, 1.f, PI} },
2238 IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Log(v); }, logf, {1.f, PI, 123.f} },
2239 IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Exp2(v); }, exp2f, {0.f, 1.f, PI, 123.f} },
2240 IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Log2(v); }, log2f, {1.f, PI, 123.f} },
2241 IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Sqrt(v); }, sqrtf, {0.f, 1.f, PI, 123.f} }
Antonio Maiorano2d7ca9c2020-02-07 16:47:02 -05002242));
2243// clang-format on
Antonio Maioranobf151b82019-12-03 09:49:14 -05002244
Antonio Maiorano2d7ca9c2020-02-07 16:47:02 -05002245// clang-format off
2246INSTANTIATE_TEST_SUITE_P(IntrinsicTestParams_Float4_Float4, IntrinsicTest_Float4_Float4, testing::Values(
Antonio Maiorano9c14bda2020-09-18 16:33:36 -04002247 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} } },
2248 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 -05002249));
2250// clang-format on
Antonio Maioranobf151b82019-12-03 09:49:14 -05002251
Ben Clayton713b8d32019-12-17 20:37:56 +00002252TEST_P(IntrinsicTest_Float, Test)
2253{
2254 test();
2255}
2256TEST_P(IntrinsicTest_Float4, Test)
2257{
2258 test();
2259}
2260TEST_P(IntrinsicTest_Float4_Float4, Test)
2261{
2262 test();
2263}
Antonio Maioranobf151b82019-12-03 09:49:14 -05002264
2265TEST(ReactorUnitTests, Intrinsics_Ctlz)
2266{
2267 // ctlz: counts number of leading zeros
2268
2269 {
2270 Function<UInt(UInt x)> function;
2271 {
2272 UInt x = function.Arg<0>();
2273 Return(rr::Ctlz(x, false));
2274 }
2275 auto routine = function("one");
2276 auto callable = (uint32_t(*)(uint32_t))routine->getEntry();
2277
Ben Clayton713b8d32019-12-17 20:37:56 +00002278 for(uint32_t i = 0; i < 31; ++i)
2279 {
Antonio Maioranobf151b82019-12-03 09:49:14 -05002280 uint32_t result = callable(1 << i);
2281 EXPECT_EQ(result, 31 - i);
2282 }
2283
2284 // Input 0 should return 32 for isZeroUndef == false
2285 {
2286 uint32_t result = callable(0);
2287 EXPECT_EQ(result, 32u);
2288 }
2289 }
2290
2291 {
2292 Function<Void(Pointer<UInt4>, UInt x)> function;
2293 {
2294 Pointer<UInt4> out = function.Arg<0>();
2295 UInt x = function.Arg<1>();
2296 *out = rr::Ctlz(UInt4(x), false);
2297 }
2298 auto routine = function("one");
Ben Clayton713b8d32019-12-17 20:37:56 +00002299 auto callable = (void (*)(uint32_t *, uint32_t))routine->getEntry();
Antonio Maioranobf151b82019-12-03 09:49:14 -05002300
2301 uint32_t x[4];
2302
Ben Clayton713b8d32019-12-17 20:37:56 +00002303 for(uint32_t i = 0; i < 31; ++i)
2304 {
Antonio Maioranobf151b82019-12-03 09:49:14 -05002305 callable(x, 1 << i);
2306 EXPECT_EQ(x[0], 31 - i);
2307 EXPECT_EQ(x[1], 31 - i);
2308 EXPECT_EQ(x[2], 31 - i);
2309 EXPECT_EQ(x[3], 31 - i);
2310 }
2311
2312 // Input 0 should return 32 for isZeroUndef == false
2313 {
2314 callable(x, 0);
2315 EXPECT_EQ(x[0], 32u);
2316 EXPECT_EQ(x[1], 32u);
2317 EXPECT_EQ(x[2], 32u);
2318 EXPECT_EQ(x[3], 32u);
2319 }
2320 }
2321}
2322
2323TEST(ReactorUnitTests, Intrinsics_Cttz)
2324{
2325 // cttz: counts number of trailing zeros
2326
2327 {
2328 Function<UInt(UInt x)> function;
2329 {
2330 UInt x = function.Arg<0>();
2331 Return(rr::Cttz(x, false));
2332 }
2333 auto routine = function("one");
2334 auto callable = (uint32_t(*)(uint32_t))routine->getEntry();
2335
Ben Clayton713b8d32019-12-17 20:37:56 +00002336 for(uint32_t i = 0; i < 31; ++i)
2337 {
Antonio Maioranobf151b82019-12-03 09:49:14 -05002338 uint32_t result = callable(1 << i);
2339 EXPECT_EQ(result, i);
2340 }
2341
2342 // Input 0 should return 32 for isZeroUndef == false
2343 {
2344 uint32_t result = callable(0);
2345 EXPECT_EQ(result, 32u);
2346 }
2347 }
2348
2349 {
2350 Function<Void(Pointer<UInt4>, UInt x)> function;
2351 {
2352 Pointer<UInt4> out = function.Arg<0>();
2353 UInt x = function.Arg<1>();
2354 *out = rr::Cttz(UInt4(x), false);
2355 }
2356 auto routine = function("one");
Ben Clayton713b8d32019-12-17 20:37:56 +00002357 auto callable = (void (*)(uint32_t *, uint32_t))routine->getEntry();
Antonio Maioranobf151b82019-12-03 09:49:14 -05002358
2359 uint32_t x[4];
2360
Ben Clayton713b8d32019-12-17 20:37:56 +00002361 for(uint32_t i = 0; i < 31; ++i)
2362 {
Antonio Maioranobf151b82019-12-03 09:49:14 -05002363 callable(x, 1 << i);
2364 EXPECT_EQ(x[0], i);
2365 EXPECT_EQ(x[1], i);
2366 EXPECT_EQ(x[2], i);
2367 EXPECT_EQ(x[3], i);
2368 }
2369
2370 // Input 0 should return 32 for isZeroUndef == false
2371 {
2372 callable(x, 0);
2373 EXPECT_EQ(x[0], 32u);
2374 EXPECT_EQ(x[1], 32u);
2375 EXPECT_EQ(x[2], 32u);
2376 EXPECT_EQ(x[3], 32u);
2377 }
2378 }
2379}
2380
2381TEST(ReactorUnitTests, Intrinsics_Scatter)
2382{
2383 Function<Void(Pointer<Float> base, Pointer<Float4> val, Pointer<Int4> offsets)> function;
2384 {
2385 Pointer<Float> base = function.Arg<0>();
2386 Pointer<Float4> val = function.Arg<1>();
2387 Pointer<Int4> offsets = function.Arg<2>();
2388
2389 auto mask = Int4(~0, ~0, ~0, ~0);
2390 unsigned int alignment = 1;
2391 Scatter(base, *val, *offsets, mask, alignment);
2392 }
2393
Ben Clayton713b8d32019-12-17 20:37:56 +00002394 float buffer[16] = { 0 };
Antonio Maioranobf151b82019-12-03 09:49:14 -05002395
2396 constexpr auto elemSize = sizeof(buffer[0]);
2397
Ben Clayton713b8d32019-12-17 20:37:56 +00002398 int offsets[] = {
2399 1 * elemSize,
2400 6 * elemSize,
2401 11 * elemSize,
2402 13 * elemSize
Antonio Maioranobf151b82019-12-03 09:49:14 -05002403 };
2404
Ben Clayton713b8d32019-12-17 20:37:56 +00002405 float val[4] = { 10, 60, 110, 130 };
Antonio Maioranobf151b82019-12-03 09:49:14 -05002406
2407 auto routine = function("one");
Ben Clayton713b8d32019-12-17 20:37:56 +00002408 auto entry = (void (*)(float *, float *, int *))routine->getEntry();
Antonio Maioranobf151b82019-12-03 09:49:14 -05002409
2410 entry(buffer, val, offsets);
2411
2412 EXPECT_EQ(buffer[offsets[0] / sizeof(buffer[0])], 10);
2413 EXPECT_EQ(buffer[offsets[1] / sizeof(buffer[0])], 60);
2414 EXPECT_EQ(buffer[offsets[2] / sizeof(buffer[0])], 110);
2415 EXPECT_EQ(buffer[offsets[3] / sizeof(buffer[0])], 130);
2416}
2417
2418TEST(ReactorUnitTests, Intrinsics_Gather)
2419{
2420 Function<Void(Pointer<Float> base, Pointer<Int4> offsets, Pointer<Float4> result)> function;
2421 {
2422 Pointer<Float> base = function.Arg<0>();
2423 Pointer<Int4> offsets = function.Arg<1>();
2424 Pointer<Float4> result = function.Arg<2>();
2425
2426 auto mask = Int4(~0, ~0, ~0, ~0);
2427 unsigned int alignment = 1;
2428 bool zeroMaskedLanes = true;
2429 *result = Gather(base, *offsets, mask, alignment, zeroMaskedLanes);
2430 }
2431
Ben Clayton713b8d32019-12-17 20:37:56 +00002432 float buffer[] = {
Antonio Maioranobf151b82019-12-03 09:49:14 -05002433 0, 10, 20, 30,
2434 40, 50, 60, 70,
2435 80, 90, 100, 110,
2436 120, 130, 140, 150
2437 };
2438
2439 constexpr auto elemSize = sizeof(buffer[0]);
2440
Ben Clayton713b8d32019-12-17 20:37:56 +00002441 int offsets[] = {
2442 1 * elemSize,
2443 6 * elemSize,
2444 11 * elemSize,
2445 13 * elemSize
Antonio Maioranobf151b82019-12-03 09:49:14 -05002446 };
2447
2448 auto routine = function("one");
Ben Clayton713b8d32019-12-17 20:37:56 +00002449 auto entry = (void (*)(float *, int *, float *))routine->getEntry();
Antonio Maioranobf151b82019-12-03 09:49:14 -05002450
2451 float result[4] = {};
2452 entry(buffer, offsets, result);
2453
2454 EXPECT_EQ(result[0], 10);
2455 EXPECT_EQ(result[1], 60);
2456 EXPECT_EQ(result[2], 110);
2457 EXPECT_EQ(result[3], 130);
2458}
2459
Antonio Maiorano7ffda5b2019-11-20 15:31:51 -05002460TEST(ReactorUnitTests, ExtractFromRValue)
2461{
2462 Function<Void(Pointer<Int4> values, Pointer<Int4> result)> function;
2463 {
2464 Pointer<Int4> vIn = function.Arg<0>();
2465 Pointer<Int4> resultIn = function.Arg<1>();
2466
2467 RValue<Int4> v = *vIn;
2468
2469 Int4 result(678);
2470
2471 If(Extract(v, 0) == 42)
2472 {
2473 result = Insert(result, 1, 0);
2474 }
2475
2476 If(Extract(v, 1) == 42)
2477 {
2478 result = Insert(result, 1, 1);
2479 }
2480
2481 *resultIn = result;
2482
2483 Return();
2484 }
2485
2486 auto routine = function("one");
Ben Clayton713b8d32019-12-17 20:37:56 +00002487 auto entry = (void (*)(int *, int *))routine->getEntry();
Antonio Maiorano7ffda5b2019-11-20 15:31:51 -05002488
2489 int v[4] = { 42, 42, 42, 42 };
2490 int result[4] = { 99, 99, 99, 99 };
2491 entry(v, result);
2492 EXPECT_EQ(result[0], 1);
2493 EXPECT_EQ(result[1], 1);
2494 EXPECT_EQ(result[2], 678);
2495 EXPECT_EQ(result[3], 678);
2496}
2497
Antonio Maiorano370cba52019-12-31 11:36:07 -05002498TEST(ReactorUnitTests, AddAtomic)
2499{
2500 FunctionT<uint32_t(uint32_t * p, uint32_t a)> function;
2501 {
2502 Pointer<UInt> p = function.Arg<0>();
2503 UInt a = function.Arg<1>();
2504 UInt r = rr::AddAtomic(p, a, std::memory_order_relaxed);
2505 Return(r);
2506 }
2507
2508 auto routine = function("one");
2509 uint32_t x = 123;
2510 uint32_t y = 456;
2511 uint32_t prevX = routine(&x, y);
2512 EXPECT_EQ(prevX, 123u);
2513 EXPECT_EQ(x, 579u);
2514}
2515
2516TEST(ReactorUnitTests, SubAtomic)
2517{
2518 FunctionT<uint32_t(uint32_t * p, uint32_t a)> function;
2519 {
2520 Pointer<UInt> p = function.Arg<0>();
2521 UInt a = function.Arg<1>();
2522 UInt r = rr::SubAtomic(p, a, std::memory_order_relaxed);
2523 Return(r);
2524 }
2525
2526 auto routine = function("one");
2527 uint32_t x = 456;
2528 uint32_t y = 123;
2529 uint32_t prevX = routine(&x, y);
2530 EXPECT_EQ(prevX, 456u);
2531 EXPECT_EQ(x, 333u);
2532}
2533
2534TEST(ReactorUnitTests, AndAtomic)
2535{
2536 FunctionT<uint32_t(uint32_t * p, uint32_t a)> function;
2537 {
2538 Pointer<UInt> p = function.Arg<0>();
2539 UInt a = function.Arg<1>();
2540 UInt r = rr::AndAtomic(p, a, std::memory_order_relaxed);
2541 Return(r);
2542 }
2543
2544 auto routine = function("one");
2545 uint32_t x = 0b1111'0000;
2546 uint32_t y = 0b1010'1100;
2547 uint32_t prevX = routine(&x, y);
2548 EXPECT_EQ(prevX, 0b1111'0000u);
2549 EXPECT_EQ(x, 0b1010'0000u);
2550}
2551
2552TEST(ReactorUnitTests, OrAtomic)
2553{
2554 FunctionT<uint32_t(uint32_t * p, uint32_t a)> function;
2555 {
2556 Pointer<UInt> p = function.Arg<0>();
2557 UInt a = function.Arg<1>();
2558 UInt r = rr::OrAtomic(p, a, std::memory_order_relaxed);
2559 Return(r);
2560 }
2561
2562 auto routine = function("one");
2563 uint32_t x = 0b1111'0000;
2564 uint32_t y = 0b1010'1100;
2565 uint32_t prevX = routine(&x, y);
2566 EXPECT_EQ(prevX, 0b1111'0000u);
2567 EXPECT_EQ(x, 0b1111'1100u);
2568}
2569
2570TEST(ReactorUnitTests, XorAtomic)
2571{
2572 FunctionT<uint32_t(uint32_t * p, uint32_t a)> function;
2573 {
2574 Pointer<UInt> p = function.Arg<0>();
2575 UInt a = function.Arg<1>();
2576 UInt r = rr::XorAtomic(p, a, std::memory_order_relaxed);
2577 Return(r);
2578 }
2579
2580 auto routine = function("one");
2581 uint32_t x = 0b1111'0000;
2582 uint32_t y = 0b1010'1100;
2583 uint32_t prevX = routine(&x, y);
2584 EXPECT_EQ(prevX, 0b1111'0000u);
2585 EXPECT_EQ(x, 0b0101'1100u);
2586}
2587
2588TEST(ReactorUnitTests, MinAtomic)
2589{
2590 {
2591 FunctionT<uint32_t(uint32_t * p, uint32_t a)> function;
2592 {
2593 Pointer<UInt> p = function.Arg<0>();
2594 UInt a = function.Arg<1>();
2595 UInt r = rr::MinAtomic(p, a, std::memory_order_relaxed);
2596 Return(r);
2597 }
2598
2599 auto routine = function("one");
2600 uint32_t x = 123;
2601 uint32_t y = 100;
2602 uint32_t prevX = routine(&x, y);
2603 EXPECT_EQ(prevX, 123u);
2604 EXPECT_EQ(x, 100u);
2605 }
2606
2607 {
2608 FunctionT<int32_t(int32_t * p, int32_t a)> function;
2609 {
2610 Pointer<Int> p = function.Arg<0>();
2611 Int a = function.Arg<1>();
2612 Int r = rr::MinAtomic(p, a, std::memory_order_relaxed);
2613 Return(r);
2614 }
2615
2616 auto routine = function("one");
2617 int32_t x = -123;
2618 int32_t y = -200;
2619 int32_t prevX = routine(&x, y);
2620 EXPECT_EQ(prevX, -123);
2621 EXPECT_EQ(x, -200);
2622 }
2623}
2624
2625TEST(ReactorUnitTests, MaxAtomic)
2626{
2627 {
2628 FunctionT<uint32_t(uint32_t * p, uint32_t a)> function;
2629 {
2630 Pointer<UInt> p = function.Arg<0>();
2631 UInt a = function.Arg<1>();
2632 UInt r = rr::MaxAtomic(p, a, std::memory_order_relaxed);
2633 Return(r);
2634 }
2635
2636 auto routine = function("one");
2637 uint32_t x = 123;
2638 uint32_t y = 100;
2639 uint32_t prevX = routine(&x, y);
2640 EXPECT_EQ(prevX, 123u);
2641 EXPECT_EQ(x, 123u);
2642 }
2643
2644 {
2645 FunctionT<int32_t(int32_t * p, int32_t a)> function;
2646 {
2647 Pointer<Int> p = function.Arg<0>();
2648 Int a = function.Arg<1>();
2649 Int r = rr::MaxAtomic(p, a, std::memory_order_relaxed);
2650 Return(r);
2651 }
2652
2653 auto routine = function("one");
2654 int32_t x = -123;
2655 int32_t y = -200;
2656 int32_t prevX = routine(&x, y);
2657 EXPECT_EQ(prevX, -123);
2658 EXPECT_EQ(x, -123);
2659 }
2660}
2661
2662TEST(ReactorUnitTests, ExchangeAtomic)
2663{
2664 FunctionT<uint32_t(uint32_t * p, uint32_t a)> function;
2665 {
2666 Pointer<UInt> p = function.Arg<0>();
2667 UInt a = function.Arg<1>();
2668 UInt r = rr::ExchangeAtomic(p, a, std::memory_order_relaxed);
2669 Return(r);
2670 }
2671
2672 auto routine = function("one");
2673 uint32_t x = 123;
2674 uint32_t y = 456;
2675 uint32_t prevX = routine(&x, y);
2676 EXPECT_EQ(prevX, 123u);
2677 EXPECT_EQ(x, y);
2678}
2679
2680TEST(ReactorUnitTests, CompareExchangeAtomic)
2681{
2682 FunctionT<uint32_t(uint32_t * x, uint32_t y, uint32_t compare)> function;
2683 {
2684 Pointer<UInt> x = function.Arg<0>();
2685 UInt y = function.Arg<1>();
2686 UInt compare = function.Arg<2>();
2687 UInt r = rr::CompareExchangeAtomic(x, y, compare, std::memory_order_relaxed, std::memory_order_relaxed);
2688 Return(r);
2689 }
2690
2691 auto routine = function("one");
2692 uint32_t x = 123;
2693 uint32_t y = 456;
2694 uint32_t compare = 123;
2695 uint32_t prevX = routine(&x, y, compare);
2696 EXPECT_EQ(prevX, 123u);
2697 EXPECT_EQ(x, y);
2698
2699 x = 123;
2700 y = 456;
2701 compare = 456;
2702 prevX = routine(&x, y, compare);
2703 EXPECT_EQ(prevX, 123u);
2704 EXPECT_EQ(x, 123u);
2705}
2706
Antonio Maiorano5ef91b82020-01-21 15:10:22 -05002707TEST(ReactorUnitTests, SRem)
2708{
2709 FunctionT<void(int4 *, int4 *)> function;
2710 {
2711 Pointer<Int4> a = function.Arg<0>();
2712 Pointer<Int4> b = function.Arg<1>();
2713 *a = *a % *b;
2714 }
2715
2716 auto routine = function("one");
2717
2718 int4_value result = invokeRoutine(routine, int4_value{ 10, 11, 12, 13 }, int4_value{ 3, 3, 3, 3 });
2719 int4_value expected = int4_value{ 10 % 3, 11 % 3, 12 % 3, 13 % 3 };
2720 EXPECT_FLOAT_EQ(result.v[0], expected.v[0]);
2721 EXPECT_FLOAT_EQ(result.v[1], expected.v[1]);
2722 EXPECT_FLOAT_EQ(result.v[2], expected.v[2]);
2723 EXPECT_FLOAT_EQ(result.v[3], expected.v[3]);
2724}
2725
2726TEST(ReactorUnitTests, FRem)
2727{
2728 FunctionT<void(float4 *, float4 *)> function;
2729 {
2730 Pointer<Float4> a = function.Arg<0>();
2731 Pointer<Float4> b = function.Arg<1>();
2732 *a = *a % *b;
2733 }
2734
2735 auto routine = function("one");
2736
2737 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 });
2738 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) };
2739 EXPECT_FLOAT_EQ(result.v[0], expected.v[0]);
2740 EXPECT_FLOAT_EQ(result.v[1], expected.v[1]);
2741 EXPECT_FLOAT_EQ(result.v[2], expected.v[2]);
2742 EXPECT_FLOAT_EQ(result.v[3], expected.v[3]);
2743}
2744
Antonio Maiorano02a39532020-01-21 15:15:34 -05002745// Subzero's load instruction assumes that a Constant ptr value is an offset, rather than an absolute
2746// pointer, and would fail during codegen. This was fixed by casting the constant to a non-const
2747// variable, and loading from it instead. This test makes sure this works.
2748TEST(ReactorUnitTests, LoadFromConstantData)
2749{
2750 const int value = 123;
2751
2752 FunctionT<int()> function;
2753 {
2754 auto p = Pointer<Int>{ ConstantData(&value, sizeof(value)) };
2755 Int v = *p;
2756 Return(v);
2757 }
2758
2759 const int result = function("one")();
2760 EXPECT_EQ(result, value);
2761}
2762
Ben Clayton20cf5c52019-07-01 11:13:27 +01002763TEST(ReactorUnitTests, Multithreaded_Function)
2764{
Ben Clayton587fbb92020-04-27 16:25:03 +01002765 constexpr int numThreads = 8;
2766 constexpr int numLoops = 16;
Ben Clayton20cf5c52019-07-01 11:13:27 +01002767
2768 auto threads = std::unique_ptr<std::thread[]>(new std::thread[numThreads]);
2769 auto results = std::unique_ptr<int[]>(new int[numThreads * numLoops]);
2770
2771 for(int t = 0; t < numThreads; t++)
2772 {
2773 auto threadFunc = [&](int t) {
2774 for(int l = 0; l < numLoops; l++)
2775 {
2776 FunctionT<int(int, int)> function;
2777 {
2778 Int a = function.Arg<0>();
2779 Int b = function.Arg<1>();
2780 Return((a << 16) | b);
2781 }
2782
2783 auto f = function("thread%d_loop%d", t, l);
2784 results[t * numLoops + l] = f(t, l);
2785 }
2786 };
2787 threads[t] = std::thread(threadFunc, t);
2788 }
2789
2790 for(int t = 0; t < numThreads; t++)
2791 {
2792 threads[t].join();
2793 }
2794
2795 for(int t = 0; t < numThreads; t++)
2796 {
2797 for(int l = 0; l < numLoops; l++)
2798 {
2799 auto expect = (t << 16) | l;
2800 auto result = results[t * numLoops + l];
2801 EXPECT_EQ(result, expect);
2802 }
2803 }
2804}
2805
2806TEST(ReactorUnitTests, Multithreaded_Coroutine)
2807{
2808 if(!rr::Caps.CoroutinesSupported)
2809 {
2810 SUCCEED() << "Coroutines not supported";
2811 return;
2812 }
2813
Ben Clayton587fbb92020-04-27 16:25:03 +01002814 constexpr int numThreads = 8;
2815 constexpr int numLoops = 16;
Ben Clayton20cf5c52019-07-01 11:13:27 +01002816
2817 struct Result
2818 {
2819 bool yieldReturns[3];
2820 int yieldValues[3];
2821 };
2822
2823 auto threads = std::unique_ptr<std::thread[]>(new std::thread[numThreads]);
2824 auto results = std::unique_ptr<Result[]>(new Result[numThreads * numLoops]);
2825
2826 for(int t = 0; t < numThreads; t++)
2827 {
2828 auto threadFunc = [&](int t) {
2829 for(int l = 0; l < numLoops; l++)
2830 {
2831 Coroutine<int(int, int)> function;
2832 {
2833 Int a = function.Arg<0>();
2834 Int b = function.Arg<1>();
2835 Yield(a);
2836 Yield(b);
2837 }
2838
2839 auto coroutine = function(t, l);
2840
2841 auto &result = results[t * numLoops + l];
2842 result = {};
2843 result.yieldReturns[0] = coroutine->await(result.yieldValues[0]);
2844 result.yieldReturns[1] = coroutine->await(result.yieldValues[1]);
2845 result.yieldReturns[2] = coroutine->await(result.yieldValues[2]);
2846 }
2847 };
2848 threads[t] = std::thread(threadFunc, t);
2849 }
2850
2851 for(int t = 0; t < numThreads; t++)
2852 {
2853 threads[t].join();
2854 }
2855
2856 for(int t = 0; t < numThreads; t++)
2857 {
2858 for(int l = 0; l < numLoops; l++)
2859 {
2860 auto const &result = results[t * numLoops + l];
2861 EXPECT_EQ(result.yieldReturns[0], true);
2862 EXPECT_EQ(result.yieldValues[0], t);
2863 EXPECT_EQ(result.yieldReturns[1], true);
2864 EXPECT_EQ(result.yieldValues[1], l);
2865 EXPECT_EQ(result.yieldReturns[2], false);
2866 EXPECT_EQ(result.yieldValues[2], 0);
2867 }
2868 }
2869}
2870
Nicolas Capensd2af84f2020-05-14 10:55:21 -04002871// For gtest printing of pairs
2872namespace std {
2873template<typename T, typename U>
2874std::ostream &operator<<(std::ostream &os, const std::pair<T, U> &value)
2875{
2876 return os << "{ " << value.first << ", " << value.second << " }";
2877}
2878} // namespace std
2879
2880class StdOutCapture
2881{
2882public:
2883 ~StdOutCapture()
2884 {
2885 stopIfCapturing();
2886 }
2887
2888 void start()
2889 {
2890 stopIfCapturing();
2891 capturing = true;
2892 testing::internal::CaptureStdout();
2893 }
2894
2895 std::string stop()
2896 {
2897 assert(capturing);
2898 capturing = false;
2899 return testing::internal::GetCapturedStdout();
2900 }
2901
2902private:
2903 void stopIfCapturing()
2904 {
2905 if(capturing)
2906 {
2907 // This stops the capture
2908 testing::internal::GetCapturedStdout();
2909 }
2910 }
2911
2912 bool capturing = false;
2913};
2914
2915std::vector<std::string> split(const std::string &s)
2916{
2917 std::vector<std::string> result;
2918 std::istringstream iss(s);
2919 for(std::string line; std::getline(iss, line);)
2920 {
2921 result.push_back(line);
2922 }
2923 return result;
2924}
2925
2926TEST(ReactorUnitTests, PrintPrimitiveTypes)
2927{
2928#if defined(ENABLE_RR_PRINT) && !defined(ENABLE_RR_EMIT_PRINT_LOCATION)
2929 FunctionT<void()> function;
2930 {
2931 bool b(true);
2932 int8_t i8(-1);
2933 uint8_t ui8(1);
2934 int16_t i16(-1);
2935 uint16_t ui16(1);
2936 int32_t i32(-1);
2937 uint32_t ui32(1);
2938 int64_t i64(-1);
2939 uint64_t ui64(1);
2940 float f(1);
2941 double d(2);
2942 const char *cstr = "const char*";
2943 std::string str = "std::string";
2944 int *p = nullptr;
2945
2946 RR_WATCH(b);
2947 RR_WATCH(i8);
2948 RR_WATCH(ui8);
2949 RR_WATCH(i16);
2950 RR_WATCH(ui16);
2951 RR_WATCH(i32);
2952 RR_WATCH(ui32);
2953 RR_WATCH(i64);
2954 RR_WATCH(ui64);
2955 RR_WATCH(f);
2956 RR_WATCH(d);
2957 RR_WATCH(cstr);
2958 RR_WATCH(str);
2959 RR_WATCH(p);
2960 }
2961
2962 auto routine = function("one");
2963
2964 char pNullptr[64];
2965 snprintf(pNullptr, sizeof(pNullptr), " p: %p", nullptr);
2966
2967 const char *expected[] = {
2968 " b: true",
2969 " i8: -1",
2970 " ui8: 1",
2971 " i16: -1",
2972 " ui16: 1",
2973 " i32: -1",
2974 " ui32: 1",
2975 " i64: -1",
2976 " ui64: 1",
2977 " f: 1.000000",
2978 " d: 2.000000",
2979 " cstr: const char*",
2980 " str: std::string",
2981 pNullptr,
2982 };
2983 constexpr size_t expectedSize = sizeof(expected) / sizeof(expected[0]);
2984
2985 StdOutCapture capture;
2986 capture.start();
2987 routine();
2988 auto output = split(capture.stop());
2989 for(size_t i = 0, j = 1; i < expectedSize; ++i, j += 2)
2990 {
2991 ASSERT_EQ(expected[i], output[j]);
2992 }
2993
2994#endif
2995}
2996
2997TEST(ReactorUnitTests, PrintReactorTypes)
2998{
2999#if defined(ENABLE_RR_PRINT) && !defined(ENABLE_RR_EMIT_PRINT_LOCATION)
3000 FunctionT<void()> function;
3001 {
3002 Bool b(true);
3003 Int i(-1);
3004 Int2 i2(-1, -2);
3005 Int4 i4(-1, -2, -3, -4);
3006 UInt ui(1);
3007 UInt2 ui2(1, 2);
3008 UInt4 ui4(1, 2, 3, 4);
3009 Short s(-1);
3010 Short4 s4(-1, -2, -3, -4);
3011 UShort us(1);
3012 UShort4 us4(1, 2, 3, 4);
3013 Float f(1);
3014 Float4 f4(1, 2, 3, 4);
3015 Long l(i);
3016 Pointer<Int> pi = nullptr;
3017 RValue<Int> rvi = i;
3018 Byte by('a');
3019 Byte4 by4(i4);
3020
3021 RR_WATCH(b);
3022 RR_WATCH(i);
3023 RR_WATCH(i2);
3024 RR_WATCH(i4);
3025 RR_WATCH(ui);
3026 RR_WATCH(ui2);
3027 RR_WATCH(ui4);
3028 RR_WATCH(s);
3029 RR_WATCH(s4);
3030 RR_WATCH(us);
3031 RR_WATCH(us4);
3032 RR_WATCH(f);
3033 RR_WATCH(f4);
3034 RR_WATCH(l);
3035 RR_WATCH(pi);
3036 RR_WATCH(rvi);
3037 RR_WATCH(by);
3038 RR_WATCH(by4);
3039 }
3040
3041 auto routine = function("one");
3042
3043 char piNullptr[64];
3044 snprintf(piNullptr, sizeof(piNullptr), " pi: %p", nullptr);
3045
3046 const char *expected[] = {
3047 " b: true",
3048 " i: -1",
3049 " i2: [-1, -2]",
3050 " i4: [-1, -2, -3, -4]",
3051 " ui: 1",
3052 " ui2: [1, 2]",
3053 " ui4: [1, 2, 3, 4]",
3054 " s: -1",
3055 " s4: [-1, -2, -3, -4]",
3056 " us: 1",
3057 " us4: [1, 2, 3, 4]",
3058 " f: 1.000000",
3059 " f4: [1.000000, 2.000000, 3.000000, 4.000000]",
3060 " l: -1",
3061 piNullptr,
3062 " rvi: -1",
3063 " by: 97",
3064 " by4: [255, 254, 253, 252]",
3065 };
3066 constexpr size_t expectedSize = sizeof(expected) / sizeof(expected[0]);
3067
3068 StdOutCapture capture;
3069 capture.start();
3070 routine();
3071 auto output = split(capture.stop());
3072 for(size_t i = 0, j = 1; i < expectedSize; ++i, j += 2)
3073 {
3074 ASSERT_EQ(expected[i], output[j]);
3075 }
3076
3077#endif
3078}
3079
Antonio Maiorano04bd4d82020-10-05 16:34:04 -04003080// Test constant <op> variable
3081template<typename T, typename Func>
3082T Arithmetic_LhsConstArg(T arg1, T arg2, Func f)
3083{
3084 using ReactorT = CToReactorT<T>;
3085
3086 FunctionT<T(T)> function;
3087 {
3088 ReactorT lhs = arg1;
3089 ReactorT rhs = function.template Arg<0>();
3090 ReactorT result = f(lhs, rhs);
3091 Return(result);
3092 }
3093
3094 auto routine = function("one");
3095 return routine(arg2);
3096}
3097
3098// Test variable <op> constant
3099template<typename T, typename Func>
3100T Arithmetic_RhsConstArg(T arg1, T arg2, Func f)
3101{
3102 using ReactorT = CToReactorT<T>;
3103
3104 FunctionT<T(T)> function;
3105 {
3106 ReactorT lhs = function.template Arg<0>();
3107 ReactorT rhs = arg2;
3108 ReactorT result = f(lhs, rhs);
3109 Return(result);
3110 }
3111
3112 auto routine = function("one");
3113 return routine(arg1);
3114}
3115
3116// Test constant <op> constant
3117template<typename T, typename Func>
3118T Arithmetic_TwoConstArgs(T arg1, T arg2, Func f)
3119{
3120 using ReactorT = CToReactorT<T>;
3121
3122 FunctionT<T()> function;
3123 {
3124 ReactorT lhs = arg1;
3125 ReactorT rhs = arg2;
3126 ReactorT result = f(lhs, rhs);
3127 Return(result);
3128 }
3129
3130 auto routine = function("one");
3131 return routine();
3132}
3133
3134template<typename T, typename Func>
3135void Arithmetic_ConstArgs(T arg1, T arg2, T expected, Func f)
3136{
3137 SCOPED_TRACE(std::to_string(arg1) + " <op> " + std::to_string(arg2) + " = " + std::to_string(expected));
3138 T result{};
3139 result = Arithmetic_LhsConstArg(arg1, arg2, std::forward<Func>(f));
3140 EXPECT_EQ(result, expected);
3141 result = Arithmetic_RhsConstArg(arg1, arg2, std::forward<Func>(f));
3142 EXPECT_EQ(result, expected);
3143 result = Arithmetic_TwoConstArgs(arg1, arg2, std::forward<Func>(f));
3144 EXPECT_EQ(result, expected);
3145}
3146
3147// Test that we generate valid code for when one or both args to arithmetic operations
3148// are constant. In particular, we want to validate the case for two const args, as
3149// often lowered instructions do not support this case.
3150TEST(ReactorUnitTests, Arithmetic_ConstantArgs)
3151{
3152 Arithmetic_ConstArgs(2, 3, 5, [](auto c1, auto c2) { return c1 + c2; });
3153 Arithmetic_ConstArgs(5, 3, 2, [](auto c1, auto c2) { return c1 - c2; });
3154 Arithmetic_ConstArgs(2, 3, 6, [](auto c1, auto c2) { return c1 * c2; });
3155 Arithmetic_ConstArgs(6, 3, 2, [](auto c1, auto c2) { return c1 / c2; });
3156 Arithmetic_ConstArgs(0xF0F0, 0xAAAA, 0xA0A0, [](auto c1, auto c2) { return c1 & c2; });
3157 Arithmetic_ConstArgs(0xF0F0, 0xAAAA, 0xFAFA, [](auto c1, auto c2) { return c1 | c2; });
3158 Arithmetic_ConstArgs(0xF0F0, 0xAAAA, 0x5A5A, [](auto c1, auto c2) { return c1 ^ c2; });
3159
3160 Arithmetic_ConstArgs(2.f, 3.f, 5.f, [](auto c1, auto c2) { return c1 + c2; });
3161 Arithmetic_ConstArgs(5.f, 3.f, 2.f, [](auto c1, auto c2) { return c1 - c2; });
3162 Arithmetic_ConstArgs(2.f, 3.f, 6.f, [](auto c1, auto c2) { return c1 * c2; });
3163 Arithmetic_ConstArgs(6.f, 3.f, 2.f, [](auto c1, auto c2) { return c1 / c2; });
3164}
3165
Antonio Maiorano6c839a62020-11-06 11:19:24 -05003166// Test for Subzero bad code-gen that was fixed in swiftshader-cl/50008
3167// This tests the case of copying enough arguments to local variables so that the locals
3168// get spilled to the stack when no more registers remain, and making sure these copies
3169// are generated correctly. Without the aforementioned fix, this fails 100% on Windows x86.
3170TEST(ReactorUnitTests, SpillLocalCopiesOfArgs)
3171{
3172 struct Helpers
3173 {
3174 static bool True() { return true; }
3175 };
3176
3177 const int numLoops = 5; // 2 should be enough, but loop more to make sure
3178
3179 FunctionT<int(int, int, int, int, int, int, int, int, int, int, int, int)> function;
3180 {
3181 Int result = 0;
3182 Int a1 = function.Arg<0>();
3183 Int a2 = function.Arg<1>();
3184 Int a3 = function.Arg<2>();
3185 Int a4 = function.Arg<3>();
3186 Int a5 = function.Arg<4>();
3187 Int a6 = function.Arg<5>();
3188 Int a7 = function.Arg<6>();
3189 Int a8 = function.Arg<7>();
3190 Int a9 = function.Arg<8>();
3191 Int a10 = function.Arg<9>();
3192 Int a11 = function.Arg<10>();
3193 Int a12 = function.Arg<11>();
3194
3195 for(int i = 0; i < numLoops; ++i)
3196 {
3197 // Copy all arguments to locals so that Ice::LocalVariableSplitter::handleSimpleVarAssign
3198 // creates Variable copies of arguments. We loop so that we create enough of these so
3199 // that some spill over to the stack.
3200 Int i1 = a1;
3201 Int i2 = a2;
3202 Int i3 = a3;
3203 Int i4 = a4;
3204 Int i5 = a5;
3205 Int i6 = a6;
3206 Int i7 = a7;
3207 Int i8 = a8;
3208 Int i9 = a9;
3209 Int i10 = a10;
3210 Int i11 = a11;
3211 Int i12 = a12;
3212
3213 // Forcibly materialize all variables so that Ice::Variable instances are created for each
3214 // local; otherwise, Reactor r-value optimizations kick in, and the locals are elided.
3215 Variable::materializeAll();
3216
3217 // We also need to create a separate block that uses the variables declared above
3218 // so that rr::optimize() doesn't optimize them out when attempting to eliminate stores
3219 // followed by a load in the same block.
3220 If(Call(Helpers::True))
3221 {
3222 result += (i1 + i2 + i3 + i4 + i5 + i6 + i7 + i8 + i9 + i10 + i11 + i12);
3223 }
3224 }
3225
3226 Return(result);
3227 }
3228
3229 auto routine = function("one");
3230 int result = routine(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);
3231 int expected = numLoops * (1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12);
3232 EXPECT_EQ(result, expected);
3233}
3234
Ben Clayton351be422019-04-30 12:26:57 +01003235////////////////////////////////
3236// Trait compile time checks. //
3237////////////////////////////////
3238
Ben Clayton51f08312019-11-08 14:39:26 +00003239// Assert CToReactorT resolves to expected types.
Ben Clayton713b8d32019-12-17 20:37:56 +00003240static_assert(std::is_same<CToReactorT<void>, Void>::value, "");
3241static_assert(std::is_same<CToReactorT<bool>, Bool>::value, "");
3242static_assert(std::is_same<CToReactorT<uint8_t>, Byte>::value, "");
3243static_assert(std::is_same<CToReactorT<int8_t>, SByte>::value, "");
3244static_assert(std::is_same<CToReactorT<int16_t>, Short>::value, "");
Ben Clayton51f08312019-11-08 14:39:26 +00003245static_assert(std::is_same<CToReactorT<uint16_t>, UShort>::value, "");
Ben Clayton713b8d32019-12-17 20:37:56 +00003246static_assert(std::is_same<CToReactorT<int32_t>, Int>::value, "");
Ben Clayton51f08312019-11-08 14:39:26 +00003247static_assert(std::is_same<CToReactorT<uint64_t>, Long>::value, "");
3248static_assert(std::is_same<CToReactorT<uint32_t>, UInt>::value, "");
Ben Clayton713b8d32019-12-17 20:37:56 +00003249static_assert(std::is_same<CToReactorT<float>, Float>::value, "");
Ben Clayton351be422019-04-30 12:26:57 +01003250
Ben Clayton51f08312019-11-08 14:39:26 +00003251// Assert CToReactorT for known pointer types resolves to expected types.
Ben Clayton713b8d32019-12-17 20:37:56 +00003252static_assert(std::is_same<CToReactorT<void *>, Pointer<Byte>>::value, "");
3253static_assert(std::is_same<CToReactorT<bool *>, Pointer<Bool>>::value, "");
3254static_assert(std::is_same<CToReactorT<uint8_t *>, Pointer<Byte>>::value, "");
3255static_assert(std::is_same<CToReactorT<int8_t *>, Pointer<SByte>>::value, "");
3256static_assert(std::is_same<CToReactorT<int16_t *>, Pointer<Short>>::value, "");
3257static_assert(std::is_same<CToReactorT<uint16_t *>, Pointer<UShort>>::value, "");
3258static_assert(std::is_same<CToReactorT<int32_t *>, Pointer<Int>>::value, "");
3259static_assert(std::is_same<CToReactorT<uint64_t *>, Pointer<Long>>::value, "");
3260static_assert(std::is_same<CToReactorT<uint32_t *>, Pointer<UInt>>::value, "");
3261static_assert(std::is_same<CToReactorT<float *>, Pointer<Float>>::value, "");
3262static_assert(std::is_same<CToReactorT<uint16_t **>, Pointer<Pointer<UShort>>>::value, "");
3263static_assert(std::is_same<CToReactorT<uint16_t ***>, Pointer<Pointer<Pointer<UShort>>>>::value, "");
Ben Clayton351be422019-04-30 12:26:57 +01003264
Ben Clayton51f08312019-11-08 14:39:26 +00003265// Assert CToReactorT for unknown pointer types resolves to Pointer<Byte>.
Ben Clayton713b8d32019-12-17 20:37:56 +00003266struct S
3267{};
3268static_assert(std::is_same<CToReactorT<S *>, Pointer<Byte>>::value, "");
3269static_assert(std::is_same<CToReactorT<S **>, Pointer<Pointer<Byte>>>::value, "");
3270static_assert(std::is_same<CToReactorT<S ***>, Pointer<Pointer<Pointer<Byte>>>>::value, "");
Ben Clayton351be422019-04-30 12:26:57 +01003271
3272// Assert IsRValue<> resolves true for RValue<> types.
3273static_assert(IsRValue<RValue<Void>>::value, "");
3274static_assert(IsRValue<RValue<Bool>>::value, "");
3275static_assert(IsRValue<RValue<Byte>>::value, "");
3276static_assert(IsRValue<RValue<SByte>>::value, "");
3277static_assert(IsRValue<RValue<Short>>::value, "");
3278static_assert(IsRValue<RValue<UShort>>::value, "");
3279static_assert(IsRValue<RValue<Int>>::value, "");
3280static_assert(IsRValue<RValue<Long>>::value, "");
3281static_assert(IsRValue<RValue<UInt>>::value, "");
3282static_assert(IsRValue<RValue<Float>>::value, "");
3283
3284// Assert IsLValue<> resolves true for LValue types.
3285static_assert(IsLValue<Bool>::value, "");
3286static_assert(IsLValue<Byte>::value, "");
3287static_assert(IsLValue<SByte>::value, "");
3288static_assert(IsLValue<Short>::value, "");
3289static_assert(IsLValue<UShort>::value, "");
3290static_assert(IsLValue<Int>::value, "");
3291static_assert(IsLValue<Long>::value, "");
3292static_assert(IsLValue<UInt>::value, "");
3293static_assert(IsLValue<Float>::value, "");
3294
Ben Clayton208ed402019-05-03 22:30:03 +01003295// Assert IsReference<> resolves true for Reference types.
3296static_assert(IsReference<Reference<Bool>>::value, "");
3297static_assert(IsReference<Reference<Byte>>::value, "");
3298static_assert(IsReference<Reference<SByte>>::value, "");
3299static_assert(IsReference<Reference<Short>>::value, "");
3300static_assert(IsReference<Reference<UShort>>::value, "");
3301static_assert(IsReference<Reference<Int>>::value, "");
3302static_assert(IsReference<Reference<Long>>::value, "");
3303static_assert(IsReference<Reference<UInt>>::value, "");
3304static_assert(IsReference<Reference<Float>>::value, "");
3305
Ben Clayton351be422019-04-30 12:26:57 +01003306// Assert IsRValue<> resolves false for LValue types.
3307static_assert(!IsRValue<Void>::value, "");
3308static_assert(!IsRValue<Bool>::value, "");
3309static_assert(!IsRValue<Byte>::value, "");
3310static_assert(!IsRValue<SByte>::value, "");
3311static_assert(!IsRValue<Short>::value, "");
3312static_assert(!IsRValue<UShort>::value, "");
3313static_assert(!IsRValue<Int>::value, "");
3314static_assert(!IsRValue<Long>::value, "");
3315static_assert(!IsRValue<UInt>::value, "");
3316static_assert(!IsRValue<Float>::value, "");
3317
Ben Clayton208ed402019-05-03 22:30:03 +01003318// Assert IsRValue<> resolves false for Reference types.
3319static_assert(!IsRValue<Reference<Void>>::value, "");
3320static_assert(!IsRValue<Reference<Bool>>::value, "");
3321static_assert(!IsRValue<Reference<Byte>>::value, "");
3322static_assert(!IsRValue<Reference<SByte>>::value, "");
3323static_assert(!IsRValue<Reference<Short>>::value, "");
3324static_assert(!IsRValue<Reference<UShort>>::value, "");
3325static_assert(!IsRValue<Reference<Int>>::value, "");
3326static_assert(!IsRValue<Reference<Long>>::value, "");
3327static_assert(!IsRValue<Reference<UInt>>::value, "");
3328static_assert(!IsRValue<Reference<Float>>::value, "");
3329
Ben Clayton351be422019-04-30 12:26:57 +01003330// Assert IsRValue<> resolves false for C types.
3331static_assert(!IsRValue<void>::value, "");
3332static_assert(!IsRValue<bool>::value, "");
3333static_assert(!IsRValue<uint8_t>::value, "");
3334static_assert(!IsRValue<int8_t>::value, "");
3335static_assert(!IsRValue<int16_t>::value, "");
3336static_assert(!IsRValue<uint16_t>::value, "");
3337static_assert(!IsRValue<int32_t>::value, "");
3338static_assert(!IsRValue<uint64_t>::value, "");
3339static_assert(!IsRValue<uint32_t>::value, "");
3340static_assert(!IsRValue<float>::value, "");
3341
3342// Assert IsLValue<> resolves false for RValue<> types.
3343static_assert(!IsLValue<RValue<Void>>::value, "");
3344static_assert(!IsLValue<RValue<Bool>>::value, "");
3345static_assert(!IsLValue<RValue<Byte>>::value, "");
3346static_assert(!IsLValue<RValue<SByte>>::value, "");
3347static_assert(!IsLValue<RValue<Short>>::value, "");
3348static_assert(!IsLValue<RValue<UShort>>::value, "");
3349static_assert(!IsLValue<RValue<Int>>::value, "");
3350static_assert(!IsLValue<RValue<Long>>::value, "");
3351static_assert(!IsLValue<RValue<UInt>>::value, "");
3352static_assert(!IsLValue<RValue<Float>>::value, "");
3353
3354// Assert IsLValue<> resolves false for Void type.
3355static_assert(!IsLValue<Void>::value, "");
3356
Ben Clayton208ed402019-05-03 22:30:03 +01003357// Assert IsLValue<> resolves false for Reference<> types.
3358static_assert(!IsLValue<Reference<Void>>::value, "");
3359static_assert(!IsLValue<Reference<Bool>>::value, "");
3360static_assert(!IsLValue<Reference<Byte>>::value, "");
3361static_assert(!IsLValue<Reference<SByte>>::value, "");
3362static_assert(!IsLValue<Reference<Short>>::value, "");
3363static_assert(!IsLValue<Reference<UShort>>::value, "");
3364static_assert(!IsLValue<Reference<Int>>::value, "");
3365static_assert(!IsLValue<Reference<Long>>::value, "");
3366static_assert(!IsLValue<Reference<UInt>>::value, "");
3367static_assert(!IsLValue<Reference<Float>>::value, "");
3368
Ben Clayton351be422019-04-30 12:26:57 +01003369// Assert IsLValue<> resolves false for C types.
3370static_assert(!IsLValue<void>::value, "");
3371static_assert(!IsLValue<bool>::value, "");
3372static_assert(!IsLValue<uint8_t>::value, "");
3373static_assert(!IsLValue<int8_t>::value, "");
3374static_assert(!IsLValue<int16_t>::value, "");
3375static_assert(!IsLValue<uint16_t>::value, "");
3376static_assert(!IsLValue<int32_t>::value, "");
3377static_assert(!IsLValue<uint64_t>::value, "");
3378static_assert(!IsLValue<uint32_t>::value, "");
3379static_assert(!IsLValue<float>::value, "");
3380
3381// Assert IsDefined<> resolves true for RValue<> types.
3382static_assert(IsDefined<RValue<Void>>::value, "");
3383static_assert(IsDefined<RValue<Bool>>::value, "");
3384static_assert(IsDefined<RValue<Byte>>::value, "");
3385static_assert(IsDefined<RValue<SByte>>::value, "");
3386static_assert(IsDefined<RValue<Short>>::value, "");
3387static_assert(IsDefined<RValue<UShort>>::value, "");
3388static_assert(IsDefined<RValue<Int>>::value, "");
3389static_assert(IsDefined<RValue<Long>>::value, "");
3390static_assert(IsDefined<RValue<UInt>>::value, "");
3391static_assert(IsDefined<RValue<Float>>::value, "");
3392
3393// Assert IsDefined<> resolves true for LValue types.
3394static_assert(IsDefined<Void>::value, "");
3395static_assert(IsDefined<Bool>::value, "");
3396static_assert(IsDefined<Byte>::value, "");
3397static_assert(IsDefined<SByte>::value, "");
3398static_assert(IsDefined<Short>::value, "");
3399static_assert(IsDefined<UShort>::value, "");
3400static_assert(IsDefined<Int>::value, "");
3401static_assert(IsDefined<Long>::value, "");
3402static_assert(IsDefined<UInt>::value, "");
3403static_assert(IsDefined<Float>::value, "");
3404
Ben Clayton208ed402019-05-03 22:30:03 +01003405// Assert IsDefined<> resolves true for Reference<> types.
3406static_assert(IsDefined<Reference<Bool>>::value, "");
3407static_assert(IsDefined<Reference<Byte>>::value, "");
3408static_assert(IsDefined<Reference<SByte>>::value, "");
3409static_assert(IsDefined<Reference<Short>>::value, "");
3410static_assert(IsDefined<Reference<UShort>>::value, "");
3411static_assert(IsDefined<Reference<Int>>::value, "");
3412static_assert(IsDefined<Reference<Long>>::value, "");
3413static_assert(IsDefined<Reference<UInt>>::value, "");
3414static_assert(IsDefined<Reference<Float>>::value, "");
3415
Ben Clayton351be422019-04-30 12:26:57 +01003416// Assert IsDefined<> resolves true for C types.
3417static_assert(IsDefined<void>::value, "");
3418static_assert(IsDefined<bool>::value, "");
3419static_assert(IsDefined<uint8_t>::value, "");
3420static_assert(IsDefined<int8_t>::value, "");
3421static_assert(IsDefined<int16_t>::value, "");
3422static_assert(IsDefined<uint16_t>::value, "");
3423static_assert(IsDefined<int32_t>::value, "");
3424static_assert(IsDefined<uint64_t>::value, "");
3425static_assert(IsDefined<uint32_t>::value, "");
3426static_assert(IsDefined<float>::value, "");