blob: fbe61ec2da0390f5ca466e75583dffff59f9bc86 [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
Antonio Maioranob1dd7f72020-11-23 11:19:34 -05001283 // LLVM takes very long to generate this routine when InstructionCombining
1284 // and O2 optimizations are enabled. Disable for now.
1285 // TODO(b/174031014): Remove this once we fix LLVM taking so long
1286 auto cfg = Config::Edit{}
1287 .remove(Optimization::Pass::InstructionCombining)
1288 .set(Optimization::Level::None);
1289
1290 auto routine = function(cfg, "one");
1291
Antonio Maiorano4d402712020-02-25 10:36:02 -05001292 std::array<int32_t, ArraySize> v;
1293
1294 // Run this in a thread, so that we get the default reserved stack size (8K on Win64).
1295 std::thread t([&] {
1296 routine(v.data());
1297 });
1298 t.join();
1299
1300 for(int i = 0; i < ArraySize; ++i)
1301 {
1302 EXPECT_EQ(v[i], i);
1303 }
1304#endif
1305}
1306
Ben Claytond853c122019-04-16 17:51:49 -04001307TEST(ReactorUnitTests, Call)
1308{
Ben Claytond853c122019-04-16 17:51:49 -04001309 struct Class
1310 {
Ben Clayton51f08312019-11-08 14:39:26 +00001311 static int Callback(Class *p, int i, float f)
Ben Claytond853c122019-04-16 17:51:49 -04001312 {
Ben Clayton51f08312019-11-08 14:39:26 +00001313 p->i = i;
1314 p->f = f;
Ben Claytond853c122019-04-16 17:51:49 -04001315 return i + int(f);
1316 }
1317
1318 int i = 0;
1319 float f = 0.0f;
1320 };
1321
Ben Clayton713b8d32019-12-17 20:37:56 +00001322 FunctionT<int(void *)> function;
Ben Claytond853c122019-04-16 17:51:49 -04001323 {
Ben Clayton51f08312019-11-08 14:39:26 +00001324 Pointer<Byte> c = function.Arg<0>();
1325 auto res = Call(Class::Callback, c, 10, 20.0f);
1326 Return(res);
Ben Claytond853c122019-04-16 17:51:49 -04001327 }
Ben Clayton51f08312019-11-08 14:39:26 +00001328
1329 auto routine = function("one");
1330
1331 Class c;
1332 int res = routine(&c);
1333 EXPECT_EQ(res, 30);
1334 EXPECT_EQ(c.i, 10);
1335 EXPECT_EQ(c.f, 20.0f);
1336}
1337
Ben Claytonb7eb3a82019-11-19 00:43:50 +00001338TEST(ReactorUnitTests, CallMemberFunction)
1339{
Ben Claytonb7eb3a82019-11-19 00:43:50 +00001340 struct Class
1341 {
1342 int Callback(int argI, float argF)
1343 {
1344 i = argI;
1345 f = argF;
1346 return i + int(f);
1347 }
1348
1349 int i = 0;
1350 float f = 0.0f;
1351 };
1352
1353 Class c;
1354
1355 FunctionT<int()> function;
1356 {
1357 auto res = Call(&Class::Callback, &c, 10, 20.0f);
1358 Return(res);
1359 }
1360
1361 auto routine = function("one");
1362
1363 int res = routine();
1364 EXPECT_EQ(res, 30);
1365 EXPECT_EQ(c.i, 10);
1366 EXPECT_EQ(c.f, 20.0f);
1367}
1368
1369TEST(ReactorUnitTests, CallMemberFunctionIndirect)
1370{
Ben Claytonb7eb3a82019-11-19 00:43:50 +00001371 struct Class
1372 {
1373 int Callback(int argI, float argF)
1374 {
1375 i = argI;
1376 f = argF;
1377 return i + int(f);
1378 }
1379
1380 int i = 0;
1381 float f = 0.0f;
1382 };
1383
Ben Clayton713b8d32019-12-17 20:37:56 +00001384 FunctionT<int(void *)> function;
Ben Claytonb7eb3a82019-11-19 00:43:50 +00001385 {
1386 Pointer<Byte> c = function.Arg<0>();
1387 auto res = Call(&Class::Callback, c, 10, 20.0f);
1388 Return(res);
1389 }
1390
1391 auto routine = function("one");
1392
1393 Class c;
1394 int res = routine(&c);
1395 EXPECT_EQ(res, 30);
1396 EXPECT_EQ(c.i, 10);
1397 EXPECT_EQ(c.f, 20.0f);
1398}
1399
Ben Clayton51f08312019-11-08 14:39:26 +00001400TEST(ReactorUnitTests, CallImplicitCast)
1401{
Ben Clayton51f08312019-11-08 14:39:26 +00001402 struct Class
1403 {
Ben Clayton713b8d32019-12-17 20:37:56 +00001404 static void Callback(Class *c, const char *s)
Ben Clayton51f08312019-11-08 14:39:26 +00001405 {
1406 c->str = s;
1407 }
1408 std::string str;
1409 };
1410
Ben Clayton713b8d32019-12-17 20:37:56 +00001411 FunctionT<void(Class * c, const char *s)> function;
Ben Clayton51f08312019-11-08 14:39:26 +00001412 {
1413 Pointer<Byte> c = function.Arg<0>();
1414 Pointer<Byte> s = function.Arg<1>();
1415 Call(Class::Callback, c, s);
1416 }
1417
1418 auto routine = function("one");
1419
1420 Class c;
1421 routine(&c, "hello world");
1422 EXPECT_EQ(c.str, "hello world");
Antonio Maioranob7dad7d2019-10-11 15:26:58 -04001423}
Ben Claytond853c122019-04-16 17:51:49 -04001424
Antonio Maiorano16ae92a2020-03-10 10:53:24 -04001425TEST(ReactorUnitTests, CallBoolReturnFunction)
1426{
1427 struct Class
1428 {
1429 static bool IsEven(int a)
1430 {
1431 return a % 2 == 0;
1432 }
1433 };
1434
1435 FunctionT<int(int)> function;
1436 {
1437 Int a = function.Arg<0>();
1438 Bool res = Call(Class::IsEven, a);
1439 If(res)
1440 {
1441 Return(1);
1442 }
1443 Return(0);
1444 }
1445
1446 auto routine = function("one");
1447
1448 for(int i = 0; i < 10; ++i)
1449 {
1450 EXPECT_EQ(routine(i), i % 2 == 0);
1451 }
1452}
1453
Antonio Maiorano01386d12019-11-20 14:43:48 -05001454TEST(ReactorUnitTests, Call_Args4)
1455{
1456 struct Class
1457 {
1458 static int Func(int a, int b, int c, int d)
1459 {
1460 return a + b + c + d;
1461 }
1462 };
1463
1464 {
1465 FunctionT<int()> function;
1466 {
1467 auto res = Call(Class::Func, 1, 2, 3, 4);
1468 Return(res);
1469 }
1470
1471 auto routine = function("one");
1472
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001473 int res = routine();
1474 EXPECT_EQ(res, 1 + 2 + 3 + 4);
Antonio Maiorano01386d12019-11-20 14:43:48 -05001475 }
1476}
1477
1478TEST(ReactorUnitTests, Call_Args5)
1479{
1480 struct Class
1481 {
1482 static int Func(int a, int b, int c, int d, int e)
1483 {
1484 return a + b + c + d + e;
1485 }
1486 };
1487
1488 {
1489 FunctionT<int()> function;
1490 {
1491 auto res = Call(Class::Func, 1, 2, 3, 4, 5);
1492 Return(res);
1493 }
1494
1495 auto routine = function("one");
1496
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001497 int res = routine();
1498 EXPECT_EQ(res, 1 + 2 + 3 + 4 + 5);
Antonio Maiorano01386d12019-11-20 14:43:48 -05001499 }
1500}
1501
1502TEST(ReactorUnitTests, Call_ArgsMany)
1503{
1504 struct Class
1505 {
1506 static int Func(int a, int b, int c, int d, int e, int f, int g, int h)
1507 {
1508 return a + b + c + d + e + f + g + h;
1509 }
1510 };
1511
1512 {
1513 FunctionT<int()> function;
1514 {
1515 auto res = Call(Class::Func, 1, 2, 3, 4, 5, 6, 7, 8);
1516 Return(res);
1517 }
1518
1519 auto routine = function("one");
1520
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001521 int res = routine();
1522 EXPECT_EQ(res, 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8);
Antonio Maiorano01386d12019-11-20 14:43:48 -05001523 }
1524}
1525
1526TEST(ReactorUnitTests, Call_ArgsMixed)
1527{
1528 struct Class
1529 {
Ben Clayton713b8d32019-12-17 20:37:56 +00001530 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 -05001531 {
1532 return a + b + *c + *d + e + f + *g + *h;
1533 }
1534 };
1535
1536 {
1537 FunctionT<int()> function;
1538 {
1539 Int c(3);
1540 Float d(4);
1541 Int g(7);
1542 Float h(8);
1543 auto res = Call(Class::Func, 1, 2.f, &c, &d, 5, 6.f, &g, &h);
1544 Return(res);
1545 }
1546
1547 auto routine = function("one");
1548
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001549 int res = routine();
1550 EXPECT_EQ(res, 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8);
Antonio Maiorano01386d12019-11-20 14:43:48 -05001551 }
1552}
1553
1554TEST(ReactorUnitTests, Call_ArgsPointer)
1555{
1556 struct Class
1557 {
1558 static int Func(int *a)
1559 {
1560 return *a;
1561 }
1562 };
1563
1564 {
1565 FunctionT<int()> function;
1566 {
1567 Int a(12345);
1568 auto res = Call(Class::Func, &a);
1569 Return(res);
1570 }
1571
1572 auto routine = function("one");
1573
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001574 int res = routine();
1575 EXPECT_EQ(res, 12345);
Antonio Maiorano01386d12019-11-20 14:43:48 -05001576 }
1577}
1578
Antonio Maioranob7dad7d2019-10-11 15:26:58 -04001579TEST(ReactorUnitTests, CallExternalCallRoutine)
1580{
Antonio Maioranob7dad7d2019-10-11 15:26:58 -04001581 // routine1 calls Class::Func, passing it a pointer to routine2, and Class::Func calls routine2
1582
1583 auto routine2 = [] {
Antonio Maiorano03935ae2019-10-29 16:20:27 -04001584 FunctionT<float(float, int)> function;
Antonio Maioranob7dad7d2019-10-11 15:26:58 -04001585 {
1586 Float a = function.Arg<0>();
1587 Int b = function.Arg<1>();
1588 Return(a + Float(b));
1589 }
1590 return function("two");
1591 }();
1592
1593 struct Class
1594 {
Ben Clayton713b8d32019-12-17 20:37:56 +00001595 static float Func(void *p, float a, int b)
Antonio Maioranob7dad7d2019-10-11 15:26:58 -04001596 {
Ben Clayton713b8d32019-12-17 20:37:56 +00001597 auto funcToCall = reinterpret_cast<float (*)(float, int)>(p);
Antonio Maioranob7dad7d2019-10-11 15:26:58 -04001598 return funcToCall(a, b);
1599 }
1600 };
1601
1602 auto routine1 = [] {
Ben Clayton713b8d32019-12-17 20:37:56 +00001603 FunctionT<float(void *, float, int)> function;
Antonio Maioranob7dad7d2019-10-11 15:26:58 -04001604 {
1605 Pointer<Byte> funcToCall = function.Arg<0>();
1606 Float a = function.Arg<1>();
1607 Int b = function.Arg<2>();
1608 Float result = Call(Class::Func, funcToCall, a, b);
1609 Return(result);
1610 }
1611 return function("one");
1612 }();
1613
Ben Clayton713b8d32019-12-17 20:37:56 +00001614 float result = routine1((void *)routine2.getEntry(), 12.f, 13);
Antonio Maioranob7dad7d2019-10-11 15:26:58 -04001615 EXPECT_EQ(result, 25.f);
Ben Claytond853c122019-04-16 17:51:49 -04001616}
1617
Stephen White17078c72019-02-27 14:39:14 -05001618// Check that a complex generated function which utilizes all 8 or 16 XMM
1619// registers computes the correct result.
1620// (Note that due to MSC's lack of support for inline assembly in x64,
Ben Claytonb1243732019-02-27 23:56:18 +00001621// this test does not actually check that the register contents are
Stephen White17078c72019-02-27 14:39:14 -05001622// preserved, just that the generated function computes the correct value.
1623// It's necessary to inspect the registers in a debugger to actually verify.)
1624TEST(ReactorUnitTests, PreserveXMMRegisters)
1625{
Ben Clayton713b8d32019-12-17 20:37:56 +00001626 FunctionT<void(void *, void *)> function;
1627 {
1628 Pointer<Byte> in = function.Arg<0>();
1629 Pointer<Byte> out = function.Arg<1>();
Stephen White17078c72019-02-27 14:39:14 -05001630
Ben Clayton713b8d32019-12-17 20:37:56 +00001631 Float4 a = *Pointer<Float4>(in + 16 * 0);
1632 Float4 b = *Pointer<Float4>(in + 16 * 1);
1633 Float4 c = *Pointer<Float4>(in + 16 * 2);
1634 Float4 d = *Pointer<Float4>(in + 16 * 3);
1635 Float4 e = *Pointer<Float4>(in + 16 * 4);
1636 Float4 f = *Pointer<Float4>(in + 16 * 5);
1637 Float4 g = *Pointer<Float4>(in + 16 * 6);
1638 Float4 h = *Pointer<Float4>(in + 16 * 7);
1639 Float4 i = *Pointer<Float4>(in + 16 * 8);
1640 Float4 j = *Pointer<Float4>(in + 16 * 9);
1641 Float4 k = *Pointer<Float4>(in + 16 * 10);
1642 Float4 l = *Pointer<Float4>(in + 16 * 11);
1643 Float4 m = *Pointer<Float4>(in + 16 * 12);
1644 Float4 n = *Pointer<Float4>(in + 16 * 13);
1645 Float4 o = *Pointer<Float4>(in + 16 * 14);
1646 Float4 p = *Pointer<Float4>(in + 16 * 15);
Stephen White17078c72019-02-27 14:39:14 -05001647
Ben Clayton713b8d32019-12-17 20:37:56 +00001648 Float4 ab = a + b;
1649 Float4 cd = c + d;
1650 Float4 ef = e + f;
1651 Float4 gh = g + h;
1652 Float4 ij = i + j;
1653 Float4 kl = k + l;
1654 Float4 mn = m + n;
1655 Float4 op = o + p;
Stephen White17078c72019-02-27 14:39:14 -05001656
Ben Clayton713b8d32019-12-17 20:37:56 +00001657 Float4 abcd = ab + cd;
1658 Float4 efgh = ef + gh;
1659 Float4 ijkl = ij + kl;
1660 Float4 mnop = mn + op;
Stephen White17078c72019-02-27 14:39:14 -05001661
Ben Clayton713b8d32019-12-17 20:37:56 +00001662 Float4 abcdefgh = abcd + efgh;
1663 Float4 ijklmnop = ijkl + mnop;
1664 Float4 sum = abcdefgh + ijklmnop;
1665 *Pointer<Float4>(out) = sum;
1666 Return();
1667 }
Stephen White17078c72019-02-27 14:39:14 -05001668
Ben Clayton713b8d32019-12-17 20:37:56 +00001669 auto routine = function("one");
1670 assert(routine);
Nicolas Capens157ba262019-12-10 17:49:14 -05001671
Ben Clayton713b8d32019-12-17 20:37:56 +00001672 float input[64] = { 1.0f, 0.0f, 0.0f, 0.0f,
1673 -1.0f, 1.0f, -1.0f, 0.0f,
1674 1.0f, 2.0f, -2.0f, 0.0f,
1675 -1.0f, 3.0f, -3.0f, 0.0f,
1676 1.0f, 4.0f, -4.0f, 0.0f,
1677 -1.0f, 5.0f, -5.0f, 0.0f,
1678 1.0f, 6.0f, -6.0f, 0.0f,
1679 -1.0f, 7.0f, -7.0f, 0.0f,
1680 1.0f, 8.0f, -8.0f, 0.0f,
1681 -1.0f, 9.0f, -9.0f, 0.0f,
1682 1.0f, 10.0f, -10.0f, 0.0f,
1683 -1.0f, 11.0f, -11.0f, 0.0f,
1684 1.0f, 12.0f, -12.0f, 0.0f,
1685 -1.0f, 13.0f, -13.0f, 0.0f,
1686 1.0f, 14.0f, -14.0f, 0.0f,
1687 -1.0f, 15.0f, -15.0f, 0.0f };
Nicolas Capens157ba262019-12-10 17:49:14 -05001688
Ben Clayton713b8d32019-12-17 20:37:56 +00001689 float result[4];
Nicolas Capens157ba262019-12-10 17:49:14 -05001690
Ben Clayton713b8d32019-12-17 20:37:56 +00001691 routine(input, result);
Nicolas Capens157ba262019-12-10 17:49:14 -05001692
Ben Clayton713b8d32019-12-17 20:37:56 +00001693 EXPECT_EQ(result[0], 0.0f);
1694 EXPECT_EQ(result[1], 120.0f);
1695 EXPECT_EQ(result[2], -120.0f);
1696 EXPECT_EQ(result[3], 0.0f);
Stephen White17078c72019-02-27 14:39:14 -05001697}
1698
Ben Clayton713b8d32019-12-17 20:37:56 +00001699template<typename T>
Ben Clayton51f08312019-11-08 14:39:26 +00001700class CToReactorTCastTest : public ::testing::Test
Nicolas Capensf0d22ad2019-03-15 17:22:42 -04001701{
Ben Claytonf3b57972019-03-15 09:56:47 +00001702public:
1703 using CType = typename std::tuple_element<0, T>::type;
1704 using ReactorType = typename std::tuple_element<1, T>::type;
1705};
1706
Ben Clayton713b8d32019-12-17 20:37:56 +00001707using CToReactorTCastTestTypes = ::testing::Types< // Subset of types that can be used as arguments.
1708 // std::pair<bool, Bool>, FIXME(capn): Not supported as argument type by Subzero.
1709 // std::pair<uint8_t, Byte>, FIXME(capn): Not supported as argument type by Subzero.
1710 // std::pair<int8_t, SByte>, FIXME(capn): Not supported as argument type by Subzero.
1711 // std::pair<int16_t, Short>, FIXME(capn): Not supported as argument type by Subzero.
1712 // std::pair<uint16_t, UShort>, FIXME(capn): Not supported as argument type by Subzero.
1713 std::pair<int, Int>,
1714 std::pair<unsigned int, UInt>,
1715 std::pair<float, Float>>;
Ben Claytonf3b57972019-03-15 09:56:47 +00001716
Ben Clayton51f08312019-11-08 14:39:26 +00001717TYPED_TEST_SUITE(CToReactorTCastTest, CToReactorTCastTestTypes);
Ben Claytonf3b57972019-03-15 09:56:47 +00001718
Ben Clayton51f08312019-11-08 14:39:26 +00001719TYPED_TEST(CToReactorTCastTest, Casts)
Nicolas Capensf0d22ad2019-03-15 17:22:42 -04001720{
Ben Claytonf3b57972019-03-15 09:56:47 +00001721 using CType = typename TestFixture::CType;
1722 using ReactorType = typename TestFixture::ReactorType;
1723
Ben Clayton6897e9b2019-07-16 17:27:27 +01001724 std::shared_ptr<Routine> routine;
Ben Claytonf3b57972019-03-15 09:56:47 +00001725
1726 {
Ben Clayton713b8d32019-12-17 20:37:56 +00001727 Function<Int(ReactorType)> function;
Ben Claytonf3b57972019-03-15 09:56:47 +00001728 {
1729 ReactorType a = function.template Arg<0>();
1730 ReactorType b = CType{};
1731 RValue<ReactorType> c = RValue<ReactorType>(CType{});
1732 Bool same = (a == b) && (a == c);
Ben Clayton713b8d32019-12-17 20:37:56 +00001733 Return(IfThenElse(same, Int(1), Int(0))); // TODO: Ability to use Bools as return values.
Ben Claytonf3b57972019-03-15 09:56:47 +00001734 }
1735
1736 routine = function("one");
1737
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001738 auto callable = (int (*)(CType))routine->getEntry();
1739 CType in = {};
1740 EXPECT_EQ(callable(in), 1);
Ben Claytonf3b57972019-03-15 09:56:47 +00001741 }
Ben Claytonf3b57972019-03-15 09:56:47 +00001742}
1743
Ben Clayton713b8d32019-12-17 20:37:56 +00001744template<typename T>
Nicolas Capensf0d22ad2019-03-15 17:22:42 -04001745class GEPTest : public ::testing::Test
1746{
Ben Claytonb1243732019-02-27 23:56:18 +00001747public:
1748 using CType = typename std::tuple_element<0, T>::type;
1749 using ReactorType = typename std::tuple_element<1, T>::type;
1750};
1751
Ben Clayton713b8d32019-12-17 20:37:56 +00001752using GEPTestTypes = ::testing::Types<
1753 std::pair<bool, Bool>,
1754 std::pair<int8_t, Byte>,
1755 std::pair<int8_t, SByte>,
1756 std::pair<int8_t[4], Byte4>,
1757 std::pair<int8_t[4], SByte4>,
1758 std::pair<int8_t[8], Byte8>,
1759 std::pair<int8_t[8], SByte8>,
1760 std::pair<int8_t[16], Byte16>,
1761 std::pair<int8_t[16], SByte16>,
1762 std::pair<int16_t, Short>,
1763 std::pair<int16_t, UShort>,
1764 std::pair<int16_t[2], Short2>,
1765 std::pair<int16_t[2], UShort2>,
1766 std::pair<int16_t[4], Short4>,
1767 std::pair<int16_t[4], UShort4>,
1768 std::pair<int16_t[8], Short8>,
1769 std::pair<int16_t[8], UShort8>,
1770 std::pair<int, Int>,
1771 std::pair<int, UInt>,
1772 std::pair<int[2], Int2>,
1773 std::pair<int[2], UInt2>,
1774 std::pair<int[4], Int4>,
1775 std::pair<int[4], UInt4>,
1776 std::pair<int64_t, Long>,
1777 std::pair<int16_t, Half>,
1778 std::pair<float, Float>,
1779 std::pair<float[2], Float2>,
1780 std::pair<float[4], Float4>>;
Ben Claytonb1243732019-02-27 23:56:18 +00001781
Alexis Hetu79d4ac92019-06-03 11:31:46 -04001782TYPED_TEST_SUITE(GEPTest, GEPTestTypes);
Ben Claytonb1243732019-02-27 23:56:18 +00001783
Nicolas Capensf0d22ad2019-03-15 17:22:42 -04001784TYPED_TEST(GEPTest, PtrOffsets)
1785{
Ben Claytonb1243732019-02-27 23:56:18 +00001786 using CType = typename TestFixture::CType;
1787 using ReactorType = typename TestFixture::ReactorType;
1788
Ben Clayton6897e9b2019-07-16 17:27:27 +01001789 std::shared_ptr<Routine> routine;
Ben Claytonb1243732019-02-27 23:56:18 +00001790
1791 {
Ben Clayton713b8d32019-12-17 20:37:56 +00001792 Function<Pointer<ReactorType>(Pointer<ReactorType>, Int)> function;
Ben Claytonb1243732019-02-27 23:56:18 +00001793 {
1794 Pointer<ReactorType> pointer = function.template Arg<0>();
1795 Int index = function.template Arg<1>();
1796 Return(&pointer[index]);
1797 }
1798
1799 routine = function("one");
1800
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001801 auto callable = (CType * (*)(CType *, unsigned int)) routine->getEntry();
1802
1803 union PtrInt
Ben Claytonb1243732019-02-27 23:56:18 +00001804 {
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001805 CType *p;
1806 size_t i;
1807 };
Ben Claytonb1243732019-02-27 23:56:18 +00001808
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001809 PtrInt base;
1810 base.i = 0x10000;
Ben Claytonb1243732019-02-27 23:56:18 +00001811
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001812 for(int i = 0; i < 5; i++)
1813 {
1814 PtrInt reference;
1815 reference.p = &base.p[i];
Ben Claytonb1243732019-02-27 23:56:18 +00001816
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001817 PtrInt result;
1818 result.p = callable(base.p, i);
Ben Claytonb1243732019-02-27 23:56:18 +00001819
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001820 auto expect = reference.i - base.i;
1821 auto got = result.i - base.i;
Ben Claytonb1243732019-02-27 23:56:18 +00001822
Nicolas Capensbdf2b722020-01-27 11:33:14 -05001823 EXPECT_EQ(got, expect) << "i:" << i;
Ben Claytonb1243732019-02-27 23:56:18 +00001824 }
1825 }
Ben Claytonb1243732019-02-27 23:56:18 +00001826}
1827
Nicolas Capensd2af84f2020-05-14 10:55:21 -04001828static const std::vector<int> fibonacci = {
1829 0,
1830 1,
1831 1,
1832 2,
1833 3,
1834 5,
1835 8,
1836 13,
1837 21,
1838 34,
1839 55,
1840 89,
1841 144,
1842 233,
1843 377,
1844 610,
1845 987,
1846 1597,
1847 2584,
1848 4181,
1849 6765,
1850 10946,
1851 17711,
1852 28657,
1853 46368,
1854 75025,
1855 121393,
1856 196418,
1857 317811,
1858};
1859
Antonio Maiorano8bce0672020-02-28 13:13:45 -05001860TEST(ReactorUnitTests, Fibonacci)
1861{
1862 FunctionT<int(int)> function;
1863 {
1864 Int n = function.Arg<0>();
1865 Int current = 0;
1866 Int next = 1;
1867 For(Int i = 0, i < n, i++)
1868 {
1869 auto tmp = current + next;
1870 current = next;
1871 next = tmp;
1872 }
1873 Return(current);
1874 }
1875
1876 auto routine = function("one");
1877
1878 for(size_t i = 0; i < fibonacci.size(); i++)
1879 {
1880 EXPECT_EQ(routine(i), fibonacci[i]);
1881 }
1882}
1883
Ben Clayton1c82c7b2019-04-30 12:49:27 +01001884TEST(ReactorUnitTests, Coroutines_Fibonacci)
1885{
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001886 if(!rr::Caps.CoroutinesSupported)
Ben Clayton1c82c7b2019-04-30 12:49:27 +01001887 {
1888 SUCCEED() << "Coroutines not supported";
1889 return;
1890 }
1891
1892 Coroutine<int()> function;
1893 {
1894 Yield(Int(0));
1895 Yield(Int(1));
1896 Int current = 1;
1897 Int next = 1;
Ben Clayton713b8d32019-12-17 20:37:56 +00001898 While(true)
1899 {
Ben Clayton1c82c7b2019-04-30 12:49:27 +01001900 Yield(next);
1901 auto tmp = current + next;
1902 current = next;
1903 next = tmp;
1904 }
1905 }
1906
1907 auto coroutine = function();
1908
Antonio Maiorano8bce0672020-02-28 13:13:45 -05001909 for(size_t i = 0; i < fibonacci.size(); i++)
Ben Clayton1c82c7b2019-04-30 12:49:27 +01001910 {
1911 int out = 0;
1912 EXPECT_EQ(coroutine->await(out), true);
Antonio Maiorano8bce0672020-02-28 13:13:45 -05001913 EXPECT_EQ(out, fibonacci[i]);
Ben Clayton1c82c7b2019-04-30 12:49:27 +01001914 }
1915}
1916
1917TEST(ReactorUnitTests, Coroutines_Parameters)
1918{
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001919 if(!rr::Caps.CoroutinesSupported)
Ben Clayton1c82c7b2019-04-30 12:49:27 +01001920 {
1921 SUCCEED() << "Coroutines not supported";
1922 return;
1923 }
1924
Ben Clayton713b8d32019-12-17 20:37:56 +00001925 Coroutine<uint8_t(uint8_t * data, int count)> function;
Ben Clayton1c82c7b2019-04-30 12:49:27 +01001926 {
1927 Pointer<Byte> data = function.Arg<0>();
1928 Int count = function.Arg<1>();
1929
1930 For(Int i = 0, i < count, i++)
1931 {
1932 Yield(data[i]);
1933 }
1934 }
1935
Ben Clayton713b8d32019-12-17 20:37:56 +00001936 uint8_t data[] = { 10, 20, 30 };
Ben Clayton1c82c7b2019-04-30 12:49:27 +01001937 auto coroutine = function(&data[0], 3);
1938
1939 uint8_t out = 0;
1940 EXPECT_EQ(coroutine->await(out), true);
Ben Clayton713b8d32019-12-17 20:37:56 +00001941 EXPECT_EQ(out, 10);
1942 out = 0;
Ben Clayton1c82c7b2019-04-30 12:49:27 +01001943 EXPECT_EQ(coroutine->await(out), true);
Ben Clayton713b8d32019-12-17 20:37:56 +00001944 EXPECT_EQ(out, 20);
1945 out = 0;
Ben Clayton1c82c7b2019-04-30 12:49:27 +01001946 EXPECT_EQ(coroutine->await(out), true);
Ben Clayton713b8d32019-12-17 20:37:56 +00001947 EXPECT_EQ(out, 30);
1948 out = 99;
Ben Clayton1c82c7b2019-04-30 12:49:27 +01001949 EXPECT_EQ(coroutine->await(out), false);
1950 EXPECT_EQ(out, 99);
1951 EXPECT_EQ(coroutine->await(out), false);
1952 EXPECT_EQ(out, 99);
1953}
1954
Antonio Maiorano5ba2a5b2020-01-17 15:29:37 -05001955// This test was written because Subzero's handling of vector types
1956// failed when more than one function is generated, as is the case
1957// with coroutines.
1958TEST(ReactorUnitTests, Coroutines_Vectors)
1959{
1960 if(!rr::Caps.CoroutinesSupported)
1961 {
1962 SUCCEED() << "Coroutines not supported";
1963 return;
1964 }
1965
1966 Coroutine<int()> function;
1967 {
1968 Int4 a{ 1, 2, 3, 4 };
1969 Yield(rr::Extract(a, 2));
1970 Int4 b{ 5, 6, 7, 8 };
1971 Yield(rr::Extract(b, 1));
1972 Int4 c{ 9, 10, 11, 12 };
1973 Yield(rr::Extract(c, 1));
1974 }
1975
1976 auto coroutine = function();
1977
1978 int out;
1979 coroutine->await(out);
1980 EXPECT_EQ(out, 3);
1981 coroutine->await(out);
1982 EXPECT_EQ(out, 6);
1983 coroutine->await(out);
1984 EXPECT_EQ(out, 10);
1985}
1986
1987// This test was written to make sure a coroutine without a Yield()
1988// works correctly, by executing like a regular function with no
1989// return (the return type is ignored).
1990// We also run it twice to ensure per instance and/or global state
1991// is properly cleaned up in between.
1992TEST(ReactorUnitTests, Coroutines_NoYield)
1993{
1994 if(!rr::Caps.CoroutinesSupported)
1995 {
1996 SUCCEED() << "Coroutines not supported";
1997 return;
1998 }
1999
2000 for(int i = 0; i < 2; ++i)
2001 {
2002 Coroutine<int()> function;
2003 {
2004 Int a;
2005 a = 4;
2006 }
2007
2008 auto coroutine = function();
2009 int out;
2010 EXPECT_EQ(coroutine->await(out), false);
2011 }
2012}
2013
2014// Test generating one coroutine, and executing it on multiple threads. This makes
2015// sure the implementation manages per-call instance data correctly.
2016TEST(ReactorUnitTests, Coroutines_Parallel)
2017{
2018 if(!rr::Caps.CoroutinesSupported)
2019 {
2020 SUCCEED() << "Coroutines not supported";
2021 return;
2022 }
2023
2024 Coroutine<int()> function;
2025 {
2026 Yield(Int(0));
2027 Yield(Int(1));
2028 Int current = 1;
2029 Int next = 1;
2030 While(true)
2031 {
2032 Yield(next);
2033 auto tmp = current + next;
2034 current = next;
2035 next = tmp;
2036 }
2037 }
2038
2039 // Must call on same thread that creates the coroutine
2040 function.finalize();
2041
Antonio Maiorano5ba2a5b2020-01-17 15:29:37 -05002042 std::vector<std::thread> threads;
2043 const size_t numThreads = 100;
2044
2045 for(size_t t = 0; t < numThreads; ++t)
2046 {
2047 threads.emplace_back([&] {
2048 auto coroutine = function();
2049
Antonio Maiorano8bce0672020-02-28 13:13:45 -05002050 for(size_t i = 0; i < fibonacci.size(); i++)
Antonio Maiorano5ba2a5b2020-01-17 15:29:37 -05002051 {
2052 int out = 0;
2053 EXPECT_EQ(coroutine->await(out), true);
Antonio Maiorano8bce0672020-02-28 13:13:45 -05002054 EXPECT_EQ(out, fibonacci[i]);
Antonio Maiorano5ba2a5b2020-01-17 15:29:37 -05002055 }
2056 });
2057 }
2058
2059 for(auto &t : threads)
2060 {
2061 t.join();
2062 }
2063}
2064
Ben Clayton713b8d32019-12-17 20:37:56 +00002065template<typename TestFuncType, typename RefFuncType, typename TestValueType>
Antonio Maioranobf151b82019-12-03 09:49:14 -05002066struct IntrinsicTestParams
2067{
Ben Clayton713b8d32019-12-17 20:37:56 +00002068 std::function<TestFuncType> testFunc; // Function we're testing (Reactor)
2069 std::function<RefFuncType> refFunc; // Reference function to test against (C)
2070 std::vector<TestValueType> testValues; // Values to input to functions
Antonio Maioranobf151b82019-12-03 09:49:14 -05002071};
2072
2073using IntrinsicTestParams_Float = IntrinsicTestParams<RValue<Float>(RValue<Float>), float(float), float>;
2074using IntrinsicTestParams_Float4 = IntrinsicTestParams<RValue<Float4>(RValue<Float4>), float(float), float>;
2075using IntrinsicTestParams_Float4_Float4 = IntrinsicTestParams<RValue<Float4>(RValue<Float4>, RValue<Float4>), float(float, float), std::pair<float, float>>;
2076
Antonio Maiorano9c14bda2020-09-18 16:33:36 -04002077// TODO(b/147818976): Each function has its own precision requirements for Vulkan, sometimes broken down
2078// by input range. These are currently validated by deqp, but we can improve our own tests as well.
2079// See https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#spirvenv-precision-operation
2080constexpr double INTRINSIC_PRECISION = 1e-4;
2081
Antonio Maioranobf151b82019-12-03 09:49:14 -05002082struct IntrinsicTest_Float : public testing::TestWithParam<IntrinsicTestParams_Float>
2083{
2084 void test()
2085 {
2086 FunctionT<float(float)> function;
2087 {
2088 Return(GetParam().testFunc((Float(function.Arg<0>()))));
2089 }
2090
2091 auto routine = function("one");
2092
Ben Clayton713b8d32019-12-17 20:37:56 +00002093 for(auto &&v : GetParam().testValues)
Antonio Maioranobf151b82019-12-03 09:49:14 -05002094 {
2095 SCOPED_TRACE(v);
Antonio Maiorano9c14bda2020-09-18 16:33:36 -04002096 EXPECT_NEAR(routine(v), GetParam().refFunc(v), INTRINSIC_PRECISION);
Antonio Maioranobf151b82019-12-03 09:49:14 -05002097 }
2098 }
2099};
2100
Nicolas Capensd2af84f2020-05-14 10:55:21 -04002101using float4 = float[4];
2102using int4 = int[4];
2103
2104// TODO: Move to Reactor.hpp
2105template<>
2106struct rr::CToReactor<int[4]>
2107{
2108 using type = Int4;
2109 static Int4 cast(float[4]);
2110};
2111
2112// Value type wrapper around a <type>[4] (i.e. float4, int4)
2113template<typename T>
2114struct type4_value
2115{
2116 using E = typename std::remove_pointer_t<std::decay_t<T>>;
2117
2118 type4_value() = default;
2119 explicit type4_value(E rep)
2120 : v{ rep, rep, rep, rep }
2121 {}
2122 type4_value(E x, E y, E z, E w)
2123 : v{ x, y, z, w }
2124 {}
2125
2126 bool operator==(const type4_value &rhs) const
2127 {
2128 return std::equal(std::begin(v), std::end(v), rhs.v);
2129 }
2130
2131 // For gtest printing
2132 friend std::ostream &operator<<(std::ostream &os, const type4_value &value)
2133 {
2134 return os << "[" << value.v[0] << ", " << value.v[1] << ", " << value.v[2] << ", " << value.v[3] << "]";
2135 }
2136
2137 T v;
2138};
2139
2140using float4_value = type4_value<float4>;
2141using int4_value = type4_value<int4>;
2142
2143// Invoke a void(type4_value<T>*) routine on &v.v, returning wrapped result in v
2144template<typename RoutineType, typename T>
2145type4_value<T> invokeRoutine(RoutineType &routine, type4_value<T> v)
2146{
2147 routine(&v.v);
2148 return v;
2149}
2150
2151// Invoke a void(type4_value<T>*, type4_value<T>*) routine on &v1.v, &v2.v returning wrapped result in v1
2152template<typename RoutineType, typename T>
2153type4_value<T> invokeRoutine(RoutineType &routine, type4_value<T> v1, type4_value<T> v2)
2154{
2155 routine(&v1.v, &v2.v);
2156 return v1;
2157}
2158
Antonio Maioranobf151b82019-12-03 09:49:14 -05002159struct IntrinsicTest_Float4 : public testing::TestWithParam<IntrinsicTestParams_Float4>
2160{
2161 void test()
2162 {
Ben Clayton713b8d32019-12-17 20:37:56 +00002163 FunctionT<void(float4 *)> function;
Antonio Maioranobf151b82019-12-03 09:49:14 -05002164 {
2165 Pointer<Float4> a = function.Arg<0>();
2166 *a = GetParam().testFunc(*a);
2167 Return();
2168 }
2169
2170 auto routine = function("one");
2171
Ben Clayton713b8d32019-12-17 20:37:56 +00002172 for(auto &&v : GetParam().testValues)
Antonio Maioranobf151b82019-12-03 09:49:14 -05002173 {
2174 SCOPED_TRACE(v);
2175 float4_value result = invokeRoutine(routine, float4_value{ v });
2176 float4_value expected = float4_value{ GetParam().refFunc(v) };
Antonio Maiorano9c14bda2020-09-18 16:33:36 -04002177 EXPECT_NEAR(result.v[0], expected.v[0], INTRINSIC_PRECISION);
2178 EXPECT_NEAR(result.v[1], expected.v[1], INTRINSIC_PRECISION);
2179 EXPECT_NEAR(result.v[2], expected.v[2], INTRINSIC_PRECISION);
2180 EXPECT_NEAR(result.v[3], expected.v[3], INTRINSIC_PRECISION);
Antonio Maioranobf151b82019-12-03 09:49:14 -05002181 }
2182 }
2183};
2184
2185struct IntrinsicTest_Float4_Float4 : public testing::TestWithParam<IntrinsicTestParams_Float4_Float4>
2186{
2187 void test()
2188 {
Ben Clayton713b8d32019-12-17 20:37:56 +00002189 FunctionT<void(float4 *, float4 *)> function;
Antonio Maioranobf151b82019-12-03 09:49:14 -05002190 {
2191 Pointer<Float4> a = function.Arg<0>();
2192 Pointer<Float4> b = function.Arg<1>();
2193 *a = GetParam().testFunc(*a, *b);
2194 Return();
2195 }
2196
2197 auto routine = function("one");
2198
Ben Clayton713b8d32019-12-17 20:37:56 +00002199 for(auto &&v : GetParam().testValues)
Antonio Maioranobf151b82019-12-03 09:49:14 -05002200 {
2201 SCOPED_TRACE(v);
2202 float4_value result = invokeRoutine(routine, float4_value{ v.first }, float4_value{ v.second });
2203 float4_value expected = float4_value{ GetParam().refFunc(v.first, v.second) };
Antonio Maiorano9c14bda2020-09-18 16:33:36 -04002204 EXPECT_NEAR(result.v[0], expected.v[0], INTRINSIC_PRECISION);
2205 EXPECT_NEAR(result.v[1], expected.v[1], INTRINSIC_PRECISION);
2206 EXPECT_NEAR(result.v[2], expected.v[2], INTRINSIC_PRECISION);
2207 EXPECT_NEAR(result.v[3], expected.v[3], INTRINSIC_PRECISION);
Antonio Maioranobf151b82019-12-03 09:49:14 -05002208 }
2209 }
2210};
2211
Antonio Maiorano2d7ca9c2020-02-07 16:47:02 -05002212// clang-format off
2213INSTANTIATE_TEST_SUITE_P(IntrinsicTestParams_Float, IntrinsicTest_Float, testing::Values(
Antonio Maiorano9c14bda2020-09-18 16:33:36 -04002214 IntrinsicTestParams_Float{ [](Float v) { return rr::Exp2(v); }, exp2f, {0.f, 1.f, 123.f} },
2215 IntrinsicTestParams_Float{ [](Float v) { return rr::Log2(v); }, log2f, {1.f, 123.f} },
2216 IntrinsicTestParams_Float{ [](Float v) { return rr::Sqrt(v); }, sqrtf, {0.f, 1.f, 123.f} }
Antonio Maiorano2d7ca9c2020-02-07 16:47:02 -05002217));
2218// clang-format on
Antonio Maioranobf151b82019-12-03 09:49:14 -05002219
Antonio Maiorano2d7ca9c2020-02-07 16:47:02 -05002220// TODO(b/149110874) Use coshf/sinhf when we've implemented SpirV versions at the SpirV level
Antonio Maiorano0aef6452020-02-07 16:50:44 -05002221float vulkan_sinhf(float a)
2222{
2223 return ((expf(a) - expf(-a)) / 2);
2224}
2225float vulkan_coshf(float a)
2226{
2227 return ((expf(a) + expf(-a)) / 2);
2228}
2229
Antonio Maiorano2d7ca9c2020-02-07 16:47:02 -05002230// clang-format off
Nicolas Capensd2af84f2020-05-14 10:55:21 -04002231constexpr float PI = 3.141592653589793f;
Antonio Maiorano2d7ca9c2020-02-07 16:47:02 -05002232INSTANTIATE_TEST_SUITE_P(IntrinsicTestParams_Float4, IntrinsicTest_Float4, testing::Values(
Antonio Maiorano9c14bda2020-09-18 16:33:36 -04002233 IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Sin(v); }, sinf, {0.f, 1.f, PI, 123.f} },
2234 IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Cos(v); }, cosf, {0.f, 1.f, PI, 123.f} },
2235 IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Tan(v); }, tanf, {0.f, 1.f, PI, 123.f} },
2236 IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Asin(v, Precision::Full); }, asinf, {0.f, 1.f, -1.f} },
2237 IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Acos(v, Precision::Full); }, acosf, {0.f, 1.f, -1.f} },
2238 IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Atan(v); }, atanf, {0.f, 1.f, PI, 123.f} },
2239 IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Sinh(v); }, vulkan_sinhf, {0.f, 1.f, PI} },
2240 IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Cosh(v); }, vulkan_coshf, {0.f, 1.f, PI} },
2241 IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Tanh(v); }, tanhf, {0.f, 1.f, PI} },
2242 IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Asinh(v); }, asinhf, {0.f, 1.f, PI, 123.f} },
2243 IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Acosh(v); }, acoshf, { 1.f, PI, 123.f} },
2244 IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Atanh(v); }, atanhf, {0.f, 0.9999f, -0.9999f} },
2245 IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Exp(v); }, expf, {0.f, 1.f, PI} },
2246 IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Log(v); }, logf, {1.f, PI, 123.f} },
2247 IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Exp2(v); }, exp2f, {0.f, 1.f, PI, 123.f} },
2248 IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Log2(v); }, log2f, {1.f, PI, 123.f} },
2249 IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Sqrt(v); }, sqrtf, {0.f, 1.f, PI, 123.f} }
Antonio Maiorano2d7ca9c2020-02-07 16:47:02 -05002250));
2251// clang-format on
Antonio Maioranobf151b82019-12-03 09:49:14 -05002252
Antonio Maiorano2d7ca9c2020-02-07 16:47:02 -05002253// clang-format off
2254INSTANTIATE_TEST_SUITE_P(IntrinsicTestParams_Float4_Float4, IntrinsicTest_Float4_Float4, testing::Values(
Antonio Maiorano9c14bda2020-09-18 16:33:36 -04002255 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} } },
2256 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 -05002257));
2258// clang-format on
Antonio Maioranobf151b82019-12-03 09:49:14 -05002259
Ben Clayton713b8d32019-12-17 20:37:56 +00002260TEST_P(IntrinsicTest_Float, Test)
2261{
2262 test();
2263}
2264TEST_P(IntrinsicTest_Float4, Test)
2265{
2266 test();
2267}
2268TEST_P(IntrinsicTest_Float4_Float4, Test)
2269{
2270 test();
2271}
Antonio Maioranobf151b82019-12-03 09:49:14 -05002272
2273TEST(ReactorUnitTests, Intrinsics_Ctlz)
2274{
2275 // ctlz: counts number of leading zeros
2276
2277 {
2278 Function<UInt(UInt x)> function;
2279 {
2280 UInt x = function.Arg<0>();
2281 Return(rr::Ctlz(x, false));
2282 }
2283 auto routine = function("one");
2284 auto callable = (uint32_t(*)(uint32_t))routine->getEntry();
2285
Ben Clayton713b8d32019-12-17 20:37:56 +00002286 for(uint32_t i = 0; i < 31; ++i)
2287 {
Antonio Maioranobf151b82019-12-03 09:49:14 -05002288 uint32_t result = callable(1 << i);
2289 EXPECT_EQ(result, 31 - i);
2290 }
2291
2292 // Input 0 should return 32 for isZeroUndef == false
2293 {
2294 uint32_t result = callable(0);
2295 EXPECT_EQ(result, 32u);
2296 }
2297 }
2298
2299 {
2300 Function<Void(Pointer<UInt4>, UInt x)> function;
2301 {
2302 Pointer<UInt4> out = function.Arg<0>();
2303 UInt x = function.Arg<1>();
2304 *out = rr::Ctlz(UInt4(x), false);
2305 }
2306 auto routine = function("one");
Ben Clayton713b8d32019-12-17 20:37:56 +00002307 auto callable = (void (*)(uint32_t *, uint32_t))routine->getEntry();
Antonio Maioranobf151b82019-12-03 09:49:14 -05002308
2309 uint32_t x[4];
2310
Ben Clayton713b8d32019-12-17 20:37:56 +00002311 for(uint32_t i = 0; i < 31; ++i)
2312 {
Antonio Maioranobf151b82019-12-03 09:49:14 -05002313 callable(x, 1 << i);
2314 EXPECT_EQ(x[0], 31 - i);
2315 EXPECT_EQ(x[1], 31 - i);
2316 EXPECT_EQ(x[2], 31 - i);
2317 EXPECT_EQ(x[3], 31 - i);
2318 }
2319
2320 // Input 0 should return 32 for isZeroUndef == false
2321 {
2322 callable(x, 0);
2323 EXPECT_EQ(x[0], 32u);
2324 EXPECT_EQ(x[1], 32u);
2325 EXPECT_EQ(x[2], 32u);
2326 EXPECT_EQ(x[3], 32u);
2327 }
2328 }
2329}
2330
2331TEST(ReactorUnitTests, Intrinsics_Cttz)
2332{
2333 // cttz: counts number of trailing zeros
2334
2335 {
2336 Function<UInt(UInt x)> function;
2337 {
2338 UInt x = function.Arg<0>();
2339 Return(rr::Cttz(x, false));
2340 }
2341 auto routine = function("one");
2342 auto callable = (uint32_t(*)(uint32_t))routine->getEntry();
2343
Ben Clayton713b8d32019-12-17 20:37:56 +00002344 for(uint32_t i = 0; i < 31; ++i)
2345 {
Antonio Maioranobf151b82019-12-03 09:49:14 -05002346 uint32_t result = callable(1 << i);
2347 EXPECT_EQ(result, i);
2348 }
2349
2350 // Input 0 should return 32 for isZeroUndef == false
2351 {
2352 uint32_t result = callable(0);
2353 EXPECT_EQ(result, 32u);
2354 }
2355 }
2356
2357 {
2358 Function<Void(Pointer<UInt4>, UInt x)> function;
2359 {
2360 Pointer<UInt4> out = function.Arg<0>();
2361 UInt x = function.Arg<1>();
2362 *out = rr::Cttz(UInt4(x), false);
2363 }
2364 auto routine = function("one");
Ben Clayton713b8d32019-12-17 20:37:56 +00002365 auto callable = (void (*)(uint32_t *, uint32_t))routine->getEntry();
Antonio Maioranobf151b82019-12-03 09:49:14 -05002366
2367 uint32_t x[4];
2368
Ben Clayton713b8d32019-12-17 20:37:56 +00002369 for(uint32_t i = 0; i < 31; ++i)
2370 {
Antonio Maioranobf151b82019-12-03 09:49:14 -05002371 callable(x, 1 << i);
2372 EXPECT_EQ(x[0], i);
2373 EXPECT_EQ(x[1], i);
2374 EXPECT_EQ(x[2], i);
2375 EXPECT_EQ(x[3], i);
2376 }
2377
2378 // Input 0 should return 32 for isZeroUndef == false
2379 {
2380 callable(x, 0);
2381 EXPECT_EQ(x[0], 32u);
2382 EXPECT_EQ(x[1], 32u);
2383 EXPECT_EQ(x[2], 32u);
2384 EXPECT_EQ(x[3], 32u);
2385 }
2386 }
2387}
2388
2389TEST(ReactorUnitTests, Intrinsics_Scatter)
2390{
2391 Function<Void(Pointer<Float> base, Pointer<Float4> val, Pointer<Int4> offsets)> function;
2392 {
2393 Pointer<Float> base = function.Arg<0>();
2394 Pointer<Float4> val = function.Arg<1>();
2395 Pointer<Int4> offsets = function.Arg<2>();
2396
2397 auto mask = Int4(~0, ~0, ~0, ~0);
2398 unsigned int alignment = 1;
2399 Scatter(base, *val, *offsets, mask, alignment);
2400 }
2401
Ben Clayton713b8d32019-12-17 20:37:56 +00002402 float buffer[16] = { 0 };
Antonio Maioranobf151b82019-12-03 09:49:14 -05002403
2404 constexpr auto elemSize = sizeof(buffer[0]);
2405
Ben Clayton713b8d32019-12-17 20:37:56 +00002406 int offsets[] = {
2407 1 * elemSize,
2408 6 * elemSize,
2409 11 * elemSize,
2410 13 * elemSize
Antonio Maioranobf151b82019-12-03 09:49:14 -05002411 };
2412
Ben Clayton713b8d32019-12-17 20:37:56 +00002413 float val[4] = { 10, 60, 110, 130 };
Antonio Maioranobf151b82019-12-03 09:49:14 -05002414
2415 auto routine = function("one");
Ben Clayton713b8d32019-12-17 20:37:56 +00002416 auto entry = (void (*)(float *, float *, int *))routine->getEntry();
Antonio Maioranobf151b82019-12-03 09:49:14 -05002417
2418 entry(buffer, val, offsets);
2419
2420 EXPECT_EQ(buffer[offsets[0] / sizeof(buffer[0])], 10);
2421 EXPECT_EQ(buffer[offsets[1] / sizeof(buffer[0])], 60);
2422 EXPECT_EQ(buffer[offsets[2] / sizeof(buffer[0])], 110);
2423 EXPECT_EQ(buffer[offsets[3] / sizeof(buffer[0])], 130);
2424}
2425
2426TEST(ReactorUnitTests, Intrinsics_Gather)
2427{
2428 Function<Void(Pointer<Float> base, Pointer<Int4> offsets, Pointer<Float4> result)> function;
2429 {
2430 Pointer<Float> base = function.Arg<0>();
2431 Pointer<Int4> offsets = function.Arg<1>();
2432 Pointer<Float4> result = function.Arg<2>();
2433
2434 auto mask = Int4(~0, ~0, ~0, ~0);
2435 unsigned int alignment = 1;
2436 bool zeroMaskedLanes = true;
2437 *result = Gather(base, *offsets, mask, alignment, zeroMaskedLanes);
2438 }
2439
Ben Clayton713b8d32019-12-17 20:37:56 +00002440 float buffer[] = {
Antonio Maioranobf151b82019-12-03 09:49:14 -05002441 0, 10, 20, 30,
2442 40, 50, 60, 70,
2443 80, 90, 100, 110,
2444 120, 130, 140, 150
2445 };
2446
2447 constexpr auto elemSize = sizeof(buffer[0]);
2448
Ben Clayton713b8d32019-12-17 20:37:56 +00002449 int offsets[] = {
2450 1 * elemSize,
2451 6 * elemSize,
2452 11 * elemSize,
2453 13 * elemSize
Antonio Maioranobf151b82019-12-03 09:49:14 -05002454 };
2455
2456 auto routine = function("one");
Ben Clayton713b8d32019-12-17 20:37:56 +00002457 auto entry = (void (*)(float *, int *, float *))routine->getEntry();
Antonio Maioranobf151b82019-12-03 09:49:14 -05002458
2459 float result[4] = {};
2460 entry(buffer, offsets, result);
2461
2462 EXPECT_EQ(result[0], 10);
2463 EXPECT_EQ(result[1], 60);
2464 EXPECT_EQ(result[2], 110);
2465 EXPECT_EQ(result[3], 130);
2466}
2467
Antonio Maiorano7ffda5b2019-11-20 15:31:51 -05002468TEST(ReactorUnitTests, ExtractFromRValue)
2469{
2470 Function<Void(Pointer<Int4> values, Pointer<Int4> result)> function;
2471 {
2472 Pointer<Int4> vIn = function.Arg<0>();
2473 Pointer<Int4> resultIn = function.Arg<1>();
2474
2475 RValue<Int4> v = *vIn;
2476
2477 Int4 result(678);
2478
2479 If(Extract(v, 0) == 42)
2480 {
2481 result = Insert(result, 1, 0);
2482 }
2483
2484 If(Extract(v, 1) == 42)
2485 {
2486 result = Insert(result, 1, 1);
2487 }
2488
2489 *resultIn = result;
2490
2491 Return();
2492 }
2493
2494 auto routine = function("one");
Ben Clayton713b8d32019-12-17 20:37:56 +00002495 auto entry = (void (*)(int *, int *))routine->getEntry();
Antonio Maiorano7ffda5b2019-11-20 15:31:51 -05002496
2497 int v[4] = { 42, 42, 42, 42 };
2498 int result[4] = { 99, 99, 99, 99 };
2499 entry(v, result);
2500 EXPECT_EQ(result[0], 1);
2501 EXPECT_EQ(result[1], 1);
2502 EXPECT_EQ(result[2], 678);
2503 EXPECT_EQ(result[3], 678);
2504}
2505
Antonio Maiorano370cba52019-12-31 11:36:07 -05002506TEST(ReactorUnitTests, AddAtomic)
2507{
2508 FunctionT<uint32_t(uint32_t * p, uint32_t a)> function;
2509 {
2510 Pointer<UInt> p = function.Arg<0>();
2511 UInt a = function.Arg<1>();
2512 UInt r = rr::AddAtomic(p, a, std::memory_order_relaxed);
2513 Return(r);
2514 }
2515
2516 auto routine = function("one");
2517 uint32_t x = 123;
2518 uint32_t y = 456;
2519 uint32_t prevX = routine(&x, y);
2520 EXPECT_EQ(prevX, 123u);
2521 EXPECT_EQ(x, 579u);
2522}
2523
2524TEST(ReactorUnitTests, SubAtomic)
2525{
2526 FunctionT<uint32_t(uint32_t * p, uint32_t a)> function;
2527 {
2528 Pointer<UInt> p = function.Arg<0>();
2529 UInt a = function.Arg<1>();
2530 UInt r = rr::SubAtomic(p, a, std::memory_order_relaxed);
2531 Return(r);
2532 }
2533
2534 auto routine = function("one");
2535 uint32_t x = 456;
2536 uint32_t y = 123;
2537 uint32_t prevX = routine(&x, y);
2538 EXPECT_EQ(prevX, 456u);
2539 EXPECT_EQ(x, 333u);
2540}
2541
2542TEST(ReactorUnitTests, AndAtomic)
2543{
2544 FunctionT<uint32_t(uint32_t * p, uint32_t a)> function;
2545 {
2546 Pointer<UInt> p = function.Arg<0>();
2547 UInt a = function.Arg<1>();
2548 UInt r = rr::AndAtomic(p, a, std::memory_order_relaxed);
2549 Return(r);
2550 }
2551
2552 auto routine = function("one");
2553 uint32_t x = 0b1111'0000;
2554 uint32_t y = 0b1010'1100;
2555 uint32_t prevX = routine(&x, y);
2556 EXPECT_EQ(prevX, 0b1111'0000u);
2557 EXPECT_EQ(x, 0b1010'0000u);
2558}
2559
2560TEST(ReactorUnitTests, OrAtomic)
2561{
2562 FunctionT<uint32_t(uint32_t * p, uint32_t a)> function;
2563 {
2564 Pointer<UInt> p = function.Arg<0>();
2565 UInt a = function.Arg<1>();
2566 UInt r = rr::OrAtomic(p, a, std::memory_order_relaxed);
2567 Return(r);
2568 }
2569
2570 auto routine = function("one");
2571 uint32_t x = 0b1111'0000;
2572 uint32_t y = 0b1010'1100;
2573 uint32_t prevX = routine(&x, y);
2574 EXPECT_EQ(prevX, 0b1111'0000u);
2575 EXPECT_EQ(x, 0b1111'1100u);
2576}
2577
2578TEST(ReactorUnitTests, XorAtomic)
2579{
2580 FunctionT<uint32_t(uint32_t * p, uint32_t a)> function;
2581 {
2582 Pointer<UInt> p = function.Arg<0>();
2583 UInt a = function.Arg<1>();
2584 UInt r = rr::XorAtomic(p, a, std::memory_order_relaxed);
2585 Return(r);
2586 }
2587
2588 auto routine = function("one");
2589 uint32_t x = 0b1111'0000;
2590 uint32_t y = 0b1010'1100;
2591 uint32_t prevX = routine(&x, y);
2592 EXPECT_EQ(prevX, 0b1111'0000u);
2593 EXPECT_EQ(x, 0b0101'1100u);
2594}
2595
2596TEST(ReactorUnitTests, MinAtomic)
2597{
2598 {
2599 FunctionT<uint32_t(uint32_t * p, uint32_t a)> function;
2600 {
2601 Pointer<UInt> p = function.Arg<0>();
2602 UInt a = function.Arg<1>();
2603 UInt r = rr::MinAtomic(p, a, std::memory_order_relaxed);
2604 Return(r);
2605 }
2606
2607 auto routine = function("one");
2608 uint32_t x = 123;
2609 uint32_t y = 100;
2610 uint32_t prevX = routine(&x, y);
2611 EXPECT_EQ(prevX, 123u);
2612 EXPECT_EQ(x, 100u);
2613 }
2614
2615 {
2616 FunctionT<int32_t(int32_t * p, int32_t a)> function;
2617 {
2618 Pointer<Int> p = function.Arg<0>();
2619 Int a = function.Arg<1>();
2620 Int r = rr::MinAtomic(p, a, std::memory_order_relaxed);
2621 Return(r);
2622 }
2623
2624 auto routine = function("one");
2625 int32_t x = -123;
2626 int32_t y = -200;
2627 int32_t prevX = routine(&x, y);
2628 EXPECT_EQ(prevX, -123);
2629 EXPECT_EQ(x, -200);
2630 }
2631}
2632
2633TEST(ReactorUnitTests, MaxAtomic)
2634{
2635 {
2636 FunctionT<uint32_t(uint32_t * p, uint32_t a)> function;
2637 {
2638 Pointer<UInt> p = function.Arg<0>();
2639 UInt a = function.Arg<1>();
2640 UInt r = rr::MaxAtomic(p, a, std::memory_order_relaxed);
2641 Return(r);
2642 }
2643
2644 auto routine = function("one");
2645 uint32_t x = 123;
2646 uint32_t y = 100;
2647 uint32_t prevX = routine(&x, y);
2648 EXPECT_EQ(prevX, 123u);
2649 EXPECT_EQ(x, 123u);
2650 }
2651
2652 {
2653 FunctionT<int32_t(int32_t * p, int32_t a)> function;
2654 {
2655 Pointer<Int> p = function.Arg<0>();
2656 Int a = function.Arg<1>();
2657 Int r = rr::MaxAtomic(p, a, std::memory_order_relaxed);
2658 Return(r);
2659 }
2660
2661 auto routine = function("one");
2662 int32_t x = -123;
2663 int32_t y = -200;
2664 int32_t prevX = routine(&x, y);
2665 EXPECT_EQ(prevX, -123);
2666 EXPECT_EQ(x, -123);
2667 }
2668}
2669
2670TEST(ReactorUnitTests, ExchangeAtomic)
2671{
2672 FunctionT<uint32_t(uint32_t * p, uint32_t a)> function;
2673 {
2674 Pointer<UInt> p = function.Arg<0>();
2675 UInt a = function.Arg<1>();
2676 UInt r = rr::ExchangeAtomic(p, a, std::memory_order_relaxed);
2677 Return(r);
2678 }
2679
2680 auto routine = function("one");
2681 uint32_t x = 123;
2682 uint32_t y = 456;
2683 uint32_t prevX = routine(&x, y);
2684 EXPECT_EQ(prevX, 123u);
2685 EXPECT_EQ(x, y);
2686}
2687
2688TEST(ReactorUnitTests, CompareExchangeAtomic)
2689{
2690 FunctionT<uint32_t(uint32_t * x, uint32_t y, uint32_t compare)> function;
2691 {
2692 Pointer<UInt> x = function.Arg<0>();
2693 UInt y = function.Arg<1>();
2694 UInt compare = function.Arg<2>();
2695 UInt r = rr::CompareExchangeAtomic(x, y, compare, std::memory_order_relaxed, std::memory_order_relaxed);
2696 Return(r);
2697 }
2698
2699 auto routine = function("one");
2700 uint32_t x = 123;
2701 uint32_t y = 456;
2702 uint32_t compare = 123;
2703 uint32_t prevX = routine(&x, y, compare);
2704 EXPECT_EQ(prevX, 123u);
2705 EXPECT_EQ(x, y);
2706
2707 x = 123;
2708 y = 456;
2709 compare = 456;
2710 prevX = routine(&x, y, compare);
2711 EXPECT_EQ(prevX, 123u);
2712 EXPECT_EQ(x, 123u);
2713}
2714
Antonio Maiorano5ef91b82020-01-21 15:10:22 -05002715TEST(ReactorUnitTests, SRem)
2716{
2717 FunctionT<void(int4 *, int4 *)> function;
2718 {
2719 Pointer<Int4> a = function.Arg<0>();
2720 Pointer<Int4> b = function.Arg<1>();
2721 *a = *a % *b;
2722 }
2723
2724 auto routine = function("one");
2725
2726 int4_value result = invokeRoutine(routine, int4_value{ 10, 11, 12, 13 }, int4_value{ 3, 3, 3, 3 });
2727 int4_value expected = int4_value{ 10 % 3, 11 % 3, 12 % 3, 13 % 3 };
2728 EXPECT_FLOAT_EQ(result.v[0], expected.v[0]);
2729 EXPECT_FLOAT_EQ(result.v[1], expected.v[1]);
2730 EXPECT_FLOAT_EQ(result.v[2], expected.v[2]);
2731 EXPECT_FLOAT_EQ(result.v[3], expected.v[3]);
2732}
2733
2734TEST(ReactorUnitTests, FRem)
2735{
2736 FunctionT<void(float4 *, float4 *)> function;
2737 {
2738 Pointer<Float4> a = function.Arg<0>();
2739 Pointer<Float4> b = function.Arg<1>();
2740 *a = *a % *b;
2741 }
2742
2743 auto routine = function("one");
2744
2745 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 });
2746 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) };
2747 EXPECT_FLOAT_EQ(result.v[0], expected.v[0]);
2748 EXPECT_FLOAT_EQ(result.v[1], expected.v[1]);
2749 EXPECT_FLOAT_EQ(result.v[2], expected.v[2]);
2750 EXPECT_FLOAT_EQ(result.v[3], expected.v[3]);
2751}
2752
Antonio Maiorano02a39532020-01-21 15:15:34 -05002753// Subzero's load instruction assumes that a Constant ptr value is an offset, rather than an absolute
2754// pointer, and would fail during codegen. This was fixed by casting the constant to a non-const
2755// variable, and loading from it instead. This test makes sure this works.
2756TEST(ReactorUnitTests, LoadFromConstantData)
2757{
2758 const int value = 123;
2759
2760 FunctionT<int()> function;
2761 {
2762 auto p = Pointer<Int>{ ConstantData(&value, sizeof(value)) };
2763 Int v = *p;
2764 Return(v);
2765 }
2766
2767 const int result = function("one")();
2768 EXPECT_EQ(result, value);
2769}
2770
Ben Clayton20cf5c52019-07-01 11:13:27 +01002771TEST(ReactorUnitTests, Multithreaded_Function)
2772{
Ben Clayton587fbb92020-04-27 16:25:03 +01002773 constexpr int numThreads = 8;
2774 constexpr int numLoops = 16;
Ben Clayton20cf5c52019-07-01 11:13:27 +01002775
2776 auto threads = std::unique_ptr<std::thread[]>(new std::thread[numThreads]);
2777 auto results = std::unique_ptr<int[]>(new int[numThreads * numLoops]);
2778
2779 for(int t = 0; t < numThreads; t++)
2780 {
2781 auto threadFunc = [&](int t) {
2782 for(int l = 0; l < numLoops; l++)
2783 {
2784 FunctionT<int(int, int)> function;
2785 {
2786 Int a = function.Arg<0>();
2787 Int b = function.Arg<1>();
2788 Return((a << 16) | b);
2789 }
2790
2791 auto f = function("thread%d_loop%d", t, l);
2792 results[t * numLoops + l] = f(t, l);
2793 }
2794 };
2795 threads[t] = std::thread(threadFunc, t);
2796 }
2797
2798 for(int t = 0; t < numThreads; t++)
2799 {
2800 threads[t].join();
2801 }
2802
2803 for(int t = 0; t < numThreads; t++)
2804 {
2805 for(int l = 0; l < numLoops; l++)
2806 {
2807 auto expect = (t << 16) | l;
2808 auto result = results[t * numLoops + l];
2809 EXPECT_EQ(result, expect);
2810 }
2811 }
2812}
2813
2814TEST(ReactorUnitTests, Multithreaded_Coroutine)
2815{
2816 if(!rr::Caps.CoroutinesSupported)
2817 {
2818 SUCCEED() << "Coroutines not supported";
2819 return;
2820 }
2821
Ben Clayton587fbb92020-04-27 16:25:03 +01002822 constexpr int numThreads = 8;
2823 constexpr int numLoops = 16;
Ben Clayton20cf5c52019-07-01 11:13:27 +01002824
2825 struct Result
2826 {
2827 bool yieldReturns[3];
2828 int yieldValues[3];
2829 };
2830
2831 auto threads = std::unique_ptr<std::thread[]>(new std::thread[numThreads]);
2832 auto results = std::unique_ptr<Result[]>(new Result[numThreads * numLoops]);
2833
2834 for(int t = 0; t < numThreads; t++)
2835 {
2836 auto threadFunc = [&](int t) {
2837 for(int l = 0; l < numLoops; l++)
2838 {
2839 Coroutine<int(int, int)> function;
2840 {
2841 Int a = function.Arg<0>();
2842 Int b = function.Arg<1>();
2843 Yield(a);
2844 Yield(b);
2845 }
2846
2847 auto coroutine = function(t, l);
2848
2849 auto &result = results[t * numLoops + l];
2850 result = {};
2851 result.yieldReturns[0] = coroutine->await(result.yieldValues[0]);
2852 result.yieldReturns[1] = coroutine->await(result.yieldValues[1]);
2853 result.yieldReturns[2] = coroutine->await(result.yieldValues[2]);
2854 }
2855 };
2856 threads[t] = std::thread(threadFunc, t);
2857 }
2858
2859 for(int t = 0; t < numThreads; t++)
2860 {
2861 threads[t].join();
2862 }
2863
2864 for(int t = 0; t < numThreads; t++)
2865 {
2866 for(int l = 0; l < numLoops; l++)
2867 {
2868 auto const &result = results[t * numLoops + l];
2869 EXPECT_EQ(result.yieldReturns[0], true);
2870 EXPECT_EQ(result.yieldValues[0], t);
2871 EXPECT_EQ(result.yieldReturns[1], true);
2872 EXPECT_EQ(result.yieldValues[1], l);
2873 EXPECT_EQ(result.yieldReturns[2], false);
2874 EXPECT_EQ(result.yieldValues[2], 0);
2875 }
2876 }
2877}
2878
Nicolas Capensd2af84f2020-05-14 10:55:21 -04002879// For gtest printing of pairs
2880namespace std {
2881template<typename T, typename U>
2882std::ostream &operator<<(std::ostream &os, const std::pair<T, U> &value)
2883{
2884 return os << "{ " << value.first << ", " << value.second << " }";
2885}
2886} // namespace std
2887
2888class StdOutCapture
2889{
2890public:
2891 ~StdOutCapture()
2892 {
2893 stopIfCapturing();
2894 }
2895
2896 void start()
2897 {
2898 stopIfCapturing();
2899 capturing = true;
2900 testing::internal::CaptureStdout();
2901 }
2902
2903 std::string stop()
2904 {
2905 assert(capturing);
2906 capturing = false;
2907 return testing::internal::GetCapturedStdout();
2908 }
2909
2910private:
2911 void stopIfCapturing()
2912 {
2913 if(capturing)
2914 {
2915 // This stops the capture
2916 testing::internal::GetCapturedStdout();
2917 }
2918 }
2919
2920 bool capturing = false;
2921};
2922
2923std::vector<std::string> split(const std::string &s)
2924{
2925 std::vector<std::string> result;
2926 std::istringstream iss(s);
2927 for(std::string line; std::getline(iss, line);)
2928 {
2929 result.push_back(line);
2930 }
2931 return result;
2932}
2933
2934TEST(ReactorUnitTests, PrintPrimitiveTypes)
2935{
2936#if defined(ENABLE_RR_PRINT) && !defined(ENABLE_RR_EMIT_PRINT_LOCATION)
2937 FunctionT<void()> function;
2938 {
2939 bool b(true);
2940 int8_t i8(-1);
2941 uint8_t ui8(1);
2942 int16_t i16(-1);
2943 uint16_t ui16(1);
2944 int32_t i32(-1);
2945 uint32_t ui32(1);
2946 int64_t i64(-1);
2947 uint64_t ui64(1);
2948 float f(1);
2949 double d(2);
2950 const char *cstr = "const char*";
2951 std::string str = "std::string";
2952 int *p = nullptr;
2953
2954 RR_WATCH(b);
2955 RR_WATCH(i8);
2956 RR_WATCH(ui8);
2957 RR_WATCH(i16);
2958 RR_WATCH(ui16);
2959 RR_WATCH(i32);
2960 RR_WATCH(ui32);
2961 RR_WATCH(i64);
2962 RR_WATCH(ui64);
2963 RR_WATCH(f);
2964 RR_WATCH(d);
2965 RR_WATCH(cstr);
2966 RR_WATCH(str);
2967 RR_WATCH(p);
2968 }
2969
2970 auto routine = function("one");
2971
2972 char pNullptr[64];
2973 snprintf(pNullptr, sizeof(pNullptr), " p: %p", nullptr);
2974
2975 const char *expected[] = {
2976 " b: true",
2977 " i8: -1",
2978 " ui8: 1",
2979 " i16: -1",
2980 " ui16: 1",
2981 " i32: -1",
2982 " ui32: 1",
2983 " i64: -1",
2984 " ui64: 1",
2985 " f: 1.000000",
2986 " d: 2.000000",
2987 " cstr: const char*",
2988 " str: std::string",
2989 pNullptr,
2990 };
2991 constexpr size_t expectedSize = sizeof(expected) / sizeof(expected[0]);
2992
2993 StdOutCapture capture;
2994 capture.start();
2995 routine();
2996 auto output = split(capture.stop());
2997 for(size_t i = 0, j = 1; i < expectedSize; ++i, j += 2)
2998 {
2999 ASSERT_EQ(expected[i], output[j]);
3000 }
3001
3002#endif
3003}
3004
3005TEST(ReactorUnitTests, PrintReactorTypes)
3006{
3007#if defined(ENABLE_RR_PRINT) && !defined(ENABLE_RR_EMIT_PRINT_LOCATION)
3008 FunctionT<void()> function;
3009 {
3010 Bool b(true);
3011 Int i(-1);
3012 Int2 i2(-1, -2);
3013 Int4 i4(-1, -2, -3, -4);
3014 UInt ui(1);
3015 UInt2 ui2(1, 2);
3016 UInt4 ui4(1, 2, 3, 4);
3017 Short s(-1);
3018 Short4 s4(-1, -2, -3, -4);
3019 UShort us(1);
3020 UShort4 us4(1, 2, 3, 4);
3021 Float f(1);
3022 Float4 f4(1, 2, 3, 4);
3023 Long l(i);
3024 Pointer<Int> pi = nullptr;
3025 RValue<Int> rvi = i;
3026 Byte by('a');
3027 Byte4 by4(i4);
3028
3029 RR_WATCH(b);
3030 RR_WATCH(i);
3031 RR_WATCH(i2);
3032 RR_WATCH(i4);
3033 RR_WATCH(ui);
3034 RR_WATCH(ui2);
3035 RR_WATCH(ui4);
3036 RR_WATCH(s);
3037 RR_WATCH(s4);
3038 RR_WATCH(us);
3039 RR_WATCH(us4);
3040 RR_WATCH(f);
3041 RR_WATCH(f4);
3042 RR_WATCH(l);
3043 RR_WATCH(pi);
3044 RR_WATCH(rvi);
3045 RR_WATCH(by);
3046 RR_WATCH(by4);
3047 }
3048
3049 auto routine = function("one");
3050
3051 char piNullptr[64];
3052 snprintf(piNullptr, sizeof(piNullptr), " pi: %p", nullptr);
3053
3054 const char *expected[] = {
3055 " b: true",
3056 " i: -1",
3057 " i2: [-1, -2]",
3058 " i4: [-1, -2, -3, -4]",
3059 " ui: 1",
3060 " ui2: [1, 2]",
3061 " ui4: [1, 2, 3, 4]",
3062 " s: -1",
3063 " s4: [-1, -2, -3, -4]",
3064 " us: 1",
3065 " us4: [1, 2, 3, 4]",
3066 " f: 1.000000",
3067 " f4: [1.000000, 2.000000, 3.000000, 4.000000]",
3068 " l: -1",
3069 piNullptr,
3070 " rvi: -1",
3071 " by: 97",
3072 " by4: [255, 254, 253, 252]",
3073 };
3074 constexpr size_t expectedSize = sizeof(expected) / sizeof(expected[0]);
3075
3076 StdOutCapture capture;
3077 capture.start();
3078 routine();
3079 auto output = split(capture.stop());
3080 for(size_t i = 0, j = 1; i < expectedSize; ++i, j += 2)
3081 {
3082 ASSERT_EQ(expected[i], output[j]);
3083 }
3084
3085#endif
3086}
3087
Antonio Maiorano04bd4d82020-10-05 16:34:04 -04003088// Test constant <op> variable
3089template<typename T, typename Func>
3090T Arithmetic_LhsConstArg(T arg1, T arg2, Func f)
3091{
3092 using ReactorT = CToReactorT<T>;
3093
3094 FunctionT<T(T)> function;
3095 {
3096 ReactorT lhs = arg1;
3097 ReactorT rhs = function.template Arg<0>();
3098 ReactorT result = f(lhs, rhs);
3099 Return(result);
3100 }
3101
3102 auto routine = function("one");
3103 return routine(arg2);
3104}
3105
3106// Test variable <op> constant
3107template<typename T, typename Func>
3108T Arithmetic_RhsConstArg(T arg1, T arg2, Func f)
3109{
3110 using ReactorT = CToReactorT<T>;
3111
3112 FunctionT<T(T)> function;
3113 {
3114 ReactorT lhs = function.template Arg<0>();
3115 ReactorT rhs = arg2;
3116 ReactorT result = f(lhs, rhs);
3117 Return(result);
3118 }
3119
3120 auto routine = function("one");
3121 return routine(arg1);
3122}
3123
3124// Test constant <op> constant
3125template<typename T, typename Func>
3126T Arithmetic_TwoConstArgs(T arg1, T arg2, Func f)
3127{
3128 using ReactorT = CToReactorT<T>;
3129
3130 FunctionT<T()> function;
3131 {
3132 ReactorT lhs = arg1;
3133 ReactorT rhs = arg2;
3134 ReactorT result = f(lhs, rhs);
3135 Return(result);
3136 }
3137
3138 auto routine = function("one");
3139 return routine();
3140}
3141
3142template<typename T, typename Func>
3143void Arithmetic_ConstArgs(T arg1, T arg2, T expected, Func f)
3144{
3145 SCOPED_TRACE(std::to_string(arg1) + " <op> " + std::to_string(arg2) + " = " + std::to_string(expected));
3146 T result{};
3147 result = Arithmetic_LhsConstArg(arg1, arg2, std::forward<Func>(f));
3148 EXPECT_EQ(result, expected);
3149 result = Arithmetic_RhsConstArg(arg1, arg2, std::forward<Func>(f));
3150 EXPECT_EQ(result, expected);
3151 result = Arithmetic_TwoConstArgs(arg1, arg2, std::forward<Func>(f));
3152 EXPECT_EQ(result, expected);
3153}
3154
3155// Test that we generate valid code for when one or both args to arithmetic operations
3156// are constant. In particular, we want to validate the case for two const args, as
3157// often lowered instructions do not support this case.
3158TEST(ReactorUnitTests, Arithmetic_ConstantArgs)
3159{
3160 Arithmetic_ConstArgs(2, 3, 5, [](auto c1, auto c2) { return c1 + c2; });
3161 Arithmetic_ConstArgs(5, 3, 2, [](auto c1, auto c2) { return c1 - c2; });
3162 Arithmetic_ConstArgs(2, 3, 6, [](auto c1, auto c2) { return c1 * c2; });
3163 Arithmetic_ConstArgs(6, 3, 2, [](auto c1, auto c2) { return c1 / c2; });
3164 Arithmetic_ConstArgs(0xF0F0, 0xAAAA, 0xA0A0, [](auto c1, auto c2) { return c1 & c2; });
3165 Arithmetic_ConstArgs(0xF0F0, 0xAAAA, 0xFAFA, [](auto c1, auto c2) { return c1 | c2; });
3166 Arithmetic_ConstArgs(0xF0F0, 0xAAAA, 0x5A5A, [](auto c1, auto c2) { return c1 ^ c2; });
3167
3168 Arithmetic_ConstArgs(2.f, 3.f, 5.f, [](auto c1, auto c2) { return c1 + c2; });
3169 Arithmetic_ConstArgs(5.f, 3.f, 2.f, [](auto c1, auto c2) { return c1 - c2; });
3170 Arithmetic_ConstArgs(2.f, 3.f, 6.f, [](auto c1, auto c2) { return c1 * c2; });
3171 Arithmetic_ConstArgs(6.f, 3.f, 2.f, [](auto c1, auto c2) { return c1 / c2; });
3172}
3173
Antonio Maiorano6c839a62020-11-06 11:19:24 -05003174// Test for Subzero bad code-gen that was fixed in swiftshader-cl/50008
3175// This tests the case of copying enough arguments to local variables so that the locals
3176// get spilled to the stack when no more registers remain, and making sure these copies
3177// are generated correctly. Without the aforementioned fix, this fails 100% on Windows x86.
3178TEST(ReactorUnitTests, SpillLocalCopiesOfArgs)
3179{
3180 struct Helpers
3181 {
3182 static bool True() { return true; }
3183 };
3184
3185 const int numLoops = 5; // 2 should be enough, but loop more to make sure
3186
3187 FunctionT<int(int, int, int, int, int, int, int, int, int, int, int, int)> function;
3188 {
3189 Int result = 0;
3190 Int a1 = function.Arg<0>();
3191 Int a2 = function.Arg<1>();
3192 Int a3 = function.Arg<2>();
3193 Int a4 = function.Arg<3>();
3194 Int a5 = function.Arg<4>();
3195 Int a6 = function.Arg<5>();
3196 Int a7 = function.Arg<6>();
3197 Int a8 = function.Arg<7>();
3198 Int a9 = function.Arg<8>();
3199 Int a10 = function.Arg<9>();
3200 Int a11 = function.Arg<10>();
3201 Int a12 = function.Arg<11>();
3202
3203 for(int i = 0; i < numLoops; ++i)
3204 {
3205 // Copy all arguments to locals so that Ice::LocalVariableSplitter::handleSimpleVarAssign
3206 // creates Variable copies of arguments. We loop so that we create enough of these so
3207 // that some spill over to the stack.
3208 Int i1 = a1;
3209 Int i2 = a2;
3210 Int i3 = a3;
3211 Int i4 = a4;
3212 Int i5 = a5;
3213 Int i6 = a6;
3214 Int i7 = a7;
3215 Int i8 = a8;
3216 Int i9 = a9;
3217 Int i10 = a10;
3218 Int i11 = a11;
3219 Int i12 = a12;
3220
3221 // Forcibly materialize all variables so that Ice::Variable instances are created for each
3222 // local; otherwise, Reactor r-value optimizations kick in, and the locals are elided.
3223 Variable::materializeAll();
3224
3225 // We also need to create a separate block that uses the variables declared above
3226 // so that rr::optimize() doesn't optimize them out when attempting to eliminate stores
3227 // followed by a load in the same block.
3228 If(Call(Helpers::True))
3229 {
3230 result += (i1 + i2 + i3 + i4 + i5 + i6 + i7 + i8 + i9 + i10 + i11 + i12);
3231 }
3232 }
3233
3234 Return(result);
3235 }
3236
3237 auto routine = function("one");
3238 int result = routine(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);
3239 int expected = numLoops * (1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12);
3240 EXPECT_EQ(result, expected);
3241}
3242
Ben Clayton351be422019-04-30 12:26:57 +01003243////////////////////////////////
3244// Trait compile time checks. //
3245////////////////////////////////
3246
Ben Clayton51f08312019-11-08 14:39:26 +00003247// Assert CToReactorT resolves to expected types.
Ben Clayton713b8d32019-12-17 20:37:56 +00003248static_assert(std::is_same<CToReactorT<void>, Void>::value, "");
3249static_assert(std::is_same<CToReactorT<bool>, Bool>::value, "");
3250static_assert(std::is_same<CToReactorT<uint8_t>, Byte>::value, "");
3251static_assert(std::is_same<CToReactorT<int8_t>, SByte>::value, "");
3252static_assert(std::is_same<CToReactorT<int16_t>, Short>::value, "");
Ben Clayton51f08312019-11-08 14:39:26 +00003253static_assert(std::is_same<CToReactorT<uint16_t>, UShort>::value, "");
Ben Clayton713b8d32019-12-17 20:37:56 +00003254static_assert(std::is_same<CToReactorT<int32_t>, Int>::value, "");
Ben Clayton51f08312019-11-08 14:39:26 +00003255static_assert(std::is_same<CToReactorT<uint64_t>, Long>::value, "");
3256static_assert(std::is_same<CToReactorT<uint32_t>, UInt>::value, "");
Ben Clayton713b8d32019-12-17 20:37:56 +00003257static_assert(std::is_same<CToReactorT<float>, Float>::value, "");
Ben Clayton351be422019-04-30 12:26:57 +01003258
Ben Clayton51f08312019-11-08 14:39:26 +00003259// Assert CToReactorT for known pointer types resolves to expected types.
Ben Clayton713b8d32019-12-17 20:37:56 +00003260static_assert(std::is_same<CToReactorT<void *>, Pointer<Byte>>::value, "");
3261static_assert(std::is_same<CToReactorT<bool *>, Pointer<Bool>>::value, "");
3262static_assert(std::is_same<CToReactorT<uint8_t *>, Pointer<Byte>>::value, "");
3263static_assert(std::is_same<CToReactorT<int8_t *>, Pointer<SByte>>::value, "");
3264static_assert(std::is_same<CToReactorT<int16_t *>, Pointer<Short>>::value, "");
3265static_assert(std::is_same<CToReactorT<uint16_t *>, Pointer<UShort>>::value, "");
3266static_assert(std::is_same<CToReactorT<int32_t *>, Pointer<Int>>::value, "");
3267static_assert(std::is_same<CToReactorT<uint64_t *>, Pointer<Long>>::value, "");
3268static_assert(std::is_same<CToReactorT<uint32_t *>, Pointer<UInt>>::value, "");
3269static_assert(std::is_same<CToReactorT<float *>, Pointer<Float>>::value, "");
3270static_assert(std::is_same<CToReactorT<uint16_t **>, Pointer<Pointer<UShort>>>::value, "");
3271static_assert(std::is_same<CToReactorT<uint16_t ***>, Pointer<Pointer<Pointer<UShort>>>>::value, "");
Ben Clayton351be422019-04-30 12:26:57 +01003272
Ben Clayton51f08312019-11-08 14:39:26 +00003273// Assert CToReactorT for unknown pointer types resolves to Pointer<Byte>.
Ben Clayton713b8d32019-12-17 20:37:56 +00003274struct S
3275{};
3276static_assert(std::is_same<CToReactorT<S *>, Pointer<Byte>>::value, "");
3277static_assert(std::is_same<CToReactorT<S **>, Pointer<Pointer<Byte>>>::value, "");
3278static_assert(std::is_same<CToReactorT<S ***>, Pointer<Pointer<Pointer<Byte>>>>::value, "");
Ben Clayton351be422019-04-30 12:26:57 +01003279
3280// Assert IsRValue<> resolves true for RValue<> types.
3281static_assert(IsRValue<RValue<Void>>::value, "");
3282static_assert(IsRValue<RValue<Bool>>::value, "");
3283static_assert(IsRValue<RValue<Byte>>::value, "");
3284static_assert(IsRValue<RValue<SByte>>::value, "");
3285static_assert(IsRValue<RValue<Short>>::value, "");
3286static_assert(IsRValue<RValue<UShort>>::value, "");
3287static_assert(IsRValue<RValue<Int>>::value, "");
3288static_assert(IsRValue<RValue<Long>>::value, "");
3289static_assert(IsRValue<RValue<UInt>>::value, "");
3290static_assert(IsRValue<RValue<Float>>::value, "");
3291
3292// Assert IsLValue<> resolves true for LValue types.
3293static_assert(IsLValue<Bool>::value, "");
3294static_assert(IsLValue<Byte>::value, "");
3295static_assert(IsLValue<SByte>::value, "");
3296static_assert(IsLValue<Short>::value, "");
3297static_assert(IsLValue<UShort>::value, "");
3298static_assert(IsLValue<Int>::value, "");
3299static_assert(IsLValue<Long>::value, "");
3300static_assert(IsLValue<UInt>::value, "");
3301static_assert(IsLValue<Float>::value, "");
3302
Ben Clayton208ed402019-05-03 22:30:03 +01003303// Assert IsReference<> resolves true for Reference types.
3304static_assert(IsReference<Reference<Bool>>::value, "");
3305static_assert(IsReference<Reference<Byte>>::value, "");
3306static_assert(IsReference<Reference<SByte>>::value, "");
3307static_assert(IsReference<Reference<Short>>::value, "");
3308static_assert(IsReference<Reference<UShort>>::value, "");
3309static_assert(IsReference<Reference<Int>>::value, "");
3310static_assert(IsReference<Reference<Long>>::value, "");
3311static_assert(IsReference<Reference<UInt>>::value, "");
3312static_assert(IsReference<Reference<Float>>::value, "");
3313
Ben Clayton351be422019-04-30 12:26:57 +01003314// Assert IsRValue<> resolves false for LValue types.
3315static_assert(!IsRValue<Void>::value, "");
3316static_assert(!IsRValue<Bool>::value, "");
3317static_assert(!IsRValue<Byte>::value, "");
3318static_assert(!IsRValue<SByte>::value, "");
3319static_assert(!IsRValue<Short>::value, "");
3320static_assert(!IsRValue<UShort>::value, "");
3321static_assert(!IsRValue<Int>::value, "");
3322static_assert(!IsRValue<Long>::value, "");
3323static_assert(!IsRValue<UInt>::value, "");
3324static_assert(!IsRValue<Float>::value, "");
3325
Ben Clayton208ed402019-05-03 22:30:03 +01003326// Assert IsRValue<> resolves false for Reference types.
3327static_assert(!IsRValue<Reference<Void>>::value, "");
3328static_assert(!IsRValue<Reference<Bool>>::value, "");
3329static_assert(!IsRValue<Reference<Byte>>::value, "");
3330static_assert(!IsRValue<Reference<SByte>>::value, "");
3331static_assert(!IsRValue<Reference<Short>>::value, "");
3332static_assert(!IsRValue<Reference<UShort>>::value, "");
3333static_assert(!IsRValue<Reference<Int>>::value, "");
3334static_assert(!IsRValue<Reference<Long>>::value, "");
3335static_assert(!IsRValue<Reference<UInt>>::value, "");
3336static_assert(!IsRValue<Reference<Float>>::value, "");
3337
Ben Clayton351be422019-04-30 12:26:57 +01003338// Assert IsRValue<> resolves false for C types.
3339static_assert(!IsRValue<void>::value, "");
3340static_assert(!IsRValue<bool>::value, "");
3341static_assert(!IsRValue<uint8_t>::value, "");
3342static_assert(!IsRValue<int8_t>::value, "");
3343static_assert(!IsRValue<int16_t>::value, "");
3344static_assert(!IsRValue<uint16_t>::value, "");
3345static_assert(!IsRValue<int32_t>::value, "");
3346static_assert(!IsRValue<uint64_t>::value, "");
3347static_assert(!IsRValue<uint32_t>::value, "");
3348static_assert(!IsRValue<float>::value, "");
3349
3350// Assert IsLValue<> resolves false for RValue<> types.
3351static_assert(!IsLValue<RValue<Void>>::value, "");
3352static_assert(!IsLValue<RValue<Bool>>::value, "");
3353static_assert(!IsLValue<RValue<Byte>>::value, "");
3354static_assert(!IsLValue<RValue<SByte>>::value, "");
3355static_assert(!IsLValue<RValue<Short>>::value, "");
3356static_assert(!IsLValue<RValue<UShort>>::value, "");
3357static_assert(!IsLValue<RValue<Int>>::value, "");
3358static_assert(!IsLValue<RValue<Long>>::value, "");
3359static_assert(!IsLValue<RValue<UInt>>::value, "");
3360static_assert(!IsLValue<RValue<Float>>::value, "");
3361
3362// Assert IsLValue<> resolves false for Void type.
3363static_assert(!IsLValue<Void>::value, "");
3364
Ben Clayton208ed402019-05-03 22:30:03 +01003365// Assert IsLValue<> resolves false for Reference<> types.
3366static_assert(!IsLValue<Reference<Void>>::value, "");
3367static_assert(!IsLValue<Reference<Bool>>::value, "");
3368static_assert(!IsLValue<Reference<Byte>>::value, "");
3369static_assert(!IsLValue<Reference<SByte>>::value, "");
3370static_assert(!IsLValue<Reference<Short>>::value, "");
3371static_assert(!IsLValue<Reference<UShort>>::value, "");
3372static_assert(!IsLValue<Reference<Int>>::value, "");
3373static_assert(!IsLValue<Reference<Long>>::value, "");
3374static_assert(!IsLValue<Reference<UInt>>::value, "");
3375static_assert(!IsLValue<Reference<Float>>::value, "");
3376
Ben Clayton351be422019-04-30 12:26:57 +01003377// Assert IsLValue<> resolves false for C types.
3378static_assert(!IsLValue<void>::value, "");
3379static_assert(!IsLValue<bool>::value, "");
3380static_assert(!IsLValue<uint8_t>::value, "");
3381static_assert(!IsLValue<int8_t>::value, "");
3382static_assert(!IsLValue<int16_t>::value, "");
3383static_assert(!IsLValue<uint16_t>::value, "");
3384static_assert(!IsLValue<int32_t>::value, "");
3385static_assert(!IsLValue<uint64_t>::value, "");
3386static_assert(!IsLValue<uint32_t>::value, "");
3387static_assert(!IsLValue<float>::value, "");
3388
3389// Assert IsDefined<> resolves true for RValue<> types.
3390static_assert(IsDefined<RValue<Void>>::value, "");
3391static_assert(IsDefined<RValue<Bool>>::value, "");
3392static_assert(IsDefined<RValue<Byte>>::value, "");
3393static_assert(IsDefined<RValue<SByte>>::value, "");
3394static_assert(IsDefined<RValue<Short>>::value, "");
3395static_assert(IsDefined<RValue<UShort>>::value, "");
3396static_assert(IsDefined<RValue<Int>>::value, "");
3397static_assert(IsDefined<RValue<Long>>::value, "");
3398static_assert(IsDefined<RValue<UInt>>::value, "");
3399static_assert(IsDefined<RValue<Float>>::value, "");
3400
3401// Assert IsDefined<> resolves true for LValue types.
3402static_assert(IsDefined<Void>::value, "");
3403static_assert(IsDefined<Bool>::value, "");
3404static_assert(IsDefined<Byte>::value, "");
3405static_assert(IsDefined<SByte>::value, "");
3406static_assert(IsDefined<Short>::value, "");
3407static_assert(IsDefined<UShort>::value, "");
3408static_assert(IsDefined<Int>::value, "");
3409static_assert(IsDefined<Long>::value, "");
3410static_assert(IsDefined<UInt>::value, "");
3411static_assert(IsDefined<Float>::value, "");
3412
Ben Clayton208ed402019-05-03 22:30:03 +01003413// Assert IsDefined<> resolves true for Reference<> types.
3414static_assert(IsDefined<Reference<Bool>>::value, "");
3415static_assert(IsDefined<Reference<Byte>>::value, "");
3416static_assert(IsDefined<Reference<SByte>>::value, "");
3417static_assert(IsDefined<Reference<Short>>::value, "");
3418static_assert(IsDefined<Reference<UShort>>::value, "");
3419static_assert(IsDefined<Reference<Int>>::value, "");
3420static_assert(IsDefined<Reference<Long>>::value, "");
3421static_assert(IsDefined<Reference<UInt>>::value, "");
3422static_assert(IsDefined<Reference<Float>>::value, "");
3423
Ben Clayton351be422019-04-30 12:26:57 +01003424// Assert IsDefined<> resolves true for C types.
3425static_assert(IsDefined<void>::value, "");
3426static_assert(IsDefined<bool>::value, "");
3427static_assert(IsDefined<uint8_t>::value, "");
3428static_assert(IsDefined<int8_t>::value, "");
3429static_assert(IsDefined<int16_t>::value, "");
3430static_assert(IsDefined<uint16_t>::value, "");
3431static_assert(IsDefined<int32_t>::value, "");
3432static_assert(IsDefined<uint64_t>::value, "");
3433static_assert(IsDefined<uint32_t>::value, "");
3434static_assert(IsDefined<float>::value, "");